diff options
author | Waldemar Brodkorb <wbx@openadk.org> | 2016-04-09 12:48:08 +0200 |
---|---|---|
committer | Waldemar Brodkorb <wbx@uclibc-ng.org> | 2016-06-30 03:44:10 +0200 |
commit | 7ed4d2a409cb24e7beef850c6b90e47f0f6b71d2 (patch) | |
tree | bc1ebdfaa9cafaab8c30fa915ff98f51a5509eee /target/linux | |
parent | c5990c364e54fae1b1d0da5f88d3cf7c9c0ba782 (diff) |
add support for nds32 architecture
Verified on a FPGA board sponsored by Andes Technology.
Signed-off-by: Waldemar Brodkorb <wbx@openadk.org>
Diffstat (limited to 'target/linux')
-rw-r--r-- | target/linux/config/Config.in.ethernet | 10 | ||||
-rw-r--r-- | target/linux/config/Config.in.kernel | 4 | ||||
-rw-r--r-- | target/linux/config/Config.in.serial | 6 | ||||
-rw-r--r-- | target/linux/patches/3.4.112/nds32.patch | 72132 |
4 files changed, 72151 insertions, 1 deletions
diff --git a/target/linux/config/Config.in.ethernet b/target/linux/config/Config.in.ethernet index 6ef03ee4b..cfb12e1db 100644 --- a/target/linux/config/Config.in.ethernet +++ b/target/linux/config/Config.in.ethernet @@ -23,6 +23,9 @@ config ADK_KERNEL_NET_VENDOR_IBM config ADK_KERNEL_NET_VENDOR_INTEL bool +config ADK_KERNEL_NET_VENDOR_FARADAY + bool + config ADK_KERNEL_NET_VENDOR_FREESCALE bool @@ -400,6 +403,13 @@ config ADK_KERNEL_ETHOC default y if ADK_TARGET_SYSTEM_QEMU_OR1K default n +config ADK_KERNEL_FTMAC100 + bool "Andes ethernet driver" + select ADK_KERNEL_NET_VENDOR_FARADAY + depends on ADK_TARGET_SYSTEM_ANDES_AG101P + default y if ADK_TARGET_SYSTEM_ANDES_AG101P + default n + config ADK_KERNEL_ATL1 tristate "Atheros/Attansic L1 Gigabit Ethernet support" select ADK_KERNEL_NET_VENDOR_ATHEROS diff --git a/target/linux/config/Config.in.kernel b/target/linux/config/Config.in.kernel index b52c621d1..924d0e6e6 100644 --- a/target/linux/config/Config.in.kernel +++ b/target/linux/config/Config.in.kernel @@ -58,11 +58,15 @@ config ADK_KERNEL_CPU_LITTLE_ENDIAN menu "Kernel options" +config ADK_KERNEL_HOTPLUG + bool + config ADK_KERNEL_DEVTMPFS bool config ADK_KERNEL_DEVTMPFS_MOUNT bool + select ADK_KERNEL_HOTPLUG config ADK_KERNEL_UEVENT_HELPER bool diff --git a/target/linux/config/Config.in.serial b/target/linux/config/Config.in.serial index 113599149..82d745271 100644 --- a/target/linux/config/Config.in.serial +++ b/target/linux/config/Config.in.serial @@ -2,7 +2,7 @@ # material, please see the LICENCE file in the top-level directory. menu "Serial devices support" -depends on ADK_TARGET_WITH_SERIAL || ADK_TARGET_QEMU || ADK_TARGET_VBOX || ADK_TARGET_SIM +depends on ADK_TARGET_WITH_SERIAL || ADK_TARGET_QEMU || ADK_TARGET_VBOX || ADK_TARGET_SIM || ADK_TARGET_GENERIC config ADK_KERNEL_SERIAL_8250_CONSOLE bool @@ -90,6 +90,7 @@ config ADK_KERNEL_SERIAL_8250 depends on ADK_TARGET_SYSTEM_XILINX_KINTEX7 \ || ADK_TARGET_SYSTEM_IMGTEC_CI20 \ || ADK_TARGET_SYSTEM_LINKSYS_NSLU2 \ + || ADK_TARGET_SYSTEM_ANDES_AG101P \ || ADK_TARGET_SYSTEM_PCENGINES_APU \ || ADK_TARGET_SYSTEM_PCENGINES_ALIX \ || ADK_TARGET_SYSTEM_QEMU_MICROBLAZE_ML605 \ @@ -102,6 +103,7 @@ config ADK_KERNEL_SERIAL_8250 || ADK_TARGET_SYSTEM_QEMU_XTENSA \ || ADK_TARGET_SYSTEM_OR1K_SIM \ || ADK_TARGET_SYSTEM_IBM_X40 \ + || ADK_TARGET_SYSTEM_GENERIC_NDS32 \ || ADK_TARGET_SYSTEM_GENERIC_X86 \ || ADK_TARGET_SYSTEM_GENERIC_X86_64 \ || ADK_TARGET_SYSTEM_MIKROTIK_RB532 \ @@ -109,6 +111,7 @@ config ADK_KERNEL_SERIAL_8250 default y if ADK_TARGET_SYSTEM_XILINX_KINTEX7 default y if ADK_TARGET_SYSTEM_IMGTEC_CI20 default y if ADK_TARGET_SYSTEM_LINKSYS_NSLU2 + default y if ADK_TARGET_SYSTEM_ANDES_AG101P default y if ADK_TARGET_SYSTEM_PCENGINES_APU default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX default y if ADK_TARGET_SYSTEM_QEMU_MICROBLAZE_ML605 @@ -121,6 +124,7 @@ config ADK_KERNEL_SERIAL_8250 default y if ADK_TARGET_SYSTEM_QEMU_XTENSA default y if ADK_TARGET_SYSTEM_OR1K_SIM default y if ADK_TARGET_SYSTEM_IBM_X40 + default y if ADK_TARGET_SYSTEM_GENERIC_NDS32 default y if ADK_TARGET_SYSTEM_GENERIC_X86 default y if ADK_TARGET_SYSTEM_GENERIC_X86_64 default y if ADK_TARGET_SYSTEM_MIKROTIK_RB532 diff --git a/target/linux/patches/3.4.112/nds32.patch b/target/linux/patches/3.4.112/nds32.patch new file mode 100644 index 000000000..d0da6f7b3 --- /dev/null +++ b/target/linux/patches/3.4.112/nds32.patch @@ -0,0 +1,72132 @@ +diff -Nur linux-3.4.110.orig/arch/nds32/boot/install.sh linux-3.4.110/arch/nds32/boot/install.sh +--- linux-3.4.110.orig/arch/nds32/boot/install.sh 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/boot/install.sh 2016-04-07 10:20:50.862077930 +0200 +@@ -0,0 +1,47 @@ ++#!/bin/sh ++# ++# arch/nds32/boot/install.sh ++# ++# 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) 1995 by Linus Torvalds ++# Copyright (C) 2009 Andes Technology Corporation ++# ++# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin ++# Adapted from code in arch/i386/boot/install.sh by Russell King ++# ++# "make install" script for arm architecture ++# ++# Arguments: ++# $1 - kernel version ++# $2 - kernel image file ++# $3 - kernel map file ++# $4 - default install path (blank if root directory) ++# ++ ++# User may have a custom install script ++if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi ++if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi ++ ++# Normal install ++echo "Installing normal kernel" ++base=vmlinux ++ ++if [ -f $4/$base-$1 ]; then ++ mv $4/$base-$1 $4/$base-$1.old ++fi ++cat $2 > $4/$base-$1 ++ ++# Install system map file ++if [ -f $4/System.map-$1 ]; then ++ mv $4/System.map-$1 $4/System.map-$1.old ++fi ++cp $3 $4/System.map-$1 ++ ++if [ -x /sbin/loadmap ]; then ++ /sbin/loadmap ++else ++ echo "You have to install it yourself" ++fi +diff -Nur linux-3.4.110.orig/arch/nds32/boot/Makefile linux-3.4.110/arch/nds32/boot/Makefile +--- linux-3.4.110.orig/arch/nds32/boot/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/boot/Makefile 2016-04-07 10:20:50.862077930 +0200 +@@ -0,0 +1,22 @@ ++# ++# arch/nds32/boot/Makefile ++# ++# 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) 1995-2002 Russell King ++# Copyright (C) 2009 Andes Technology Corporation ++# ++ ++targets := Image ++ ++$(obj)/Image: vmlinux FORCE ++ $(call if_changed,objcopy) ++ @echo ' Kernel: $@ is ready' ++ ++.PHONY: FORCE ++install: $(obj)/Image ++ $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \ ++ $(obj)/Image System.map "$(INSTALL_PATH)" ++ +diff -Nur linux-3.4.110.orig/arch/nds32/common/dmabounce.c linux-3.4.110/arch/nds32/common/dmabounce.c +--- linux-3.4.110.orig/arch/nds32/common/dmabounce.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/common/dmabounce.c 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,672 @@ ++/* ++ * arch/nds32/common/dmabounce.c ++ * ++ * Special dma_{map/unmap/dma_sync}_* routines for systems that have ++ * limited DMA windows. These functions utilize bounce buffers to ++ * copy data to/from buffers located outside the DMA region. This ++ * only works for systems in which DMA memory is at the bottom of ++ * RAM and the remainder of memory is at the top an the DMA memory ++ * can be marked as ZONE_DMA. Anything beyond that such as discontigous ++ * DMA windows will require custom implementations that reserve memory ++ * areas at early bootup. ++ * ++ * Original version by Brad Parker (brad@heeltoe.com) ++ * Re-written by Christopher Hoover <ch@murgatroid.com> ++ * Made generic by Deepak Saxena <dsaxena@plexity.net> ++ * ++ * Copyright (C) 2002 Hewlett Packard Company. ++ * Copyright (C) 2004 MontaVista Software, Inc. ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/device.h> ++#include <linux/dma-mapping.h> ++#include <linux/dmapool.h> ++#include <linux/list.h> ++ ++#undef DEBUG ++ ++#undef STATS ++#ifdef STATS ++#define DO_STATS(X) do { X ; } while (0) ++#else ++#define DO_STATS(X) do { } while (0) ++#endif ++ ++/* ************************************************** */ ++ ++struct safe_buffer { ++ struct list_head node; ++ ++ /* original request */ ++ void *ptr; ++ size_t size; ++ int direction; ++ ++ /* safe buffer info */ ++ struct dma_pool *pool; ++ void *safe; ++ dma_addr_t safe_dma_addr; ++}; ++ ++struct dmabounce_device_info { ++ struct list_head node; ++ ++ struct device *dev; ++ struct dma_pool *small_buffer_pool; ++ struct dma_pool *large_buffer_pool; ++ struct list_head safe_buffers; ++ unsigned long small_buffer_size, large_buffer_size; ++#ifdef STATS ++ unsigned long sbp_allocs; ++ unsigned long lbp_allocs; ++ unsigned long total_allocs; ++ unsigned long map_op_count; ++ unsigned long bounce_count; ++#endif ++}; ++ ++static LIST_HEAD(dmabounce_devs); ++ ++#ifdef STATS ++static void print_alloc_stats(struct dmabounce_device_info *device_info) ++{ ++ printk(KERN_INFO ++ "%s: dmabounce: sbp: %lu, lbp: %lu, other: %lu, total: %lu\n", ++ device_info->dev->bus_id, ++ device_info->sbp_allocs, device_info->lbp_allocs, ++ device_info->total_allocs - device_info->sbp_allocs - ++ device_info->lbp_allocs, device_info->total_allocs); ++} ++#endif ++ ++/* find the given device in the dmabounce device list */ ++static inline struct dmabounce_device_info *find_dmabounce_dev(struct device ++ *dev) ++{ ++ struct list_head *entry; ++ ++ list_for_each(entry, &dmabounce_devs) { ++ struct dmabounce_device_info *d = ++ list_entry(entry, struct dmabounce_device_info, node); ++ ++ if (d->dev == dev) ++ return d; ++ } ++ return NULL; ++} ++ ++/* allocate a 'safe' buffer and keep track of it */ ++static inline struct safe_buffer *alloc_safe_buffer(struct dmabounce_device_info ++ *device_info, void *ptr, ++ size_t size, ++ enum dma_data_direction dir) ++{ ++ struct safe_buffer *buf; ++ struct dma_pool *pool; ++ struct device *dev = device_info->dev; ++ void *safe; ++ dma_addr_t safe_dma_addr; ++ ++ dev_dbg(dev, "%s(ptr=%p, size=%d, dir=%d)\n", __func__, ptr, size, dir); ++ ++ DO_STATS(device_info->total_allocs++); ++ ++ buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC); ++ if (buf == NULL) { ++ dev_warn(dev, "%s: kmalloc failed\n", __func__); ++ return NULL; ++ } ++ ++ if (size <= device_info->small_buffer_size) { ++ pool = device_info->small_buffer_pool; ++ safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); ++ ++ DO_STATS(device_info->sbp_allocs++); ++ } else if (size <= device_info->large_buffer_size) { ++ pool = device_info->large_buffer_pool; ++ safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); ++ ++ DO_STATS(device_info->lbp_allocs++); ++ } else { ++ pool = NULL; ++ safe = ++ dma_alloc_coherent(dev, size, &safe_dma_addr, GFP_ATOMIC); ++ } ++ ++ if (safe == NULL) { ++ dev_warn(device_info->dev, ++ "%s: could not alloc dma memory (size=%d)\n", ++ __func__, size); ++ kfree(buf); ++ return NULL; ++ } ++#ifdef STATS ++ if (device_info->total_allocs % 1000 == 0) ++ print_alloc_stats(device_info); ++#endif ++ ++ buf->ptr = ptr; ++ buf->size = size; ++ buf->direction = dir; ++ buf->pool = pool; ++ buf->safe = safe; ++ buf->safe_dma_addr = safe_dma_addr; ++ ++ list_add(&buf->node, &device_info->safe_buffers); ++ ++ return buf; ++} ++ ++/* determine if a buffer is from our "safe" pool */ ++static inline struct safe_buffer *find_safe_buffer(struct dmabounce_device_info ++ *device_info, ++ dma_addr_t safe_dma_addr) ++{ ++ struct list_head *entry; ++ ++ list_for_each(entry, &device_info->safe_buffers) { ++ struct safe_buffer *b = ++ list_entry(entry, struct safe_buffer, node); ++ ++ if (b->safe_dma_addr == safe_dma_addr) ++ return b; ++ } ++ ++ return NULL; ++} ++ ++static inline void ++free_safe_buffer(struct dmabounce_device_info *device_info, ++ struct safe_buffer *buf) ++{ ++ dev_dbg(device_info->dev, "%s(buf=%p)\n", __func__, buf); ++ ++ list_del(&buf->node); ++ ++ if (buf->pool) ++ dma_pool_free(buf->pool, buf->safe, buf->safe_dma_addr); ++ else ++ dma_free_coherent(device_info->dev, buf->size, buf->safe, ++ buf->safe_dma_addr); ++ ++ kfree(buf); ++} ++ ++/* ************************************************** */ ++ ++#ifdef STATS ++ ++static void print_map_stats(struct dmabounce_device_info *device_info) ++{ ++ printk(KERN_INFO ++ "%s: dmabounce: map_op_count=%lu, bounce_count=%lu\n", ++ device_info->dev->bus_id, ++ device_info->map_op_count, device_info->bounce_count); ++} ++#endif ++ ++static inline dma_addr_t ++map_single(struct device *dev, void *ptr, size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); ++ dma_addr_t dma_addr; ++ int needs_bounce = 0; ++ ++ if (device_info) ++ DO_STATS(device_info->map_op_count++); ++ ++ dma_addr = virt_to_dma(dev, ptr); ++ ++ if (dev->dma_mask) { ++ unsigned long mask = *dev->dma_mask; ++ unsigned long limit; ++ ++ limit = (mask + 1) & ~mask; ++ if (limit && size > limit) { ++ dev_err(dev, "DMA mapping too big (requested %#x " ++ "mask %#Lx)\n", size, *dev->dma_mask); ++ return ~0; ++ } ++ ++ /* ++ * Figure out if we need to bounce from the DMA mask. ++ */ ++ needs_bounce = (dma_addr | (dma_addr + size - 1)) & ~mask; ++ } ++ ++ if (device_info ++ && (needs_bounce || dma_needs_bounce(dev, dma_addr, size))) { ++ struct safe_buffer *buf; ++ ++ buf = alloc_safe_buffer(device_info, ptr, size, dir); ++ if (buf == 0) { ++ dev_err(dev, "%s: unable to map unsafe buffer %p!\n", ++ __func__, ptr); ++ return 0; ++ } ++ ++ dev_dbg(dev, ++ "%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", ++ __func__, buf->ptr, (void *)virt_to_dma(dev, buf->ptr), ++ buf->safe, (void *)buf->safe_dma_addr); ++ ++ if ((dir == DMA_TO_DEVICE) || (dir == DMA_BIDIRECTIONAL)) { ++ dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", ++ __func__, ptr, buf->safe, size); ++ memcpy(buf->safe, ptr, size); ++ } ++ consistent_sync(buf->safe, size, dir); ++ ++ dma_addr = buf->safe_dma_addr; ++ } else { ++ consistent_sync(ptr, size, dir); ++ } ++ ++ return dma_addr; ++} ++ ++static inline void ++unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); ++ struct safe_buffer *buf = NULL; ++ ++ /* ++ * Trying to unmap an invalid mapping ++ */ ++ if (dma_addr == ~0) { ++ dev_err(dev, "Trying to unmap invalid mapping\n"); ++ return; ++ } ++ ++ if (device_info) ++ buf = find_safe_buffer(device_info, dma_addr); ++ ++ if (buf) { ++ BUG_ON(buf->size != size); ++ ++ dev_dbg(dev, ++ "%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", ++ __func__, buf->ptr, (void *)virt_to_dma(dev, buf->ptr), ++ buf->safe, (void *)buf->safe_dma_addr); ++ ++ DO_STATS(device_info->bounce_count++); ++ ++ if ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)) { ++ dev_dbg(dev, ++ "%s: copy back safe %p to unsafe %p size %d\n", ++ __func__, buf->safe, buf->ptr, size); ++ memcpy(buf->ptr, buf->safe, size); ++ } ++ free_safe_buffer(device_info, buf); ++ } ++} ++ ++static inline void ++sync_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); ++ struct safe_buffer *buf = NULL; ++ ++ if (device_info) ++ buf = find_safe_buffer(device_info, dma_addr); ++ ++ if (buf) { ++ /* ++ * Both of these checks from original code need to be ++ * commented out b/c some drivers rely on the following: ++ * ++ * 1) Drivers may map a large chunk of memory into DMA space ++ * but only sync a small portion of it. Good example is ++ * allocating a large buffer, mapping it, and then ++ * breaking it up into small descriptors. No point ++ * in syncing the whole buffer if you only have to ++ * touch one descriptor. ++ * ++ * 2) Buffers that are mapped as DMA_BIDIRECTIONAL are ++ * usually only synced in one dir at a time. ++ * ++ * See drivers/net/eepro100.c for examples of both cases. ++ * ++ * -ds ++ * ++ * BUG_ON(buf->size != size); ++ * BUG_ON(buf->direction != dir); ++ */ ++ ++ dev_dbg(dev, ++ "%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", ++ __func__, buf->ptr, (void *)virt_to_dma(dev, buf->ptr), ++ buf->safe, (void *)buf->safe_dma_addr); ++ ++ DO_STATS(device_info->bounce_count++); ++ ++ switch (dir) { ++ case DMA_FROM_DEVICE: ++ dev_dbg(dev, ++ "%s: copy back safe %p to unsafe %p size %d\n", ++ __func__, buf->safe, buf->ptr, size); ++ memcpy(buf->ptr, buf->safe, size); ++ break; ++ case DMA_TO_DEVICE: ++ dev_dbg(dev, ++ "%s: copy out unsafe %p to safe %p, size %d\n", ++ __func__, buf->ptr, buf->safe, size); ++ memcpy(buf->safe, buf->ptr, size); ++ break; ++ case DMA_BIDIRECTIONAL: ++ BUG(); /* is this allowed? what does it mean? */ ++ default: ++ BUG(); ++ } ++ consistent_sync(buf->safe, size, dir); ++ } else { ++ consistent_sync(dma_to_virt(dev, dma_addr), size, dir); ++ } ++} ++ ++/* ************************************************** */ ++ ++/* ++ * see if a buffer address is in an 'unsafe' range. if it is ++ * allocate a 'safe' buffer and copy the unsafe buffer into it. ++ * substitute the safe buffer for the unsafe one. ++ * (basically move the buffer from an unsafe area to a safe one) ++ */ ++dma_addr_t ++dma_map_single(struct device *dev, void *ptr, size_t size, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ dma_addr_t dma_addr; ++ ++ dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", __func__, ptr, size, dir); ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ local_irq_save(flags); ++ ++ dma_addr = map_single(dev, ptr, size, dir); ++ ++ local_irq_restore(flags); ++ ++ return dma_addr; ++} ++ ++/* ++ * see if a mapped address was really a "safe" buffer and if so, copy ++ * the data from the safe buffer back to the unsafe buffer and free up ++ * the safe buffer. (basically return things back to the way they ++ * should be) ++ */ ++ ++void ++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ ++ dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", ++ __func__, (void *)dma_addr, size, dir); ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ local_irq_save(flags); ++ ++ unmap_single(dev, dma_addr, size, dir); ++ ++ local_irq_restore(flags); ++} ++ ++int ++dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ int i; ++ ++ dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", __func__, sg, nents, dir); ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ local_irq_save(flags); ++ ++ for (i = 0; i < nents; i++, sg++) { ++ struct page *page = sg->page; ++ unsigned int offset = sg->offset; ++ unsigned int length = sg->length; ++ void *ptr = page_address(page) + offset; ++ ++ sg->dma_address = map_single(dev, ptr, length, dir); ++ } ++ ++ local_irq_restore(flags); ++ ++ return nents; ++} ++ ++void ++dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ int i; ++ ++ dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", __func__, sg, nents, dir); ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ local_irq_save(flags); ++ ++ for (i = 0; i < nents; i++, sg++) { ++ dma_addr_t dma_addr = sg->dma_address; ++ unsigned int length = sg->length; ++ ++ unmap_single(dev, dma_addr, length, dir); ++ } ++ ++ local_irq_restore(flags); ++} ++ ++void ++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ ++ dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", ++ __func__, (void *)dma_addr, size, dir); ++ ++ local_irq_save(flags); ++ ++ sync_single(dev, dma_addr, size, dir); ++ ++ local_irq_restore(flags); ++} ++ ++void ++dma_sync_single_for_device(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ ++ dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", ++ __func__, (void *)dma_addr, size, dir); ++ ++ local_irq_save(flags); ++ ++ sync_single(dev, dma_addr, size, dir); ++ ++ local_irq_restore(flags); ++} ++ ++void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ int i; ++ ++ dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", __func__, sg, nents, dir); ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ local_irq_save(flags); ++ ++ for (i = 0; i < nents; i++, sg++) { ++ dma_addr_t dma_addr = sg->dma_address; ++ unsigned int length = sg->length; ++ ++ sync_single(dev, dma_addr, length, dir); ++ } ++ ++ local_irq_restore(flags); ++} ++ ++void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ int i; ++ ++ dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", __func__, sg, nents, dir); ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ local_irq_save(flags); ++ ++ for (i = 0; i < nents; i++, sg++) { ++ dma_addr_t dma_addr = sg->dma_address; ++ unsigned int length = sg->length; ++ ++ sync_single(dev, dma_addr, length, dir); ++ } ++ ++ local_irq_restore(flags); ++} ++ ++int ++dmabounce_register_dev(struct device *dev, unsigned long small_buffer_size, ++ unsigned long large_buffer_size) ++{ ++ struct dmabounce_device_info *device_info; ++ ++ device_info = kmalloc(sizeof(struct dmabounce_device_info), GFP_ATOMIC); ++ if (!device_info) { ++ printk(KERN_ERR ++ "Could not allocated dmabounce_device_info for %s", ++ dev->bus_id); ++ return -ENOMEM; ++ } ++ ++ device_info->small_buffer_pool = ++ dma_pool_create("small_dmabounce_pool", ++ dev, small_buffer_size, 0 /* byte alignment */ , ++ 0 /* no page-crossing issues */ ); ++ if (!device_info->small_buffer_pool) { ++ printk(KERN_ERR ++ "dmabounce: could not allocate small DMA pool for %s\n", ++ dev->bus_id); ++ kfree(device_info); ++ return -ENOMEM; ++ } ++ ++ if (large_buffer_size) { ++ device_info->large_buffer_pool = ++ dma_pool_create("large_dmabounce_pool", ++ dev, ++ large_buffer_size, 0 /* byte alignment */ , ++ 0 /* no page-crossing issues */ ); ++ if (!device_info->large_buffer_pool) { ++ printk(KERN_ERR ++ "dmabounce: could not allocate large DMA pool for %s\n", ++ dev->bus_id); ++ dma_pool_destroy(device_info->small_buffer_pool); ++ ++ return -ENOMEM; ++ } ++ } ++ ++ device_info->dev = dev; ++ device_info->small_buffer_size = small_buffer_size; ++ device_info->large_buffer_size = large_buffer_size; ++ INIT_LIST_HEAD(&device_info->safe_buffers); ++ ++#ifdef STATS ++ device_info->sbp_allocs = 0; ++ device_info->lbp_allocs = 0; ++ device_info->total_allocs = 0; ++ device_info->map_op_count = 0; ++ device_info->bounce_count = 0; ++#endif ++ ++ list_add(&device_info->node, &dmabounce_devs); ++ ++ printk(KERN_INFO "dmabounce: registered device %s on %s bus\n", ++ dev->bus_id, dev->bus->name); ++ ++ return 0; ++} ++ ++void dmabounce_unregister_dev(struct device *dev) ++{ ++ struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); ++ ++ if (!device_info) { ++ printk(KERN_WARNING ++ "%s: Never registered with dmabounce but attempting" ++ "to unregister!\n", dev->bus_id); ++ return; ++ } ++ ++ if (!list_empty(&device_info->safe_buffers)) { ++ printk(KERN_ERR ++ "%s: Removing from dmabounce with pending buffers!\n", ++ dev->bus_id); ++ BUG(); ++ } ++ ++ if (device_info->small_buffer_pool) ++ dma_pool_destroy(device_info->small_buffer_pool); ++ if (device_info->large_buffer_pool) ++ dma_pool_destroy(device_info->large_buffer_pool); ++ ++#ifdef STATS ++ print_alloc_stats(device_info); ++ print_map_stats(device_info); ++#endif ++ ++ list_del(&device_info->node); ++ ++ kfree(device_info); ++ ++ printk(KERN_INFO "dmabounce: device %s on %s bus unregistered\n", ++ dev->bus_id, dev->bus->name); ++} ++ ++EXPORT_SYMBOL(dma_map_single); ++EXPORT_SYMBOL(dma_unmap_single); ++EXPORT_SYMBOL(dma_map_sg); ++EXPORT_SYMBOL(dma_unmap_sg); ++EXPORT_SYMBOL(dma_sync_single); ++EXPORT_SYMBOL(dma_sync_sg); ++EXPORT_SYMBOL(dmabounce_register_dev); ++EXPORT_SYMBOL(dmabounce_unregister_dev); ++ ++MODULE_AUTHOR ++ ("Christopher Hoover <ch@hpl.hp.com>, Deepak Saxena <dsaxena@plexity.net>"); ++MODULE_DESCRIPTION ++ ("Special dma_{map/unmap/dma_sync}_* routines for systems with limited DMA windows"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.4.110.orig/arch/nds32/common/Makefile linux-3.4.110/arch/nds32/common/Makefile +--- linux-3.4.110.orig/arch/nds32/common/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/common/Makefile 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,6 @@ ++# ++# Makefile for the linux kernel. ++# ++ ++obj-y += rtctime.o ++obj-$(CONFIG_DMABOUNCE) += dmabounce.o +diff -Nur linux-3.4.110.orig/arch/nds32/common/rtctime.c linux-3.4.110/arch/nds32/common/rtctime.c +--- linux-3.4.110.orig/arch/nds32/common/rtctime.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/common/rtctime.c 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,441 @@ ++/* ++ * linux/arch/nds32/common/rtctime.c ++ * ++ * Copyright (C) 2003 Deep Blue Solutions Ltd. ++ * Based on sa1100-rtc.c, Nils Faerber, CIH, Nicolas Pitre. ++ * Based on rtc.c by Paul Gortmaker ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/time.h> ++#include <linux/rtc.h> ++#include <linux/poll.h> ++#include <linux/proc_fs.h> ++#include <linux/miscdevice.h> ++#include <linux/spinlock.h> ++#include <linux/capability.h> ++#include <linux/device.h> ++#include <linux/mutex.h> ++#include <linux/rtc.h> ++ ++#include <asm/rtc.h> ++#include <asm/semaphore.h> ++ ++static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); ++static struct fasync_struct *rtc_async_queue; ++ ++/* ++ * rtc_lock protects rtc_irq_data ++ */ ++static DEFINE_SPINLOCK(rtc_lock); ++static unsigned long rtc_irq_data; ++ ++/* ++ * rtc_sem protects rtc_inuse and rtc_ops ++ */ ++static DEFINE_MUTEX(rtc_mutex); ++static unsigned long rtc_inuse; ++static struct rtc_ops *rtc_ops; ++ ++#define rtc_epoch 1900UL ++ ++/* ++ * Calculate the next alarm time given the requested alarm time mask ++ * and the current time. ++ */ ++void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, ++ struct rtc_time *alrm) ++{ ++ unsigned long next_time; ++ unsigned long now_time; ++ ++ next->tm_year = now->tm_year; ++ next->tm_mon = now->tm_mon; ++ next->tm_mday = now->tm_mday; ++ next->tm_hour = alrm->tm_hour; ++ next->tm_min = alrm->tm_min; ++ next->tm_sec = alrm->tm_sec; ++ ++ rtc_tm_to_time(now, &now_time); ++ rtc_tm_to_time(next, &next_time); ++ ++ if (next_time < now_time) { ++ /* Advance one day */ ++ next_time += 60 * 60 * 24; ++ rtc_time_to_tm(next_time, next); ++ } ++} ++ ++static inline int rtc_arm_read_time(struct rtc_ops *ops, struct rtc_time *tm) ++{ ++ memset(tm, 0, sizeof(struct rtc_time)); ++ return ops->read_time(tm); ++} ++ ++static inline int rtc_arm_set_time(struct rtc_ops *ops, struct rtc_time *tm) ++{ ++ int ret; ++ ++ ret = rtc_valid_tm(tm); ++ if (ret == 0) ++ ret = ops->set_time(tm); ++ ++ return ret; ++} ++ ++static inline int rtc_arm_read_alarm(struct rtc_ops *ops, ++ struct rtc_wkalrm *alrm) ++{ ++ int ret = -EINVAL; ++ if (ops->read_alarm) { ++ memset(alrm, 0, sizeof(struct rtc_wkalrm)); ++ ret = ops->read_alarm(alrm); ++ } ++ return ret; ++} ++ ++static inline int rtc_arm_set_alarm(struct rtc_ops *ops, ++ struct rtc_wkalrm *alrm) ++{ ++ int ret = -EINVAL; ++ if (ops->set_alarm) ++ ret = ops->set_alarm(alrm); ++ return ret; ++} ++ ++void rtc_update(unsigned long num, unsigned long events) ++{ ++ spin_lock(&rtc_lock); ++ rtc_irq_data = (rtc_irq_data + (num << 8)) | events; ++ spin_unlock(&rtc_lock); ++ ++ wake_up_interruptible(&rtc_wait); ++ kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); ++} ++ ++EXPORT_SYMBOL(rtc_update); ++ ++static ssize_t ++rtc_read(struct file *file, char __user * buf, size_t count, loff_t * ppos) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ unsigned long data; ++ ssize_t ret; ++ ++ if (count < sizeof(unsigned long)) ++ return -EINVAL; ++ ++ add_wait_queue(&rtc_wait, &wait); ++ do { ++ __set_current_state(TASK_INTERRUPTIBLE); ++ ++ spin_lock_irq(&rtc_lock); ++ data = rtc_irq_data; ++ rtc_irq_data = 0; ++ spin_unlock_irq(&rtc_lock); ++ ++ if (data != 0) { ++ ret = 0; ++ break; ++ } ++ if (file->f_flags & O_NONBLOCK) { ++ ret = -EAGAIN; ++ break; ++ } ++ if (signal_pending(current)) { ++ ret = -ERESTARTSYS; ++ break; ++ } ++ schedule(); ++ } while (1); ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(&rtc_wait, &wait); ++ ++ if (ret == 0) { ++ ret = put_user(data, (unsigned long __user *)buf); ++ if (ret == 0) ++ ret = sizeof(unsigned long); ++ } ++ return ret; ++} ++ ++static unsigned int rtc_poll(struct file *file, poll_table * wait) ++{ ++ unsigned long data; ++ ++ poll_wait(file, &rtc_wait, wait); ++ ++ spin_lock_irq(&rtc_lock); ++ data = rtc_irq_data; ++ spin_unlock_irq(&rtc_lock); ++ ++ return data != 0 ? POLLIN | POLLRDNORM : 0; ++} ++ ++static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ struct rtc_ops *ops = file->private_data; ++ struct rtc_time tm; ++ struct rtc_wkalrm alrm; ++ void __user *uarg = (void __user *)arg; ++ int ret = -EINVAL; ++ ++ switch (cmd) { ++ case RTC_ALM_READ: ++ ret = rtc_arm_read_alarm(ops, &alrm); ++ if (ret) ++ break; ++ ret = copy_to_user(uarg, &alrm.time, sizeof(tm)); ++ if (ret) ++ ret = -EFAULT; ++ break; ++ ++ case RTC_ALM_SET: ++ ret = copy_from_user(&alrm.time, uarg, sizeof(tm)); ++ if (ret) { ++ ret = -EFAULT; ++ break; ++ } ++ alrm.enabled = 0; ++ alrm.pending = 0; ++ alrm.time.tm_mday = -1; ++ alrm.time.tm_mon = -1; ++ alrm.time.tm_year = -1; ++ alrm.time.tm_wday = -1; ++ alrm.time.tm_yday = -1; ++ alrm.time.tm_isdst = -1; ++ ret = rtc_arm_set_alarm(ops, &alrm); ++ break; ++ ++ case RTC_RD_TIME: ++ ret = rtc_arm_read_time(ops, &tm); ++ if (ret) ++ break; ++ ret = copy_to_user(uarg, &tm, sizeof(tm)); ++ if (ret) ++ ret = -EFAULT; ++ break; ++ ++ case RTC_SET_TIME: ++ if (!capable(CAP_SYS_TIME)) { ++ ret = -EACCES; ++ break; ++ } ++ ret = copy_from_user(&tm, uarg, sizeof(tm)); ++ if (ret) { ++ ret = -EFAULT; ++ break; ++ } ++ ret = rtc_arm_set_time(ops, &tm); ++ break; ++ ++ case RTC_EPOCH_SET: ++#ifndef rtc_epoch ++ /* ++ * There were no RTC clocks before 1900. ++ */ ++ if (arg < 1900) { ++ ret = -EINVAL; ++ break; ++ } ++ if (!capable(CAP_SYS_TIME)) { ++ ret = -EACCES; ++ break; ++ } ++ rtc_epoch = arg; ++ ret = 0; ++#endif ++ break; ++ ++ case RTC_EPOCH_READ: ++ ret = put_user(rtc_epoch, (unsigned long __user *)uarg); ++ break; ++ ++ case RTC_WKALM_SET: ++ ret = copy_from_user(&alrm, uarg, sizeof(alrm)); ++ if (ret) { ++ ret = -EFAULT; ++ break; ++ } ++ ret = rtc_arm_set_alarm(ops, &alrm); ++ break; ++ ++ case RTC_WKALM_RD: ++ ret = rtc_arm_read_alarm(ops, &alrm); ++ if (ret) ++ break; ++ ret = copy_to_user(uarg, &alrm, sizeof(alrm)); ++ if (ret) ++ ret = -EFAULT; ++ break; ++ ++ default: ++ if (ops->ioctl) ++ ret = ops->ioctl(cmd, arg); ++ break; ++ } ++ return ret; ++} ++ ++static int rtc_open(struct inode *inode, struct file *file) ++{ ++ int ret; ++ ++ mutex_lock(&rtc_mutex); ++ ++ if (rtc_inuse) { ++ ret = -EBUSY; ++ } else if (!rtc_ops || !try_module_get(rtc_ops->owner)) { ++ ret = -ENODEV; ++ } else { ++ file->private_data = rtc_ops; ++ ++ ret = rtc_ops->open ? rtc_ops->open() : 0; ++ if (ret == 0) { ++ spin_lock_irq(&rtc_lock); ++ rtc_irq_data = 0; ++ spin_unlock_irq(&rtc_lock); ++ ++ rtc_inuse = 1; ++ } ++ } ++ mutex_unlock(&rtc_mutex); ++ ++ return ret; ++} ++ ++static int rtc_release(struct inode *inode, struct file *file) ++{ ++ struct rtc_ops *ops = file->private_data; ++ ++ if (ops->release) ++ ops->release(); ++ ++ spin_lock_irq(&rtc_lock); ++ rtc_irq_data = 0; ++ spin_unlock_irq(&rtc_lock); ++ ++ module_put(rtc_ops->owner); ++ rtc_inuse = 0; ++ ++ return 0; ++} ++ ++static int rtc_fasync(int fd, struct file *file, int on) ++{ ++ return fasync_helper(fd, file, on, &rtc_async_queue); ++} ++ ++static struct file_operations rtc_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .read = rtc_read, ++ .poll = rtc_poll, ++ .ioctl = rtc_ioctl, ++ .open = rtc_open, ++ .release = rtc_release, ++ .fasync = rtc_fasync, ++}; ++ ++static struct miscdevice rtc_miscdev = { ++ .minor = RTC_MINOR, ++ .name = "rtc", ++ .fops = &rtc_fops, ++}; ++ ++static int rtc_read_proc(char *page, char **start, off_t off, int count, ++ int *eof, void *data) ++{ ++ struct rtc_ops *ops = data; ++ struct rtc_wkalrm alrm; ++ struct rtc_time tm; ++ char *p = page; ++ ++ if (rtc_arm_read_time(ops, &tm) == 0) { ++ p += sprintf(p, ++ "rtc_time\t: %02d:%02d:%02d\n" ++ "rtc_date\t: %04d-%02d-%02d\n" ++ "rtc_epoch\t: %04lu\n", ++ tm.tm_hour, tm.tm_min, tm.tm_sec, ++ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, ++ rtc_epoch); ++ } ++ ++ if (rtc_arm_read_alarm(ops, &alrm) == 0) { ++ p += sprintf(p, "alrm_time\t: "); ++ if ((unsigned int)alrm.time.tm_hour <= 24) ++ p += sprintf(p, "%02d:", alrm.time.tm_hour); ++ else ++ p += sprintf(p, "**:"); ++ if ((unsigned int)alrm.time.tm_min <= 59) ++ p += sprintf(p, "%02d:", alrm.time.tm_min); ++ else ++ p += sprintf(p, "**:"); ++ if ((unsigned int)alrm.time.tm_sec <= 59) ++ p += sprintf(p, "%02d\n", alrm.time.tm_sec); ++ else ++ p += sprintf(p, "**\n"); ++ ++ p += sprintf(p, "alrm_date\t: "); ++ if ((unsigned int)alrm.time.tm_year <= 200) ++ p += sprintf(p, "%04d-", alrm.time.tm_year + 1900); ++ else ++ p += sprintf(p, "****-"); ++ if ((unsigned int)alrm.time.tm_mon <= 11) ++ p += sprintf(p, "%02d-", alrm.time.tm_mon + 1); ++ else ++ p += sprintf(p, "**-"); ++ if ((unsigned int)alrm.time.tm_mday <= 31) ++ p += sprintf(p, "%02d\n", alrm.time.tm_mday); ++ else ++ p += sprintf(p, "**\n"); ++ p += sprintf(p, "alrm_wakeup\t: %s\n", ++ alrm.enabled ? "yes" : "no"); ++ p += sprintf(p, "alrm_pending\t: %s\n", ++ alrm.pending ? "yes" : "no"); ++ } ++ ++ if (ops->proc) ++ p += ops->proc(p); ++ ++ return p - page; ++} ++ ++int register_rtc(struct rtc_ops *ops) ++{ ++ int ret = -EBUSY; ++ ++ mutex_lock(&rtc_mutex); ++ if (rtc_ops == NULL) { ++ rtc_ops = ops; ++ ++ ret = misc_register(&rtc_miscdev); ++ if (ret == 0) ++ create_proc_read_entry("driver/rtc", 0, NULL, ++ rtc_read_proc, ops); ++ } ++ mutex_unlock(&rtc_mutex); ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL(register_rtc); ++ ++void unregister_rtc(struct rtc_ops *rtc) ++{ ++ mutex_lock(&rtc_mutex); ++ if (rtc == rtc_ops) { ++ remove_proc_entry("driver/rtc", NULL); ++ misc_deregister(&rtc_miscdev); ++ rtc_ops = NULL; ++ } ++ mutex_unlock(&rtc_mutex); ++} ++ ++EXPORT_SYMBOL(unregister_rtc); +diff -Nur linux-3.4.110.orig/arch/nds32/configs/orca_8k_defconfig linux-3.4.110/arch/nds32/configs/orca_8k_defconfig +--- linux-3.4.110.orig/arch/nds32/configs/orca_8k_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/configs/orca_8k_defconfig 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,132 @@ ++CONFIG_EXPERIMENTAL=y ++CONFIG_CROSS_COMPILE="nds32le-linux-" ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_SYSVIPC=y ++CONFIG_POSIX_MQUEUE=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_BSD_PROCESS_ACCT_V3=y ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_LOG_BUF_SHIFT=14 ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_SYSCTL_SYSCALL=y ++# CONFIG_HOTPLUG is not set ++# CONFIG_SIGNALFD is not set ++CONFIG_EMBEDDED=y ++# CONFIG_VM_EVENT_COUNTERS is not set ++CONFIG_PROFILING=y ++CONFIG_OPROFILE=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++# CONFIG_BLK_DEV_BSG is not set ++CONFIG_PLATFORM_AHBDMA=y ++CONFIG_PLATFORM_APBDMA=y ++CONFIG_SYS_CLK=30000000 ++CONFIG_UART_CLK=14745600 ++CONFIG_SDRAM_SIZE=0x40000000 ++CONFIG_CPU_CACHE_NONALIASING=y ++CONFIG_ANDES_PAGE_SIZE_8KB=y ++CONFIG_HIGHMEM=y ++CONFIG_HZ_100=y ++CONFIG_CMDLINE="root=/dev/ram0 rw mem=1024M@0x0 initrd=0x1000000,8M earlyprintk=uart8250-32bit,0x99600000 console=ttyS0,38400n8 loglevel=7 rootfstype=ext2 init=/bin/busybox init -s user_debug=-1" ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_NET_KEY=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++# CONFIG_INET_DIAG is not set ++# CONFIG_IPV6 is not set ++CONFIG_BRIDGE=y ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_CFI=y ++CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_PHYSMAP=y ++CONFIG_MTD_PHYSMAP_COMPAT=y ++CONFIG_MTD_PHYSMAP_START=0x80400000 ++CONFIG_MTD_PHYSMAP_LEN=0x2000000 ++CONFIG_MTD_PHYSMAP_BANKWIDTH=4 ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=8192 ++CONFIG_NETDEVICES=y ++CONFIG_TUN=y ++CONFIG_FTMAC100=y ++# CONFIG_INPUT_MOUSEDEV is not set ++CONFIG_INPUT_EVDEV=y ++# CONFIG_INPUT_KEYBOARD is not set ++# CONFIG_INPUT_MOUSE is not set ++CONFIG_INPUT_TOUCHSCREEN=y ++CONFIG_TOUCHSCREEN_CPE_TS=y ++# CONFIG_SERIO is not set ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250_NR_UARTS=3 ++CONFIG_SERIAL_8250_RUNTIME_UARTS=3 ++# CONFIG_HW_RANDOM is not set ++CONFIG_GPIOLIB=y ++CONFIG_GPIO_SYSFS=y ++CONFIG_GPIO_FTGPIO010=y ++# CONFIG_HWMON is not set ++CONFIG_WATCHDOG=y ++CONFIG_FTWDT010_WATCHDOG=y ++CONFIG_FB=y ++CONFIG_FB_FTLCDC100=y ++# CONFIG_VGA_CONSOLE is not set ++CONFIG_FRAMEBUFFER_CONSOLE=y ++CONFIG_LOGO=y ++CONFIG_SOUND=y ++CONFIG_SND=y ++CONFIG_SND_PCM_OSS=y ++# CONFIG_SND_SUPPORT_OLD_API is not set ++# CONFIG_SND_VERBOSE_PROCFS is not set ++CONFIG_SND_FTSSP010=y ++# CONFIG_HID_SUPPORT is not set ++# CONFIG_USB_SUPPORT is not set ++CONFIG_MMC=y ++CONFIG_MMC_FTSDC010=y ++CONFIG_RTC_CLASS=y ++# CONFIG_RTC_HCTOSYS is not set ++CONFIG_RTC_DRV_FTRTC010=y ++CONFIG_EXT2_FS=y ++CONFIG_FUSE_FS=y ++CONFIG_MSDOS_FS=y ++CONFIG_VFAT_FS=y ++# CONFIG_PROC_PAGE_MONITOR is not set ++CONFIG_TMPFS=y ++CONFIG_JFFS2_FS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_NFS_V3_ACL=y ++CONFIG_NFS_V4=y ++CONFIG_NFS_V4_1=y ++CONFIG_NFS_USE_LEGACY_DNS=y ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_ISO8859_1=y ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_DEBUG_FS=y ++CONFIG_DEBUG_SHIRQ=y ++CONFIG_SCHEDSTATS=y ++CONFIG_TIMER_STATS=y ++CONFIG_SLUB_DEBUG_ON=y ++CONFIG_DEBUG_RT_MUTEXES=y ++CONFIG_DEBUG_SPINLOCK=y ++CONFIG_DEBUG_MUTEXES=y ++CONFIG_DEBUG_INFO=y ++CONFIG_DEBUG_MEMORY_INIT=y ++CONFIG_DEBUG_LIST=y ++CONFIG_DEBUG_SG=y ++# CONFIG_FTRACE is not set ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_ERRORS=y ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++# CONFIG_CRYPTO_HW is not set +diff -Nur linux-3.4.110.orig/arch/nds32/configs/orca_defconfig linux-3.4.110/arch/nds32/configs/orca_defconfig +--- linux-3.4.110.orig/arch/nds32/configs/orca_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/configs/orca_defconfig 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,125 @@ ++CONFIG_EXPERIMENTAL=y ++CONFIG_CROSS_COMPILE="nds32le-linux-" ++CONFIG_SYSVIPC=y ++CONFIG_POSIX_MQUEUE=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_BSD_PROCESS_ACCT_V3=y ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_LOG_BUF_SHIFT=14 ++CONFIG_NAMESPACES=y ++CONFIG_SYSCTL_SYSCALL=y ++CONFIG_KALLSYMS_ALL=y ++# CONFIG_HOTPLUG is not set ++CONFIG_EMBEDDED=y ++# CONFIG_VM_EVENT_COUNTERS is not set ++CONFIG_PROFILING=y ++CONFIG_OPROFILE=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++# CONFIG_BLK_DEV_BSG is not set ++CONFIG_MEASURE_INTERRUPT_LATENCY=y ++CONFIG_PLATFORM_AHBDMA=y ++CONFIG_PLATFORM_APBDMA=y ++CONFIG_SYS_CLK=30000000 ++CONFIG_UART_CLK=14745600 ++CONFIG_SDRAM_SIZE=0x40000000 ++CONFIG_MEMORY_START=0x0 ++# CONFIG_HWZOL is not set ++CONFIG_IVIC=y ++CONFIG_HIGH_RES_TIMERS=y ++CONFIG_PREEMPT=y ++CONFIG_HZ_100=y ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_NET_KEY=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++# CONFIG_INET_DIAG is not set ++# CONFIG_IPV6 is not set ++CONFIG_BRIDGE=y ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_CFI=y ++CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_PHYSMAP=y ++CONFIG_MTD_PHYSMAP_COMPAT=y ++CONFIG_MTD_PHYSMAP_START=0x80400000 ++CONFIG_MTD_PHYSMAP_LEN=0x2000000 ++CONFIG_MTD_PHYSMAP_BANKWIDTH=4 ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=8192 ++CONFIG_NETDEVICES=y ++CONFIG_TUN=y ++CONFIG_FTMAC100=y ++# CONFIG_INPUT_MOUSEDEV is not set ++CONFIG_INPUT_EVDEV=y ++# CONFIG_INPUT_KEYBOARD is not set ++# CONFIG_INPUT_MOUSE is not set ++CONFIG_INPUT_TOUCHSCREEN=y ++CONFIG_TOUCHSCREEN_CPE_TS=m ++# CONFIG_SERIO is not set ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250_NR_UARTS=3 ++CONFIG_SERIAL_8250_RUNTIME_UARTS=3 ++# CONFIG_HW_RANDOM is not set ++CONFIG_GPIOLIB=y ++CONFIG_GPIO_SYSFS=y ++CONFIG_GPIO_FTGPIO010=m ++# CONFIG_HWMON is not set ++CONFIG_WATCHDOG=y ++CONFIG_FTWDT010_WATCHDOG=m ++CONFIG_FB=y ++CONFIG_FB_FTLCDC100=y ++# CONFIG_VGA_CONSOLE is not set ++CONFIG_FRAMEBUFFER_CONSOLE=y ++CONFIG_LOGO=y ++CONFIG_SOUND=y ++CONFIG_SND=y ++CONFIG_SND_PCM_OSS=y ++# CONFIG_SND_SUPPORT_OLD_API is not set ++# CONFIG_SND_VERBOSE_PROCFS is not set ++CONFIG_SND_FTSSP010=m ++# CONFIG_HID_SUPPORT is not set ++# CONFIG_USB_SUPPORT is not set ++CONFIG_MMC=y ++CONFIG_MMC_FTSDC010=y ++CONFIG_RTC_CLASS=y ++# CONFIG_RTC_HCTOSYS is not set ++CONFIG_RTC_DRV_FTRTC010=y ++CONFIG_EXT2_FS=y ++CONFIG_FUSE_FS=y ++CONFIG_MSDOS_FS=y ++CONFIG_VFAT_FS=y ++CONFIG_TMPFS=y ++CONFIG_TMPFS_POSIX_ACL=y ++CONFIG_CONFIGFS_FS=y ++CONFIG_JFFS2_FS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_NFS_V3_ACL=y ++CONFIG_NFS_V4=y ++CONFIG_NFS_V4_1=y ++CONFIG_NFS_USE_LEGACY_DNS=y ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_ISO8859_1=y ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_HEADERS_CHECK=y ++CONFIG_DEBUG_SECTION_MISMATCH=y ++# CONFIG_SCHED_DEBUG is not set ++CONFIG_DEBUG_INFO=y ++# CONFIG_FTRACE is not set ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_ERRORS=y ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++# CONFIG_CRYPTO_HW is not set +diff -Nur linux-3.4.110.orig/arch/nds32/configs/qemu_defconfig linux-3.4.110/arch/nds32/configs/qemu_defconfig +--- linux-3.4.110.orig/arch/nds32/configs/qemu_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/configs/qemu_defconfig 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,98 @@ ++CONFIG_EXPERIMENTAL=y ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_SYSVIPC=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_BSD_PROCESS_ACCT_V3=y ++CONFIG_LOG_BUF_SHIFT=14 ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_SYSCTL_SYSCALL=y ++# CONFIG_HOTPLUG is not set ++# CONFIG_SIGNALFD is not set ++CONFIG_EMBEDDED=y ++# CONFIG_VM_EVENT_COUNTERS is not set ++CONFIG_PROFILING=y ++CONFIG_OPROFILE=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++# CONFIG_BLK_DEV_BSG is not set ++CONFIG_PLAT_QEMU=y ++CONFIG_SYS_CLK=40000000 ++CONFIG_UART_CLK=14745600 ++CONFIG_SDRAM_SIZE=0x10000000 ++CONFIG_HZ_100=y ++CONFIG_CMDLINE="root=/dev/ram0 rw mem=1024M@0x0 initrd=0x1000000,8M earlyprintk=uart8250-32bit,0x99600000 console=ttyS0,38400n8 loglevel=7 rootfstype=ext2 init=/bin/busybox init -s user_debug=-1" ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_NET_KEY=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++# CONFIG_INET_DIAG is not set ++# CONFIG_IPV6 is not set ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=8192 ++CONFIG_FTSDC010=y ++CONFIG_NETDEVICES=y ++CONFIG_FTMAC100=y ++# CONFIG_INPUT_MOUSEDEV is not set ++CONFIG_INPUT_EVDEV=y ++# CONFIG_INPUT_KEYBOARD is not set ++# CONFIG_INPUT_MOUSE is not set ++CONFIG_INPUT_TOUCHSCREEN=y ++# CONFIG_SERIO is not set ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250_NR_UARTS=3 ++CONFIG_SERIAL_8250_RUNTIME_UARTS=3 ++# CONFIG_HW_RANDOM is not set ++# CONFIG_HWMON is not set ++CONFIG_FB=y ++# CONFIG_VGA_CONSOLE is not set ++CONFIG_FRAMEBUFFER_CONSOLE=y ++CONFIG_LOGO=y ++# CONFIG_HID_SUPPORT is not set ++# CONFIG_USB_SUPPORT is not set ++CONFIG_EXT2_FS=y ++CONFIG_EXT2_FS_XATTR=y ++CONFIG_EXT2_FS_POSIX_ACL=y ++CONFIG_EXT2_FS_SECURITY=y ++CONFIG_EXT2_FS_XIP=y ++CONFIG_EXT3_FS=y ++CONFIG_EXT3_FS_POSIX_ACL=y ++CONFIG_EXT3_FS_SECURITY=y ++CONFIG_EXT4_FS=y ++CONFIG_EXT4_FS_POSIX_ACL=y ++CONFIG_EXT4_FS_SECURITY=y ++CONFIG_EXT4_DEBUG=y ++CONFIG_FUSE_FS=y ++CONFIG_MSDOS_FS=y ++CONFIG_VFAT_FS=y ++# CONFIG_PROC_PAGE_MONITOR is not set ++CONFIG_TMPFS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_ISO8859_1=y ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_DEBUG_FS=y ++CONFIG_DEBUG_SHIRQ=y ++CONFIG_DETECT_HUNG_TASK=y ++CONFIG_SCHEDSTATS=y ++CONFIG_TIMER_STATS=y ++CONFIG_SLUB_DEBUG_ON=y ++CONFIG_DEBUG_RT_MUTEXES=y ++CONFIG_DEBUG_MUTEXES=y ++CONFIG_DEBUG_INFO=y ++CONFIG_DEBUG_LIST=y ++CONFIG_DEBUG_SG=y ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_ERRORS=y ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++# CONFIG_CRYPTO_HW is not set +diff -Nur linux-3.4.110.orig/arch/nds32/configs/vep-be_defconfig linux-3.4.110/arch/nds32/configs/vep-be_defconfig +--- linux-3.4.110.orig/arch/nds32/configs/vep-be_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/configs/vep-be_defconfig 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,777 @@ ++# ++# Automatically generated make config: don't edit ++# Linux kernel version: 2.6.29 ++# Mon Jul 13 11:42:57 2009 ++# ++CONFIG_NDS32=y ++CONFIG_NO_IOPORT=y ++CONFIG_GENERIC_IOMAP=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++CONFIG_GENERIC_HWEIGHT=y ++CONFIG_GENERIC_FIND_NEXT_BIT=y ++CONFIG_GENERIC_CALIBRATE_DELAY=y ++CONFIG_GENERIC_HARDIRQS=y ++CONFIG_LOCKDEP_SUPPORT=y ++CONFIG_STACKTRACE_SUPPORT=y ++CONFIG_HAVE_LATENCYTOP_SUPPORT=y ++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" ++ ++# ++# General setup ++# ++CONFIG_EXPERIMENTAL=y ++CONFIG_BROKEN_ON_SMP=y ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++CONFIG_LOCALVERSION="" ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_SWAP=y ++CONFIG_SYSVIPC=y ++CONFIG_SYSVIPC_SYSCTL=y ++# CONFIG_POSIX_MQUEUE is not set ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_BSD_PROCESS_ACCT_V3=y ++# CONFIG_TASKSTATS is not set ++# CONFIG_AUDIT is not set ++ ++# ++# RCU Subsystem ++# ++CONFIG_CLASSIC_RCU=y ++# CONFIG_TREE_RCU is not set ++# CONFIG_PREEMPT_RCU is not set ++# CONFIG_TREE_RCU_TRACE is not set ++# CONFIG_PREEMPT_RCU_TRACE is not set ++# CONFIG_IKCONFIG is not set ++CONFIG_LOG_BUF_SHIFT=14 ++# CONFIG_GROUP_SCHED is not set ++# CONFIG_CGROUPS is not set ++# CONFIG_SYSFS_DEPRECATED_V2 is not set ++# CONFIG_RELAY is not set ++# CONFIG_NAMESPACES is not set ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_INITRAMFS_SOURCE="" ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_SYSCTL=y ++CONFIG_ANON_INODES=y ++CONFIG_EMBEDDED=y ++CONFIG_UID16=y ++CONFIG_SYSCTL_SYSCALL=y ++# CONFIG_KALLSYMS is not set ++# CONFIG_HOTPLUG is not set ++CONFIG_PRINTK=y ++CONFIG_BUG=y ++# CONFIG_ELF_CORE is not set ++CONFIG_BASE_FULL=y ++CONFIG_FUTEX=y ++CONFIG_EPOLL=y ++# CONFIG_SIGNALFD is not set ++CONFIG_TIMERFD=y ++CONFIG_EVENTFD=y ++CONFIG_SHMEM=y ++CONFIG_AIO=y ++# CONFIG_VM_EVENT_COUNTERS is not set ++CONFIG_SLUB_DEBUG=y ++CONFIG_COMPAT_BRK=y ++# CONFIG_SLAB is not set ++CONFIG_SLUB=y ++# CONFIG_SLOB is not set ++CONFIG_PROFILING=y ++CONFIG_TRACEPOINTS=y ++# CONFIG_MARKERS is not set ++CONFIG_OPROFILE=y ++CONFIG_HAVE_OPROFILE=y ++CONFIG_HAVE_KPROBES=y ++CONFIG_HAVE_KRETPROBES=y ++# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set ++CONFIG_SLABINFO=y ++CONFIG_RT_MUTEXES=y ++CONFIG_BASE_SMALL=0 ++CONFIG_MODULES=y ++# CONFIG_MODULE_FORCE_LOAD is not set ++CONFIG_MODULE_UNLOAD=y ++# CONFIG_MODULE_FORCE_UNLOAD is not set ++# CONFIG_MODVERSIONS is not set ++# CONFIG_MODULE_SRCVERSION_ALL is not set ++CONFIG_BLOCK=y ++# CONFIG_LBD is not set ++# CONFIG_BLK_DEV_IO_TRACE is not set ++# CONFIG_BLK_DEV_BSG is not set ++# CONFIG_BLK_DEV_INTEGRITY is not set ++ ++# ++# IO Schedulers ++# ++CONFIG_IOSCHED_NOOP=y ++# CONFIG_IOSCHED_AS is not set ++# CONFIG_IOSCHED_DEADLINE is not set ++# CONFIG_IOSCHED_CFQ is not set ++# CONFIG_DEFAULT_AS is not set ++# CONFIG_DEFAULT_DEADLINE is not set ++# CONFIG_DEFAULT_CFQ is not set ++CONFIG_DEFAULT_NOOP=y ++CONFIG_DEFAULT_IOSCHED="noop" ++# CONFIG_FREEZER is not set ++ ++# ++# System Type ++# ++# CONFIG_PLAT_FARADAY is not set ++CONFIG_PLAT_VEP=y ++# CONFIG_PLAT_AG101 is not set ++# CONFIG_PLAT_AG102 is not set ++# CONFIG_PLAT_AG101P is not set ++# CONFIG_PLAT_QEMU is not set ++CONFIG_PLATFORM_INTC=y ++ ++# ++# VEP Platform Options ++# ++# CONFIG_CACHE_L2 is not set ++ ++# ++# Common Platform Options ++# ++# CONFIG_PLATFORM_AHBDMA is not set ++# CONFIG_PLATFORM_APBDMA is not set ++CONFIG_SYS_CLK=67737600 ++CONFIG_UART_CLK=36864000 ++CONFIG_SDRAM_SIZE=0x10000000 ++ ++# ++# Processor Features ++# ++CONFIG_CPU_CUSTOM=y ++# CONFIG_FPU is not set ++# CONFIG_AUDIO is not set ++# CONFIG_EVIC is not set ++CONFIG_CPU_CONTEXT_ID=y ++CONFIG_ANDES_PAGE_SIZE_4KB=y ++# CONFIG_ANDES_PAGE_SIZE_8KB is not set ++# CONFIG_KERNEL_SPACE_LARGE_PAGE is not set ++# CONFIG_CPU_ICACHE_DISABLE is not set ++# CONFIG_CPU_DCACHE_DISABLE is not set ++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set ++# CONFIG_ALIGNMENT_TRAP is not set ++CONFIG_MMU=y ++ ++# ++# Kernel Features ++# ++CONFIG_PREEMPT_NONE=y ++# CONFIG_PREEMPT_VOLUNTARY is not set ++# CONFIG_PREEMPT is not set ++CONFIG_SELECT_MEMORY_MODEL=y ++CONFIG_FLATMEM_MANUAL=y ++# CONFIG_DISCONTIGMEM_MANUAL is not set ++# CONFIG_SPARSEMEM_MANUAL is not set ++CONFIG_FLATMEM=y ++CONFIG_FLAT_NODE_MEM_MAP=y ++CONFIG_PAGEFLAGS_EXTENDED=y ++CONFIG_SPLIT_PTLOCK_CPUS=4 ++# CONFIG_PHYS_ADDR_T_64BIT is not set ++CONFIG_ZONE_DMA_FLAG=0 ++CONFIG_VIRT_TO_BUS=y ++CONFIG_UNEVICTABLE_LRU=y ++CONFIG_FORCE_MAX_ZONEORDER=11 ++CONFIG_HZ_100=y ++# CONFIG_HZ_250 is not set ++# CONFIG_HZ_300 is not set ++# CONFIG_HZ_1000 is not set ++CONFIG_HZ=100 ++# CONFIG_SCHED_HRTICK is not set ++CONFIG_CMDLINE="root=/dev/ram0 rw mem=64M@0x0 initrd=0x1000000,8M console=ttyS0,38400n8 rootfstype=ext2 init=/bin/busybox init -s user_debug=-1" ++ ++# ++# Power management options ++# ++CONFIG_SYS_SUPPORTS_APM_EMULATION=y ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++# CONFIG_PM is not set ++ ++# ++# Bus options ++# ++# CONFIG_PCI is not set ++# CONFIG_ARCH_SUPPORTS_MSI is not set ++ ++# ++# Executable file formats ++# ++CONFIG_BINFMT_ELF=y ++# CONFIG_HAVE_AOUT is not set ++# CONFIG_BINFMT_MISC is not set ++CONFIG_NET=y ++ ++# ++# Networking options ++# ++CONFIG_COMPAT_NET_DEV_OPS=y ++CONFIG_PACKET=y ++# CONFIG_PACKET_MMAP is not set ++CONFIG_UNIX=y ++CONFIG_XFRM=y ++# CONFIG_XFRM_USER is not set ++# CONFIG_XFRM_SUB_POLICY is not set ++# CONFIG_XFRM_MIGRATE is not set ++# CONFIG_XFRM_STATISTICS is not set ++CONFIG_NET_KEY=y ++# CONFIG_NET_KEY_MIGRATE is not set ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_FIB_HASH=y ++# CONFIG_IP_PNP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_IP_MROUTE is not set ++# CONFIG_ARPD is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_INET_AH is not set ++# CONFIG_INET_ESP is not set ++# CONFIG_INET_IPCOMP is not set ++# CONFIG_INET_XFRM_TUNNEL is not set ++# CONFIG_INET_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++# CONFIG_INET_DIAG is not set ++# CONFIG_TCP_CONG_ADVANCED is not set ++CONFIG_TCP_CONG_CUBIC=y ++CONFIG_DEFAULT_TCP_CONG="cubic" ++# CONFIG_TCP_MD5SIG is not set ++# CONFIG_IPV6 is not set ++# CONFIG_NETWORK_SECMARK is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_IP_DCCP is not set ++# CONFIG_IP_SCTP is not set ++# CONFIG_TIPC is not set ++# CONFIG_ATM is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_NET_DSA is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_DECNET is not set ++# CONFIG_LLC2 is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_SCHED is not set ++# CONFIG_DCB is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++# CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set ++# CONFIG_IRDA is not set ++# CONFIG_BT is not set ++# CONFIG_AF_RXRPC is not set ++# CONFIG_PHONET is not set ++CONFIG_WIRELESS=y ++# CONFIG_CFG80211 is not set ++CONFIG_WIRELESS_OLD_REGULATORY=y ++# CONFIG_WIRELESS_EXT is not set ++# CONFIG_LIB80211 is not set ++# CONFIG_MAC80211 is not set ++# CONFIG_WIMAX is not set ++# CONFIG_RFKILL is not set ++# CONFIG_NET_9P is not set ++ ++# ++# Device Drivers ++# ++ ++# ++# Generic Driver Options ++# ++CONFIG_STANDALONE=y ++CONFIG_PREVENT_FIRMWARE_BUILD=y ++# CONFIG_SYS_HYPERVISOR is not set ++# CONFIG_CONNECTOR is not set ++# CONFIG_MTD is not set ++# CONFIG_PARPORT is not set ++CONFIG_BLK_DEV=y ++# CONFIG_BLK_DEV_COW_COMMON is not set ++CONFIG_BLK_DEV_LOOP=y ++# CONFIG_BLK_DEV_CRYPTOLOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_COUNT=16 ++CONFIG_BLK_DEV_RAM_SIZE=8192 ++# CONFIG_BLK_DEV_XIP is not set ++# CONFIG_CDROM_PKTCDVD is not set ++# CONFIG_ATA_OVER_ETH is not set ++# CONFIG_FTSDC010 is not set ++# CONFIG_FTCFC010 is not set ++# CONFIG_BLK_DEV_HD is not set ++# CONFIG_MISC_DEVICES is not set ++CONFIG_HAVE_IDE=y ++# CONFIG_IDE is not set ++ ++# ++# SCSI device support ++# ++# CONFIG_RAID_ATTRS is not set ++# CONFIG_SCSI is not set ++# CONFIG_SCSI_DMA is not set ++# CONFIG_SCSI_NETLINK is not set ++# CONFIG_ATA is not set ++# CONFIG_MD is not set ++CONFIG_NETDEVICES=y ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_MACVLAN is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_VETH is not set ++# CONFIG_PHYLIB is not set ++CONFIG_NET_ETHERNET=y ++# CONFIG_MII is not set ++# CONFIG_SMC91X is not set ++# CONFIG_DNET is not set ++# CONFIG_IBM_NEW_EMAC_ZMII is not set ++# CONFIG_IBM_NEW_EMAC_RGMII is not set ++# CONFIG_IBM_NEW_EMAC_TAH is not set ++# CONFIG_IBM_NEW_EMAC_EMAC4 is not set ++# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set ++# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set ++# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set ++# CONFIG_B44 is not set ++CONFIG_FTMAC100=y ++# CONFIG_NETDEV_1000 is not set ++# CONFIG_NETDEV_10000 is not set ++ ++# ++# Wireless LAN ++# ++# CONFIG_WLAN_PRE80211 is not set ++# CONFIG_WLAN_80211 is not set ++# CONFIG_IWLWIFI_LEDS is not set ++ ++# ++# Enable WiMAX (Networking options) to see the WiMAX drivers ++# ++# CONFIG_WAN is not set ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++# CONFIG_NETCONSOLE is not set ++# CONFIG_NETPOLL is not set ++# CONFIG_NET_POLL_CONTROLLER is not set ++# CONFIG_ISDN is not set ++# CONFIG_PHONE is not set ++ ++# ++# Input device support ++# ++CONFIG_INPUT=y ++# CONFIG_INPUT_FF_MEMLESS is not set ++# CONFIG_INPUT_POLLDEV is not set ++ ++# ++# Userland interfaces ++# ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++# CONFIG_INPUT_EVDEV is not set ++# CONFIG_INPUT_EVBUG is not set ++ ++# ++# Input Device Drivers ++# ++# CONFIG_INPUT_KEYBOARD is not set ++# CONFIG_INPUT_MOUSE is not set ++# CONFIG_INPUT_JOYSTICK is not set ++# CONFIG_INPUT_TABLET is not set ++# CONFIG_INPUT_TOUCHSCREEN is not set ++# CONFIG_INPUT_MISC is not set ++ ++# ++# Hardware I/O ports ++# ++# CONFIG_SERIO is not set ++# CONFIG_GAMEPORT is not set ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_CONSOLE_TRANSLATIONS=y ++CONFIG_VT_CONSOLE=y ++CONFIG_HW_CONSOLE=y ++# CONFIG_VT_HW_CONSOLE_BINDING is not set ++CONFIG_DEVKMEM=y ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# Serial drivers ++# ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250_NR_UARTS=3 ++CONFIG_SERIAL_8250_RUNTIME_UARTS=3 ++# CONFIG_SERIAL_8250_EXTENDED is not set ++ ++# ++# Non-8250 serial port support ++# ++CONFIG_SERIAL_CORE=y ++CONFIG_SERIAL_CORE_CONSOLE=y ++CONFIG_UNIX98_PTYS=y ++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set ++CONFIG_LEGACY_PTYS=y ++CONFIG_LEGACY_PTY_COUNT=256 ++# CONFIG_IPMI_HANDLER is not set ++# CONFIG_HW_RANDOM is not set ++# CONFIG_R3964 is not set ++# CONFIG_GPIO_FTGPIO010 is not set ++# CONFIG_RAW_DRIVER is not set ++# CONFIG_TCG_TPM is not set ++# CONFIG_I2C is not set ++# CONFIG_SPI is not set ++# CONFIG_W1 is not set ++# CONFIG_POWER_SUPPLY is not set ++# CONFIG_HWMON is not set ++# CONFIG_THERMAL is not set ++# CONFIG_THERMAL_HWMON is not set ++# CONFIG_WATCHDOG is not set ++CONFIG_SSB_POSSIBLE=y ++ ++# ++# Sonics Silicon Backplane ++# ++# CONFIG_SSB is not set ++ ++# ++# Multifunction device drivers ++# ++# CONFIG_MFD_CORE is not set ++# CONFIG_MFD_SM501 is not set ++# CONFIG_HTC_PASIC3 is not set ++# CONFIG_MFD_TMIO is not set ++# CONFIG_REGULATOR is not set ++ ++# ++# Multimedia devices ++# ++ ++# ++# Multimedia core support ++# ++# CONFIG_VIDEO_DEV is not set ++# CONFIG_DVB_CORE is not set ++# CONFIG_VIDEO_MEDIA is not set ++ ++# ++# Multimedia drivers ++# ++# CONFIG_DAB is not set ++ ++# ++# Graphics support ++# ++# CONFIG_VGASTATE is not set ++# CONFIG_VIDEO_OUTPUT_CONTROL is not set ++# CONFIG_FB is not set ++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set ++ ++# ++# Display device support ++# ++# CONFIG_DISPLAY_SUPPORT is not set ++ ++# ++# Console display driver support ++# ++# CONFIG_VGA_CONSOLE is not set ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_SOUND is not set ++# CONFIG_HID_SUPPORT is not set ++# CONFIG_USB_SUPPORT is not set ++# CONFIG_MMC is not set ++# CONFIG_MEMSTICK is not set ++# CONFIG_NEW_LEDS is not set ++# CONFIG_ACCESSIBILITY is not set ++CONFIG_RTC_LIB=y ++# CONFIG_RTC_CLASS is not set ++# CONFIG_DMADEVICES is not set ++# CONFIG_UIO is not set ++# CONFIG_STAGING is not set ++ ++# ++# File systems ++# ++CONFIG_EXT2_FS=y ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XIP is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_EXT4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_FS_POSIX_ACL is not set ++CONFIG_FILE_LOCKING=y ++# CONFIG_XFS_FS is not set ++# CONFIG_OCFS2_FS is not set ++# CONFIG_BTRFS_FS is not set ++CONFIG_DNOTIFY=y ++CONFIG_INOTIFY=y ++CONFIG_INOTIFY_USER=y ++# CONFIG_QUOTA is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++CONFIG_FUSE_FS=y ++ ++# ++# CD-ROM/DVD Filesystems ++# ++# CONFIG_ISO9660_FS is not set ++# CONFIG_UDF_FS is not set ++ ++# ++# DOS/FAT/NT Filesystems ++# ++# CONFIG_MSDOS_FS is not set ++# CONFIG_VFAT_FS is not set ++# CONFIG_NTFS_FS is not set ++ ++# ++# Pseudo filesystems ++# ++CONFIG_PROC_FS=y ++# CONFIG_PROC_KCORE is not set ++CONFIG_PROC_SYSCTL=y ++# CONFIG_PROC_PAGE_MONITOR is not set ++CONFIG_SYSFS=y ++CONFIG_TMPFS=y ++# CONFIG_TMPFS_POSIX_ACL is not set ++# CONFIG_HUGETLB_PAGE is not set ++# CONFIG_CONFIGFS_FS is not set ++CONFIG_MISC_FILESYSTEMS=y ++# CONFIG_ADFS_FS is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_HFSPLUS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EFS_FS is not set ++# CONFIG_CRAMFS is not set ++# CONFIG_SQUASHFS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_OMFS_FS is not set ++# CONFIG_HPFS_FS is not set ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_SYSV_FS is not set ++# CONFIG_UFS_FS is not set ++CONFIG_NETWORK_FILESYSTEMS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++# CONFIG_NFS_V3_ACL is not set ++# CONFIG_NFS_V4 is not set ++# CONFIG_NFSD is not set ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++CONFIG_NFS_COMMON=y ++CONFIG_SUNRPC=y ++# CONFIG_SUNRPC_REGISTER_V4 is not set ++# CONFIG_RPCSEC_GSS_KRB5 is not set ++# CONFIG_RPCSEC_GSS_SPKM3 is not set ++# CONFIG_SMB_FS is not set ++# CONFIG_CIFS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_CODA_FS is not set ++# CONFIG_AFS_FS is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=y ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++# CONFIG_NLS_ASCII is not set ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++# CONFIG_DLM is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_TRACE_IRQFLAGS_SUPPORT=y ++# CONFIG_PRINTK_TIME is not set ++CONFIG_ENABLE_WARN_DEPRECATED=y ++CONFIG_ENABLE_MUST_CHECK=y ++CONFIG_FRAME_WARN=1024 ++# CONFIG_MAGIC_SYSRQ is not set ++# CONFIG_UNUSED_SYMBOLS is not set ++CONFIG_DEBUG_FS=y ++# CONFIG_HEADERS_CHECK is not set ++# CONFIG_DEBUG_KERNEL is not set ++# CONFIG_SLUB_DEBUG_ON is not set ++# CONFIG_SLUB_STATS is not set ++CONFIG_STACKTRACE=y ++# CONFIG_DEBUG_MEMORY_INIT is not set ++CONFIG_FRAME_POINTER=y ++# CONFIG_RCU_CPU_STALL_DETECTOR is not set ++# CONFIG_LATENCYTOP is not set ++CONFIG_SYSCTL_SYSCALL_CHECK=y ++CONFIG_NOP_TRACER=y ++CONFIG_RING_BUFFER=y ++CONFIG_TRACING=y ++ ++# ++# Tracers ++# ++# CONFIG_DYNAMIC_PRINTK_DEBUG is not set ++# CONFIG_SAMPLES is not set ++CONFIG_HAVE_ARCH_KGDB=y ++CONFIG_DEBUG_USER=y ++# CONFIG_CCTL is not set ++CONFIG_ELFCHK_DEFAULT_ENABLE=y ++ ++# ++# Security options ++# ++# CONFIG_KEYS is not set ++# CONFIG_SECURITY is not set ++# CONFIG_SECURITYFS is not set ++# CONFIG_SECURITY_FILE_CAPABILITIES is not set ++CONFIG_CRYPTO=y ++ ++# ++# Crypto core or helper ++# ++# CONFIG_CRYPTO_FIPS is not set ++# CONFIG_CRYPTO_MANAGER is not set ++# CONFIG_CRYPTO_MANAGER2 is not set ++# CONFIG_CRYPTO_GF128MUL is not set ++# CONFIG_CRYPTO_NULL is not set ++# CONFIG_CRYPTO_CRYPTD is not set ++# CONFIG_CRYPTO_AUTHENC is not set ++# CONFIG_CRYPTO_TEST is not set ++ ++# ++# Authenticated Encryption with Associated Data ++# ++# CONFIG_CRYPTO_CCM is not set ++# CONFIG_CRYPTO_GCM is not set ++# CONFIG_CRYPTO_SEQIV is not set ++ ++# ++# Block modes ++# ++# CONFIG_CRYPTO_CBC is not set ++# CONFIG_CRYPTO_CTR is not set ++# CONFIG_CRYPTO_CTS is not set ++# CONFIG_CRYPTO_ECB is not set ++# CONFIG_CRYPTO_LRW is not set ++# CONFIG_CRYPTO_PCBC is not set ++# CONFIG_CRYPTO_XTS is not set ++ ++# ++# Hash modes ++# ++# CONFIG_CRYPTO_HMAC is not set ++# CONFIG_CRYPTO_XCBC is not set ++ ++# ++# Digest ++# ++# CONFIG_CRYPTO_CRC32C is not set ++# CONFIG_CRYPTO_MD4 is not set ++# CONFIG_CRYPTO_MD5 is not set ++# CONFIG_CRYPTO_MICHAEL_MIC is not set ++# CONFIG_CRYPTO_RMD128 is not set ++# CONFIG_CRYPTO_RMD160 is not set ++# CONFIG_CRYPTO_RMD256 is not set ++# CONFIG_CRYPTO_RMD320 is not set ++# CONFIG_CRYPTO_SHA1 is not set ++# CONFIG_CRYPTO_SHA256 is not set ++# CONFIG_CRYPTO_SHA512 is not set ++# CONFIG_CRYPTO_TGR192 is not set ++# CONFIG_CRYPTO_WP512 is not set ++ ++# ++# Ciphers ++# ++# CONFIG_CRYPTO_AES is not set ++# CONFIG_CRYPTO_ANUBIS is not set ++# CONFIG_CRYPTO_ARC4 is not set ++# CONFIG_CRYPTO_BLOWFISH is not set ++# CONFIG_CRYPTO_CAMELLIA is not set ++# CONFIG_CRYPTO_CAST5 is not set ++# CONFIG_CRYPTO_CAST6 is not set ++# CONFIG_CRYPTO_DES is not set ++# CONFIG_CRYPTO_FCRYPT is not set ++# CONFIG_CRYPTO_KHAZAD is not set ++# CONFIG_CRYPTO_SALSA20 is not set ++# CONFIG_CRYPTO_SEED is not set ++# CONFIG_CRYPTO_SERPENT is not set ++# CONFIG_CRYPTO_TEA is not set ++# CONFIG_CRYPTO_TWOFISH is not set ++ ++# ++# Compression ++# ++# CONFIG_CRYPTO_DEFLATE is not set ++# CONFIG_CRYPTO_LZO is not set ++ ++# ++# Random Number Generation ++# ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++# CONFIG_CRYPTO_HW is not set ++ ++# ++# Library routines ++# ++CONFIG_GENERIC_FIND_LAST_BIT=y ++# CONFIG_CRC_CCITT is not set ++# CONFIG_CRC16 is not set ++# CONFIG_CRC_T10DIF is not set ++# CONFIG_CRC_ITU_T is not set ++# CONFIG_CRC32 is not set ++# CONFIG_CRC7 is not set ++# CONFIG_LIBCRC32C is not set ++CONFIG_PLIST=y ++CONFIG_HAS_IOMEM=y ++CONFIG_HAS_DMA=y +diff -Nur linux-3.4.110.orig/arch/nds32/configs/vep-le_defconfig linux-3.4.110/arch/nds32/configs/vep-le_defconfig +--- linux-3.4.110.orig/arch/nds32/configs/vep-le_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/configs/vep-le_defconfig 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,777 @@ ++# ++# Automatically generated make config: don't edit ++# Linux kernel version: 2.6.29 ++# Mon Jul 13 11:41:30 2009 ++# ++CONFIG_NDS32=y ++CONFIG_NO_IOPORT=y ++CONFIG_GENERIC_IOMAP=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++CONFIG_GENERIC_HWEIGHT=y ++CONFIG_GENERIC_FIND_NEXT_BIT=y ++CONFIG_GENERIC_CALIBRATE_DELAY=y ++CONFIG_GENERIC_HARDIRQS=y ++CONFIG_LOCKDEP_SUPPORT=y ++CONFIG_STACKTRACE_SUPPORT=y ++CONFIG_HAVE_LATENCYTOP_SUPPORT=y ++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" ++ ++# ++# General setup ++# ++CONFIG_EXPERIMENTAL=y ++CONFIG_BROKEN_ON_SMP=y ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++CONFIG_LOCALVERSION="" ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_SWAP=y ++CONFIG_SYSVIPC=y ++CONFIG_SYSVIPC_SYSCTL=y ++# CONFIG_POSIX_MQUEUE is not set ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_BSD_PROCESS_ACCT_V3=y ++# CONFIG_TASKSTATS is not set ++# CONFIG_AUDIT is not set ++ ++# ++# RCU Subsystem ++# ++CONFIG_CLASSIC_RCU=y ++# CONFIG_TREE_RCU is not set ++# CONFIG_PREEMPT_RCU is not set ++# CONFIG_TREE_RCU_TRACE is not set ++# CONFIG_PREEMPT_RCU_TRACE is not set ++# CONFIG_IKCONFIG is not set ++CONFIG_LOG_BUF_SHIFT=14 ++# CONFIG_GROUP_SCHED is not set ++# CONFIG_CGROUPS is not set ++# CONFIG_SYSFS_DEPRECATED_V2 is not set ++# CONFIG_RELAY is not set ++# CONFIG_NAMESPACES is not set ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_INITRAMFS_SOURCE="" ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_SYSCTL=y ++CONFIG_ANON_INODES=y ++CONFIG_EMBEDDED=y ++CONFIG_UID16=y ++CONFIG_SYSCTL_SYSCALL=y ++# CONFIG_KALLSYMS is not set ++# CONFIG_HOTPLUG is not set ++CONFIG_PRINTK=y ++CONFIG_BUG=y ++# CONFIG_ELF_CORE is not set ++CONFIG_BASE_FULL=y ++CONFIG_FUTEX=y ++CONFIG_EPOLL=y ++# CONFIG_SIGNALFD is not set ++CONFIG_TIMERFD=y ++CONFIG_EVENTFD=y ++CONFIG_SHMEM=y ++CONFIG_AIO=y ++# CONFIG_VM_EVENT_COUNTERS is not set ++CONFIG_SLUB_DEBUG=y ++CONFIG_COMPAT_BRK=y ++# CONFIG_SLAB is not set ++CONFIG_SLUB=y ++# CONFIG_SLOB is not set ++CONFIG_PROFILING=y ++CONFIG_TRACEPOINTS=y ++# CONFIG_MARKERS is not set ++CONFIG_OPROFILE=y ++CONFIG_HAVE_OPROFILE=y ++CONFIG_HAVE_KPROBES=y ++CONFIG_HAVE_KRETPROBES=y ++# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set ++CONFIG_SLABINFO=y ++CONFIG_RT_MUTEXES=y ++CONFIG_BASE_SMALL=0 ++CONFIG_MODULES=y ++# CONFIG_MODULE_FORCE_LOAD is not set ++CONFIG_MODULE_UNLOAD=y ++# CONFIG_MODULE_FORCE_UNLOAD is not set ++# CONFIG_MODVERSIONS is not set ++# CONFIG_MODULE_SRCVERSION_ALL is not set ++CONFIG_BLOCK=y ++# CONFIG_LBD is not set ++# CONFIG_BLK_DEV_IO_TRACE is not set ++# CONFIG_BLK_DEV_BSG is not set ++# CONFIG_BLK_DEV_INTEGRITY is not set ++ ++# ++# IO Schedulers ++# ++CONFIG_IOSCHED_NOOP=y ++# CONFIG_IOSCHED_AS is not set ++# CONFIG_IOSCHED_DEADLINE is not set ++# CONFIG_IOSCHED_CFQ is not set ++# CONFIG_DEFAULT_AS is not set ++# CONFIG_DEFAULT_DEADLINE is not set ++# CONFIG_DEFAULT_CFQ is not set ++CONFIG_DEFAULT_NOOP=y ++CONFIG_DEFAULT_IOSCHED="noop" ++# CONFIG_FREEZER is not set ++ ++# ++# System Type ++# ++# CONFIG_PLAT_FARADAY is not set ++CONFIG_PLAT_VEP=y ++# CONFIG_PLAT_AG101 is not set ++# CONFIG_PLAT_AG102 is not set ++# CONFIG_PLAT_AG101P is not set ++# CONFIG_PLAT_QEMU is not set ++CONFIG_PLATFORM_INTC=y ++ ++# ++# VEP Platform Options ++# ++# CONFIG_CACHE_L2 is not set ++ ++# ++# Common Platform Options ++# ++# CONFIG_PLATFORM_AHBDMA is not set ++# CONFIG_PLATFORM_APBDMA is not set ++CONFIG_SYS_CLK=67737600 ++CONFIG_UART_CLK=36864000 ++CONFIG_SDRAM_SIZE=0x10000000 ++ ++# ++# Processor Features ++# ++CONFIG_CPU_CUSTOM=y ++# CONFIG_FPU is not set ++# CONFIG_AUDIO is not set ++# CONFIG_EVIC is not set ++CONFIG_CPU_CONTEXT_ID=y ++CONFIG_ANDES_PAGE_SIZE_4KB=y ++# CONFIG_ANDES_PAGE_SIZE_8KB is not set ++# CONFIG_KERNEL_SPACE_LARGE_PAGE is not set ++# CONFIG_CPU_ICACHE_DISABLE is not set ++# CONFIG_CPU_DCACHE_DISABLE is not set ++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set ++# CONFIG_ALIGNMENT_TRAP is not set ++CONFIG_MMU=y ++ ++# ++# Kernel Features ++# ++CONFIG_PREEMPT_NONE=y ++# CONFIG_PREEMPT_VOLUNTARY is not set ++# CONFIG_PREEMPT is not set ++CONFIG_SELECT_MEMORY_MODEL=y ++CONFIG_FLATMEM_MANUAL=y ++# CONFIG_DISCONTIGMEM_MANUAL is not set ++# CONFIG_SPARSEMEM_MANUAL is not set ++CONFIG_FLATMEM=y ++CONFIG_FLAT_NODE_MEM_MAP=y ++CONFIG_PAGEFLAGS_EXTENDED=y ++CONFIG_SPLIT_PTLOCK_CPUS=4 ++# CONFIG_PHYS_ADDR_T_64BIT is not set ++CONFIG_ZONE_DMA_FLAG=0 ++CONFIG_VIRT_TO_BUS=y ++CONFIG_UNEVICTABLE_LRU=y ++CONFIG_FORCE_MAX_ZONEORDER=11 ++CONFIG_HZ_100=y ++# CONFIG_HZ_250 is not set ++# CONFIG_HZ_300 is not set ++# CONFIG_HZ_1000 is not set ++CONFIG_HZ=100 ++# CONFIG_SCHED_HRTICK is not set ++CONFIG_CMDLINE="root=/dev/ram0 rw mem=64M@0x0 initrd=0x1000000,8M console=ttyS0,38400n8 rootfstype=ext2 init=/bin/busybox init -s user_debug=-1" ++ ++# ++# Power management options ++# ++CONFIG_SYS_SUPPORTS_APM_EMULATION=y ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++# CONFIG_PM is not set ++ ++# ++# Bus options ++# ++# CONFIG_PCI is not set ++# CONFIG_ARCH_SUPPORTS_MSI is not set ++ ++# ++# Executable file formats ++# ++CONFIG_BINFMT_ELF=y ++# CONFIG_HAVE_AOUT is not set ++# CONFIG_BINFMT_MISC is not set ++CONFIG_NET=y ++ ++# ++# Networking options ++# ++CONFIG_COMPAT_NET_DEV_OPS=y ++CONFIG_PACKET=y ++# CONFIG_PACKET_MMAP is not set ++CONFIG_UNIX=y ++CONFIG_XFRM=y ++# CONFIG_XFRM_USER is not set ++# CONFIG_XFRM_SUB_POLICY is not set ++# CONFIG_XFRM_MIGRATE is not set ++# CONFIG_XFRM_STATISTICS is not set ++CONFIG_NET_KEY=y ++# CONFIG_NET_KEY_MIGRATE is not set ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_FIB_HASH=y ++# CONFIG_IP_PNP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_IP_MROUTE is not set ++# CONFIG_ARPD is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_INET_AH is not set ++# CONFIG_INET_ESP is not set ++# CONFIG_INET_IPCOMP is not set ++# CONFIG_INET_XFRM_TUNNEL is not set ++# CONFIG_INET_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++# CONFIG_INET_DIAG is not set ++# CONFIG_TCP_CONG_ADVANCED is not set ++CONFIG_TCP_CONG_CUBIC=y ++CONFIG_DEFAULT_TCP_CONG="cubic" ++# CONFIG_TCP_MD5SIG is not set ++# CONFIG_IPV6 is not set ++# CONFIG_NETWORK_SECMARK is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_IP_DCCP is not set ++# CONFIG_IP_SCTP is not set ++# CONFIG_TIPC is not set ++# CONFIG_ATM is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_NET_DSA is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_DECNET is not set ++# CONFIG_LLC2 is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_SCHED is not set ++# CONFIG_DCB is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++# CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set ++# CONFIG_IRDA is not set ++# CONFIG_BT is not set ++# CONFIG_AF_RXRPC is not set ++# CONFIG_PHONET is not set ++CONFIG_WIRELESS=y ++# CONFIG_CFG80211 is not set ++CONFIG_WIRELESS_OLD_REGULATORY=y ++# CONFIG_WIRELESS_EXT is not set ++# CONFIG_LIB80211 is not set ++# CONFIG_MAC80211 is not set ++# CONFIG_WIMAX is not set ++# CONFIG_RFKILL is not set ++# CONFIG_NET_9P is not set ++ ++# ++# Device Drivers ++# ++ ++# ++# Generic Driver Options ++# ++CONFIG_STANDALONE=y ++CONFIG_PREVENT_FIRMWARE_BUILD=y ++# CONFIG_SYS_HYPERVISOR is not set ++# CONFIG_CONNECTOR is not set ++# CONFIG_MTD is not set ++# CONFIG_PARPORT is not set ++CONFIG_BLK_DEV=y ++# CONFIG_BLK_DEV_COW_COMMON is not set ++CONFIG_BLK_DEV_LOOP=y ++# CONFIG_BLK_DEV_CRYPTOLOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_COUNT=16 ++CONFIG_BLK_DEV_RAM_SIZE=8192 ++# CONFIG_BLK_DEV_XIP is not set ++# CONFIG_CDROM_PKTCDVD is not set ++# CONFIG_ATA_OVER_ETH is not set ++# CONFIG_FTSDC010 is not set ++# CONFIG_FTCFC010 is not set ++# CONFIG_BLK_DEV_HD is not set ++# CONFIG_MISC_DEVICES is not set ++CONFIG_HAVE_IDE=y ++# CONFIG_IDE is not set ++ ++# ++# SCSI device support ++# ++# CONFIG_RAID_ATTRS is not set ++# CONFIG_SCSI is not set ++# CONFIG_SCSI_DMA is not set ++# CONFIG_SCSI_NETLINK is not set ++# CONFIG_ATA is not set ++# CONFIG_MD is not set ++CONFIG_NETDEVICES=y ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_MACVLAN is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_VETH is not set ++# CONFIG_PHYLIB is not set ++CONFIG_NET_ETHERNET=y ++# CONFIG_MII is not set ++# CONFIG_SMC91X is not set ++# CONFIG_DNET is not set ++# CONFIG_IBM_NEW_EMAC_ZMII is not set ++# CONFIG_IBM_NEW_EMAC_RGMII is not set ++# CONFIG_IBM_NEW_EMAC_TAH is not set ++# CONFIG_IBM_NEW_EMAC_EMAC4 is not set ++# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set ++# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set ++# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set ++# CONFIG_B44 is not set ++CONFIG_FTMAC100=y ++# CONFIG_NETDEV_1000 is not set ++# CONFIG_NETDEV_10000 is not set ++ ++# ++# Wireless LAN ++# ++# CONFIG_WLAN_PRE80211 is not set ++# CONFIG_WLAN_80211 is not set ++# CONFIG_IWLWIFI_LEDS is not set ++ ++# ++# Enable WiMAX (Networking options) to see the WiMAX drivers ++# ++# CONFIG_WAN is not set ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++# CONFIG_NETCONSOLE is not set ++# CONFIG_NETPOLL is not set ++# CONFIG_NET_POLL_CONTROLLER is not set ++# CONFIG_ISDN is not set ++# CONFIG_PHONE is not set ++ ++# ++# Input device support ++# ++CONFIG_INPUT=y ++# CONFIG_INPUT_FF_MEMLESS is not set ++# CONFIG_INPUT_POLLDEV is not set ++ ++# ++# Userland interfaces ++# ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++# CONFIG_INPUT_EVDEV is not set ++# CONFIG_INPUT_EVBUG is not set ++ ++# ++# Input Device Drivers ++# ++# CONFIG_INPUT_KEYBOARD is not set ++# CONFIG_INPUT_MOUSE is not set ++# CONFIG_INPUT_JOYSTICK is not set ++# CONFIG_INPUT_TABLET is not set ++# CONFIG_INPUT_TOUCHSCREEN is not set ++# CONFIG_INPUT_MISC is not set ++ ++# ++# Hardware I/O ports ++# ++# CONFIG_SERIO is not set ++# CONFIG_GAMEPORT is not set ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_CONSOLE_TRANSLATIONS=y ++CONFIG_VT_CONSOLE=y ++CONFIG_HW_CONSOLE=y ++# CONFIG_VT_HW_CONSOLE_BINDING is not set ++CONFIG_DEVKMEM=y ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# Serial drivers ++# ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250_NR_UARTS=3 ++CONFIG_SERIAL_8250_RUNTIME_UARTS=3 ++# CONFIG_SERIAL_8250_EXTENDED is not set ++ ++# ++# Non-8250 serial port support ++# ++CONFIG_SERIAL_CORE=y ++CONFIG_SERIAL_CORE_CONSOLE=y ++CONFIG_UNIX98_PTYS=y ++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set ++CONFIG_LEGACY_PTYS=y ++CONFIG_LEGACY_PTY_COUNT=256 ++# CONFIG_IPMI_HANDLER is not set ++# CONFIG_HW_RANDOM is not set ++# CONFIG_R3964 is not set ++# CONFIG_GPIO_FTGPIO010 is not set ++# CONFIG_RAW_DRIVER is not set ++# CONFIG_TCG_TPM is not set ++# CONFIG_I2C is not set ++# CONFIG_SPI is not set ++# CONFIG_W1 is not set ++# CONFIG_POWER_SUPPLY is not set ++# CONFIG_HWMON is not set ++# CONFIG_THERMAL is not set ++# CONFIG_THERMAL_HWMON is not set ++# CONFIG_WATCHDOG is not set ++CONFIG_SSB_POSSIBLE=y ++ ++# ++# Sonics Silicon Backplane ++# ++# CONFIG_SSB is not set ++ ++# ++# Multifunction device drivers ++# ++# CONFIG_MFD_CORE is not set ++# CONFIG_MFD_SM501 is not set ++# CONFIG_HTC_PASIC3 is not set ++# CONFIG_MFD_TMIO is not set ++# CONFIG_REGULATOR is not set ++ ++# ++# Multimedia devices ++# ++ ++# ++# Multimedia core support ++# ++# CONFIG_VIDEO_DEV is not set ++# CONFIG_DVB_CORE is not set ++# CONFIG_VIDEO_MEDIA is not set ++ ++# ++# Multimedia drivers ++# ++# CONFIG_DAB is not set ++ ++# ++# Graphics support ++# ++# CONFIG_VGASTATE is not set ++# CONFIG_VIDEO_OUTPUT_CONTROL is not set ++# CONFIG_FB is not set ++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set ++ ++# ++# Display device support ++# ++# CONFIG_DISPLAY_SUPPORT is not set ++ ++# ++# Console display driver support ++# ++# CONFIG_VGA_CONSOLE is not set ++CONFIG_DUMMY_CONSOLE=y ++# CONFIG_SOUND is not set ++# CONFIG_HID_SUPPORT is not set ++# CONFIG_USB_SUPPORT is not set ++# CONFIG_MMC is not set ++# CONFIG_MEMSTICK is not set ++# CONFIG_NEW_LEDS is not set ++# CONFIG_ACCESSIBILITY is not set ++CONFIG_RTC_LIB=y ++# CONFIG_RTC_CLASS is not set ++# CONFIG_DMADEVICES is not set ++# CONFIG_UIO is not set ++# CONFIG_STAGING is not set ++ ++# ++# File systems ++# ++CONFIG_EXT2_FS=y ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XIP is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_EXT4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_FS_POSIX_ACL is not set ++CONFIG_FILE_LOCKING=y ++# CONFIG_XFS_FS is not set ++# CONFIG_OCFS2_FS is not set ++# CONFIG_BTRFS_FS is not set ++CONFIG_DNOTIFY=y ++CONFIG_INOTIFY=y ++CONFIG_INOTIFY_USER=y ++# CONFIG_QUOTA is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++CONFIG_FUSE_FS=y ++ ++# ++# CD-ROM/DVD Filesystems ++# ++# CONFIG_ISO9660_FS is not set ++# CONFIG_UDF_FS is not set ++ ++# ++# DOS/FAT/NT Filesystems ++# ++# CONFIG_MSDOS_FS is not set ++# CONFIG_VFAT_FS is not set ++# CONFIG_NTFS_FS is not set ++ ++# ++# Pseudo filesystems ++# ++CONFIG_PROC_FS=y ++# CONFIG_PROC_KCORE is not set ++CONFIG_PROC_SYSCTL=y ++# CONFIG_PROC_PAGE_MONITOR is not set ++CONFIG_SYSFS=y ++CONFIG_TMPFS=y ++# CONFIG_TMPFS_POSIX_ACL is not set ++# CONFIG_HUGETLB_PAGE is not set ++# CONFIG_CONFIGFS_FS is not set ++CONFIG_MISC_FILESYSTEMS=y ++# CONFIG_ADFS_FS is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_HFSPLUS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EFS_FS is not set ++# CONFIG_CRAMFS is not set ++# CONFIG_SQUASHFS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_OMFS_FS is not set ++# CONFIG_HPFS_FS is not set ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_SYSV_FS is not set ++# CONFIG_UFS_FS is not set ++CONFIG_NETWORK_FILESYSTEMS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++# CONFIG_NFS_V3_ACL is not set ++# CONFIG_NFS_V4 is not set ++# CONFIG_NFSD is not set ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++CONFIG_NFS_COMMON=y ++CONFIG_SUNRPC=y ++# CONFIG_SUNRPC_REGISTER_V4 is not set ++# CONFIG_RPCSEC_GSS_KRB5 is not set ++# CONFIG_RPCSEC_GSS_SPKM3 is not set ++# CONFIG_SMB_FS is not set ++# CONFIG_CIFS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_CODA_FS is not set ++# CONFIG_AFS_FS is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=y ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++# CONFIG_NLS_ASCII is not set ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++# CONFIG_DLM is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_TRACE_IRQFLAGS_SUPPORT=y ++# CONFIG_PRINTK_TIME is not set ++CONFIG_ENABLE_WARN_DEPRECATED=y ++CONFIG_ENABLE_MUST_CHECK=y ++CONFIG_FRAME_WARN=1024 ++# CONFIG_MAGIC_SYSRQ is not set ++# CONFIG_UNUSED_SYMBOLS is not set ++CONFIG_DEBUG_FS=y ++# CONFIG_HEADERS_CHECK is not set ++# CONFIG_DEBUG_KERNEL is not set ++# CONFIG_SLUB_DEBUG_ON is not set ++# CONFIG_SLUB_STATS is not set ++CONFIG_STACKTRACE=y ++# CONFIG_DEBUG_MEMORY_INIT is not set ++CONFIG_FRAME_POINTER=y ++# CONFIG_RCU_CPU_STALL_DETECTOR is not set ++# CONFIG_LATENCYTOP is not set ++CONFIG_SYSCTL_SYSCALL_CHECK=y ++CONFIG_NOP_TRACER=y ++CONFIG_RING_BUFFER=y ++CONFIG_TRACING=y ++ ++# ++# Tracers ++# ++# CONFIG_DYNAMIC_PRINTK_DEBUG is not set ++# CONFIG_SAMPLES is not set ++CONFIG_HAVE_ARCH_KGDB=y ++CONFIG_DEBUG_USER=y ++# CONFIG_CCTL is not set ++CONFIG_ELFCHK_DEFAULT_ENABLE=y ++ ++# ++# Security options ++# ++# CONFIG_KEYS is not set ++# CONFIG_SECURITY is not set ++# CONFIG_SECURITYFS is not set ++# CONFIG_SECURITY_FILE_CAPABILITIES is not set ++CONFIG_CRYPTO=y ++ ++# ++# Crypto core or helper ++# ++# CONFIG_CRYPTO_FIPS is not set ++# CONFIG_CRYPTO_MANAGER is not set ++# CONFIG_CRYPTO_MANAGER2 is not set ++# CONFIG_CRYPTO_GF128MUL is not set ++# CONFIG_CRYPTO_NULL is not set ++# CONFIG_CRYPTO_CRYPTD is not set ++# CONFIG_CRYPTO_AUTHENC is not set ++# CONFIG_CRYPTO_TEST is not set ++ ++# ++# Authenticated Encryption with Associated Data ++# ++# CONFIG_CRYPTO_CCM is not set ++# CONFIG_CRYPTO_GCM is not set ++# CONFIG_CRYPTO_SEQIV is not set ++ ++# ++# Block modes ++# ++# CONFIG_CRYPTO_CBC is not set ++# CONFIG_CRYPTO_CTR is not set ++# CONFIG_CRYPTO_CTS is not set ++# CONFIG_CRYPTO_ECB is not set ++# CONFIG_CRYPTO_LRW is not set ++# CONFIG_CRYPTO_PCBC is not set ++# CONFIG_CRYPTO_XTS is not set ++ ++# ++# Hash modes ++# ++# CONFIG_CRYPTO_HMAC is not set ++# CONFIG_CRYPTO_XCBC is not set ++ ++# ++# Digest ++# ++# CONFIG_CRYPTO_CRC32C is not set ++# CONFIG_CRYPTO_MD4 is not set ++# CONFIG_CRYPTO_MD5 is not set ++# CONFIG_CRYPTO_MICHAEL_MIC is not set ++# CONFIG_CRYPTO_RMD128 is not set ++# CONFIG_CRYPTO_RMD160 is not set ++# CONFIG_CRYPTO_RMD256 is not set ++# CONFIG_CRYPTO_RMD320 is not set ++# CONFIG_CRYPTO_SHA1 is not set ++# CONFIG_CRYPTO_SHA256 is not set ++# CONFIG_CRYPTO_SHA512 is not set ++# CONFIG_CRYPTO_TGR192 is not set ++# CONFIG_CRYPTO_WP512 is not set ++ ++# ++# Ciphers ++# ++# CONFIG_CRYPTO_AES is not set ++# CONFIG_CRYPTO_ANUBIS is not set ++# CONFIG_CRYPTO_ARC4 is not set ++# CONFIG_CRYPTO_BLOWFISH is not set ++# CONFIG_CRYPTO_CAMELLIA is not set ++# CONFIG_CRYPTO_CAST5 is not set ++# CONFIG_CRYPTO_CAST6 is not set ++# CONFIG_CRYPTO_DES is not set ++# CONFIG_CRYPTO_FCRYPT is not set ++# CONFIG_CRYPTO_KHAZAD is not set ++# CONFIG_CRYPTO_SALSA20 is not set ++# CONFIG_CRYPTO_SEED is not set ++# CONFIG_CRYPTO_SERPENT is not set ++# CONFIG_CRYPTO_TEA is not set ++# CONFIG_CRYPTO_TWOFISH is not set ++ ++# ++# Compression ++# ++# CONFIG_CRYPTO_DEFLATE is not set ++# CONFIG_CRYPTO_LZO is not set ++ ++# ++# Random Number Generation ++# ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++# CONFIG_CRYPTO_HW is not set ++ ++# ++# Library routines ++# ++CONFIG_GENERIC_FIND_LAST_BIT=y ++# CONFIG_CRC_CCITT is not set ++# CONFIG_CRC16 is not set ++# CONFIG_CRC_T10DIF is not set ++# CONFIG_CRC_ITU_T is not set ++# CONFIG_CRC32 is not set ++# CONFIG_CRC7 is not set ++# CONFIG_LIBCRC32C is not set ++CONFIG_PLIST=y ++CONFIG_HAS_IOMEM=y ++CONFIG_HAS_DMA=y +diff -Nur linux-3.4.110.orig/arch/nds32/configs/xc5_8k_defconfig linux-3.4.110/arch/nds32/configs/xc5_8k_defconfig +--- linux-3.4.110.orig/arch/nds32/configs/xc5_8k_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/configs/xc5_8k_defconfig 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,1051 @@ ++# ++# Automatically generated make config: don't edit ++# Linux kernel version: 2.6.29 ++# Fri Oct 2 14:21:05 2009 ++# ++CONFIG_NDS32=y ++# CONFIG_GENERIC_GPIO is not set ++CONFIG_NO_IOPORT=y ++CONFIG_GENERIC_IOMAP=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++CONFIG_GENERIC_HWEIGHT=y ++CONFIG_GENERIC_FIND_NEXT_BIT=y ++CONFIG_GENERIC_CALIBRATE_DELAY=y ++CONFIG_GENERIC_HARDIRQS=y ++CONFIG_LOCKDEP_SUPPORT=y ++CONFIG_STACKTRACE_SUPPORT=y ++CONFIG_HAVE_LATENCYTOP_SUPPORT=y ++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" ++ ++# ++# General setup ++# ++CONFIG_EXPERIMENTAL=y ++CONFIG_BROKEN_ON_SMP=y ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++CONFIG_LOCALVERSION="" ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_SWAP=y ++CONFIG_SYSVIPC=y ++CONFIG_SYSVIPC_SYSCTL=y ++# CONFIG_POSIX_MQUEUE is not set ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_BSD_PROCESS_ACCT_V3=y ++# CONFIG_TASKSTATS is not set ++# CONFIG_AUDIT is not set ++ ++# ++# RCU Subsystem ++# ++CONFIG_CLASSIC_RCU=y ++# CONFIG_TREE_RCU is not set ++# CONFIG_PREEMPT_RCU is not set ++# CONFIG_TREE_RCU_TRACE is not set ++# CONFIG_PREEMPT_RCU_TRACE is not set ++# CONFIG_IKCONFIG is not set ++CONFIG_LOG_BUF_SHIFT=14 ++# CONFIG_GROUP_SCHED is not set ++# CONFIG_CGROUPS is not set ++# CONFIG_SYSFS_DEPRECATED_V2 is not set ++# CONFIG_RELAY is not set ++# CONFIG_NAMESPACES is not set ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_INITRAMFS_SOURCE="" ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_SYSCTL=y ++CONFIG_ANON_INODES=y ++CONFIG_EMBEDDED=y ++CONFIG_UID16=y ++CONFIG_SYSCTL_SYSCALL=y ++CONFIG_KALLSYMS=y ++# CONFIG_KALLSYMS_ALL is not set ++CONFIG_KALLSYMS_EXTRA_PASS=y ++# CONFIG_HOTPLUG is not set ++CONFIG_PRINTK=y ++CONFIG_BUG=y ++CONFIG_ELF_CORE=y ++CONFIG_BASE_FULL=y ++CONFIG_FUTEX=y ++CONFIG_EPOLL=y ++# CONFIG_SIGNALFD is not set ++CONFIG_TIMERFD=y ++CONFIG_EVENTFD=y ++CONFIG_SHMEM=y ++CONFIG_AIO=y ++# CONFIG_VM_EVENT_COUNTERS is not set ++CONFIG_SLUB_DEBUG=y ++CONFIG_COMPAT_BRK=y ++# CONFIG_SLAB is not set ++CONFIG_SLUB=y ++# CONFIG_SLOB is not set ++CONFIG_PROFILING=y ++CONFIG_TRACEPOINTS=y ++# CONFIG_MARKERS is not set ++CONFIG_OPROFILE=y ++CONFIG_HAVE_OPROFILE=y ++# CONFIG_KPROBES is not set ++CONFIG_HAVE_KPROBES=y ++CONFIG_HAVE_KRETPROBES=y ++# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set ++CONFIG_SLABINFO=y ++CONFIG_RT_MUTEXES=y ++CONFIG_BASE_SMALL=0 ++CONFIG_MODULES=y ++# CONFIG_MODULE_FORCE_LOAD is not set ++CONFIG_MODULE_UNLOAD=y ++# CONFIG_MODULE_FORCE_UNLOAD is not set ++# CONFIG_MODVERSIONS is not set ++# CONFIG_MODULE_SRCVERSION_ALL is not set ++CONFIG_BLOCK=y ++# CONFIG_LBD is not set ++# CONFIG_BLK_DEV_IO_TRACE is not set ++# CONFIG_BLK_DEV_BSG is not set ++# CONFIG_BLK_DEV_INTEGRITY is not set ++ ++# ++# IO Schedulers ++# ++CONFIG_IOSCHED_NOOP=y ++CONFIG_IOSCHED_AS=y ++CONFIG_IOSCHED_DEADLINE=y ++CONFIG_IOSCHED_CFQ=y ++# CONFIG_DEFAULT_AS is not set ++# CONFIG_DEFAULT_DEADLINE is not set ++CONFIG_DEFAULT_CFQ=y ++# CONFIG_DEFAULT_NOOP is not set ++CONFIG_DEFAULT_IOSCHED="cfq" ++# CONFIG_FREEZER is not set ++ ++# ++# System Type ++# ++# CONFIG_PLAT_VEP is not set ++# CONFIG_PLAT_AG101 is not set ++# CONFIG_PLAT_AG102 is not set ++CONFIG_PLAT_AG101P=y ++# CONFIG_PLAT_QEMU is not set ++CONFIG_PLATFORM_INTC=y ++CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y ++ ++# ++# AG101P Platform Options ++# ++ ++# ++# Common Platform Options ++# ++CONFIG_PLATFORM_AHBDMA=y ++CONFIG_PLATFORM_APBDMA=y ++CONFIG_SYS_CLK=40000000 ++CONFIG_UART_CLK=14745600 ++CONFIG_SDRAM_SIZE=0x10000000 ++ ++# ++# Processor Features ++# ++CONFIG_CPU_CUSTOM=y ++# CONFIG_FPU is not set ++# CONFIG_AUDIO is not set ++# CONFIG_EVIC is not set ++CONFIG_CPU_CONTEXT_ID=y ++# CONFIG_CPU_CACHE_NONALIASING is not set ++# CONFIG_ANDES_PAGE_SIZE_4KB is not set ++CONFIG_ANDES_PAGE_SIZE_8KB=y ++CONFIG_KERNEL_SPACE_LARGE_PAGE=y ++# CONFIG_CPU_ICACHE_DISABLE is not set ++# CONFIG_CPU_DCACHE_DISABLE is not set ++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set ++# CONFIG_ABI1 is not set ++CONFIG_ALIGNMENT_TRAP=y ++CONFIG_GENERIC_TIME=y ++CONFIG_GENERIC_CLOCKEVENTS=y ++CONFIG_MMU=y ++ ++# ++# Kernel Features ++# ++# CONFIG_NO_HZ is not set ++# CONFIG_HIGH_RES_TIMERS is not set ++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y ++CONFIG_PREEMPT_NONE=y ++# CONFIG_PREEMPT_VOLUNTARY is not set ++# CONFIG_PREEMPT is not set ++CONFIG_SELECT_MEMORY_MODEL=y ++CONFIG_FLATMEM_MANUAL=y ++# CONFIG_DISCONTIGMEM_MANUAL is not set ++# CONFIG_SPARSEMEM_MANUAL is not set ++CONFIG_FLATMEM=y ++CONFIG_FLAT_NODE_MEM_MAP=y ++CONFIG_PAGEFLAGS_EXTENDED=y ++CONFIG_SPLIT_PTLOCK_CPUS=4 ++# CONFIG_PHYS_ADDR_T_64BIT is not set ++CONFIG_ZONE_DMA_FLAG=0 ++CONFIG_VIRT_TO_BUS=y ++CONFIG_UNEVICTABLE_LRU=y ++CONFIG_FORCE_MAX_ZONEORDER=11 ++CONFIG_HZ_100=y ++# CONFIG_HZ_250 is not set ++# CONFIG_HZ_300 is not set ++# CONFIG_HZ_1000 is not set ++CONFIG_HZ=100 ++# CONFIG_SCHED_HRTICK is not set ++CONFIG_CMDLINE="root=/dev/ram0 rw mem=128M@0x0 initrd=0x1000000,8M console=ttyS0,38400n8 rootfstype=ext2 init=/bin/busybox init -s user_debug=-1" ++ ++# ++# Power management options ++# ++CONFIG_SYS_SUPPORTS_APM_EMULATION=y ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++# CONFIG_PM is not set ++ ++# ++# Bus options ++# ++# CONFIG_PCI is not set ++# CONFIG_ARCH_SUPPORTS_MSI is not set ++ ++# ++# Executable file formats ++# ++CONFIG_BINFMT_ELF=y ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++# CONFIG_HAVE_AOUT is not set ++# CONFIG_BINFMT_MISC is not set ++CONFIG_NET=y ++ ++# ++# Networking options ++# ++CONFIG_COMPAT_NET_DEV_OPS=y ++CONFIG_PACKET=y ++# CONFIG_PACKET_MMAP is not set ++CONFIG_UNIX=y ++CONFIG_XFRM=y ++# CONFIG_XFRM_USER is not set ++# CONFIG_XFRM_SUB_POLICY is not set ++# CONFIG_XFRM_MIGRATE is not set ++# CONFIG_XFRM_STATISTICS is not set ++CONFIG_NET_KEY=y ++# CONFIG_NET_KEY_MIGRATE is not set ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_FIB_HASH=y ++# CONFIG_IP_PNP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_IP_MROUTE is not set ++# CONFIG_ARPD is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_INET_AH is not set ++# CONFIG_INET_ESP is not set ++# CONFIG_INET_IPCOMP is not set ++# CONFIG_INET_XFRM_TUNNEL is not set ++# CONFIG_INET_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++# CONFIG_INET_DIAG is not set ++# CONFIG_TCP_CONG_ADVANCED is not set ++CONFIG_TCP_CONG_CUBIC=y ++CONFIG_DEFAULT_TCP_CONG="cubic" ++# CONFIG_TCP_MD5SIG is not set ++# CONFIG_IPV6 is not set ++# CONFIG_NETWORK_SECMARK is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_IP_DCCP is not set ++# CONFIG_IP_SCTP is not set ++# CONFIG_TIPC is not set ++# CONFIG_ATM is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_NET_DSA is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_DECNET is not set ++# CONFIG_LLC2 is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_SCHED is not set ++# CONFIG_DCB is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++# CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set ++# CONFIG_IRDA is not set ++# CONFIG_BT is not set ++# CONFIG_AF_RXRPC is not set ++# CONFIG_PHONET is not set ++CONFIG_WIRELESS=y ++# CONFIG_CFG80211 is not set ++CONFIG_WIRELESS_OLD_REGULATORY=y ++# CONFIG_WIRELESS_EXT is not set ++# CONFIG_LIB80211 is not set ++# CONFIG_MAC80211 is not set ++# CONFIG_WIMAX is not set ++# CONFIG_RFKILL is not set ++# CONFIG_NET_9P is not set ++ ++# ++# Device Drivers ++# ++ ++# ++# Generic Driver Options ++# ++CONFIG_STANDALONE=y ++CONFIG_PREVENT_FIRMWARE_BUILD=y ++# CONFIG_DEBUG_DRIVER is not set ++# CONFIG_DEBUG_DEVRES is not set ++# CONFIG_SYS_HYPERVISOR is not set ++# CONFIG_CONNECTOR is not set ++CONFIG_MTD=y ++# CONFIG_MTD_DEBUG is not set ++# CONFIG_MTD_CONCAT is not set ++CONFIG_MTD_PARTITIONS=y ++# CONFIG_MTD_TESTS is not set ++# CONFIG_MTD_REDBOOT_PARTS is not set ++CONFIG_MTD_CMDLINE_PARTS=y ++# CONFIG_MTD_AR7_PARTS is not set ++ ++# ++# User Modules And Translation Layers ++# ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLKDEVS=y ++CONFIG_MTD_BLOCK=y ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++# CONFIG_INFTL is not set ++# CONFIG_RFD_FTL is not set ++# CONFIG_SSFDC is not set ++# CONFIG_MTD_OOPS is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++CONFIG_MTD_CFI=y ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_GEN_PROBE=y ++# CONFIG_MTD_CFI_ADV_OPTIONS is not set ++CONFIG_MTD_MAP_BANK_WIDTH_1=y ++CONFIG_MTD_MAP_BANK_WIDTH_2=y ++CONFIG_MTD_MAP_BANK_WIDTH_4=y ++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set ++CONFIG_MTD_CFI_I1=y ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_CFI_STAA is not set ++CONFIG_MTD_CFI_UTIL=y ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_COMPLEX_MAPPINGS is not set ++CONFIG_MTD_PHYSMAP=y ++CONFIG_MTD_PHYSMAP_COMPAT=y ++CONFIG_MTD_PHYSMAP_START=0x80400000 ++CONFIG_MTD_PHYSMAP_LEN=0x2000000 ++CONFIG_MTD_PHYSMAP_BANKWIDTH=4 ++# CONFIG_MTD_PLATRAM is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_PHRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++# CONFIG_MTD_BLOCK2MTD is not set ++ ++# ++# Disk-On-Chip Device Drivers ++# ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOC2001PLUS is not set ++# CONFIG_MTD_NAND is not set ++# CONFIG_MTD_ONENAND is not set ++ ++# ++# LPDDR flash memory drivers ++# ++# CONFIG_MTD_LPDDR is not set ++ ++# ++# UBI - Unsorted block images ++# ++# CONFIG_MTD_UBI is not set ++# CONFIG_PARPORT is not set ++CONFIG_BLK_DEV=y ++# CONFIG_BLK_DEV_COW_COMMON is not set ++CONFIG_BLK_DEV_LOOP=y ++# CONFIG_BLK_DEV_CRYPTOLOOP is not set ++# CONFIG_BLK_DEV_NBD is not set ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_COUNT=16 ++CONFIG_BLK_DEV_RAM_SIZE=8192 ++# CONFIG_BLK_DEV_XIP is not set ++# CONFIG_CDROM_PKTCDVD is not set ++# CONFIG_ATA_OVER_ETH is not set ++CONFIG_FTSDC010=y ++# CONFIG_FTCFC010 is not set ++# CONFIG_BLK_DEV_HD is not set ++# CONFIG_MISC_DEVICES is not set ++CONFIG_HAVE_IDE=y ++# CONFIG_IDE is not set ++ ++# ++# SCSI device support ++# ++# CONFIG_RAID_ATTRS is not set ++# CONFIG_SCSI is not set ++# CONFIG_SCSI_DMA is not set ++# CONFIG_SCSI_NETLINK is not set ++# CONFIG_ATA is not set ++# CONFIG_MD is not set ++CONFIG_NETDEVICES=y ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_MACVLAN is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_VETH is not set ++# CONFIG_PHYLIB is not set ++CONFIG_NET_ETHERNET=y ++# CONFIG_MII is not set ++# CONFIG_SMC91X is not set ++# CONFIG_DNET is not set ++# CONFIG_IBM_NEW_EMAC_ZMII is not set ++# CONFIG_IBM_NEW_EMAC_RGMII is not set ++# CONFIG_IBM_NEW_EMAC_TAH is not set ++# CONFIG_IBM_NEW_EMAC_EMAC4 is not set ++# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set ++# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set ++# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set ++# CONFIG_B44 is not set ++CONFIG_FTMAC100=y ++# CONFIG_NETDEV_1000 is not set ++# CONFIG_NETDEV_10000 is not set ++ ++# ++# Wireless LAN ++# ++# CONFIG_WLAN_PRE80211 is not set ++# CONFIG_WLAN_80211 is not set ++# CONFIG_IWLWIFI_LEDS is not set ++ ++# ++# Enable WiMAX (Networking options) to see the WiMAX drivers ++# ++# CONFIG_WAN is not set ++# CONFIG_PPP is not set ++# CONFIG_SLIP is not set ++# CONFIG_NETCONSOLE is not set ++# CONFIG_NETPOLL is not set ++# CONFIG_NET_POLL_CONTROLLER is not set ++# CONFIG_ISDN is not set ++# CONFIG_PHONE is not set ++ ++# ++# Input device support ++# ++CONFIG_INPUT=y ++# CONFIG_INPUT_FF_MEMLESS is not set ++# CONFIG_INPUT_POLLDEV is not set ++ ++# ++# Userland interfaces ++# ++# CONFIG_INPUT_MOUSEDEV is not set ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++# CONFIG_INPUT_EVBUG is not set ++ ++# ++# Input Device Drivers ++# ++# CONFIG_INPUT_KEYBOARD is not set ++# CONFIG_INPUT_MOUSE is not set ++# CONFIG_INPUT_JOYSTICK is not set ++# CONFIG_INPUT_TABLET is not set ++CONFIG_INPUT_TOUCHSCREEN=y ++CONFIG_TOUCHSCREEN_CPE_TS=y ++CONFIG_TOUCHSCREEN_CPE_TS_DEJITTER=y ++# CONFIG_TOUCHSCREEN_FUJITSU is not set ++# CONFIG_TOUCHSCREEN_GUNZE is not set ++# CONFIG_TOUCHSCREEN_ELO is not set ++# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set ++# CONFIG_TOUCHSCREEN_MTOUCH is not set ++# CONFIG_TOUCHSCREEN_INEXIO is not set ++# CONFIG_TOUCHSCREEN_MK712 is not set ++# CONFIG_TOUCHSCREEN_PENMOUNT is not set ++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set ++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set ++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set ++# CONFIG_INPUT_MISC is not set ++ ++# ++# Hardware I/O ports ++# ++# CONFIG_SERIO is not set ++# CONFIG_GAMEPORT is not set ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_CONSOLE_TRANSLATIONS=y ++CONFIG_VT_CONSOLE=y ++CONFIG_HW_CONSOLE=y ++# CONFIG_VT_HW_CONSOLE_BINDING is not set ++CONFIG_DEVKMEM=y ++# CONFIG_SERIAL_NONSTANDARD is not set ++ ++# ++# Serial drivers ++# ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250_NR_UARTS=3 ++CONFIG_SERIAL_8250_RUNTIME_UARTS=3 ++# CONFIG_SERIAL_8250_EXTENDED is not set ++ ++# ++# Non-8250 serial port support ++# ++CONFIG_SERIAL_CORE=y ++CONFIG_SERIAL_CORE_CONSOLE=y ++CONFIG_UNIX98_PTYS=y ++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set ++CONFIG_LEGACY_PTYS=y ++CONFIG_LEGACY_PTY_COUNT=256 ++# CONFIG_IPMI_HANDLER is not set ++# CONFIG_HW_RANDOM is not set ++# CONFIG_R3964 is not set ++# CONFIG_GPIO_FTGPIO010_OLD is not set ++# CONFIG_RAW_DRIVER is not set ++# CONFIG_TCG_TPM is not set ++# CONFIG_I2C is not set ++# CONFIG_SPI is not set ++# CONFIG_GPIOLIB is not set ++# CONFIG_W1 is not set ++# CONFIG_POWER_SUPPLY is not set ++# CONFIG_HWMON is not set ++# CONFIG_THERMAL is not set ++# CONFIG_THERMAL_HWMON is not set ++# CONFIG_WATCHDOG is not set ++CONFIG_SSB_POSSIBLE=y ++ ++# ++# Sonics Silicon Backplane ++# ++# CONFIG_SSB is not set ++ ++# ++# Multifunction device drivers ++# ++# CONFIG_MFD_CORE is not set ++# CONFIG_MFD_SM501 is not set ++# CONFIG_HTC_PASIC3 is not set ++# CONFIG_MFD_TMIO is not set ++# CONFIG_REGULATOR is not set ++ ++# ++# Multimedia devices ++# ++ ++# ++# Multimedia core support ++# ++# CONFIG_VIDEO_DEV is not set ++# CONFIG_DVB_CORE is not set ++# CONFIG_VIDEO_MEDIA is not set ++ ++# ++# Multimedia drivers ++# ++# CONFIG_DAB is not set ++ ++# ++# Graphics support ++# ++# CONFIG_VGASTATE is not set ++# CONFIG_VIDEO_OUTPUT_CONTROL is not set ++CONFIG_FB=y ++# CONFIG_FIRMWARE_EDID is not set ++# CONFIG_FB_DDC is not set ++# CONFIG_FB_BOOT_VESA_SUPPORT is not set ++CONFIG_FB_CFB_FILLRECT=y ++CONFIG_FB_CFB_COPYAREA=y ++CONFIG_FB_CFB_IMAGEBLIT=y ++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set ++# CONFIG_FB_SYS_FILLRECT is not set ++# CONFIG_FB_SYS_COPYAREA is not set ++# CONFIG_FB_SYS_IMAGEBLIT is not set ++# CONFIG_FB_FOREIGN_ENDIAN is not set ++# CONFIG_FB_SYS_FOPS is not set ++# CONFIG_FB_SVGALIB is not set ++# CONFIG_FB_MACMODES is not set ++# CONFIG_FB_BACKLIGHT is not set ++# CONFIG_FB_MODE_HELPERS is not set ++# CONFIG_FB_TILEBLITTING is not set ++ ++# ++# Frame buffer hardware drivers ++# ++# CONFIG_FB_S1D13XXX is not set ++CONFIG_FB_FTLCDC100=y ++CONFIG_PANEL_AUA036QN01=y ++# CONFIG_PANEL_CH7013A is not set ++# CONFIG_PANEL_AUA070VW04 is not set ++# CONFIG_PANEL_LW500AC9601 is not set ++CONFIG_FFB_MODE_RGB=y ++# CONFIG_FFB_MODE_YUV422 is not set ++# CONFIG_FFB_MODE_YUV420 is not set ++# CONFIG_FFB_MODE_8BPP is not set ++CONFIG_FFB_MODE_16BPP=y ++# CONFIG_FFB_MODE_24BPP is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FB_METRONOME is not set ++# CONFIG_FB_MB862XX is not set ++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set ++ ++# ++# Display device support ++# ++# CONFIG_DISPLAY_SUPPORT is not set ++ ++# ++# Console display driver support ++# ++# CONFIG_VGA_CONSOLE is not set ++CONFIG_DUMMY_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE=y ++# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set ++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set ++# CONFIG_FONTS is not set ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++CONFIG_LOGO=y ++CONFIG_LOGO_LINUX_MONO=y ++CONFIG_LOGO_LINUX_VGA16=y ++CONFIG_LOGO_LINUX_CLUT224=y ++CONFIG_SOUND=y ++CONFIG_SOUND_OSS_CORE=y ++CONFIG_SND=y ++CONFIG_SND_TIMER=y ++CONFIG_SND_PCM=y ++# CONFIG_SND_SEQUENCER is not set ++CONFIG_SND_OSSEMUL=y ++# CONFIG_SND_MIXER_OSS is not set ++CONFIG_SND_PCM_OSS=y ++CONFIG_SND_PCM_OSS_PLUGINS=y ++# CONFIG_SND_DYNAMIC_MINORS is not set ++# CONFIG_SND_SUPPORT_OLD_API is not set ++# CONFIG_SND_VERBOSE_PROCFS is not set ++# CONFIG_SND_VERBOSE_PRINTK is not set ++# CONFIG_SND_DEBUG is not set ++CONFIG_SND_DRIVERS=y ++# CONFIG_SND_DUMMY is not set ++# CONFIG_SND_MTPAV is not set ++# CONFIG_SND_SERIAL_U16550 is not set ++# CONFIG_SND_MPU401 is not set ++ ++# ++# ALSA NDS32 devices ++# ++CONFIG_SND_FTSSP010=y ++CONFIG_SND_FTSSP010_AC97=y ++# CONFIG_SND_FTSSP010_I2S is not set ++# CONFIG_SND_SOC is not set ++# CONFIG_SOUND_PRIME is not set ++# CONFIG_HID_SUPPORT is not set ++# CONFIG_USB_SUPPORT is not set ++# CONFIG_MMC is not set ++# CONFIG_MEMSTICK is not set ++# CONFIG_NEW_LEDS is not set ++# CONFIG_ACCESSIBILITY is not set ++CONFIG_RTC_LIB=y ++CONFIG_RTC_CLASS=y ++# CONFIG_RTC_HCTOSYS is not set ++# CONFIG_RTC_DEBUG is not set ++ ++# ++# RTC interfaces ++# ++CONFIG_RTC_INTF_SYSFS=y ++CONFIG_RTC_INTF_PROC=y ++CONFIG_RTC_INTF_DEV=y ++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set ++# CONFIG_RTC_DRV_TEST is not set ++ ++# ++# SPI RTC drivers ++# ++ ++# ++# Platform RTC drivers ++# ++# CONFIG_RTC_DRV_DS1286 is not set ++# CONFIG_RTC_DRV_DS1511 is not set ++# CONFIG_RTC_DRV_DS1553 is not set ++# CONFIG_RTC_DRV_DS1742 is not set ++# CONFIG_RTC_DRV_STK17TA8 is not set ++# CONFIG_RTC_DRV_M48T86 is not set ++# CONFIG_RTC_DRV_M48T35 is not set ++# CONFIG_RTC_DRV_M48T59 is not set ++# CONFIG_RTC_DRV_BQ4802 is not set ++# CONFIG_RTC_DRV_V3020 is not set ++ ++# ++# on-CPU RTC drivers ++# ++CONFIG_RTC_DRV_FTRTC010=y ++# CONFIG_DMADEVICES is not set ++# CONFIG_UIO is not set ++# CONFIG_STAGING is not set ++ ++# ++# File systems ++# ++CONFIG_EXT2_FS=y ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XIP is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_EXT4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_FS_POSIX_ACL is not set ++CONFIG_FILE_LOCKING=y ++# CONFIG_XFS_FS is not set ++# CONFIG_OCFS2_FS is not set ++# CONFIG_BTRFS_FS is not set ++CONFIG_DNOTIFY=y ++CONFIG_INOTIFY=y ++CONFIG_INOTIFY_USER=y ++# CONFIG_QUOTA is not set ++# CONFIG_AUTOFS_FS is not set ++# CONFIG_AUTOFS4_FS is not set ++CONFIG_FUSE_FS=y ++ ++# ++# CD-ROM/DVD Filesystems ++# ++# CONFIG_ISO9660_FS is not set ++# CONFIG_UDF_FS is not set ++ ++# ++# DOS/FAT/NT Filesystems ++# ++CONFIG_FAT_FS=y ++CONFIG_MSDOS_FS=y ++CONFIG_VFAT_FS=y ++CONFIG_FAT_DEFAULT_CODEPAGE=437 ++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" ++# CONFIG_NTFS_FS is not set ++ ++# ++# Pseudo filesystems ++# ++CONFIG_PROC_FS=y ++# CONFIG_PROC_KCORE is not set ++CONFIG_PROC_SYSCTL=y ++# CONFIG_PROC_PAGE_MONITOR is not set ++CONFIG_SYSFS=y ++CONFIG_TMPFS=y ++# CONFIG_TMPFS_POSIX_ACL is not set ++# CONFIG_HUGETLB_PAGE is not set ++# CONFIG_CONFIGFS_FS is not set ++CONFIG_MISC_FILESYSTEMS=y ++# CONFIG_ADFS_FS is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_HFSPLUS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++CONFIG_JFFS2_FS_WRITEBUFFER=y ++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set ++# CONFIG_JFFS2_SUMMARY is not set ++# CONFIG_JFFS2_FS_XATTR is not set ++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set ++CONFIG_JFFS2_ZLIB=y ++# CONFIG_JFFS2_LZO is not set ++CONFIG_JFFS2_RTIME=y ++# CONFIG_JFFS2_RUBIN is not set ++# CONFIG_CRAMFS is not set ++# CONFIG_SQUASHFS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_OMFS_FS is not set ++# CONFIG_HPFS_FS is not set ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_SYSV_FS is not set ++# CONFIG_UFS_FS is not set ++CONFIG_NETWORK_FILESYSTEMS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++# CONFIG_NFS_V3_ACL is not set ++# CONFIG_NFS_V4 is not set ++# CONFIG_NFSD is not set ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++CONFIG_NFS_COMMON=y ++CONFIG_SUNRPC=y ++# CONFIG_SUNRPC_REGISTER_V4 is not set ++# CONFIG_RPCSEC_GSS_KRB5 is not set ++# CONFIG_RPCSEC_GSS_SPKM3 is not set ++# CONFIG_SMB_FS is not set ++# CONFIG_CIFS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_CODA_FS is not set ++# CONFIG_AFS_FS is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=y ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++# CONFIG_NLS_ASCII is not set ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++# CONFIG_DLM is not set ++ ++# ++# Kernel hacking ++# ++CONFIG_TRACE_IRQFLAGS_SUPPORT=y ++# CONFIG_PRINTK_TIME is not set ++CONFIG_ENABLE_WARN_DEPRECATED=y ++CONFIG_ENABLE_MUST_CHECK=y ++CONFIG_FRAME_WARN=1024 ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_UNUSED_SYMBOLS is not set ++CONFIG_DEBUG_FS=y ++# CONFIG_HEADERS_CHECK is not set ++CONFIG_DEBUG_KERNEL=y ++CONFIG_DEBUG_SHIRQ=y ++CONFIG_DETECT_SOFTLOCKUP=y ++# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set ++CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 ++CONFIG_SCHED_DEBUG=y ++CONFIG_SCHEDSTATS=y ++CONFIG_TIMER_STATS=y ++# CONFIG_DEBUG_OBJECTS is not set ++# CONFIG_SLUB_DEBUG_ON is not set ++# CONFIG_SLUB_STATS is not set ++CONFIG_DEBUG_RT_MUTEXES=y ++CONFIG_DEBUG_PI_LIST=y ++# CONFIG_RT_MUTEX_TESTER is not set ++CONFIG_DEBUG_SPINLOCK=y ++CONFIG_DEBUG_MUTEXES=y ++# CONFIG_DEBUG_LOCK_ALLOC is not set ++# CONFIG_PROVE_LOCKING is not set ++# CONFIG_LOCK_STAT is not set ++CONFIG_DEBUG_SPINLOCK_SLEEP=y ++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set ++CONFIG_STACKTRACE=y ++# CONFIG_DEBUG_KOBJECT is not set ++CONFIG_DEBUG_INFO=y ++# CONFIG_DEBUG_VM is not set ++# CONFIG_DEBUG_WRITECOUNT is not set ++# CONFIG_DEBUG_MEMORY_INIT is not set ++CONFIG_DEBUG_LIST=y ++CONFIG_DEBUG_SG=y ++# CONFIG_DEBUG_NOTIFIERS is not set ++CONFIG_FRAME_POINTER=y ++# CONFIG_BOOT_PRINTK_DELAY is not set ++# CONFIG_RCU_TORTURE_TEST is not set ++# CONFIG_RCU_CPU_STALL_DETECTOR is not set ++# CONFIG_BACKTRACE_SELF_TEST is not set ++# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set ++# CONFIG_FAULT_INJECTION is not set ++# CONFIG_LATENCYTOP is not set ++CONFIG_SYSCTL_SYSCALL_CHECK=y ++CONFIG_NOP_TRACER=y ++CONFIG_RING_BUFFER=y ++CONFIG_TRACING=y ++ ++# ++# Tracers ++# ++# CONFIG_IRQSOFF_TRACER is not set ++# CONFIG_SCHED_TRACER is not set ++# CONFIG_CONTEXT_SWITCH_TRACER is not set ++# CONFIG_BOOT_TRACER is not set ++# CONFIG_TRACE_BRANCH_PROFILING is not set ++# CONFIG_FTRACE_STARTUP_TEST is not set ++# CONFIG_DYNAMIC_PRINTK_DEBUG is not set ++# CONFIG_SAMPLES is not set ++CONFIG_HAVE_ARCH_KGDB=y ++# CONFIG_KGDB is not set ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_ERRORS=y ++# CONFIG_DEBUG_LL is not set ++# CONFIG_CCTL is not set ++# CONFIG_ELFCHK_DEFAULT_ENABLE is not set ++ ++# ++# Security options ++# ++# CONFIG_KEYS is not set ++# CONFIG_SECURITY is not set ++# CONFIG_SECURITYFS is not set ++# CONFIG_SECURITY_FILE_CAPABILITIES is not set ++CONFIG_CRYPTO=y ++ ++# ++# Crypto core or helper ++# ++# CONFIG_CRYPTO_FIPS is not set ++# CONFIG_CRYPTO_MANAGER is not set ++# CONFIG_CRYPTO_MANAGER2 is not set ++# CONFIG_CRYPTO_GF128MUL is not set ++# CONFIG_CRYPTO_NULL is not set ++# CONFIG_CRYPTO_CRYPTD is not set ++# CONFIG_CRYPTO_AUTHENC is not set ++# CONFIG_CRYPTO_TEST is not set ++ ++# ++# Authenticated Encryption with Associated Data ++# ++# CONFIG_CRYPTO_CCM is not set ++# CONFIG_CRYPTO_GCM is not set ++# CONFIG_CRYPTO_SEQIV is not set ++ ++# ++# Block modes ++# ++# CONFIG_CRYPTO_CBC is not set ++# CONFIG_CRYPTO_CTR is not set ++# CONFIG_CRYPTO_CTS is not set ++# CONFIG_CRYPTO_ECB is not set ++# CONFIG_CRYPTO_LRW is not set ++# CONFIG_CRYPTO_PCBC is not set ++# CONFIG_CRYPTO_XTS is not set ++ ++# ++# Hash modes ++# ++# CONFIG_CRYPTO_HMAC is not set ++# CONFIG_CRYPTO_XCBC is not set ++ ++# ++# Digest ++# ++# CONFIG_CRYPTO_CRC32C is not set ++# CONFIG_CRYPTO_MD4 is not set ++# CONFIG_CRYPTO_MD5 is not set ++# CONFIG_CRYPTO_MICHAEL_MIC is not set ++# CONFIG_CRYPTO_RMD128 is not set ++# CONFIG_CRYPTO_RMD160 is not set ++# CONFIG_CRYPTO_RMD256 is not set ++# CONFIG_CRYPTO_RMD320 is not set ++# CONFIG_CRYPTO_SHA1 is not set ++# CONFIG_CRYPTO_SHA256 is not set ++# CONFIG_CRYPTO_SHA512 is not set ++# CONFIG_CRYPTO_TGR192 is not set ++# CONFIG_CRYPTO_WP512 is not set ++ ++# ++# Ciphers ++# ++# CONFIG_CRYPTO_AES is not set ++# CONFIG_CRYPTO_ANUBIS is not set ++# CONFIG_CRYPTO_ARC4 is not set ++# CONFIG_CRYPTO_BLOWFISH is not set ++# CONFIG_CRYPTO_CAMELLIA is not set ++# CONFIG_CRYPTO_CAST5 is not set ++# CONFIG_CRYPTO_CAST6 is not set ++# CONFIG_CRYPTO_DES is not set ++# CONFIG_CRYPTO_FCRYPT is not set ++# CONFIG_CRYPTO_KHAZAD is not set ++# CONFIG_CRYPTO_SALSA20 is not set ++# CONFIG_CRYPTO_SEED is not set ++# CONFIG_CRYPTO_SERPENT is not set ++# CONFIG_CRYPTO_TEA is not set ++# CONFIG_CRYPTO_TWOFISH is not set ++ ++# ++# Compression ++# ++# CONFIG_CRYPTO_DEFLATE is not set ++# CONFIG_CRYPTO_LZO is not set ++ ++# ++# Random Number Generation ++# ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++# CONFIG_CRYPTO_HW is not set ++ ++# ++# Library routines ++# ++CONFIG_BITREVERSE=y ++CONFIG_GENERIC_FIND_LAST_BIT=y ++# CONFIG_CRC_CCITT is not set ++# CONFIG_CRC16 is not set ++# CONFIG_CRC_T10DIF is not set ++# CONFIG_CRC_ITU_T is not set ++CONFIG_CRC32=y ++# CONFIG_CRC7 is not set ++# CONFIG_LIBCRC32C is not set ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=y ++CONFIG_PLIST=y ++CONFIG_HAS_IOMEM=y ++CONFIG_HAS_DMA=y +diff -Nur linux-3.4.110.orig/arch/nds32/configs/xc5_defconfig linux-3.4.110/arch/nds32/configs/xc5_defconfig +--- linux-3.4.110.orig/arch/nds32/configs/xc5_defconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/configs/xc5_defconfig 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,117 @@ ++CONFIG_EXPERIMENTAL=y ++CONFIG_CROSS_COMPILE="nds32le-linux-" ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_SYSVIPC=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_BSD_PROCESS_ACCT_V3=y ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_LOG_BUF_SHIFT=14 ++CONFIG_BLK_DEV_INITRD=y ++CONFIG_INITRAMFS_SOURCE="/home/users/greentime/os/ramdisk/disk-nds32le-linux-glibc-v3 /home/users/greentime/os/ramdisk/disk-nds32le-linux-glibc-v3/dev/initramfs.devnodes" ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_SYSCTL_SYSCALL=y ++# CONFIG_HOTPLUG is not set ++# CONFIG_SIGNALFD is not set ++CONFIG_EMBEDDED=y ++# CONFIG_VM_EVENT_COUNTERS is not set ++CONFIG_PROFILING=y ++CONFIG_OPROFILE=y ++CONFIG_MODULES=y ++CONFIG_MODULE_UNLOAD=y ++# CONFIG_BLK_DEV_BSG is not set ++CONFIG_PLATFORM_AHBDMA=y ++CONFIG_PLATFORM_APBDMA=y ++CONFIG_SYS_CLK=30000000 ++CONFIG_UART_CLK=14745600 ++CONFIG_SDRAM_SIZE=0x8000000 ++CONFIG_HZ_100=y ++CONFIG_CMDLINE="root=/dev/ram0 rw mem=128M@0x0 initrd=0x1000000,8M console=ttyS0,38400n8 earlyprintk=uart8250-32bit,0x99600000 rootfstype=ext2 init=/bin/busybox init -s user_debug=-1" ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++CONFIG_NET=y ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++CONFIG_NET_KEY=y ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++# CONFIG_INET_DIAG is not set ++# CONFIG_IPV6 is not set ++CONFIG_BRIDGE=y ++CONFIG_MTD=y ++CONFIG_MTD_CMDLINE_PARTS=y ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++CONFIG_MTD_CFI=y ++CONFIG_MTD_CFI_INTELEXT=y ++CONFIG_MTD_PHYSMAP=y ++CONFIG_MTD_PHYSMAP_COMPAT=y ++CONFIG_MTD_PHYSMAP_START=0x80400000 ++CONFIG_MTD_PHYSMAP_LEN=0x2000000 ++CONFIG_MTD_PHYSMAP_BANKWIDTH=4 ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=8192 ++CONFIG_NETDEVICES=y ++CONFIG_TUN=y ++CONFIG_FTMAC100=y ++# CONFIG_INPUT_MOUSEDEV is not set ++CONFIG_INPUT_EVDEV=y ++# CONFIG_INPUT_KEYBOARD is not set ++# CONFIG_INPUT_MOUSE is not set ++CONFIG_INPUT_TOUCHSCREEN=y ++# CONFIG_SERIO is not set ++CONFIG_SERIAL_8250=y ++CONFIG_SERIAL_8250_CONSOLE=y ++CONFIG_SERIAL_8250_NR_UARTS=3 ++CONFIG_SERIAL_8250_RUNTIME_UARTS=3 ++# CONFIG_HW_RANDOM is not set ++# CONFIG_HWMON is not set ++CONFIG_FB=y ++# CONFIG_VGA_CONSOLE is not set ++CONFIG_FRAMEBUFFER_CONSOLE=y ++CONFIG_LOGO=y ++CONFIG_SOUND=y ++CONFIG_SND=y ++CONFIG_SND_PCM_OSS=y ++# CONFIG_SND_SUPPORT_OLD_API is not set ++# CONFIG_SND_VERBOSE_PROCFS is not set ++# CONFIG_HID_SUPPORT is not set ++# CONFIG_USB_SUPPORT is not set ++CONFIG_MMC=y ++CONFIG_MMC_FTSDC010=y ++# CONFIG_MEMSTICK is not set ++# CONFIG_NEW_LEDS is not set ++# CONFIG_ACCESSIBILITY is not set ++CONFIG_RTC_LIB=y ++CONFIG_RTC_CLASS=y ++# CONFIG_RTC_HCTOSYS is not set ++CONFIG_EXT2_FS=y ++CONFIG_FUSE_FS=y ++CONFIG_MSDOS_FS=y ++CONFIG_VFAT_FS=y ++# CONFIG_PROC_PAGE_MONITOR is not set ++CONFIG_TMPFS=y ++CONFIG_JFFS2_FS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_NLS_CODEPAGE_437=y ++CONFIG_NLS_ISO8859_1=y ++CONFIG_MAGIC_SYSRQ=y ++CONFIG_DEBUG_FS=y ++CONFIG_DEBUG_SHIRQ=y ++CONFIG_SCHEDSTATS=y ++CONFIG_TIMER_STATS=y ++CONFIG_DEBUG_RT_MUTEXES=y ++CONFIG_DEBUG_SPINLOCK=y ++CONFIG_DEBUG_MUTEXES=y ++CONFIG_DEBUG_INFO=y ++CONFIG_DEBUG_LIST=y ++CONFIG_DEBUG_SG=y ++CONFIG_DEBUG_USER=y ++CONFIG_DEBUG_ERRORS=y ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++# CONFIG_CRYPTO_HW is not set +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/amic.h linux-3.4.110/arch/nds32/include/asm/amic.h +--- linux-3.4.110.orig/arch/nds32/include/asm/amic.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/amic.h 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,60 @@ ++/* ++ * linux/arch/nds32/include/asm/amic.h ++ * ++ * Andes Multi-core Interrupt Controller Device Driver Interface ++ * ++ * Copyright (C) 2010 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ChangeLog ++ * ++ * Shawn Lin 09/02/2010 Created for Andes AG102 platform code. ++ */ ++ ++#ifndef __NDS32_AMIC_HEADER__ ++#define __NDS32_AMIC_HEADER__ ++ ++#define IRQ_BASE 0x0 ++#define IRQ_TOTAL 0x20 ++#define DEFAULT_MODE 0x000ecc00 ++#define DEFAULT_LEVEL 0xffffffff ++#define AMIC_BASE AMIC_VA_BASE ++#define CONFIG 0x00 ++#define CPUDC 0x04 ++#define CPUID0 0x08 ++#define CPUID1 0x0c ++#define INTTRG 0x20 ++#define INTLVL 0x24 ++#define INTSRC 0x28 ++#define IPITRG 0x40 ++#define IPISTA 0x44 ++#define IPIPTR 0x48 ++#define IPIGST 0x4c ++#define IPIGPT 0x50 ++#define INTEN 0x80 ++#define INTSTA 0x84 ++#define HW0STA 0x88 ++#define HW1STA 0x8c ++#define HW2STA 0x90 ++#define HW3STA 0x94 ++#define HW4STA 0x98 ++#define HW5STA 0x9c ++#define PRITY0 0xa0 ++#define PRITY1 0xa4 ++#define PRITY2 0xa8 ++#define PRITY3 0xac ++ ++#endif /* __NDS32_AMIC_HEADER__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/asm-offsets.h linux-3.4.110/arch/nds32/include/asm/asm-offsets.h +--- linux-3.4.110.orig/arch/nds32/include/asm/asm-offsets.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/asm-offsets.h 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1 @@ ++#include <generated/asm-offsets.h> +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/assembler.h linux-3.4.110/arch/nds32/include/asm/assembler.h +--- linux-3.4.110.orig/arch/nds32/include/asm/assembler.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/assembler.h 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,141 @@ ++/* ++ * linux/arch/nds32/include/asm/assembler.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_ASSEMBLER_H__ ++#define __NDS32_ASSEMBLER_H__ ++ ++/* ++ * Stack format ++ */ ++ ++#define S_PAD 0xac /* Padding for stack pointer 8-byte alignment. */ ++#define S_FUCOP_CTL 0xa8 ++#define S_LP 0xa4 ++#define S_GP 0xa0 ++#define S_FP 0x9c ++#define S_R25 0x98 ++#define S_R24 0x94 ++#define S_R23 0x90 ++#define S_R22 0x8c ++#define S_R21 0x88 ++#define S_R20 0x84 ++#define S_R19 0x80 ++#define S_R18 0x7c ++#define S_R17 0x78 ++#define S_R16 0x74 ++#define S_R15 0x70 ++#define S_R14 0x6c ++#define S_R13 0x68 ++#define S_R12 0x64 ++#define S_R11 0x60 ++#define S_R10 0x5c ++#define S_R9 0x58 ++#define S_R8 0x54 ++#define S_R7 0x50 ++#define S_R6 0x4c ++#define S_R5 0x48 ++#define S_R4 0x44 ++#define S_R3 0x40 ++#define S_R2 0x3c ++#define S_R1 0x38 ++#define S_R0 0x34 ++#define S_D1LO 0x30 ++#define S_D1HI 0x2c ++#define S_D0LO 0x28 ++#define S_D0HI 0x24 ++#define S_PP1 0x20 ++#define S_PP0 0x1c ++#define S_PIPC 0x18 ++#define S_PIPSW 0x14 ++#define S_ORIG_R0 0x10 ++#define S_SP 0xc ++#define S_IPC 0x8 ++#define S_IPSW 0x4 ++#define S_IR0 0x0 ++ ++#if !defined(CONFIG_ABI1) ++#define S_OFF 0 ++#else ++#define S_OFF 24 ++#endif ++ ++#ifdef __ASSEMBLY__ ++.macro get_thread_info, rd ++ srli \rd, $sp, #13 ++ slli \rd, \rd, #13 ++.endm ++ ++.macro gie_disable ++ setgie.d ++#ifdef CONFIG_CPU_N1213_43U1HA0 ++ isb ++#else ++ dsb ++#endif ++.endm ++ ++.macro gie_enable ++ setgie.e ++#ifdef CONFIG_CPU_N1213_43U1HA0 ++ isb ++#else ++ dsb ++#endif ++.endm ++ ++.macro gie_save oldpsw ++ mfsr \oldpsw, $ir0 ++ setgie.d ++#ifdef CONFIG_CPU_N1213_43U1HA0 ++ isb ++#else ++ dsb ++#endif ++.endm ++ ++.macro gie_restore oldpsw ++ andi \oldpsw, \oldpsw, #0x1 ++ beqz \oldpsw, 7001f ++ setgie.e ++#ifdef CONFIG_CPU_N1213_43U1HA0 ++ isb ++#else ++ dsb ++#endif ++7001: ++.endm ++ ++ ++#define USER(insn, reg, addr, opr) \ ++9999: insn reg, addr, opr; \ ++ .section __ex_table,"a"; \ ++ .align 3; \ ++ .long 9999b, 9001f; \ ++ .previous ++ ++#else /* __ASSEMBLY__ */ ++ ++__asm__ (".macro gie_disable\n\t" ++ "setgie.d\n\t" ++#ifdef CONFIG_CPU_N1213_43U1HA0 ++ "isb\n\t" ++#else ++ "dsb\n\t" ++#endif ++ ".endm\n\t" ++ ); ++ ++__asm__ (".macro gie_enable\n\t" ++ "setgie.e\n\t" ++#ifdef CONFIG_CPU_N1213_43U1HA0 ++ "isb\n\t" ++#else ++ "dsb\n\t" ++#endif ++ ".endm\n\t" ++ ); ++ ++#endif /* !__ASSEMBLY__ */ ++#endif /* __NDS32_ASSEMBLER_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/atomic.h linux-3.4.110/arch/nds32/include/asm/atomic.h +--- linux-3.4.110.orig/arch/nds32/include/asm/atomic.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/atomic.h 2016-04-07 10:20:50.890079013 +0200 +@@ -0,0 +1,267 @@ ++/* ++ * linux/arch/nds32/include/asm/atomic.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_ATOMIC_H__ ++#define __NDS32_ATOMIC_H__ ++ ++#include <linux/types.h> ++#include <asm/barrier.h> ++#include <asm/cmpxchg.h> ++ ++#if defined(CONFIG_SMP) || !defined(CONFIG_CPU_DCACHE_WRITETHROUGH) ++ ++#define ATOMIC_INIT(i) { (i) } ++#define atomic_set(v,i) (((v)->counter) = (i)) ++#define atomic_read(v) (*(volatile int *)&(v)->counter) ++ ++static inline void atomic_add(int i, atomic_t *v) ++{ ++ int temp; ++ __asm__ __volatile__( ++ "movi\t$r15, #0\n" ++ "1:\n" ++ "\tllw\t%0, [%1+$r15]\n" ++ "\tadd\t%0, %0, %2\n" ++ "\tscw\t%0, [%1+$r15]\n" ++ "\tbeqz\t%0, 1b\n" ++ : "=&r" (temp) : "r" (&v->counter), "r" (i)); ++} ++ ++static inline void atomic_sub(int i, atomic_t *v) ++{ ++ int temp; ++ __asm__ __volatile__( ++ "movi\t$r15, #0\n" ++ "1:\n" ++ "\tllw\t%0, [%1+$r15]\n" ++ "\tsub\t%0, %0, %2\n" ++ "\tscw\t%0, [%1+$r15]\n" ++ "\tbeqz\t%0, 1b\n" ++ : "=&r" (temp) : "r" (&v->counter), "r" (i)); ++} ++ ++#define atomic_inc(v) atomic_add(1, v) ++#define atomic_dec(v) atomic_sub(1, v) ++ ++static inline int atomic_inc_return(atomic_t *v) ++{ ++ int temp1, temp2; ++ __asm__ __volatile__( ++ "movi\t$r15, #0\n" ++ "1:\n" ++ "\tllw\t%1, [%2+$r15]\n" ++ "\taddi\t%1, %1, #1\n" ++ "\tori\t%0, %1, #0\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (temp2), "=&r" (temp1) ++ : "r" (&v->counter)); ++ return temp2; ++} ++ ++static inline int atomic_dec_return(atomic_t *v) ++{ ++ int temp1, temp2; ++ __asm__ __volatile__( ++ "movi\t$r15, #0\n" ++ "1:\n" ++ "\tllw\t%1, [%2+$r15]\n" ++ "\taddi\t%1, %1, #-1\n" ++ "\tori\t%0, %1, #0\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (temp2), "=&r" (temp1) ++ : "r" (&v->counter)); ++ return temp2; ++} ++ ++static inline int atomic_add_return(int i, atomic_t *v) ++{ ++ int temp1, temp2; ++ ++ smp_mb(); ++ ++ __asm__ __volatile__( ++ "movi\t$r15, #0\n" ++ "1:\n" ++ "\tllw\t%1, [%2+$r15]\n" ++ "\tadd\t%1, %1, %3\n" ++ "\tori\t%0, %1, #0\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (temp2), "=&r" (temp1) ++ : "r" (&v->counter), "r" (i)); ++ ++ smp_mb(); ++ ++ return temp2; ++} ++ ++static inline int atomic_sub_return(int i, atomic_t *v) ++{ ++ int temp1, temp2; ++ ++ smp_mb(); ++ ++ __asm__ __volatile__( ++ "movi\t$r15, #0\n" ++ "1:\n" ++ "\tllw\t%1, [%2+$r15]\n" ++ "\tsub\t%1, %1, %3\n" ++ "\tori\t%0, %1, #0\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (temp2), "=&r" (temp1) ++ : "r" (&v->counter), "r" (i)); ++ ++ smp_mb(); ++ ++ return temp2; ++} ++ ++/* ++ * atomic_dec_if_positive - conditionally subtract one from atomic variable ++ * @v: pointer of type atomic_t ++ * ++ * Atomically test @v and subtract one if @v is greater or equal than one. ++ * The function returns the old value of @v minus one. ++ */ ++static inline int atomic_dec_if_positive(atomic_t * v) ++{ ++ int temp1, temp2, temp3; ++ __asm__ __volatile__( ++ "movi\t$r15, #0\n" ++ "1:\n" ++ "\tllw\t%2, [%3+$r15]\n" ++ "\taddi\t%0, %2, #-1\n" ++ "\tslts\t%1, $r15, %2\n" ++ "\tsub\t%2, %2, %1\n" ++ "\tscw\t%2, [%3+$r15]\n" ++ "\tbeqz\t%2, 1b\n" ++ : "=&r" (temp3), "=&r" (temp2), "=&r" (temp1) ++ : "r" (&v->counter)); ++ return temp3; ++} ++ ++ ++#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) ++#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) ++#define atomic_sub_and_test(i,v) (atomic_sub_return((i),(v)) == 0) ++#define atomic_add_negative(i,v) (atomic_add_return((i),(v)) < 0) ++ ++ ++static inline int atomic_cmpxchg(atomic_t *v, int old, int new) ++{ ++ int temp1, temp2, temp3; ++ ++ smp_mb(); ++ ++ __asm__ __volatile__( ++ "movi\t$r15, #0\n" ++ "1:\n" ++ "\tllw\t%0, [%3+$r15]\n" ++ "\tsub\t%2, %0, %5\n" ++ "\tcmovz\t%1, %4, %2\n" ++ "\tcmovn\t%1, %0, %2\n" ++ "\tscw\t%1, [%3+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (temp3), "=&r" (temp2), "=&r" (temp1) ++ : "r" (&v->counter), "r" (new), "r" (old)); ++ ++ smp_mb(); ++ ++ return temp3; ++} ++ ++static inline int atomic_xchg(atomic_t *v, int new) ++{ ++ int temp1, temp2; ++ __asm__ __volatile__( ++ "movi\t$r15, #0\n" ++ "1:\n" ++ "\tllw\t%0, [%2+$r15]\n" ++ "\tori\t%1, %3, #0\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (temp2), "=&r" (temp1) ++ : "r" (&v->counter), "r" (new)); ++ return temp2; ++} ++ ++static inline int __atomic_add_unless(atomic_t *v, int a, int u) ++{ ++ int c, old; ++ ++ c = atomic_read(v); ++ while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c) ++ c = old; ++ return c; ++} ++ ++static inline int atomic_inc_not_zero(atomic_t *v) ++{ ++ int temp1, temp2; ++ __asm__ __volatile__( ++ "movi\t$r15, #0\n" ++ "1:\n" ++ "\tllw\t%1, [%2+$r15]\n" ++ "\tslt\t%0, $r15, %1\n" ++ "\tadd\t%1, %1, %0\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (temp2), "=&r" (temp1) ++ : "r" (&v->counter)); ++ return temp2; ++} ++ ++#define smp_mb__before_atomic_dec() barrier() ++#define smp_mb__after_atomic_dec() barrier() ++#define smp_mb__before_atomic_inc() barrier() ++#define smp_mb__after_atomic_inc() barrier() ++ ++//#include <asm-generic/atomic-long.h> ++#else /* CONFIG_SMP*/ ++ ++ ++ ++#define ATOMIC_INIT(i) { (i) } ++ ++#ifdef __KERNEL__ ++ ++#include <asm-generic/atomic.h> ++ ++static inline int atomic_dec_if_positive(atomic_t * v) ++{ ++ unsigned long flags; ++ int result; ++ ++ local_irq_save(flags); ++ result = v->counter; ++ result -= 1; ++ if (result >= 0) ++ v->counter = result; ++ local_irq_restore(flags); ++ return result; ++} ++ ++/* Atomic operations are already serializing on ARM */ ++#define smp_mb__before_atomic_dec() barrier() ++#define smp_mb__after_atomic_dec() barrier() ++#define smp_mb__before_atomic_inc() barrier() ++#define smp_mb__after_atomic_inc() barrier() ++ ++#endif ++ ++#endif /* CONFIG_SMP */ ++ ++#ifndef CONFIG_GENERIC_ATOMIC64 ++typedef struct { ++ u64 __aligned(8) counter; ++} atomic64_t; ++#define ATOMIC64_INIT(i) { (i) } ++static inline u64 atomic64_add_return(u64 i, atomic64_t *v){ return 0; } ++#endif /* CONFIG_GENERIC_ATOMIC64 */ ++ ++#endif /* __NDS32_ATOMIC_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/audio.h linux-3.4.110/arch/nds32/include/asm/audio.h +--- linux-3.4.110.orig/arch/nds32/include/asm/audio.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/audio.h 2016-04-07 10:20:50.890079013 +0200 +@@ -0,0 +1,65 @@ ++/* ++ * linux/arch/nds32/include/asm/audio.h ++ * Copyright (C) 2009 Andes Technology Corporation ++ */ ++ ++#ifndef __ASM_NDS32_AUDIO_H ++#define __ASM_NDS32_AUDIO_H ++ ++#ifndef __ASSEMBLY__ ++#include <linux/preempt.h> ++#include <asm/ptrace.h> ++ ++extern void save_audio(struct task_struct *tsk); ++extern void audioload(struct audio_struct *audioregs); ++extern void save_audio(struct task_struct *__tsk); ++extern void do_audio_context_switch(unsigned long error_code, struct pt_regs *regs); ++ ++#ifdef CONFIG_AUDIO ++ ++#define test_tsk_audio(regs) (regs->NDS32_FUCOP_CTL & FUCOP_CTL_mskAUEN) ++ ++struct task_struct; ++ ++static inline void enable_audio(void) ++{ ++ SET_FUCOP_CTL(GET_FUCOP_CTL() | FUCOP_CTL_mskAUEN); ++} ++ ++static inline void disable_audio(void) ++{ ++ SET_FUCOP_CTL(GET_FUCOP_CTL() & ~FUCOP_CTL_mskAUEN); ++} ++ ++static inline void release_audio(struct pt_regs *regs) ++{ ++ regs->NDS32_FUCOP_CTL &= ~FUCOP_CTL_mskAUEN; ++ regs->NDS32_ipsw &= ~PSW_mskAEN; ++} ++ ++static inline void grab_audio(struct pt_regs *regs) ++{ ++ regs->NDS32_FUCOP_CTL |= FUCOP_CTL_mskAUEN; ++ regs->NDS32_ipsw |= PSW_mskAEN; ++} ++#ifdef CONFIG_UNLAZY_AUDIO ++static inline void unlazy_audio(struct task_struct *tsk) ++{ ++ preempt_disable(); ++ if (test_tsk_audio(task_pt_regs(tsk))) ++ save_audio(tsk); ++ preempt_enable(); ++} ++#endif ++static inline void clear_audio(struct pt_regs *regs) ++{ ++ preempt_disable(); ++ if (test_tsk_audio(regs)) { ++ release_audio(regs); ++ } ++ preempt_enable(); ++} ++#endif /* CONFIG_AUDIO */ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* __ASM_NDS32_AUDIO_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/auxvec.h linux-3.4.110/arch/nds32/include/asm/auxvec.h +--- linux-3.4.110.orig/arch/nds32/include/asm/auxvec.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/auxvec.h 2016-04-07 10:20:50.890079013 +0200 +@@ -0,0 +1,9 @@ ++/* ++ * linux/arch/nds32/include/asm/auxvec.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_AUXVEC_H__ ++#define __NDS32_AUXVEC_H__ ++ ++#endif /*__NDS32_AUXVEC_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/barrier.h linux-3.4.110/arch/nds32/include/asm/barrier.h +--- linux-3.4.110.orig/arch/nds32/include/asm/barrier.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/barrier.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,85 @@ ++/* ============================================================================ ++ * ++ * linux/arch/nds32/include/asm/system.h ++ * ++ * Copyright (C) 2007 Andes Technology Corporation ++ * This file is part of Linux and should be licensed under the GPL. ++ * See the file COPYING for conditions for redistribution. ++ * ++ * Abstract: ++ * ++ * This program is for NDS32 architecture. ++ * ++ * Revision History: ++ * ++ * Nov.26.2007 Initial ported by Tom, Shawn, and Steven, ++ * patched for KGDB and refined code by Harry. ++ * ++ * Note: ++ * ++ * ============================================================================ ++ */ ++#ifndef __ASM_NDS32_BARRIER_H ++#define __ASM_NDS32_BARRIER_H ++ ++#ifdef __KERNEL__ ++ ++/* ++ * This is used to ensure the compiler did actually allocate the register we ++ * asked it for some inline assembly sequences. Apparently we can't trust ++ * the compiler from one version to another so a bit of paranoia won't hurt. ++ * This string is meant to be concatenated with the inline asm string and ++ * will cause compilation to stop on mismatch. ++ * (for details, see gcc PR 15089) ++ */ ++#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t" ++ ++#ifndef __ASSEMBLY__ ++ ++#include <linux/linkage.h> ++#include <linux/irqflags.h> ++ ++struct thread_info; ++struct task_struct; ++ ++struct pt_regs; ++ ++void die(const char *msg, struct pt_regs *regs, int err) ++ __attribute__((noreturn)); ++ ++void die_if_kernel(const char *str, struct pt_regs *regs, int err); ++ ++#include <asm/proc-fns.h> ++ ++#define UDBG_UNDEFINED (1 << 0) ++#define UDBG_SYSCALL (1 << 1) ++#define UDBG_BADABORT (1 << 2) ++#define UDBG_SEGV (1 << 3) ++#define UDBG_BUS (1 << 4) ++ ++extern unsigned int user_debug; ++ ++#define mb() __asm__ __volatile__ ("" : : : "memory") ++#define rmb() mb() ++#define wmb() mb() ++#define read_barrier_depends() do { } while(0) ++#define set_mb(var, value) do { var = value; mb(); } while (0) ++#define set_wmb(var, value) do { var = value; wmb(); } while (0) ++ ++#ifdef CONFIG_SMP ++#define smp_mb() mb() ++#define smp_rmb() rmb() ++#define smp_wmb() wmb() ++#define smp_read_barrier_depends() read_barrier_depends() ++#else ++#define smp_mb() barrier() ++#define smp_rmb() barrier() ++#define smp_wmb() barrier() ++#define smp_read_barrier_depends() do { } while(0) ++#endif ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif //__ASM_NDS32_SYSTEM_H +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/bitfield.h linux-3.4.110/arch/nds32/include/asm/bitfield.h +--- linux-3.4.110.orig/arch/nds32/include/asm/bitfield.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/bitfield.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,895 @@ ++/* ++ * linux/arch/nds32/include/asm/bitfield.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_BITFIELD_H__ ++#define __NDS32_BITFIELD_H__ ++/****************************************************************************** ++ * cr0: CPU_VER (CPU Version Register) ++ *****************************************************************************/ ++#define CPU_VER_offCFGID 0 /* Minor configuration */ ++#define CPU_VER_offREV 16 /* Revision of the CPU version */ ++#define CPU_VER_offCPUID 24 /* Major CPU versions */ ++ ++#define CPU_VER_mskCFGID ( 0xFFFF << CPU_VER_offCFGID ) ++#define CPU_VER_mskREV ( 0xFF << CPU_VER_offREV ) ++#define CPU_VER_mskCPUID ( 0xFF << CPU_VER_offCPUID ) ++ ++/****************************************************************************** ++ * cr1: ICM_CFG (Instruction Cache/Memory Configuration Register) ++ *****************************************************************************/ ++#define ICM_CFG_offISET 0 /* I-cache sets (# of cache lines) per way */ ++#define ICM_CFG_offIWAY 3 /* I-cache ways */ ++#define ICM_CFG_offISZ 6 /* I-cache line size */ ++#define ICM_CFG_offILCK 9 /* I-cache locking support */ ++#define ICM_CFG_offILMB 10 /* On-chip ILM banks */ ++#define ICM_CFG_offBSAV 13 /* ILM base register alignment version */ ++/* bit 15:31 reserved */ ++ ++#define ICM_CFG_mskISET ( 0x7 << ICM_CFG_offISET ) ++#define ICM_CFG_mskIWAY ( 0x7 << ICM_CFG_offIWAY ) ++#define ICM_CFG_mskISZ ( 0x7 << ICM_CFG_offISZ ) ++#define ICM_CFG_mskILCK ( 0x1 << ICM_CFG_offILCK ) ++#define ICM_CFG_mskILMB ( 0x7 << ICM_CFG_offILMB ) ++#define ICM_CFG_mskBSAV ( 0x3 << ICM_CFG_offBSAV ) ++ ++/****************************************************************************** ++ * cr2: DCM_CFG (Data Cache/Memory Configuration Register) ++ *****************************************************************************/ ++#define DCM_CFG_offDSET 0 /* D-cache sets (# of cache lines) per way */ ++#define DCM_CFG_offDWAY 3 /* D-cache ways */ ++#define DCM_CFG_offDSZ 6 /* D-cache line size */ ++#define DCM_CFG_offDLCK 9 /* D-cache locking support */ ++#define DCM_CFG_offDLMB 10 /* On-chip DLM banks */ ++#define DCM_CFG_offBSAV 13 /* DLM base register alignment version */ ++/* bit 15:31 reserved */ ++ ++#define DCM_CFG_mskDSET ( 0x7 << DCM_CFG_offDSET ) ++#define DCM_CFG_mskDWAY ( 0x7 << DCM_CFG_offDWAY ) ++#define DCM_CFG_mskDSZ ( 0x7 << DCM_CFG_offDSZ ) ++#define DCM_CFG_mskDLCK ( 0x1 << DCM_CFG_offDLCK ) ++#define DCM_CFG_mskDLMB ( 0x7 << DCM_CFG_offDLMB ) ++#define DCM_CFG_mskBSAV ( 0x3 << DCM_CFG_offBSAV ) ++ ++/****************************************************************************** ++ * cr3: MMU_CFG (MMU Configuration Register) ++ *****************************************************************************/ ++#define MMU_CFG_offMMPS 0 /* Memory management protection scheme */ ++#define MMU_CFG_offMMPV 2 /* Memory management protection version number */ ++#define MMU_CFG_offFATB 7 /* Fully-associative or non-fully-associative TLB */ ++ ++#ifdef CONFIG_FULL_ASSOC ++#define MMU_CFG_offFATBSZ 8 /* TLB entries while using full-associative TLB */ ++#else ++#define MMU_CFG_offTBW 8 /* TLB ways(non-associative) TBS */ ++#define MMU_CFG_offTBS 11 /* TLB sets per way(non-associative) TBS */ ++/* bit 14:14 reserved */ ++#endif ++ ++#define MMU_CFG_offEP8MIN4 15 /* 8KB page supported while minimum page is 4KB */ ++#define MMU_CFG_offfEPSZ 16 /* Extra page size supported */ ++#define MMU_CFG_offTLBLCK 24 /* TLB locking support */ ++#define MMU_CFG_offHPTWK 25 /* Hardware Page Table Walker implemented */ ++#define MMU_CFG_offDE 26 /* Default endian */ ++#define MMU_CFG_offNTPT 27 /* Partitions for non-translated attributes */ ++#define MMU_CFG_offIVTB 28 /* Invisible TLB */ ++#define MMU_CFG_offVLPT 29 /* VLPT for fast TLB fill handling implemented */ ++#define MMU_CFG_offNTME 30 /* Non-translated VA to PA mapping */ ++/* bit 31 reserved */ ++ ++#define MMU_CFG_mskMMPS ( 0x3 << MMU_CFG_offMMPS ) ++#define MMU_CFG_mskMMPV ( 0x1F << MMU_CFG_offMMPV ) ++#define MMU_CFG_mskFATB ( 0x1 << MMU_CFG_offFATB ) ++#ifdef CONFIG_FULL_ASSOC ++#define MMU_CFG_mskFATBSZ ( 0x7f << MMU_CFG_offFATBSZ ) ++#else ++#define MMU_CFG_mskTBW ( 0x7 << MMU_CFG_offTBW ) ++#define MMU_CFG_mskTBS ( 0x7 << MMU_CFG_offTBS ) ++#endif ++#define MMU_CFG_mskEP8MIN4 ( 0x1 << MMU_CFG_offEP8MIN4 ) ++#define MMU_CFG_mskfEPSZ ( 0xFF << MMU_CFG_offfEPSZ ) ++#define MMU_CFG_mskTLBLCK ( 0x1 << MMU_CFG_offTLBLCK ) ++#define MMU_CFG_mskHPTWK ( 0x1 << MMU_CFG_offHPTWK ) ++#define MMU_CFG_mskDE ( 0x1 << MMU_CFG_offDE ) ++#define MMU_CFG_mskNTPT ( 0x1 << MMU_CFG_offNTPT ) ++#define MMU_CFG_mskIVTB ( 0x1 << MMU_CFG_offIVTB ) ++#define MMU_CFG_mskVLPT ( 0x1 << MMU_CFG_offVLPT ) ++#define MMU_CFG_mskNTME ( 0x1 << MMU_CFG_offNTME ) ++ ++/****************************************************************************** ++ * cr4: MSC_CFG (Misc Configuration Register) ++ *****************************************************************************/ ++#define MSC_CFG_offEDM 0 ++#define MSC_CFG_offLMDMA 1 ++#define MSC_CFG_offPFM 2 ++#define MSC_CFG_offHSMP 3 ++#define MSC_CFG_offTRACE 4 ++#define MSC_CFG_offDIV 5 ++#define MSC_CFG_offMAC 6 ++#define MSC_CFG_offAUDIO 7 ++#define MSC_CFG_offL2C 9 ++#define MSC_CFG_offRDREG 10 ++#define MSC_CFG_offADR24 11 ++#define MSC_CFG_offINTLC 12 ++#define MSC_CFG_offBASEV 13 ++#define MSC_CFG_offNOD 16 ++/* bit 13:31 reserved */ ++ ++#define MSC_CFG_mskEDM ( 0x1 << MSC_CFG_offEDM ) ++#define MSC_CFG_mskLMDMA ( 0x1 << MSC_CFG_offLMDMA ) ++#define MSC_CFG_mskPFM ( 0x1 << MSC_CFG_offPFM ) ++#define MSC_CFG_mskHSMP ( 0x1 << MSC_CFG_offHSMP ) ++#define MSC_CFG_mskTRACE ( 0x1 << MSC_CFG_offTRACE ) ++#define MSC_CFG_mskDIV ( 0x1 << MSC_CFG_offDIV ) ++#define MSC_CFG_mskMAC ( 0x1 << MSC_CFG_offMAC ) ++#define MSC_CFG_mskAUDIO ( 0x3 << MSC_CFG_offAUDIO ) ++#define MSC_CFG_mskL2C ( 0x1 << MSC_CFG_offL2C ) ++#define MSC_CFG_mskRDREG ( 0x1 << MSC_CFG_offRDREG ) ++#define MSC_CFG_mskADR24 ( 0x1 << MSC_CFG_offADR24 ) ++#define MSC_CFG_mskINTLC ( 0x1 << MSC_CFG_offINTLC ) ++#define MSC_CFG_mskBASEV ( 0x7 << MSC_CFG_offBASEV ) ++#define MSC_CFG_mskNOD ( 0x1 << MSC_CFG_offNOD ) ++ ++/****************************************************************************** ++ * cr5: CORE_CFG (Core Identification Register) ++ *****************************************************************************/ ++#define CORE_ID_offCOREID 0 ++/* bit 4:31 reserved */ ++ ++#define CORE_ID_mskCOREID ( 0xF << CORE_ID_offCOREID ) ++ ++/****************************************************************************** ++ * cr6: FUCOP_EXIST (FPU and Coprocessor Existence Configuration Register) ++ *****************************************************************************/ ++#define FUCOP_EXIST_offCP0EX 0 ++#define FUCOP_EXIST_offCP1EX 1 ++#define FUCOP_EXIST_offCP2EX 2 ++#define FUCOP_EXIST_offCP3EX 3 ++#define FUCOP_EXIST_offCP0ISFPU 31 ++ ++#define FUCOP_EXIST_mskCP0EX ( 0x1 << FUCOP_EXIST_offCP0EX ) ++#define FUCOP_EXIST_mskCP1EX ( 0x1 << FUCOP_EXIST_offCP1EX ) ++#define FUCOP_EXIST_mskCP2EX ( 0x1 << FUCOP_EXIST_offCP2EX ) ++#define FUCOP_EXIST_mskCP3EX ( 0x1 << FUCOP_EXIST_offCP3EX ) ++#define FUCOP_EXIST_mskCP0ISFPU ( 0x1 << FUCOP_EXIST_offCP0ISFPU ) ++ ++/****************************************************************************** ++ * ir0: PSW (Processor Status Word Register) ++ * ir1: IPSW (Interruption PSW Register) ++ * ir2: P_IPSW (Previous IPSW Register) ++ *****************************************************************************/ ++#define PSW_offGIE 0 /* Global Interrupt Enable */ ++#define PSW_offINTL 1 /* Interruption Stack Level */ ++#define PSW_offPOM 3 /* Processor Operation Mode, User/Superuser */ ++#define PSW_offBE 5 /* Endianness for data memory access, 1:MSB, 0:LSB */ ++#define PSW_offIT 6 /* Enable instruction address translation */ ++#define PSW_offDT 7 /* Enable data address translation */ ++#define PSW_offIME 8 /* Instruction Machine Error flag */ ++#define PSW_offDME 9 /* Data Machine Error flag */ ++#define PSW_offDEX 10 /* Debug Exception */ ++#define PSW_offHSS 11 /* Hardware Single Stepping */ ++#define PSW_offDRBE 12 /* Device Register Endian Mode */ ++#define PSW_offAEN 13 /* Audio ISA special feature */ ++#define PSW_offWBNA 14 /* Write Back Non-Allocate */ ++#define PSW_offIFCON 15 /* IFC On */ ++#define PSW_offCPL 16 /* Current Priority Level */ ++/* bit 19:31 reserved */ ++ ++#define PSW_mskGIE ( 0x1 << PSW_offGIE ) ++#define PSW_mskINTL ( 0x3 << PSW_offINTL ) ++#define PSW_mskPOM ( 0x3 << PSW_offPOM ) ++#define PSW_mskBE ( 0x1 << PSW_offBE ) ++#define PSW_mskIT ( 0x1 << PSW_offIT ) ++#define PSW_mskDT ( 0x1 << PSW_offDT ) ++#define PSW_mskIME ( 0x1 << PSW_offIME ) ++#define PSW_mskDME ( 0x1 << PSW_offDME ) ++#define PSW_mskDEX ( 0x1 << PSW_offDEX ) ++#define PSW_mskHSS ( 0x1 << PSW_offHSS ) ++#define PSW_mskDRBE ( 0x1 << PSW_offDRBE ) ++#define PSW_mskAEN ( 0x1 << PSW_offAEN ) ++#define PSW_mskWBNA ( 0x1 << PSW_offWBNA ) ++#define PSW_mskIFCON ( 0x1 << PSW_offIFCON ) ++#define PSW_mskCPL ( 0x7 << PSW_offCPL ) ++ ++#define PSW_SYSTEM ( 1 << PSW_offPOM ) ++#define PSW_INTL_1 ( 1 << PSW_offINTL ) ++#define PSW_CPL_NO ( 0 << PSW_offCPL ) ++#define PSW_CPL_ANY ( 7 << PSW_offCPL ) ++/****************************************************************************** ++ * ir3: IVB (Interruption Vector Base Register) ++ *****************************************************************************/ ++/* bit 0:12 reserved */ ++#define IVB_offNIVIC 1 /* Number of input for IVIC Controller */ ++#define IVB_offIVIC_VER 11 /* IVIC Version */ ++#define IVB_offEVIC 13 /* External Vector Interrupt Controller mode */ ++#define IVB_offESZ 14 /* Size of each vector entry */ ++#define IVB_offIVBASE 16 /* BasePA of interrupt vector table */ ++ ++#define IVB_mskNIVIC ( 0x7 << IVB_offNIVIC ) ++#define IVB_mskIVIC_VER ( 0x3 << IVB_offIVIC_VER ) ++#define IVB_mskEVIC ( 0x1 << IVB_offEVIC ) ++#define IVB_mskESZ ( 0x3 << IVB_offESZ ) ++#define IVB_mskIVBASE ( 0xFFFF << IVB_offIVBASE ) ++ ++/****************************************************************************** ++ * ir4: EVA (Exception Virtual Address Register) ++ * ir5: P_EVA (Previous EVA Register) ++ *****************************************************************************/ ++ ++ /* This register contains the VA that causes the exception */ ++ ++/****************************************************************************** ++ * ir6: ITYPE (Interruption Type Register) ++ * ir7: P_ITYPE (Previous ITYPE Register) ++ *****************************************************************************/ ++#define ITYPE_offETYPE 0 /* Exception Type */ ++#define ITYPE_offINST 4 /* Exception caused by insn fetch or data access */ ++/* bit 5:15 reserved */ ++#define ITYPE_offSWID 16 /* SWID of debugging exception */ ++/* bit 31:31 reserved */ ++ ++#define ITYPE_mskETYPE ( 0xF << ITYPE_offETYPE ) ++#define ITYPE_mskINST ( 0x1 << ITYPE_offINST ) ++#define ITYPE_mskSWID ( 0x7FFF << ITYPE_offSWID ) ++ ++/* Additional definitions for ITYPE register */ ++#define ITYPE_offSTYPE 16 /* Arithmetic Sub Type */ ++#define ITYPE_offCPID 20 /* Co-Processor ID which generate the exception */ ++ ++#define ITYPE_mskSTYPE ( 0xF << ITYPE_offSTYPE ) ++#define ITYPE_mskCPID ( 0x3 << ITYPE_offCPID ) ++ ++/****************************************************************************** ++ * ir8: MERR (Machine Error Log Register) ++ *****************************************************************************/ ++/* bit 0:30 reserved */ ++#define MERR_offBUSERR 31 /* Bus error caused by a load insn */ ++ ++#define MERR_mskBUSERR ( 0x1 << MERR_offBUSERR ) ++ ++/****************************************************************************** ++ * ir9: IPC (Interruption Program Counter Register) ++ * ir10: P_IPC (Previous IPC Register) ++ * ir11: OIPC (Overflow Interruption Program Counter Register) ++ *****************************************************************************/ ++ ++ /* This is the shadow stack register of the Program Counter */ ++ ++/****************************************************************************** ++ * ir12: P_P0 (Previous P0 Register) ++ * ir13: P_P1 (Previous P1 Register) ++ *****************************************************************************/ ++ ++ /* These are shadow registers of $p0 and $p1 */ ++ ++/****************************************************************************** ++ * ir14: INT_MASK (Interruption Masking Register) ++ *****************************************************************************/ ++#define INT_MASK_offH0IM 0 /* Hardware Interrupt 0 Mask bit */ ++#define INT_MASK_offH1IM 1 /* Hardware Interrupt 1 Mask bit */ ++#define INT_MASK_offH2IM 2 /* Hardware Interrupt 2 Mask bit */ ++#define INT_MASK_offH3IM 3 /* Hardware Interrupt 3 Mask bit */ ++#define INT_MASK_offH4IM 4 /* Hardware Interrupt 4 Mask bit */ ++#define INT_MASK_offH5IM 5 /* Hardware Interrupt 5 Mask bit */ ++/* bit 6:15 reserved */ ++#define INT_MASK_offSIM 16 /* Software Interrupt Mask bit */ ++/* bit 17:29 reserved */ ++#define INT_MASK_offIDIVZE 30 /* Enable detection for Divide-By-Zero */ ++#define INT_MASK_offDSSIM 31 /* Default Single Stepping Interruption Mask */ ++ ++#define INT_MASK_mskH0IM ( 0x1 << INT_MASK_offH0IM ) ++#define INT_MASK_mskH1IM ( 0x1 << INT_MASK_offH1IM ) ++#define INT_MASK_mskH2IM ( 0x1 << INT_MASK_offH2IM ) ++#define INT_MASK_mskH3IM ( 0x1 << INT_MASK_offH3IM ) ++#define INT_MASK_mskH4IM ( 0x1 << INT_MASK_offH4IM ) ++#define INT_MASK_mskH5IM ( 0x1 << INT_MASK_offH5IM ) ++#define INT_MASK_mskSIM ( 0x1 << INT_MASK_offSIM ) ++#define INT_MASK_mskIDIVZE ( 0x1 << INT_MASK_offIDIVZE ) ++#define INT_MASK_mskDSSIM ( 0x1 << INT_MASK_offDSSIM ) ++ ++/****************************************************************************** ++ * ir15: INT_PEND (Interrupt Pending Register) ++ *****************************************************************************/ ++#define INT_PEND_offH0I 0 /* Hardware Interrupt 0 pending bit */ ++#define INT_PEND_offH1I 1 /* Hardware Interrupt 1 pending bit */ ++#define INT_PEND_offH2I 2 /* Hardware Interrupt 2 pending bit */ ++#define INT_PEND_offH3I 3 /* Hardware Interrupt 3 pending bit */ ++#define INT_PEND_offH4I 4 /* Hardware Interrupt 4 pending bit */ ++#define INT_PEND_offH5I 5 /* Hardware Interrupt 5 pending bit */ ++ ++#define INT_PEND_offCIPL 0 /* Current Interrupt Priority Level */ ++ ++/* bit 6:15 reserved */ ++#define INT_PEND_offSWI 16 /* Software Interrupt pending bit */ ++/* bit 17:31 reserved */ ++ ++#define INT_PEND_mskH0I ( 0x1 << INT_PEND_offH0I ) ++#define INT_PEND_mskH1I ( 0x1 << INT_PEND_offH1I ) ++#define INT_PEND_mskH2I ( 0x1 << INT_PEND_offH2I ) ++#define INT_PEND_mskH3I ( 0x1 << INT_PEND_offH3I ) ++#define INT_PEND_mskH4I ( 0x1 << INT_PEND_offH4I ) ++#define INT_PEND_mskH5I ( 0x1 << INT_PEND_offH5I ) ++#define INT_PEND_mskCIPL ( 0x1 << INT_PEND_offCIPL ) ++#define INT_PEND_mskSWI ( 0x1 << INT_PEND_offSWI ) ++ ++/****************************************************************************** ++ * mr0: MMU_CTL (MMU Control Register) ++ *****************************************************************************/ ++#define MMU_CTL_offD 0 /* Default minimum page size */ ++#define MMU_CTL_offNTC0 1 /* Non-Translated Cachebility of partition 0 */ ++#define MMU_CTL_offNTC1 3 /* Non-Translated Cachebility of partition 1 */ ++#define MMU_CTL_offNTC2 5 /* Non-Translated Cachebility of partition 2 */ ++#define MMU_CTL_offNTC3 7 /* Non-Translated Cachebility of partition 3 */ ++#define MMU_CTL_offTBALCK 9 /* TLB all-lock resolution scheme */ ++#define MMU_CTL_offMPZIU 10 /* Multiple Page Size In Use bit */ ++#define MMU_CTL_offNTM0 11 /* Non-Translated VA to PA of partition 0 */ ++#define MMU_CTL_offNTM1 13 /* Non-Translated VA to PA of partition 1 */ ++#define MMU_CTL_offNTM2 15 /* Non-Translated VA to PA of partition 2 */ ++#define MMU_CTL_offNTM3 17 /* Non-Translated VA to PA of partition 3 */ ++/* bit 19:31 reserved */ ++ ++#define MMU_CTL_mskD ( 0x1 << MMU_CTL_offD ) ++#define MMU_CTL_mskNTC0 ( 0x3 << MMU_CTL_offNTC0 ) ++#define MMU_CTL_mskNTC1 ( 0x3 << MMU_CTL_offNTC1 ) ++#define MMU_CTL_mskNTC2 ( 0x3 << MMU_CTL_offNTC2 ) ++#define MMU_CTL_mskNTC3 ( 0x3 << MMU_CTL_offNTC3 ) ++#define MMU_CTL_mskTBALCK ( 0x1 << MMU_CTL_offTBALCK ) ++#define MMU_CTL_mskMPZIU ( 0x1 << MMU_CTL_offMPZIU ) ++#define MMU_CTL_mskNTM0 ( 0x3 << MMU_CTL_offNTM0 ) ++#define MMU_CTL_mskNTM1 ( 0x3 << MMU_CTL_offNTM1 ) ++#define MMU_CTL_mskNTM2 ( 0x3 << MMU_CTL_offNTM2 ) ++#define MMU_CTL_mskNTM3 ( 0x3 << MMU_CTL_offNTM3 ) ++ ++/****************************************************************************** ++ * mr1: L1_PPTB (L1 Physical Page Table Base Register) ++ *****************************************************************************/ ++#define L1_PPTB_offNV 0 /* Enable Hardware Page Table Walker (HPTWK) */ ++/* bit 1:11 reserved */ ++#define L1_PPTB_offBASE 12 /* First level physical page table base address */ ++ ++#define L1_PPTB_mskNV ( 0x1 << L1_PPTB_offNV ) ++#define L1_PPTB_mskBASE ( 0xFFFFF << L1_PPTB_offBASE ) ++ ++/****************************************************************************** ++ * mr2: TLB_VPN (TLB Access VPN Register) ++ *****************************************************************************/ ++/* bit 0:11 reserved */ ++#define TLB_VPN_offVPN 12 /* Virtual Page Number */ ++ ++#define TLB_VPN_mskVPN ( 0xFFFFF << TLB_VPN_offVPN ) ++ ++/****************************************************************************** ++ * mr3: TLB_DATA (TLB Access Data Register) ++ *****************************************************************************/ ++#define TLB_DATA_offV 0 /* PTE is valid and present */ ++#define TLB_DATA_offM 1 /* Page read/write access privilege */ ++#define TLB_DATA_offD 4 /* Dirty bit */ ++#define TLB_DATA_offX 5 /* Executable bit */ ++#define TLB_DATA_offA 6 /* Access bit */ ++#define TLB_DATA_offG 7 /* Global page (shared across contexts) */ ++#define TLB_DATA_offC 8 /* Cacheability atribute */ ++/* bit 11:11 reserved */ ++#define TLB_DATA_offPPN 12 /* Phisical Page Number */ ++ ++#define TLB_DATA_mskV ( 0x1 << TLB_DATA_offV ) ++#define TLB_DATA_mskM ( 0x7 << TLB_DATA_offM ) ++#define TLB_DATA_mskD ( 0x1 << TLB_DATA_offD ) ++#define TLB_DATA_mskX ( 0x1 << TLB_DATA_offX ) ++#define TLB_DATA_mskA ( 0x1 << TLB_DATA_offA ) ++#define TLB_DATA_mskG ( 0x1 << TLB_DATA_offG ) ++#define TLB_DATA_mskC ( 0x7 << TLB_DATA_offC ) ++#define TLB_DATA_mskPPN ( 0xFFFFF << TLB_DATA_offPPN ) ++ ++/****************************************************************************** ++ * mr4: TLB_MISC (TLB Access Misc Register) ++ *****************************************************************************/ ++#define TLB_MISC_offACC_PSZ 0 /* Page size of a PTE entry */ ++#define TLB_MISC_offCID 4 /* Context id */ ++/* bit 13:31 reserved */ ++ ++#define TLB_MISC_mskACC_PSZ ( 0xF << TLB_MISC_offACC_PSZ ) ++#define TLB_MISC_mskCID ( 0x1FF << TLB_MISC_offCID ) ++ ++/****************************************************************************** ++ * mr5: VLPT_IDX (Virtual Linear Page Table Index Register) ++ *****************************************************************************/ ++#define VLPT_IDX_offZERO 0 /* Always 0 */ ++#define VLPT_IDX_offEVPN 2 /* Exception Virtual Page Number */ ++#define VLPT_IDX_offVLPTB 22 /* Base VA of VLPT */ ++ ++#define VLPT_IDX_mskZERO ( 0x3 << VLPT_IDX_offZERO ) ++#define VLPT_IDX_mskEVPN ( 0xFFFFF << VLPT_IDX_offEVPN ) ++#define VLPT_IDX_mskVLPTB ( 0x3FF << VLPT_IDX_offVLPTB ) ++ ++/****************************************************************************** ++ * mr6: ILMB (Instruction Local Memory Base Register) ++ *****************************************************************************/ ++#define ILMB_offIEN 0 /* Enable ILM */ ++#define ILMB_offILMSZ 1 /* Size of ILM */ ++/* bit 5:19 reserved */ ++#define ILMB_offIBPA 20 /* Base PA of ILM */ ++ ++#define ILMB_mskIEN ( 0x1 << ILMB_offIEN ) ++#define ILMB_mskILMSZ ( 0xF << ILMB_offILMSZ ) ++#define ILMB_mskIBPA ( 0xFFF << ILMB_offIBPA ) ++ ++/****************************************************************************** ++ * mr7: DLMB (Data Local Memory Base Register) ++ *****************************************************************************/ ++#define DLMB_offDEN 0 /* Enable DLM */ ++#define DLMB_offDLMSZ 1 /* Size of DLM */ ++#define DLMB_offDBM 5 /* Enable Double-Buffer Mode for DLM */ ++#define DLMB_offDBB 6 /* Double-buffer bank which can be accessed by the processor */ ++/* bit 7:19 reserved */ ++#define DLMB_offDBPA 20 /* Base PA of DLM */ ++ ++#define DLMB_mskDEN ( 0x1 << DLMB_offDEN ) ++#define DLMB_mskDLMSZ ( 0xF << DLMB_offDLMSZ ) ++#define DLMB_mskDBM ( 0x1 << DLMB_offDBM ) ++#define DLMB_mskDBB ( 0x1 << DLMB_offDBB ) ++#define DLMB_mskDBPA ( 0xFFF << DLMB_offDBPA ) ++ ++/****************************************************************************** ++ * mr8: CACHE_CTL (Cache Control Register) ++ *****************************************************************************/ ++#define CACHE_CTL_offIC_EN 0 /* Enable I-cache */ ++#define CACHE_CTL_offDC_EN 1 /* Enable D-cache */ ++#define CACHE_CTL_offICALCK 2 /* I-cache all-lock resolution scheme */ ++#define CACHE_CTL_offDCALCK 3 /* D-cache all-lock resolution scheme */ ++#define CACHE_CTL_offDCCWF 4 /* Enable D-cache Critical Word Forwarding */ ++#define CACHE_CTL_offDCPMW 5 /* Enable D-cache concurrent miss and write-back processing */ ++/* bit 6:31 reserved */ ++ ++#define CACHE_CTL_mskIC_EN ( 0x1 << CACHE_CTL_offIC_EN ) ++#define CACHE_CTL_mskDC_EN ( 0x1 << CACHE_CTL_offDC_EN ) ++#define CACHE_CTL_mskICALCK ( 0x1 << CACHE_CTL_offICALCK ) ++#define CACHE_CTL_mskDCALCK ( 0x1 << CACHE_CTL_offDCALCK ) ++#define CACHE_CTL_mskDCCWF ( 0x1 << CACHE_CTL_offDCCWF ) ++#define CACHE_CTL_mskDCPMW ( 0x1 << CACHE_CTL_offDCPMW ) ++ ++/****************************************************************************** ++ * mr9: HSMP_SADDR (High Speed Memory Port Starting Address) ++ *****************************************************************************/ ++#define HSMP_SADDR_offEN 0 /* Enable control bit for the High Speed Memory port */ ++/* bit 1:19 reserved */ ++ ++#define HSMP_SADDR_offRANGE 1 /* Denote the address range (only defined in HSMP v2 ) */ ++#define HSMP_SADDR_offSADDR 20 /* Starting base PA of the High Speed Memory Port region */ ++ ++#define HSMP_SADDR_mskEN ( 0x1 << HSMP_SADDR_offEN ) ++#define HSMP_SADDR_mskRANGE ( 0xFFF << HSMP_SADDR_offRANGE ) ++#define HSMP_SADDR_mskSADDR ( 0xFFF << HSMP_SADDR_offSADDR ) ++ ++/****************************************************************************** ++ * mr10: HSMP_EADDR (High Speed Memory Port Ending Address) ++ *****************************************************************************/ ++/* bit 0:19 reserved */ ++#define HSMP_EADDR_offEADDR 20 ++ ++#define HSMP_EADDR_mskEADDR ( 0xFFF << HSMP_EADDR_offEADDR ) ++ ++/****************************************************************************** ++ * dr0+(n*5): BPCn (n=0-7) (Breakpoint Control Register) ++ *****************************************************************************/ ++#define BPC_offWP 0 /* Configuration of BPAn */ ++#define BPC_offEL 1 /* Enable BPAn */ ++#define BPC_offS 2 /* Data address comparison for a store instruction */ ++#define BPC_offP 3 /* Compared data address is PA */ ++#define BPC_offC 4 /* CID value is compared with the BPCIDn register */ ++#define BPC_offBE0 5 /* Enable byte mask for the comparison with register */ ++#define BPC_offBE1 6 /* Enable byte mask for the comparison with register */ ++#define BPC_offBE2 7 /* Enable byte mask for the comparison with register */ ++#define BPC_offBE3 8 /* Enable byte mask for the comparison with register */ ++#define BPC_offT 9 /* Enable breakpoint Embedded Tracer triggering operation */ ++ ++#define BPC_mskWP ( 0x1 << BPC_offWP ) ++#define BPC_mskEL ( 0x1 << BPC_offEL ) ++#define BPC_mskS ( 0x1 << BPC_offS ) ++#define BPC_mskP ( 0x1 << BPC_offP ) ++#define BPC_mskC ( 0x1 << BPC_offC ) ++#define BPC_mskBE0 ( 0x1 << BPC_offBE0 ) ++#define BPC_mskBE1 ( 0x1 << BPC_offBE1 ) ++#define BPC_mskBE2 ( 0x1 << BPC_offBE2 ) ++#define BPC_mskBE3 ( 0x1 << BPC_offBE3 ) ++#define BPC_mskT ( 0x1 << BPC_offT ) ++ ++/****************************************************************************** ++ * dr1+(n*5): BPAn (n=0-7) (Breakpoint Address Register) ++ *****************************************************************************/ ++ ++ /* These registers contain break point address */ ++ ++/****************************************************************************** ++ * dr2+(n*5): BPAMn (n=0-7) (Breakpoint Address Mask Register) ++ *****************************************************************************/ ++ ++ /* These registerd contain the address comparison mask for the BPAn register */ ++ ++/****************************************************************************** ++ * dr3+(n*5): BPVn (n=0-7) Breakpoint Data Value Register ++ *****************************************************************************/ ++ ++ /* The BPVn register contains the data value that will be compared with the ++ * incoming load/store data value */ ++ ++/****************************************************************************** ++ * dr4+(n*5): BPCIDn (n=0-7) (Breakpoint Context ID Register) ++ *****************************************************************************/ ++#define BPCID_offCID 0 /* CID that will be compared with a process's CID */ ++/* bit 9:31 reserved */ ++ ++#define BPCID_mskCID ( 0x1FF << BPCID_offCID ) ++ ++/****************************************************************************** ++ * dr40: EDM_CFG (EDM Configuration Register) ++ *****************************************************************************/ ++#define EDM_CFG_offBC 0 /* Number of hardware breakpoint sets implemented */ ++#define EDM_CFG_offDIMU 3 /* Debug Instruction Memory Unit exists */ ++/* bit 4:15 reserved */ ++#define EDM_CFG_offVER 16 /* EDM version */ ++ ++#define EDM_CFG_mskBC ( 0x7 << EDM_CFG_offBC ) ++#define EDM_CFG_mskDIMU ( 0x1 << EDM_CFG_offDIMU ) ++#define EDM_CFG_mskVER ( 0xFFFF << EDM_CFG_offVER ) ++ ++/****************************************************************************** ++ * dr41: EDMSW (EDM Status Word) ++ *****************************************************************************/ ++#define EDMSW_offWV 0 /* Write Valid */ ++#define EDMSW_offRV 1 /* Read Valid */ ++#define EDMSW_offDE 2 /* Debug exception has occurred for this core */ ++/* bit 3:31 reserved */ ++ ++#define EDMSW_mskWV ( 0x1 << EDMSW_offWV ) ++#define EDMSW_mskRV ( 0x1 << EDMSW_offRV ) ++#define EDMSW_mskDE ( 0x1 << EDMSW_offDE ) ++ ++/****************************************************************************** ++ * dr42: EDM_CTL (EDM Control Register) ++ *****************************************************************************/ ++/* bit 0:30 reserved */ ++#define EDM_CTL_offV3_EDM_MODE 6 /* EDM compatibility control bit */ ++#define EDM_CTL_offDEH_SEL 31 /* Controls where debug exception is directed to */ ++ ++#define EDM_CTL_mskV3_EDM_MODE ( 0x1 << EDM_CTL_offV3_EDM_MODE ) ++#define EDM_CTL_mskDEH_SEL ( 0x1 << EDM_CTL_offDEH_SEL ) ++ ++/****************************************************************************** ++ * dr43: EDM_DTR (EDM Data Transfer Register) ++ *****************************************************************************/ ++ ++ /* This is used to exchange data between the embedded EDM logic ++ * and the processor core */ ++ ++/****************************************************************************** ++ * dr44: BPMTC (Breakpoint Match Trigger Counter Register) ++ *****************************************************************************/ ++#define BPMTC_offBPMTC 0 /* Breakpoint match trigger counter value */ ++/* bit 16:31 reserved */ ++ ++#define BPMTC_mskBPMTC ( 0xFFFF << BPMTC_offBPMTC ) ++ ++/****************************************************************************** ++ * dr45: DIMBR (Debug Instruction Memory Base Register) ++ *****************************************************************************/ ++/* bit 0:11 reserved */ ++#define DIMBR_offDIMB 12 /* Base address of the Debug Instruction Memory (DIM) */ ++#define DIMBR_mskDIMB ( 0xFFFFF << DIMBR_offDIMB ) ++ ++/****************************************************************************** ++ * dr46: TECR0(Trigger Event Control register 0) ++ * dr47: TECR1 (Trigger Event Control register 1) ++ *****************************************************************************/ ++#define TECR_offBP 0 /* Controld which BP is used as a trigger source */ ++#define TECR_offNMI 8 /* Use NMI as a trigger source */ ++#define TECR_offHWINT 9 /* Corresponding interrupt is used as a trigger source */ ++#define TECR_offEVIC 15 /* Enable HWINT as a trigger source in EVIC mode */ ++#define TECR_offSYS 16 /* Enable SYSCALL instruction as a trigger source */ ++#define TECR_offDBG 17 /* Enable debug exception as a trigger source */ ++#define TECR_offMRE 18 /* Enable MMU related exception as a trigger source */ ++#define TECR_offE 19 /* An exception is used as a trigger source */ ++/* bit 20:30 reserved */ ++#define TECR_offL 31 /* Link/Cascade TECR0 trigger event to TECR1 trigger event */ ++ ++#define TECR_mskBP ( 0xFF << TECR_offBP ) ++#define TECR_mskNMI ( 0x1 << TECR_offBNMI ) ++#define TECR_mskHWINT ( 0x3F << TECR_offBHWINT ) ++#define TECR_mskEVIC ( 0x1 << TECR_offBEVIC ) ++#define TECR_mskSYS ( 0x1 << TECR_offBSYS ) ++#define TECR_mskDBG ( 0x1 << TECR_offBDBG ) ++#define TECR_mskMRE ( 0x1 << TECR_offBMRE ) ++#define TECR_mskE ( 0x1 << TECR_offE ) ++#define TECR_mskL ( 0x1 << TECR_offL ) ++ ++/****************************************************************************** ++ * pfr0-2: PFMC0-2 (Performance Counter Register 0-2) ++ *****************************************************************************/ ++ ++ /* These registers contains performance event count */ ++ ++/****************************************************************************** ++ * pfr3: PFM_CTL (Performance Counter Control Register) ++ *****************************************************************************/ ++#define PFM_CTL_offEN0 0 /* Enable PFMC0 */ ++#define PFM_CTL_offEN1 1 /* Enable PFMC1 */ ++#define PFM_CTL_offEN2 2 /* Enable PFMC2 */ ++#define PFM_CTL_offIE0 3 /* Enable interrupt for PFMC0 */ ++#define PFM_CTL_offIE1 4 /* Enable interrupt for PFMC1 */ ++#define PFM_CTL_offIE2 5 /* Enable interrupt for PFMC2 */ ++#define PFM_CTL_offOVF0 6 /* Overflow bit of PFMC0 */ ++#define PFM_CTL_offOVF1 7 /* Overflow bit of PFMC1 */ ++#define PFM_CTL_offOVF2 8 /* Overflow bit of PFMC2 */ ++#define PFM_CTL_offKS0 9 /* Enable superuser mode event counting for PFMC0 */ ++#define PFM_CTL_offKS1 10 /* Enable superuser mode event counting for PFMC1 */ ++#define PFM_CTL_offKS2 11 /* Enable superuser mode event counting for PFMC2 */ ++#define PFM_CTL_offKU0 12 /* Enable user mode event counting for PFMC0 */ ++#define PFM_CTL_offKU1 13 /* Enable user mode event counting for PFMC1 */ ++#define PFM_CTL_offKU2 14 /* Enable user mode event counting for PFMC2 */ ++#define PFM_CTL_offSEL0 15 /* The event selection for PFMC0 */ ++#define PFM_CTL_offSEL1 21 /* The event selection for PFMC1 */ ++#define PFM_CTL_offSEL2 27 /* The event selection for PFMC2 */ ++/* bit 28:31 reserved */ ++ ++#define PFM_CTL_mskEN0 ( 0x01 << PFM_CTL_offEN0 ) ++#define PFM_CTL_mskEN1 ( 0x01 << PFM_CTL_offEN1 ) ++#define PFM_CTL_mskEN2 ( 0x01 << PFM_CTL_offEN2 ) ++#define PFM_CTL_mskIE0 ( 0x01 << PFM_CTL_offIE0 ) ++#define PFM_CTL_mskIE1 ( 0x01 << PFM_CTL_offIE1 ) ++#define PFM_CTL_mskIE2 ( 0x01 << PFM_CTL_offIE2 ) ++#define PFM_CTL_mskOVF0 ( 0x01 << PFM_CTL_offOVF0 ) ++#define PFM_CTL_mskOVF1 ( 0x01 << PFM_CTL_offOVF1 ) ++#define PFM_CTL_mskOVF2 ( 0x01 << PFM_CTL_offOVF2 ) ++#define PFM_CTL_mskKS0 ( 0x01 << PFM_CTL_offKS0 ) ++#define PFM_CTL_mskKS1 ( 0x01 << PFM_CTL_offKS1 ) ++#define PFM_CTL_mskKS2 ( 0x01 << PFM_CTL_offKS2 ) ++#define PFM_CTL_mskKU0 ( 0x01 << PFM_CTL_offKU0 ) ++#define PFM_CTL_mskKU1 ( 0x01 << PFM_CTL_offKU1 ) ++#define PFM_CTL_mskKU2 ( 0x01 << PFM_CTL_offKU2 ) ++#define PFM_CTL_mskSEL0 ( 0x01 << PFM_CTL_offSEL0 ) ++#define PFM_CTL_mskSEL1 ( 0x3F << PFM_CTL_offSEL1 ) ++#define PFM_CTL_mskSEL2 ( 0x3F << PFM_CTL_offSEL2 ) ++ ++/****************************************************************************** ++ * SDZ_CTL (Structure Downsizing Control Register) ++ *****************************************************************************/ ++#define SDZ_CTL_offICDZ 0 /* I-cache downsizing control */ ++#define SDZ_CTL_offDCDZ 3 /* D-cache downsizing control */ ++#define SDZ_CTL_offMTBDZ 6 /* MTLB downsizing control */ ++#define SDZ_CTL_offBTBDZ 9 /* Branch Target Table downsizing control */ ++/* bit 12:31 reserved */ ++#define SDZ_CTL_mskICDZ ( 0x07 << SDZ_CTL_offICDZ ) ++#define SDZ_CTL_mskDCDZ ( 0x07 << SDZ_CTL_offDCDZ ) ++#define SDZ_CTL_mskMTBDZ ( 0x07 << SDZ_CTL_offMTBDZ ) ++#define SDZ_CTL_mskBTBDZ ( 0x07 << SDZ_CTL_offBTBDZ ) ++ ++/****************************************************************************** ++ * N12MISC_CTL (N12 Miscellaneous Control Register) ++ *****************************************************************************/ ++#define N12MISC_CTL_offBTB 0 /* Disable Branch Target Buffer */ ++#define N12MISC_CTL_offRTP 1 /* Disable Return Target Predictor */ ++#define N12MISC_CTL_offPTEPF 2 /* Disable HPTWK L2 PTE pefetch */ ++/* bit 3:31 reserved */ ++ ++#define N12MISC_CTL_makBTB ( 0x1 << N12MISC_CTL_offBTB ) ++#define N12MISC_CTL_makRTP ( 0x1 << N12MISC_CTL_offRTP ) ++#define N12MISC_CTL_makPTEPF ( 0x1 << N12MISC_CTL_offPTEPF ) ++ ++/****************************************************************************** ++ * PRUSR_ACC_CTL (Privileged Resource User Access Control Registers) ++ *****************************************************************************/ ++#define PRUSR_ACC_CTL_offDMA_EN 0 /* Allow user mode access of DMA registers */ ++#define PRUSR_ACC_CTL_offPFM_EN 1 /* Allow user mode access of PFM registers */ ++ ++#define PRUSR_ACC_CTL_mskDMA_EN ( 0x1 << PRUSR_ACC_CTL_offDMA_EN ) ++#define PRUSR_ACC_CTL_mskPFM_EN ( 0x1 << PRUSR_ACC_CTL_offPFM_EN ) ++ ++/****************************************************************************** ++ * dmar0: DMA_CFG (DMA Configuration Register) ++ *****************************************************************************/ ++#define DMA_CFG_offNCHN 0 /* The number of DMA channels implemented */ ++#define DMA_CFG_offUNEA 2 /* Un-aligned External Address transfer feature */ ++#define DMA_CFG_off2DET 3 /* 2-D Element Transfer feature */ ++/* bit 4:15 reserved */ ++#define DMA_CFG_offVER 16 /* DMA architecture and implementation version */ ++ ++#define DMA_CFG_mskNCHN ( 0x3 << DMA_CFG_offNCHN ) ++#define DMA_CFG_mskUNEA ( 0x1 << DMA_CFG_offUNEA ) ++#define DMA_CFG_msk2DET ( 0x1 << DMA_CFG_off2DET ) ++#define DMA_CFG_mskVER ( 0xFFFF << DMA_CFG_offVER ) ++ ++/****************************************************************************** ++ * dmar1: DMA_GCSW (DMA Global Control and Status Word Register) ++ *****************************************************************************/ ++#define DMA_GCSW_offC0STAT 0 /* DMA channel 0 state */ ++#define DMA_GCSW_offC1STAT 3 /* DMA channel 1 state */ ++/* bit 6:11 reserved */ ++#define DMA_GCSW_offC0INT 12 /* DMA channel 0 generate interrupt */ ++#define DMA_GCSW_offC1INT 13 /* DMA channel 1 generate interrupt */ ++/* bit 14:30 reserved */ ++#define DMA_GCSW_offEN 31 /* Enable DMA engine */ ++ ++#define DMA_GCSW_mskC0STAT ( 0x7 << DMA_GCSW_offC0STAT ) ++#define DMA_GCSW_mskC1STAT ( 0x7 << DMA_GCSW_offC1STAT ) ++#define DMA_GCSW_mskC0INT ( 0x1 << DMA_GCSW_offC0INT ) ++#define DMA_GCSW_mskC1INT ( 0x1 << DMA_GCSW_offC1INT ) ++#define DMA_GCSW_mskEN ( 0x1 << DMA_GCSW_offEN ) ++ ++/****************************************************************************** ++ * dmar2: DMA_CHNSEL (DMA Channel Selection Register) ++ *****************************************************************************/ ++#define DMA_CHNSEL_offCHAN 0 /* Selected channel number */ ++/* bit 2:31 reserved */ ++ ++#define DMA_CHNSEL_mskCHAN ( 0x3 << DMA_CHNSEL_offCHAN ) ++ ++/****************************************************************************** ++ * dmar3: DMA_ACT (DMA Action Register) ++ *****************************************************************************/ ++#define DMA_ACT_offACMD 0 /* DMA Action Command */ ++/* bit 2:31 reserved */ ++#define DMA_ACT_mskACMD ( 0x3 << DMA_ACT_offACMD ) ++ ++/****************************************************************************** ++ * dmar4: DMA_SETUP (DMA Setup Register) ++ *****************************************************************************/ ++#define DMA_SETUP_offLM 0 /* Local Memory Selection */ ++#define DMA_SETUP_offTDIR 1 /* Transfer Direction */ ++#define DMA_SETUP_offTES 2 /* Transfer Element Size */ ++#define DMA_SETUP_offESTR 4 /* External memory transfer Stride */ ++#define DMA_SETUP_offCIE 16 /* Interrupt Enable on Completion */ ++#define DMA_SETUP_offSIE 17 /* Interrupt Enable on explicit Stop */ ++#define DMA_SETUP_offEIE 18 /* Interrupt Enable on Error */ ++#define DMA_SETUP_offUE 19 /* Enable the Un-aligned External Address */ ++#define DMA_SETUP_off2DE 20 /* Enable the 2-D External Transfer */ ++#define DMA_SETUP_offCOA 21 /* Transfer Coalescable */ ++/* bit 22:31 reserved */ ++ ++#define DMA_SETUP_mskLM ( 0x1 << DMA_SETUP_offLM ) ++#define DMA_SETUP_mskTDIR ( 0x1 << DMA_SETUP_offTDIR ) ++#define DMA_SETUP_mskTES ( 0x3 << DMA_SETUP_offTES ) ++#define DMA_SETUP_mskESTR ( 0xFFF << DMA_SETUP_offESTR ) ++#define DMA_SETUP_mskCIE ( 0x1 << DMA_SETUP_offCIE ) ++#define DMA_SETUP_mskSIE ( 0x1 << DMA_SETUP_offSIE ) ++#define DMA_SETUP_mskEIE ( 0x1 << DMA_SETUP_offEIE ) ++#define DMA_SETUP_mskUE ( 0x1 << DMA_SETUP_offUE ) ++#define DMA_SETUP_msk2DE ( 0x1 << DMA_SETUP_off2DE ) ++#define DMA_SETUP_mskCOA ( 0x1 << DMA_SETUP_offCOA ) ++ ++/****************************************************************************** ++ * dmar5: DMA_ISADDR (DMA Internal Start Address Register) ++ *****************************************************************************/ ++#define DMA_ISADDR_offISADDR 0 /* Internal Start Address */ ++/* bit 20:31 reserved */ ++#define DMA_ISADDR_mskISADDR ( 0xFFFFF << DMA_ISADDR_offISADDR ) ++ ++/****************************************************************************** ++ * dmar6: DMA_ESADDR (DMA External Start Address Register) ++ *****************************************************************************/ ++/* This register holds External Start Address */ ++ ++/****************************************************************************** ++ * dmar7: DMA_TCNT (DMA Transfer Element Count Register) ++ *****************************************************************************/ ++#define DMA_TCNT_offTCNT 0 /* DMA transfer element count */ ++/* bit 18:31 reserved */ ++#define DMA_TCNT_mskTCNT ( 0x3FFFF << DMA_TCNT_offTCNT ) ++ ++/****************************************************************************** ++ * dmar8: DMA_STATUS (DMA Status Register) ++ *****************************************************************************/ ++#define DMA_STATUS_offSTAT 0 /* DMA channel state */ ++#define DMA_STATUS_offSTUNA 3 /* Un-aligned error on External Stride value */ ++#define DMA_STATUS_offDERR 4 /* DMA Transfer Disruption Error */ ++#define DMA_STATUS_offEUNA 5 /* Un-aligned error on the External address */ ++#define DMA_STATUS_offIUNA 6 /* Un-aligned error on the Internal address */ ++#define DMA_STATUS_offIOOR 7 /* Out-Of-Range error on the Internal address */ ++#define DMA_STATUS_offEBUS 8 /* Bus Error on an External DMA transfer */ ++#define DMA_STATUS_offESUP 9 /* DMA setup error */ ++/* bit 10:31 reserved */ ++ ++#define DMA_STATUS_mskSTAT ( 0x7 << DMA_STATUS_offSTAT ) ++#define DMA_STATUS_mskSTUNA ( 0x1 << DMDMA_STATUS_offSTUNA ) ++#define DMA_STATUS_mskDERR ( 0x1 << DMDMA_STATUS_offDERR ) ++#define DMA_STATUS_mskEUNA ( 0x1 << DMDMA_STATUS_offEUNA ) ++#define DMA_STATUS_mskIUNA ( 0x1 << DMDMA_STATUS_offIUNA ) ++#define DMA_STATUS_mskIOOR ( 0x1 << DMDMA_STATUS_offIOOR ) ++#define DMA_STATUS_mskEBUS ( 0x1 << DMDMA_STATUS_offEBUS ) ++#define DMA_STATUS_mskESUP ( 0x1 << DMDMA_STATUS_offESUP ) ++ ++/****************************************************************************** ++ * dmar9: DMA_2DSET (DMA 2D Setup Register) ++ *****************************************************************************/ ++#define DMA_2DSET_offWECNT 0 /* The Width Element Count for a 2-D region */ ++#define DMA_2DSET_offHTSTR 16 /* The Height Stride for a 2-D region */ ++ ++#define DMA_2DSET_mskHTSTR ( 0xFFFF << DMA_2DSET_offHTSTR ) ++#define DMA_2DSET_mskWECNT ( 0xFFFF << DMA_2DSET_offWECNT ) ++ ++/****************************************************************************** ++ * dmar10: DMA_2DSCTL (DMA 2D Startup Control Register) ++ *****************************************************************************/ ++#define DMA_2DSCTL_offSTWECNT 0 /* Startup Width Element Count for a 2-D region */ ++/* bit 16:31 reserved */ ++ ++#define DMA_2DSCTL_mskSTWECNT ( 0xFFFF << DMA_2DSCTL_offSTWECNT ) ++ ++/****************************************************************************** ++ * fpcsr: FPCSR (Floating-Point Control Status Register) ++ *****************************************************************************/ ++#define FPCSR_offRM 0 ++#define FPCSR_offIVO 2 ++#define FPCSR_offDBZ 3 ++#define FPCSR_offOVF 4 ++#define FPCSR_offUDF 5 ++#define FPCSR_offIEX 6 ++#define FPCSR_offIVOE 7 ++#define FPCSR_offDBZE 8 ++#define FPCSR_offOVFE 9 ++#define FPCSR_offUDFE 10 ++#define FPCSR_offIEXE 11 ++#define FPCSR_offDNZ 12 ++#define FPCSR_offIVOT 13 ++#define FPCSR_offDBZT 14 ++#define FPCSR_offOVFT 15 ++#define FPCSR_offUDFT 16 ++#define FPCSR_offIEXT 17 ++#define FPCSR_offDNIT 18 ++#define FPCSR_offRIT 19 ++ ++#define FPCSR_mskRM ( 0x3 << FPCSR_offRM ) ++#define FPCSR_mskIVO ( 0x1 << FPCSR_offIVO ) ++#define FPCSR_mskDBZ ( 0x1 << FPCSR_offDBZ ) ++#define FPCSR_mskOVF ( 0x1 << FPCSR_offOVF ) ++#define FPCSR_mskUDF ( 0x1 << FPCSR_offUDF ) ++#define FPCSR_mskIEX ( 0x1 << FPCSR_offIEX ) ++#define FPCSR_mskIVOE ( 0x1 << FPCSR_offIVOE ) ++#define FPCSR_mskDBZE ( 0x1 << FPCSR_offDBZE ) ++#define FPCSR_mskOVFE ( 0x1 << FPCSR_offOVFE ) ++#define FPCSR_mskUDFE ( 0x1 << FPCSR_offUDFE ) ++#define FPCSR_mskIEXE ( 0x1 << FPCSR_offIEXE ) ++#define FPCSR_mskDNZ ( 0x1 << FPCSR_offDNZ ) ++#define FPCSR_mskIVOT ( 0x1 << FPCSR_offIVOT ) ++#define FPCSR_mskDBZT ( 0x1 << FPCSR_offDBZT ) ++#define FPCSR_mskOVFT ( 0x1 << FPCSR_offOVFT ) ++#define FPCSR_mskUDFT ( 0x1 << FPCSR_offUDFT ) ++#define FPCSR_mskIEXT ( 0x1 << FPCSR_offIEXT ) ++#define FPCSR_mskDNIT ( 0x1 << FPCSR_offDNIT ) ++#define FPCSR_mskRIT ( 0x1 << FPCSR_offRIT ) ++#define FPCSR_mskALL (FPCSR_mskIVO | FPCSR_mskDBZ | FPCSR_mskOVF | FPCSR_mskUDF | FPCSR_mskIEX) ++#define FPCSR_mskALLE (FPCSR_mskIVOE | FPCSR_mskDBZE | FPCSR_mskOVFE | FPCSR_mskUDFE | FPCSR_mskIEXE) ++#define FPCSR_mskALLT (FPCSR_mskIVOT | FPCSR_mskDBZT | FPCSR_mskOVFT | FPCSR_mskUDFT | FPCSR_mskIEXT |FPCSR_mskDNIT | FPCSR_mskRIT) ++ ++/****************************************************************************** ++ * fpcfg: FPCFG (Floating-Point Configuration Register) ++ *****************************************************************************/ ++#define FPCFG_offSP 0 ++#define FPCFG_offDP 1 ++#define FPCFG_offFREG 2 ++#define FPCFG_offFMA 4 ++#define FPCFG_offIMVER 22 ++#define FPCFG_offAVER 27 ++ ++#define FPCFG_mskSP ( 0x1 << FPCFG_offSP ) ++#define FPCFG_mskDP ( 0x1 << FPCFG_offDP ) ++#define FPCFG_mskFREG ( 0x3 << FPCFG_offFREG ) ++#define FPCFG_mskFMA ( 0x1 << FPCFG_offFMA ) ++#define FPCFG_mskIMVER ( 0x1F << FPCFG_offIMVER ) ++#define FPCFG_mskAVER ( 0x1F << FPCFG_offAVER ) ++ ++/****************************************************************************** ++ * fucpr: FUCOP_CTL (FPU and Coprocessor Enable Control Register) ++ *****************************************************************************/ ++#define FUCOP_CTL_offCP0EN 0 ++#define FUCOP_CTL_offCP1EN 1 ++#define FUCOP_CTL_offCP2EN 2 ++#define FUCOP_CTL_offCP3EN 3 ++#define FUCOP_CTL_offAUEN 31 ++ ++#define FUCOP_CTL_mskCP0EN ( 0x1 << FUCOP_CTL_offCP0EN ) ++#define FUCOP_CTL_mskCP1EN ( 0x1 << FUCOP_CTL_offCP1EN ) ++#define FUCOP_CTL_mskCP2EN ( 0x1 << FUCOP_CTL_offCP2EN ) ++#define FUCOP_CTL_mskCP3EN ( 0x1 << FUCOP_CTL_offCP3EN ) ++#define FUCOP_CTL_mskAUEN ( 0x1 << FUCOP_CTL_offAUEN ) ++ ++#endif /* __NDS32_BITFIELD_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/bitops.h linux-3.4.110/arch/nds32/include/asm/bitops.h +--- linux-3.4.110.orig/arch/nds32/include/asm/bitops.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/bitops.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,256 @@ ++/* ++ * linux/arch/nds32/include/asm/bitops.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_BITOPS_H__ ++#define __NDS32_BITOPS_H__ ++ ++#if defined(CONFIG_SMP) || !defined(CONFIG_CPU_DCACHE_WRITETHROUGH) ++ ++/* ++#include <linux/irqflags.h> ++ ++static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long *p) ++{ ++ unsigned long flags; ++ unsigned long mask = 1UL << (bit & 31); ++ ++ p += bit >> 5; ++ ++ raw_local_irq_save(flags); ++ *p |= mask; ++ raw_local_irq_restore(flags); ++} ++ ++static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long *p) ++{ ++ unsigned long flags; ++ unsigned long mask = 1UL << (bit & 31); ++ ++ p += bit >> 5; ++ ++ raw_local_irq_save(flags); ++ *p &= ~mask; ++ raw_local_irq_restore(flags); ++} ++ ++static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned long *p) ++{ ++ unsigned long flags; ++ unsigned long mask = 1UL << (bit & 31); ++ ++ p += bit >> 5; ++ ++ raw_local_irq_save(flags); ++ *p ^= mask; ++ raw_local_irq_restore(flags); ++} ++ ++static inline int ++____atomic_test_and_set_bit(unsigned int bit, volatile unsigned long *p) ++{ ++ unsigned long flags; ++ unsigned int res; ++ unsigned long mask = 1UL << (bit & 31); ++ ++ p += bit >> 5; ++ ++ raw_local_irq_save(flags); ++ res = *p; ++ *p = res | mask; ++ raw_local_irq_restore(flags); ++ ++ return (res & mask) != 0; ++} ++static inline int ++____atomic_test_and_clear_bit(unsigned int bit, volatile unsigned long *p) ++{ ++ unsigned long flags; ++ unsigned int res; ++ unsigned long mask = 1UL << (bit & 31); ++ ++ p += bit >> 5; ++ ++ raw_local_irq_save(flags); ++ res = *p; ++ *p = res & ~mask; ++ raw_local_irq_restore(flags); ++ ++ return (res & mask) != 0; ++} ++ ++static inline int ++____atomic_test_and_change_bit(unsigned int bit, volatile unsigned long *p) ++{ ++ unsigned long flags; ++ unsigned int res; ++ unsigned long mask = 1UL << (bit & 31); ++ ++ p += bit >> 5; ++ ++ raw_local_irq_save(flags); ++ res = *p; ++ *p = res ^ mask; ++ raw_local_irq_restore(flags); ++ ++ return (res & mask) != 0; ++} ++ ++#include <asm-generic/bitops/non-atomic.h> ++#ifndef CONFIG_SMP ++#define ATOMIC_BITOP(name,nr,p) \ ++ (__builtin_constant_p(nr) ? ____atomic_##name(nr, p) : _##name(nr,p)) ++#else ++#define ATOMIC_BITOP(name,nr,p) _##name(nr,p) ++#endif ++ ++#define set_bit(nr,p) ATOMIC_BITOP(set_bit,nr,p) ++*/ ++ ++static inline void set_bit(int nr,volatile unsigned long *addr) ++{ ++ unsigned long mask = BIT_MASK(nr); ++ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); ++ unsigned long tmp; ++ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%1+$r15]\n" ++ "\tor\t%0, %0, %2\n" ++ "\tscw\t%0, [%1+$r15]\n" ++ "\tbeqz\t%0, 1b\n" ++ : "=&r" (tmp) ++ : "r" (p), "r" (mask) ++ : "memory"); ++} ++ ++static inline void clear_bit(int nr, volatile unsigned long *addr) ++{ ++ unsigned long mask = BIT_MASK(nr); ++ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); ++ unsigned long tmp; ++ ++ mask = ~mask; ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%1+$r15]\n" ++ "\tand\t%0, %0, %2\n" ++ "\tscw\t%0, [%1+$r15]\n" ++ "\tbeqz\t%0, 1b\n" ++ : "=&r" (tmp) ++ : "r" (p), "r" (mask) ++ : "memory"); ++} ++ ++static inline void change_bit(int nr, volatile unsigned long *addr) ++{ ++ unsigned long mask = BIT_MASK(nr); ++ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); ++ unsigned long tmp; ++ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%1+$r15]\n" ++ "\txor\t%0, %0, %2\n" ++ "\tscw\t%0, [%1+$r15]\n" ++ "\tbeqz\t%0, 1b\n" ++ : "=&r" (tmp) ++ : "r" (p), "r" (mask) ++ : "memory"); ++} ++ ++static inline int test_and_set_bit(int nr, volatile unsigned long *addr) ++{ ++ unsigned long mask = BIT_MASK(nr); ++ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); ++ unsigned long tmp ,ret; ++ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%2+$r15]\n" ++ "\tor\t%1, %0, %3\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (ret), "=&r" (tmp) ++ : "r" (p), "r" (mask) ++ : "memory"); ++ return (ret & mask) != 0; ++} ++ ++static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) ++{ ++ unsigned long mask = BIT_MASK(nr); ++ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); ++ unsigned long tmp, ret; ++ unsigned long mask2 = ~mask; ++ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%2+$r15]\n" ++ "\tand\t%1, %0, %3\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (ret), "=&r" (tmp) ++ : "r" (p), "r" (mask2) ++ : "memory"); ++ return (ret & mask) != 0; ++} ++ ++static inline int test_and_change_bit(int nr, volatile unsigned long *addr) ++{ ++ unsigned long mask = BIT_MASK(nr); ++ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); ++ unsigned long tmp, ret; ++ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%2+$r15]\n" ++ "\txor\t%1, %0, %3\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (ret), "=&r" (tmp) ++ : "r" (p), "r" (mask) ++ : "memory"); ++ return (ret & mask) != 0; ++} ++#else ++#include <linux/irqflags.h> ++#include <asm-generic/bitops/atomic.h> ++#endif ++ ++#include <linux/compiler.h> ++#include <asm-generic/bitops/non-atomic.h> ++#include <asm-generic/bitops/__ffs.h> ++#include <asm-generic/bitops/ffz.h> ++#include <asm-generic/bitops/fls.h> ++#include <asm-generic/bitops/__fls.h> ++#include <asm-generic/bitops/fls64.h> ++#include <asm-generic/bitops/find.h> ++ ++#ifdef __KERNEL__ ++ ++#include <asm-generic/bitops/sched.h> ++#include <asm-generic/bitops/ffs.h> ++#include <asm-generic/bitops/hweight.h> ++#include <asm-generic/bitops/lock.h> ++ ++#include <asm-generic/bitops/le.h> ++ ++/* ++ * Ext2 is defined to use little-endian byte ordering. ++ */ ++#include <asm-generic/bitops/ext2-atomic-setbit.h> ++ ++#endif /* __KERNEL__ */ ++ ++#define smp_mb__before_clear_bit() barrier() ++#define smp_mb__after_clear_bit() barrier() ++ ++#endif /* __NDS32_BITOPS_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/bitsperlong.h linux-3.4.110/arch/nds32/include/asm/bitsperlong.h +--- linux-3.4.110.orig/arch/nds32/include/asm/bitsperlong.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/bitsperlong.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1 @@ ++#include <asm-generic/bitsperlong.h> +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/bug.h linux-3.4.110/arch/nds32/include/asm/bug.h +--- linux-3.4.110.orig/arch/nds32/include/asm/bug.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/bug.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * linux/arch/nds32/include/asm/bug.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_BUG_H__ ++#define __NDS32_BUG_H__ ++ ++#define HAVE_ARCH_BUG ++#include <asm-generic/bug.h> ++ ++#define BUG() do { \ ++ dump_stack(); \ ++ printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \ ++ panic("BUG!"); \ ++} while (0) ++ ++#endif /* __NDS32_BUG_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/bugs.h linux-3.4.110/arch/nds32/include/asm/bugs.h +--- linux-3.4.110.orig/arch/nds32/include/asm/bugs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/bugs.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/bugs.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_BUGS_H__ ++#define __NDS32_BUGS_H__ ++ ++static inline void check_bugs(void) {} ++ ++#endif /* __NDS32_BUGS_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/byteorder.h linux-3.4.110/arch/nds32/include/asm/byteorder.h +--- linux-3.4.110.orig/arch/nds32/include/asm/byteorder.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/byteorder.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,15 @@ ++/* ++ * linux/arch/nds32/include/asm/byteorder.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_BYTEORDER_H__ ++#define __NDS32_BYTEORDER_H__ ++ ++#ifdef __NDS32_EB__ ++#include <linux/byteorder/big_endian.h> ++#else ++#include <linux/byteorder/little_endian.h> ++#endif ++ ++#endif /* __NDS32_BYTEORDER_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/cacheflush.h linux-3.4.110/arch/nds32/include/asm/cacheflush.h +--- linux-3.4.110.orig/arch/nds32/include/asm/cacheflush.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/cacheflush.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,55 @@ ++/* ++ * linux/arch/nds32/include/asm/cacheflush.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_CACHEFLUSH_H__ ++#define __NDS32_CACHEFLUSH_H__ ++ ++#include <linux/mm.h> ++ ++#define PG_dcache_dirty PG_arch_1 ++ ++void flush_cache_mm(struct mm_struct *mm); ++ ++void flush_cache_dup_mm(struct mm_struct *mm); ++ ++void flush_cache_range(struct vm_area_struct *vma, ++ unsigned long start, unsigned long end); ++ ++void flush_cache_page(struct vm_area_struct *vma, ++ unsigned long addr, unsigned long pfn); ++ ++void flush_cache_kmaps(void); ++ ++void flush_cache_vmap(unsigned long start, unsigned long end); ++ ++void flush_cache_vunmap(unsigned long start, unsigned long end); ++ ++ ++void flush_dcache_page(struct page *page); ++ ++void copy_to_user_page(struct vm_area_struct *vma, struct page *page, ++ unsigned long vaddr, void *dst, void *src, int len); ++ ++void copy_from_user_page(struct vm_area_struct *vma, struct page *page, ++ unsigned long vaddr, void *dst, void *src, int len); ++ ++#ifndef CONFIG_CPU_CACHE_NONALIASING ++#define ARCH_HAS_FLUSH_ANON_PAGE ++void flush_anon_page(struct vm_area_struct *vma, ++ struct page *page, unsigned long vaddr); ++ ++#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE ++void flush_kernel_dcache_page(struct page *page); ++#endif ++ ++void flush_icache_range(unsigned long start, unsigned long end); ++ ++void flush_icache_page(struct vm_area_struct *vma, struct page *page); ++ ++#define flush_dcache_mmap_lock(mapping) spin_lock_irq(&(mapping)->tree_lock) ++#define flush_dcache_mmap_unlock(mapping) spin_unlock_irq(&(mapping)->tree_lock) ++ ++#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 ++#endif /* __NDS32_CACHEFLUSH_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/cache.h linux-3.4.110/arch/nds32/include/asm/cache.h +--- linux-3.4.110.orig/arch/nds32/include/asm/cache.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/cache.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,22 @@ ++/* ++ * linux/arch/nds32/include/asm/cache.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_CACHE_H__ ++#define __NDS32_CACHE_H__ ++ ++#define L1_CACHE_BYTES 32 ++#define L1_CACHE_SHIFT 5 ++ ++/* ++ * * Memory returned by kmalloc() may be used for DMA, so we must make ++ * * sure that all such allocations are cache aligned. Otherwise, ++ * * unrelated code may cause parts of the buffer to be read into the ++ * * cache before the transfer is done, causing old data to be seen by ++ * * the CPU. ++ * */ ++#define ARCH_DMA_MINALIGN L1_CACHE_BYTES ++ ++ ++#endif /* __NDS32_CACHE_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/cache_info.h linux-3.4.110/arch/nds32/include/asm/cache_info.h +--- linux-3.4.110.orig/arch/nds32/include/asm/cache_info.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/cache_info.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,17 @@ ++/* ++ * linux/arch/nds32/include/asm/cache.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++struct cache_info { ++ unsigned char cache_type; ++ unsigned char ways; ++ unsigned char way_bits; ++ unsigned char line_bits; ++ unsigned char line_size; ++ unsigned char set_bits; ++ unsigned short sets; ++ unsigned short size; ++ unsigned short aliasing_num; ++ unsigned int aliasing_mask; ++ unsigned int not_aliasing_mask; ++}; +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/checksum.h linux-3.4.110/arch/nds32/include/asm/checksum.h +--- linux-3.4.110.orig/arch/nds32/include/asm/checksum.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/checksum.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,173 @@ ++/* ++ * 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) 1995, 96, 97, 98, 99, 2001 by Ralf Baechle ++ * Copyright (C) 1999 Silicon Graphics, Inc. ++ * Copyright (C) 2001 Thiemo Seufer. ++ * Copyright (C) 2002 Maciej W. Rozycki ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++#ifndef _ASM_CHECKSUM_H ++#define _ASM_CHECKSUM_H ++ ++#include <linux/in6.h> ++ ++#include <asm/uaccess.h> ++ ++/* ++ * computes the checksum of a memory block at buff, length len, ++ * and adds in "sum" (32-bit) ++ * ++ * returns a 32-bit number suitable for feeding into itself ++ * or csum_tcpudp_magic ++ * ++ * this function must be called with even lengths, except ++ * for the last fragment, which may be odd ++ * ++ * it's best to have buff aligned on a 32-bit boundary ++ */ ++unsigned int csum_partial(const void *buff, int len, unsigned int sum); ++ ++/* ++ * this is a new version of the above that records errors it finds in *errp, ++ * but continues and zeros the rest of the buffer. ++ */ ++unsigned int csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst, int len, ++ unsigned int sum, int *errp); ++ ++/* ++ * Copy and checksum to user ++ */ ++#define HAVE_CSUM_COPY_USER ++static inline unsigned int csum_and_copy_to_user (const unsigned char *src, ++ unsigned char __user *dst, ++ int len, int sum, ++ int *err_ptr) ++{ ++ sum = csum_partial(src, len, sum); ++ ++ if (copy_to_user(dst, src, len)) { ++ *err_ptr = -EFAULT; ++ return -1; ++ } ++ ++ return sum; ++} ++ ++/* ++ * the same as csum_partial, but copies from user space (but on MIPS ++ * we have just one address space, so this is identical to the above) ++ */ ++unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char *dst, ++ int len, unsigned int sum); ++ ++/* ++ * Fold a partial checksum without adding pseudo headers ++ */ ++static inline unsigned short int csum_fold(unsigned int sum) ++{ ++ __asm__( ++ "slli\t$p1,%0,16\n\t" ++ "add\t%0,%0,$p1\n\t" ++ "slt\t$p1,%0,$p1\n\t" ++ "srli\t%0,%0,16\n\t" ++ "add\t%0,%0,$p1\n\t" ++ "movi\t$p1,0xffff\n\t" ++ "xor\t%0,%0,$p1" ++ : "=r" (sum) ++ : "0" (sum)); ++ ++ return sum; ++} ++ ++/* ++ * This is a version of ip_compute_csum() optimized for IP headers, ++ * which always checksum on 4 octet boundaries. ++ * ++ * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by ++ * Arnt Gulbrandsen. ++ */ ++static inline unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) ++{ ++ unsigned int *word = (unsigned int *) iph; ++ unsigned int *stop = word + ihl; ++ unsigned int csum; ++ int carry; ++ ++ csum = word[0]; ++ csum += word[1]; ++ carry = (csum < word[1]); ++ csum += carry; ++ ++ csum += word[2]; ++ carry = (csum < word[2]); ++ csum += carry; ++ ++ csum += word[3]; ++ carry = (csum < word[3]); ++ csum += carry; ++ ++ word += 4; ++ do { ++ csum += *word; ++ carry = (csum < *word); ++ csum += carry; ++ word++; ++ } while (word != stop); ++ ++ return csum_fold(csum); ++} ++ ++static inline unsigned int csum_tcpudp_nofold(unsigned long saddr, ++ unsigned long daddr, unsigned short len, unsigned short proto, ++ unsigned int sum) ++{ ++ __asm__( ++ "add\t%0, %0, %2\n\t" ++ "slt\t$p1, %0, %2\n\t" ++ "add\t%0, %0, $p1\n\t" ++ ++ "add\t%0, %0, %3\n\t" ++ "slt\t$p1, %0, %3\n\t" ++ "add\t%0, %0, $p1\n\t" ++ ++ "add\t%0, %0, %4\n\t" ++ "slt\t$p1, %0, %4\n\t" ++ "add\t%0, %0, $p1" ++ : "=r" (sum) ++ : "0" (daddr), "r"(saddr), ++#ifdef __NDS32_EL__ ++ "r" (((unsigned long)htons(len)<<16) + proto*256), ++#else ++ "r" (((unsigned long)(proto)<<16) + len), ++#endif ++ "r" ((__force unsigned long)sum)); ++ ++ return sum; ++} ++ ++/* ++ * computes the checksum of the TCP/UDP pseudo-header ++ * returns a 16-bit checksum, already complemented ++ */ ++static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, ++ unsigned long daddr, ++ unsigned short len, ++ unsigned short proto, ++ unsigned int sum) ++{ ++ return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); ++} ++ ++/* ++ * this routine is used for miscellaneous IP-like checksums, mainly ++ * in icmp.c ++ */ ++static inline unsigned short ip_compute_csum(const void * buff, int len) ++{ ++ return csum_fold(csum_partial(buff, len, 0)); ++} ++ ++#endif /* _ASM_CHECKSUM_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/cmpxchg.h linux-3.4.110/arch/nds32/include/asm/cmpxchg.h +--- linux-3.4.110.orig/arch/nds32/include/asm/cmpxchg.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/cmpxchg.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,88 @@ ++#ifndef __ASM_NDS32_CMPXCHG_H ++#define __ASM_NDS32_CMPXCHG_H ++ ++#include <asm/barrier.h> ++ ++#define xchg(ptr,x) \ ++ ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) ++ ++static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) ++{ ++ extern void __bad_xchg(volatile void *, int); ++ unsigned long ret; ++ unsigned long flags; ++ ++ switch (size) { ++ case 4: ++#if defined(CONFIG_SMP) || !defined(CONFIG_CPU_DCACHE_WRITETHROUGH) ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%2+$r15]\n" ++ "\tori\t%1, %3, #0x0\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (ret), "=&r" (flags) ++ : "r" (ptr), "r" (x) ++ : "memory"); ++#else ++ raw_local_irq_save(flags); ++ ret = *(volatile unsigned long *)ptr; ++ *(volatile unsigned long *)ptr = x; ++ raw_local_irq_restore(flags); ++#endif ++ break; ++ default: ++ __bad_xchg(ptr, size); ++ ret = 0; ++ } ++ return ret; ++} ++ ++ ++#define __HAVE_ARCH_CMPXCHG 1 ++ ++static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old, ++ unsigned long new, int size) ++{ ++ extern void __cmpxchg_called_with_bad_pointer(void); /*nonexistence */ ++ unsigned long retval, tmp; ++ unsigned long flags; ++ switch (size) { ++ case 4: ++#if defined(CONFIG_SMP) || !defined(CONFIG_CPU_DCACHE_WRITETHROUGH) ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%3+$r15]\n" ++ "\tsub\t%2, %0, %5\n" ++ "\tcmovz\t%1, %4, %2\n" ++ "\tcmovn\t%1, %0, %2\n" ++ "\tscw\t%1, [%3+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (retval), "=&r" (flags), "=&r" (tmp) ++ : "r" (ptr), "r" (new), "r" (old)); ++#else ++ raw_local_irq_save(flags); ++ retval = *(volatile unsigned long *)ptr; ++ if (retval == old) ++ *(volatile unsigned long *)ptr = new; ++ raw_local_irq_restore(flags); ++#endif ++ break; ++ default: ++ __cmpxchg_called_with_bad_pointer(); ++ tmp = 0; ++ } ++ return retval; ++} ++ ++#define cmpxchg(ptr,o,n) \ ++ ({ \ ++ __typeof__(*(ptr)) _o_ = (o); \ ++ __typeof__(*(ptr)) _n_ = (n); \ ++ (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ ++ (unsigned long)_n_, sizeof(*(ptr))); \ ++ }) ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/cpu.h linux-3.4.110/arch/nds32/include/asm/cpu.h +--- linux-3.4.110.orig/arch/nds32/include/asm/cpu.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/cpu.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,25 @@ ++/* ++ * linux/arch/nds32/include/asm/cpu.h ++ * ++ * Copyright (C) 2004-2005 ARM Ltd. ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __ASM_NDS32_CPU_H ++#define __ASM_NDS32_CPU_H ++ ++#include <linux/percpu.h> ++ ++struct cpuinfo_nds32 { ++ struct cpu cpu; ++#ifdef CONFIG_SMP ++ unsigned int loops_per_jiffy; ++#endif ++}; ++ ++DECLARE_PER_CPU(struct cpuinfo_nds32, cpu_data); ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/cputime.h linux-3.4.110/arch/nds32/include/asm/cputime.h +--- linux-3.4.110.orig/arch/nds32/include/asm/cputime.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/cputime.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/cputime.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_CPUTIME_H__ ++#define __NDS32_CPUTIME_H__ ++ ++#include <asm-generic/cputime.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/cpuver.h linux-3.4.110/arch/nds32/include/asm/cpuver.h +--- linux-3.4.110.orig/arch/nds32/include/asm/cpuver.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/cpuver.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,34 @@ ++/* ++ * linux/arch/nds32/include/asm/cpuver.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_CPUVER_H__ ++#define __NDS32_CPUVER_H__ ++ ++#include <asm/bitfield.h> ++#include <asm/reg_access.h> ++ ++#define GET_CPU_ID()\ ++ (( GET_CPU_VER() & CPU_VER_mskCPUID) >> CPU_VER_offCPUID) ++ ++#define GET_CPU_REV()\ ++ (( GET_CPU_VER() & CPU_VER_mskREV) >> CPU_VER_offREV) ++ ++#define GET_CPU_CFGID()\ ++ (( GET_CPU_VER() & CPU_VER_mskCFGID) >> CPU_VER_offCFGID) ++ ++#define CPU_IS_N1213_43U1HA0()\ ++ (((GET_CPU_VER() & CPU_VER_mskCPUID) == 0x0c000000) &&\ ++ ((GET_CPU_VER() & CPU_VER_mskREV) == 0x00010000)) ++ ++#define CPU_IS_N1213_43U1HB0()\ ++ (((GET_CPU_VER() & CPU_VER_mskCPUID) == 0x0c000000) &&\ ++ ((GET_CPU_VER() & CPU_VER_mskREV) == 0x00020000)) ++ ++#define CPU_IS_N1033_S()\ ++ (((GET_CPU_VER() & CPU_VER_mskCPUID) == 0x0a000000) &&\ ++ ((GET_CPU_VER() & CPU_VER_mskREV) == 0x000c0000)) ++ ++#endif ++ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/current.h linux-3.4.110/arch/nds32/include/asm/current.h +--- linux-3.4.110.orig/arch/nds32/include/asm/current.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/current.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * linux/arch/nds32/include/asm/current.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_CURRENT_H__ ++#define __NDS32_CURRENT_H__ ++ ++#include <linux/thread_info.h> ++ ++static inline struct task_struct *get_current(void) ++{ ++ return current_thread_info()->task; ++} ++ ++#define current get_current() ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/delay.h linux-3.4.110/arch/nds32/include/asm/delay.h +--- linux-3.4.110.orig/arch/nds32/include/asm/delay.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/delay.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,39 @@ ++/* ++ * linux/arch/nds32/include/asm/delay.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_DELAY_H__ ++#define __NDS32_DELAY_H__ ++ ++#include <asm/param.h> ++ ++static inline void __delay(unsigned long loops) ++{ ++ __asm__ __volatile__ ( ++ "1:\n" ++ "\taddi\t%0, %0, -1\n" ++ "\tbgtz\t%0, 1b\n" ++ : "=r" (loops) : "0" (loops)); ++} ++ ++static inline void __udelay(unsigned long usecs, unsigned long lpj) ++{ ++ usecs *= (unsigned long) (((0x8000000000000000ULL / (500000 / HZ)) + ++ 0x80000000ULL) >> 32); ++ usecs=(unsigned long)(((unsigned long long)usecs*lpj)>>32); ++ __delay(usecs); ++} ++ ++#define udelay(usecs) __udelay((usecs), loops_per_jiffy) ++ ++/* make sure "usecs *= ..." in udelay do not overflow. */ ++#if HZ >= 1000 ++#define MAX_UDELAY_MS 1 ++#elif HZ <= 200 ++#define MAX_UDELAY_MS 5 ++#else ++#define MAX_UDELAY_MS (1000 / HZ) ++#endif ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/device.h linux-3.4.110/arch/nds32/include/asm/device.h +--- linux-3.4.110.orig/arch/nds32/include/asm/device.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/device.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/device.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_DEVICE_H__ ++#define __NDS32_DEVICE_H__ ++ ++#include <asm-generic/device.h> ++ ++#endif /* __NDS32_DEVICE_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/div64.h linux-3.4.110/arch/nds32/include/asm/div64.h +--- linux-3.4.110.orig/arch/nds32/include/asm/div64.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/div64.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/div64.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_DIV64_H__ ++#define __NDS32_DIV64_H__ ++ ++#include <asm-generic/div64.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/dmad.h linux-3.4.110/arch/nds32/include/asm/dmad.h +--- linux-3.4.110.orig/arch/nds32/include/asm/dmad.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/dmad.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,1071 @@ ++/* ++ * Copyright Andes Technology Corporation 2007-2008 ++ * All Rights Reserved. ++ * ++ * Revision History: ++ * ++ * Aug.21.2007 Created. ++ * ++ * DESCRIPTION ++ * ++ * DMA controller driver internal supplement library. ++ * ++ */ ++ ++#ifndef __NDS_DMAD_INC__ ++#define __NDS_DMAD_INC__ ++ ++#include <asm/spec.h> ++ ++/***************************************************************************** ++ * Configuration section ++*****************************************************************************/ ++ ++/* Debug trace enable switch */ ++#define DMAD_ERROR_TRACE 1 /* message for fatal errors */ ++//MOD by river 2010.10.19 ++#define DMAD_DEBUG_TRACE 0 /* message for debug trace */ ++//End MOD by river 2010.10.19 ++ ++//#ifndef addr_t ++typedef u32 addr_t; ++//#endif ++/* for amerald */ ++#define AMERALD_PRODUCT_ID 0x41471000 ++#define AMERALD_MASK 0xFFFFF000 ++ ++/***************************************************************************** ++ * DMAC - AG101 AHB ++*****************************************************************************/ ++/* Device base address */ ++#define DMAC_BASE DMAC_FTDMAC020_0_VA_BASE ++ ++/* DMA controller registers (8-bit width) */ ++#define DMAC_INT (DMAC_BASE + 0x00) ++#define DMAC_INT_TC (DMAC_BASE + 0x04) ++#define DMAC_INT_TC_CLR (DMAC_BASE + 0x08) ++#define DMAC_INT_ERRABT (DMAC_BASE + 0x0c) ++#define DMAC_INT_ERRABT_CLR (DMAC_BASE + 0x10) ++#define DMAC_TC (DMAC_BASE + 0x14) ++#define DMAC_ERRABT (DMAC_BASE + 0x18) ++#define DMAC_CH_EN (DMAC_BASE + 0x1c) ++#define DMAC_CH_BUSY (DMAC_BASE + 0x20) ++#define DMAC_CSR (DMAC_BASE + 0x24) ++#define DMAC_SYNC (DMAC_BASE + 0x28) ++ ++/* DMA channel registers base address */ ++#define DMAC_C0_OFFSET 0x100 ++#define DMAC_C1_OFFSET 0x120 ++#define DMAC_C2_OFFSET 0x140 ++#define DMAC_C3_OFFSET 0x160 ++#define DMAC_C4_OFFSET 0x180 ++#define DMAC_C5_OFFSET 0x1a0 ++#define DMAC_C6_OFFSET 0x1c0 ++#define DMAC_C7_OFFSET 0x1e0 ++ ++#define DMAC_C0_BASE (DMAC_BASE + DMAC_C0_OFFSET) ++#define DMAC_C1_BASE (DMAC_BASE + DMAC_C1_OFFSET) ++#define DMAC_C2_BASE (DMAC_BASE + DMAC_C2_OFFSET) ++#define DMAC_C3_BASE (DMAC_BASE + DMAC_C3_OFFSET) ++#define DMAC_C4_BASE (DMAC_BASE + DMAC_C4_OFFSET) ++#define DMAC_C5_BASE (DMAC_BASE + DMAC_C5_OFFSET) ++#define DMAC_C6_BASE (DMAC_BASE + DMAC_C6_OFFSET) ++#define DMAC_C7_BASE (DMAC_BASE + DMAC_C7_OFFSET) ++ ++#define DMAC_MAX_CHANNELS 8 ++#define DMAC_BASE_CH(n) (DMAC_C0_BASE + \ ++ (DMAC_C1_OFFSET - DMAC_C0_OFFSET) * \ ++ (addr_t)(n)) /* n = 0 ~ 3 */ ++ ++#define DMAC_CSR_OFFSET 0x00 ++#define DMAC_CFG_OFFSET 0x04 ++#define DMAC_SRC_ADDR_OFFSET 0x08 ++#define DMAC_DST_ADDR_OFFSET 0x0c ++#define DMAC_LLP_OFFSET 0x10 ++#define DMAC_SIZE_OFFSET 0x14 ++ ++/* DMA channel 0 registers (32-bit width) */ ++#define DMAC_C0_CSR (DMAC_C0_BASE + DMAC_CSR_OFFSET) ++#define DMAC_C0_CFG (DMAC_C0_BASE + DMAC_CFG_OFFSET) ++#define DMAC_C0_SRC_ADDR (DMAC_C0_BASE + DMAC_SRC_ADDR_OFFSET) ++#define DMAC_C0_DST_ADDR (DMAC_C0_BASE + DMAC_DST_ADDR_OFFSET) ++#define DMAC_C0_LLP (DMAC_C0_BASE + DMAC_LLP_OFFSET) ++#define DMAC_C0_SIZE (DMAC_C0_BASE + DMAC_SIZE_OFFSET) ++ ++/* DMA channel 1 registers (32-bit width) */ ++#define DMAC_C1_CSR (DMAC_C1_BASE + DMAC_CSR_OFFSET) ++#define DMAC_C1_CFG (DMAC_C1_BASE + DMAC_CFG_OFFSET) ++#define DMAC_C1_SRC_ADDR (DMAC_C1_BASE + DMAC_SRC_ADDR_OFFSET) ++#define DMAC_C1_DST_ADDR (DMAC_C1_BASE + DMAC_DST_ADDR_OFFSET) ++#define DMAC_C1_LLP (DMAC_C1_BASE + DMAC_LLP_OFFSET) ++#define DMAC_C1_SIZE (DMAC_C1_BASE + DMAC_SIZE_OFFSET) ++ ++/* DMA channel 2 registers (32-bit width) */ ++#define DMAC_C2_CSR (DMAC_C2_BASE + DMAC_CSR_OFFSET) ++#define DMAC_C2_CFG (DMAC_C2_BASE + DMAC_CFG_OFFSET) ++#define DMAC_C2_SRC_ADDR (DMAC_C2_BASE + DMAC_SRC_ADDR_OFFSET) ++#define DMAC_C2_DST_ADDR (DMAC_C2_BASE + DMAC_DST_ADDR_OFFSET) ++#define DMAC_C2_LLP (DMAC_C2_BASE + DMAC_LLP_OFFSET) ++#define DMAC_C2_SIZE (DMAC_C2_BASE + DMAC_SIZE_OFFSET) ++ ++/* DMA channel 3 registers (32-bit width) */ ++#define DMAC_C3_CSR (DMAC_C3_BASE + DMAC_CSR_OFFSET) ++#define DMAC_C3_CFG (DMAC_C3_BASE + DMAC_CFG_OFFSET) ++#define DMAC_C3_SRC_ADDR (DMAC_C3_BASE + DMAC_SRC_ADDR_OFFSET) ++#define DMAC_C3_DST_ADDR (DMAC_C3_BASE + DMAC_DST_ADDR_OFFSET) ++#define DMAC_C3_LLP (DMAC_C3_BASE + DMAC_LLP_OFFSET) ++#define DMAC_C3_SIZE (DMAC_C3_BASE + DMAC_SIZE_OFFSET) ++ ++/* DMA channel 4 registers (32-bit width) */ ++#define DMAC_C4_CSR (DMAC_C4_BASE + DMAC_CSR_OFFSET) ++#define DMAC_C4_CFG (DMAC_C4_BASE + DMAC_CFG_OFFSET) ++#define DMAC_C4_SRC_ADDR (DMAC_C4_BASE + DMAC_SRC_ADDR_OFFSET) ++#define DMAC_C4_DST_ADDR (DMAC_C4_BASE + DMAC_DST_ADDR_OFFSET) ++#define DMAC_C4_LLP (DMAC_C4_BASE + DMAC_LLP_OFFSET) ++#define DMAC_C4_SIZE (DMAC_C4_BASE + DMAC_SIZE_OFFSET) ++ ++/* DMA channel 5 registers (32-bit width) */ ++#define DMAC_C5_CSR (DMAC_C5_BASE + DMAC_CSR_OFFSET) ++#define DMAC_C5_CFG (DMAC_C5_BASE + DMAC_CFG_OFFSET) ++#define DMAC_C5_SRC_ADDR (DMAC_C5_BASE + DMAC_SRC_ADDR_OFFSET) ++#define DMAC_C5_DST_ADDR (DMAC_C5_BASE + DMAC_DST_ADDR_OFFSET) ++#define DMAC_C5_LLP (DMAC_C5_BASE + DMAC_LLP_OFFSET) ++#define DMAC_C5_SIZE (DMAC_C5_BASE + DMAC_SIZE_OFFSET) ++ ++/* DMA channel 6 registers (32-bit width) */ ++#define DMAC_C6_CSR (DMAC_C6_BASE + DMAC_CSR_OFFSET) ++#define DMAC_C6_CFG (DMAC_C6_BASE + DMAC_CFG_OFFSET) ++#define DMAC_C6_SRC_ADDR (DMAC_C6_BASE + DMAC_SRC_ADDR_OFFSET) ++#define DMAC_C6_DST_ADDR (DMAC_C6_BASE + DMAC_DST_ADDR_OFFSET) ++#define DMAC_C6_LLP (DMAC_C6_BASE + DMAC_LLP_OFFSET) ++#define DMAC_C6_SIZE (DMAC_C6_BASE + DMAC_SIZE_OFFSET) ++ ++/* DMA channel 7 registers (32-bit width) */ ++#define DMAC_C7_CSR (DMAC_C7_BASE + DMAC_CSR_OFFSET) ++#define DMAC_C7_CFG (DMAC_C7_BASE + DMAC_CFG_OFFSET) ++#define DMAC_C7_SRC_ADDR (DMAC_C7_BASE + DMAC_SRC_ADDR_OFFSET) ++#define DMAC_C7_DST_ADDR (DMAC_C7_BASE + DMAC_DST_ADDR_OFFSET) ++#define DMAC_C7_LLP (DMAC_C7_BASE + DMAC_LLP_OFFSET) ++#define DMAC_C7_SIZE (DMAC_C7_BASE + DMAC_SIZE_OFFSET) ++ ++/***************************************************************************** ++ * DMAC defs - AG101 AHB ++*****************************************************************************/ ++ ++/* Interrupt status register (+00) */ ++#define DMAC_INT0_MASK 0x01 ++#define DMAC_INT0_BIT 0 ++#define DMAC_INT1_MASK 0x02 ++#define DMAC_INT1_BIT 1 ++#define DMAC_INT2_MASK 0x04 ++#define DMAC_INT2_BIT 2 ++#define DMAC_INT3_MASK 0x08 ++#define DMAC_INT3_BIT 3 ++ ++/* Interrupt for terminal count status register (+0x04) */ ++#define DMAC_INT_TC0_MASK 0x01 ++#define DMAC_INT_TC0_BIT 0 ++#define DMAC_INT_TC1_MASK 0x02 ++#define DMAC_INT_TC1_BIT 1 ++#define DMAC_INT_TC2_MASK 0x04 ++#define DMAC_INT_TC2_BIT 2 ++#define DMAC_INT_TC3_MASK 0x08 ++#define DMAC_INT_TC3_BIT 3 ++#define DMAC_INT_TC4_MASK 0x01 ++#define DMAC_INT_TC4_BIT 0 ++#define DMAC_INT_TC5_MASK 0x02 ++#define DMAC_INT_TC5_BIT 1 ++#define DMAC_INT_TC6_MASK 0x04 ++#define DMAC_INT_TC6_BIT 2 ++#define DMAC_INT_TC7_MASK 0x08 ++#define DMAC_INT_TC7_BIT 3 ++ ++#define DMAC_INT_TC_MASK 0xff ++#define DMAC_INT_TC_SHIFT 0 ++ ++/* Interrupt for terminal count clear register (+0x08) */ ++#define DMAC_INT_TC0_CLR_MASK 0x01 ++#define DMAC_INT_TC0_CLR_BIT 0 ++#define DMAC_INT_TC1_CLR_MASK 0x02 ++#define DMAC_INT_TC1_CLR_BIT 1 ++#define DMAC_INT_TC2_CLR_MASK 0x04 ++#define DMAC_INT_TC2_CLR_BIT 2 ++#define DMAC_INT_TC3_CLR_MASK 0x08 ++#define DMAC_INT_TC3_CLR_BIT 3 ++ ++#define DMAC_INT_TC_CLR_MASK 0x0f ++#define DMAC_INT_TC_CLR_SHIFT 0 ++ ++/* Interrupt for error/abort status register (+0x0c, 32-bits width) */ ++#define DMAC_INT_ERR0_MASK 0x00000001 ++#define DMAC_INT_ERR0_BIT 0 ++#define DMAC_INT_ERR1_MASK 0x00000002 ++#define DMAC_INT_ERR1_BIT 1 ++#define DMAC_INT_ERR2_MASK 0x00000004 ++#define DMAC_INT_ERR2_BIT 2 ++#define DMAC_INT_ERR3_MASK 0x00000008 ++#define DMAC_INT_ERR3_BIT 3 ++ ++#define DMAC_INT_ERR_MASK 0x0000000f ++#define DMAC_INT_ERR_SHIFT 0 ++ ++#define DMAC_INT_ABT0_MASK 0x00010000 ++#define DMAC_INT_ABT0_BIT 16 ++#define DMAC_INT_ABT1_MASK 0x00020000 ++#define DMAC_INT_ABT1_BIT 17 ++#define DMAC_INT_ABT2_MASK 0x00040000 ++#define DMAC_INT_ABT2_BIT 18 ++#define DMAC_INT_ABT3_MASK 0x00080000 ++#define DMAC_INT_ABT3_BIT 19 ++ ++#define DMAC_INT_ABT_MASK 0x000f0000 ++#define DMAC_INT_ABT_SHIFT 16 ++ ++/* Interrupt for error/abort status clear register (+0x10, 32-bits width) */ ++#define DMAC_INT_ERR0_CLR_MASK 0x00000001 ++#define DMAC_INT_ERR0_CLR_BIT 0 ++#define DMAC_INT_ERR1_CLR_MASK 0x00000002 ++#define DMAC_INT_ERR1_CLR_BIT 1 ++#define DMAC_INT_ERR2_CLR_MASK 0x00000004 ++#define DMAC_INT_ERR2_CLR_BIT 2 ++#define DMAC_INT_ERR3_CLR_MASK 0x00000008 ++#define DMAC_INT_ERR3_CLR_BIT 3 ++ ++#define DMAC_INT_ERR_CLR_MASK 0x0000000f ++#define DMAC_INT_ERR_CLR_SHIFT 0 ++ ++#define DMAC_INT_ABT0_CLR_MASK 0x00010000 ++#define DMAC_INT_ABT0_CLR_BIT 16 ++#define DMAC_INT_ABT1_CLR_MASK 0x00020000 ++#define DMAC_INT_ABT1_CLR_BIT 17 ++#define DMAC_INT_ABT2_CLR_MASK 0x00040000 ++#define DMAC_INT_ABT2_CLR_BIT 18 ++#define DMAC_INT_ABT3_CLR_MASK 0x00080000 ++#define DMAC_INT_ABT3_CLR_BIT 19 ++ ++#define DMAC_INT_ABT_CLR_MASK 0x000f0000 ++#define DMAC_INT_ABT_CLR_SHIFT 16 ++ ++/* Terminal count status register (+0x14) */ ++#define DMAC_TC0_MASK 0x01 ++#define DMAC_TC0_BIT 0 ++#define DMAC_TC1_MASK 0x02 ++#define DMAC_TC1_BIT 1 ++#define DMAC_TC2_MASK 0x04 ++#define DMAC_TC2_BIT 2 ++#define DMAC_TC3_MASK 0x08 ++#define DMAC_TC3_BIT 3 ++ ++/* Error/abort status register (+0x18, 32-bits width) */ ++#define DMAC_ERR0_MASK 0x00000001 ++#define DMAC_ERR0_BIT 0 ++#define DMAC_ERR1_MASK 0x00000002 ++#define DMAC_ERR1_BIT 1 ++#define DMAC_ERR2_MASK 0x00000004 ++#define DMAC_ERR2_BIT 2 ++#define DMAC_ERR3_MASK 0x00000008 ++#define DMAC_ERR3_BIT 3 ++ ++#define DMAC_ABT0_MASK 0x00010000 ++#define DMAC_ABT0_BIT 16 ++#define DMAC_ABT1_MASK 0x00020000 ++#define DMAC_ABT1_BIT 17 ++#define DMAC_ABT2_MASK 0x00040000 ++#define DMAC_ABT2_BIT 18 ++#define DMAC_ABT3_MASK 0x00080000 ++#define DMAC_ABT3_BIT 19 ++ ++/* Channel enable status register (+0x1c) */ ++#define DMAC_CH0_EN_MASK 0x01 ++#define DMAC_CH0_EN_BIT 0 ++#define DMAC_CH1_EN_MASK 0x02 ++#define DMAC_CH1_EN_BIT 1 ++#define DMAC_CH2_EN_MASK 0x04 ++#define DMAC_CH2_EN_BIT 2 ++#define DMAC_CH3_EN_MASK 0x08 ++#define DMAC_CH3_EN_BIT 3 ++ ++/* Channel busy status register (+0x20) */ ++#define DMAC_CH0_BUSY_MASK 0x01 ++#define DMAC_CH0_BUSY_BIT 0 ++#define DMAC_CH1_BUSY_MASK 0x02 ++#define DMAC_CH1_BUSY_BIT 1 ++#define DMAC_CH2_BUSY_MASK 0x04 ++#define DMAC_CH2_BUSY_BIT 2 ++#define DMAC_CH3_BUSY_MASK 0x08 ++#define DMAC_CH3_BUSY_BIT 3 ++ ++/* Main configuration status register (+0x24) */ ++#define DMAC_DMACEN_MASK 0x01 ++#define DMAC_DMACEN_BIT 0 ++#define DMAC_M0ENDIAN_MASK 0x02 ++#define DMAC_M0ENDIAN_BIT 1 ++#define DMAC_M1ENDIAN_MASK 0x04 ++#define DMAC_M1ENDIAN_BIT 2 ++ ++ #define DMAC_ENDIAN_LITTLE 0 ++ #define DMAC_ENDIAN_BIG 1 ++ ++/* Sync register (+0x28) */ ++#define DMAC_SYNC0_MASK 0x01 ++#define DMAC_SYNC0_BIT 0 ++#define DMAC_SYNC1_MASK 0x02 ++#define DMAC_SYNC1_BIT 1 ++#define DMAC_SYNC2_MASK 0x04 ++#define DMAC_SYNC2_BIT 2 ++#define DMAC_SYNC3_MASK 0x08 ++#define DMAC_SYNC3_BIT 3 ++ ++/* DMA channel 0~n Control Registers (CH[n]_BASE + 0x00) */ ++#define DMAC_CSR_CH_EN_MASK 0x00000001 ++#define DMAC_CSR_CH_EN_BIT 0 ++ ++#define DMAC_CSR_DST_SEL_MASK 0x00000002 ++#define DMAC_CSR_DST_SEL_BIT 1 ++#define DMAC_CSR_SRC_SEL_MASK 0x00000004 ++#define DMAC_CSR_SRC_SEL_BIT 2 ++ #define DMAC_CSR_SEL_MASTER0 0x00 ++ #define DMAC_CSR_SEL_MASTER1 0x01 ++ ++#define DMAC_CSR_DSTAD_CTL_MASK 0x00000018 ++#define DMAC_CSR_DSTAD_CTL_SHIFT 3 ++#define DMAC_CSR_SRCAD_CTL_MASK 0x00000060 ++#define DMAC_CSR_SRCAD_CTL_SHIFT 5 ++ #define DMAC_CSR_AD_INC 0x00 ++ #define DMAC_CSR_AD_DEC 0x01 ++ #define DMAC_CSR_AD_FIX 0x02 ++ ++#define DMAC_CSR_MODE_MASK 0x00000080 ++#define DMAC_CSR_MODE_BIT 7 ++ #define DMAC_CSR_MODE_NORMAL 0x00 ++ #define DMAC_CSR_MODE_HSHK 0x01 ++ ++#define DMAC_CSR_DST_WIDTH_MASK 0x00000700 ++#define DMAC_CSR_DST_WIDTH_SHIFT 8 ++#define DMAC_CSR_SRC_WIDTH_MASK 0x00003800 ++#define DMAC_CSR_SRC_WIDTH_SHIFT 11 ++ #define DMAC_CSR_WIDTH_8 0x00 ++ #define DMAC_CSR_WIDTH_16 0x01 ++ #define DMAC_CSR_WIDTH_32 0x02 ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++#define DMAC_CYCLE_TO_BYTES(cycle, width) ((cycle) << (width)) ++#define DMAC_BYTES_TO_CYCLE(bytes, width) ((bytes) >> (width)) ++#else ++#define DMAC_CYCLE_TO_BYTES(cycle, width) 0 ++#define DMAC_BYTES_TO_CYCLE(bytes, width) 0 ++#endif /* CONFIG_PLATFORM_AHBDMA */ ++ ++#define DMAC_CSR_ABT 0x00008000 ++#define DMAC_CSR_ABT_BIT 15 ++ ++#define DMAC_CSR_SRC_SIZE_MASK 0x00070000 ++#define DMAC_CSR_SRC_SIZE_SHIFT 16 ++ #define DMAC_CSR_SIZE_1 0x00 ++ #define DMAC_CSR_SIZE_4 0x01 ++ #define DMAC_CSR_SIZE_8 0x02 ++ #define DMAC_CSR_SIZE_16 0x03 ++ #define DMAC_CSR_SIZE_32 0x04 ++ #define DMAC_CSR_SIZE_64 0x05 ++ #define DMAC_CSR_SIZE_128 0x06 ++ #define DMAC_CSR_SIZE_256 0x07 ++ ++#define DMAC_CSR_PROT1 0x00080000 ++#define DMAC_CSR_PROT1_BIT 19 ++#define DMAC_CSR_PROT2 0x00100000 ++#define DMAC_CSR_PROT2_BIT 20 ++#define DMAC_CSR_PROT3 0x00200000 ++#define DMAC_CSR_PROT3_BIT 21 ++ ++#define DMAC_CSR_CHPRI_MASK 0x00c00000 ++#define DMAC_CSR_CHPRI_SHIFT 22 ++ #define DMAC_CSR_CHPRI_0 0x00 ++ #define DMAC_CSR_CHPRI_1 0x01 ++ #define DMAC_CSR_CHPRI_2 0x02 ++ #define DMAC_CSR_CHPRI_3 0x03 ++ ++#define DMAC_CSR_FF_TH_MASK 0x07000000 ++#define DMAC_CSR_FF_TH_SHIFT 24 ++ #define DMAC_CSR_FF_TH_1 0x00 ++ #define DMAC_CSR_FF_TH_2 0x01 ++ #define DMAC_CSR_FF_TH_4 0x02 ++ #define DMAC_CSR_FF_TH_8 0x03 ++ #define DMAC_CSR_FF_TH_16 0x04 ++ ++#define DMAC_CSR_TC_MSK_MSK 0x80000000 ++#define DMAC_CSR_TC_MSK_BIT 31 ++ ++/* DMA channel 0~n Configuration Registers (CH[n]_BASE + 0x04) */ ++#define DMAC_CFG_INT_TC_MSK 0x00000001 ++#define DMAC_CFG_INT_TC_MSK_BIT 0 ++#define DMAC_CFG_INT_ERR_MSK 0x00000002 ++#define DMAC_CFG_INT_ERR_MSK_BIT 1 ++#define DMAC_CFG_INT_ABT_MSK 0x00000004 ++#define DMAC_CFG_INT_ABT_MSK_BIT 2 ++ ++#define DMAC_CFG_INT_SRC_RS_MASK 0x00000078 ++#define DMAC_CFG_INT_SRC_RS_SHIFT 3 ++#define DMAC_CFG_INT_SRC_HE_MASK 0x00000080 ++#define DMAC_CFG_INT_SRC_HE_BIT 7 ++ ++#define DMAC_CFG_BUSY_MASK 0x00000100 ++#define DMAC_CFG_BUSY_BIT 8 ++ ++#define DMAC_CFG_INT_DST_RS_MASK 0x00001e00 ++#define DMAC_CFG_INT_DST_RS_SHIFT 9 ++#define DMAC_CFG_INT_DST_HE_MASK 0x00002000 ++#define DMAC_CFG_INT_DST_HE_BIT 13 ++ ++#ifdef CONFIG_PLAT_AG102 ++ #define DMAC_REQN_IDERX 0 ++ #define DMAC_REQN_IDETX 1 ++ #define DMAC_REQN_I2SAC97RX 2 ++ #define DMAC_REQN_I2SAC97TX 3 ++ #define DMAC_REQN_UART2RX 4 ++ #define DMAC_REQN_UART2TX 5 ++ #define DMAC_REQN_UART1RX 6 ++ #define DMAC_REQN_UART1TX 7 ++ #define DMAC_REQN_SDC 8 ++ #define DMAC_REQN_CFC 9 ++ #define DMAC_REQN_LPCREQ0 10 ++ #define DMAC_REQN_LPCREQ1 11 ++ #define DMAC_REQN_LPCREQ2 12 ++ #define DMAC_REQN_LPCREQ3 13 ++ #define DMAC_REQN_NONE 14 ++ #define DMAC_REQN_LPCREQ5 15 ++ #define DMAC_REQN_MAX 15 ++#else ++ #define DMAC_REQN_NONE PMU_REQN_NONE ++ #define DMAC_REQN_CFC PMU_REQN_CFC ++ #define DMAC_REQN_SSP PMU_REQN_SSP ++ #define DMAC_REQN_UART1TX PMU_REQN_UART1TX ++ #define DMAC_REQN_UART1RX PMU_REQN_UART1RX ++ #define DMAC_REQN_UART2TX PMU_REQN_UART2TX ++ #define DMAC_REQN_UART2RX PMU_REQN_UART2RX ++ #define DMAC_REQN_SDC PMU_REQN_SDC ++ #define DMAC_REQN_I2SAC97TX PMU_REQN_I2SAC97TX ++ #define DMAC_REQN_I2SAC97RX PMU_REQN_I2SAC97RX ++/* for amerald ac97 ssp2 */ ++ #define DMAC_REQN_I2SAC97TX_AMERALD PMU_REQN_I2SAC97TX_AMERALD ++ #define DMAC_REQN_I2SAC97RX_AMERALD PMU_REQN_I2SAC97RX_AMERALD ++ #define DMAC_REQN_USB PMU_REQN_USB ++ #define DMAC_REQN_EXT0 PMU_REQN_EXT0 ++ #define DMAC_REQN_EXT1 PMU_REQN_EXT1 ++ #define DMAC_REQN_MAX PMU_REQN_MAX ++#endif ++#define DMAC_CFG_INT_LLPCNT_MASK 0x000f0000 ++#define DMAC_CFG_INT_LLPCNT_SHIFT 16 ++ ++/* DMA channel 0~n Linked List Descriptor Registers (CH[n]_BASE + 0x10) */ ++#define DMAC_LLP_ADDR_MASK 0xfffffffc ++#define DMAC_LLP_ADDR_SHIFT 2 ++#define DMAC_LLP_MASTER_MASK 0x00000001 ++#define DMAC_LLP_MASTER_BIT 0 ++ #define DMAC_LLP_MASTER_0 0 ++ #define DMAC_LLP_MASTER_1 1 ++ ++/* DMA channel 0~3 Transfer Size Registers (CH[n]_BASE + 0x14) */ ++#define DMAC_TOT_SIZE_MASK 0x003fffff ++#define DMAC_TOT_SIZE_SHIFT 0 ++ ++ ++/***************************************************************************** ++ * APBBR - AG101 AHB to APB Bridge ++*****************************************************************************/ ++/* Device base address */ ++#ifdef CONFIG_PLAT_AG102 ++#define APBBR_BASE APBBR_VA_BASE ++#else ++#define APBBR_BASE APBBRG_FTAPBBRG020S_0_VA_BASE ++#endif ++ ++/* DMA channel A registers (32-bit width) */ ++#define APBBR_DMAA_BASE (APBBR_BASE + 0x80) ++#define APBBR_DMAB_BASE (APBBR_BASE + 0x90) ++#define APBBR_DMAC_BASE (APBBR_BASE + 0xa0) ++#define APBBR_DMAD_BASE (APBBR_BASE + 0xb0) ++ ++#define APBBR_DMA_MAX_CHANNELS APBBRG_FTAPBBRG020S_IRQ_COUNT ++/* n = 0 ~ APBBRG_FTAPBBRG020S_IRQ_COUNT */ ++#define APBBR_DMA_BASE_CH(n) (APBBR_DMAA_BASE + \ ++ (APBBR_DMAB_BASE - APBBR_DMAA_BASE) * \ ++ (addr_t)(n)) ++ ++#define APBBR_DMA_SAD_OFFSET 0x00 ++#define APBBR_DMA_DAD_OFFSET 0x04 ++#define APBBR_DMA_CYC_OFFSET 0x08 ++#define APBBR_DMA_CMD_OFFSET 0x0c ++ ++ ++/***************************************************************************** ++ * APBBR defs - AG101 AHB to APB Bridge ++*****************************************************************************/ ++ ++/* APBBR slave#n (n = 1~6, 8, 11, 16~23) base/size register */ ++#define APBBR_SLAVE_SIZE_MASK 0x000f0000 /* Size of address space */ ++#define APBBR_SLAVE_SIZE_SHIFT 16 ++ #define APBBR_SIZE_1M 0 ++ #define APBBR_SIZE_2M 1 ++ #define APBBR_SIZE_4M 2 ++ #define APBBR_SIZE_8M 3 ++ #define APBBR_SIZE_16M 4 ++ #define APBBR_SIZE_32M 5 ++ #define APBBR_SIZE_64M 6 ++ #define APBBR_SIZE_128M 7 ++ #define APBBR_SIZE_256M 8 ++ ++#define APBBR_SLAVE_BASE_MASK 0x3ff00000 ++#define APBBR_SLAVE_BASE_SHIFT 20 ++ ++/* APBBR DMA channel transfer cycles register ++ * DMA cycles (data size), 1 or 4 bus data transfer cycles per DMA cycle ++ * => transfer size = cycles * data_width * burst(1 or 4) ++ * so, max = 16M*4*4 = 256M ++ */ ++#define APBBR_DMA_CYC_MASK 0x00ffffff ++#define APBBR_DMA_CYC_SHIFT 0 ++ ++/* APBBR DMA channel command register */ ++#define APBBR_DMA_CHEN_MASK 0x00000001 ++#define APBBR_DMA_CHEN_BIT 0 ++ ++#define APBBR_DMA_FINTST_MASK 0x00000002 ++#define APBBR_DMA_FINTST_BIT 1 ++#define APBBR_DMA_FINTEN_MASK 0x00000004 ++#define APBBR_DMA_FINTEN_BIT 2 ++ ++#define APBBR_DMA_BURST_MASK 0x00000008 ++#define APBBR_DMA_BURST_BIT 3 ++ ++#define APBBR_DMA_ERRINTST_MASK 0x00000010 ++#define APBBR_DMA_ERRINTST_BIT 4 ++#define APBBR_DMA_ERRINTEN_MASK 0x00000020 ++#define APBBR_DMA_ERRINTEN_BIT 5 ++ ++#define APBBR_DMA_SRCADDRSEL_MASK 0x00000040 ++#define APBBR_DMA_SRCADDRSEL_BIT 6 ++#define APBBR_DMA_DSTADDRSEL_MASK 0x00000080 ++#define APBBR_DMA_DSTADDRSEL_BIT 7 ++ #define APBBR_ADDRSEL_APB 0 ++ #define APBBR_ADDRSEL_AHB 1 ++ ++#define APBBR_DMA_SRCADDRINC_MASK 0x00000700 ++#define APBBR_DMA_SRCADDRINC_SHIFT 8 ++#define APBBR_DMA_DSTADDRINC_MASK 0x00007000 ++#define APBBR_DMA_DSTADDRINC_SHIFT 12 ++ #define APBBR_ADDRINC_FIXED 0 /* no increment */ ++ #define APBBR_ADDRINC_I1X 1 /* +1, +4 (burst) */ ++ #define APBBR_ADDRINC_I2X 2 /* +2, +8 (burst) */ ++ #define APBBR_ADDRINC_I4X 3 /* +4, +16 (burst) */ ++ #define APBBR_ADDRINC_D1 5 /* -1 */ ++ #define APBBR_ADDRINC_D2 6 /* -2 */ ++ #define APBBR_ADDRINC_D4 7 /* -4 */ ++ ++#define APBBR_DMA_DREQSEL_MASK 0x000f0000 ++#define APBBR_DMA_DREQSEL_SHIFT 16 ++#define APBBR_DMA_SREQSEL_MASK 0x0f000000 ++#define APBBR_DMA_SREQSEL_SHIFT 24 ++ ++#ifdef CONFIG_PLAT_AG102 ++ #define APBBR_REQN_NONE 0 ++ #define APBBR_REQN_CFC 1 ++ #define APBBR_REQN_SSP 2 ++ #define APBBR_REQN_SDC 8 ++ #define APBBR_REQN_I2SAC97TX 6 ++ #define APBBR_REQN_SSP2 8 ++ #define APBBR_REQN_STUART 9 ++ #define APBBR_REQN_BTUART 10 ++ #define APBBR_REQN_IRDA 11 ++ #define APBBR_REQN_SMMC 12 ++// #define APBBR_REQN_USB 0 ++ #define APBBR_REQN_I2SAC97RX 13 ++ #define APBBR_REQN_FUSB220 14 ++ #define APBBR_REQN_MMSC 15 ++ #define APBBR_REQN_MAX 15 ++#else ++ #define APBBR_REQN_NONE 0 ++ #define APBBR_REQN_CFC 1 ++ #define APBBR_REQN_SSP 2 ++ #define APBBR_REQN_SDC 5 ++/* for amerald sd */ ++ #define APBBR_REQN_SDC_AMERALD 7 ++/* for amerald ac97 ssp2 */ ++ #define APBBR_REQN_I2SAC97TX_AMERALD 8 ++ #define APBBR_REQN_I2SAC97RX_AMERALD 9 ++ ++ #define APBBR_REQN_I2SAC97TX 6 ++ #define APBBR_REQN_SSP2 8 ++ #define APBBR_REQN_STUART 9 /* UART1 ? */ ++ #define APBBR_REQN_BTUART 10 /* UART2 ? */ ++ #define APBBR_REQN_IRDA 11 ++ #define APBBR_REQN_SMMC 12 ++ //#define APBBR_REQN_USB 13 ++ #define APBBR_REQN_I2SAC97RX 13 ++ #define APBBR_REQN_FUSB220 14 ++ #define APBBR_REQN_MMSC 15 ++ #define APBBR_REQN_MAX 15 ++#endif ++ ++#define APBBR_DMA_DATAWIDTH_MASK 0x00300000 /* Data width of transfer */ ++#define APBBR_DMA_DATAWIDTH_SHIFT 20 ++ #define APBBR_DATAWIDTH_4 0 /* word */ ++ #define APBBR_DATAWIDTH_2 1 /* half-word */ ++ #define APBBR_DATAWIDTH_1 2 /* byte */ ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++#define APBBR_DMA_CYCLE_TO_BYTES(cycle, width) ((cycle) << (2-(width))) ++#define APBBR_DMA_BYTES_TO_CYCLE(bytes, width) ((bytes) >> (2-(width))) ++#else ++#define APBBR_DMA_CYCLE_TO_BYTES(cycle, width) 0 ++#define APBBR_DMA_BYTES_TO_CYCLE(bytes, width) 0 ++#endif /* CONFIG_PLATFORM_APBDMA */ ++ ++ ++#ifdef CONFIG_PLAT_AG102 ++ ++/***************************************************************************** ++ * PCU - AG102 Core APB ++*****************************************************************************/ ++/* Device base address */ ++#define PCU_BASE PCU_VA_BASE ++/* PMU registers (32-bit width) */ ++/* Add by Dennis on 2011.03.09 */ ++#define PCU_DMA_SEL (PCU_BASE+ 0x38) ++ ++#else /* CONFIG_PLAT_AG102 */ ++ ++/***************************************************************************** ++ * PMU - AG101 Core APB ++*****************************************************************************/ ++/* Device base address */ ++#define PMU_BASE PMU_FTPMU010_0_VA_BASE ++ ++/* PMU registers (32-bit width) */ ++#define PMU_AHBDMA_REQACK (PMU_BASE + 0x90) ++ ++#define PMU_CFC_REQACK_CFG (PMU_BASE + 0xa0) ++#define PMU_SSP1_REQACK_CFG (PMU_BASE + 0xa4) ++#define PMU_UART1TX_REQACK_CFG (PMU_BASE + 0xa8) ++#define PMU_UART1RX_REQACK_CFG (PMU_BASE + 0xac) ++#define PMU_UART2TX_REQACK_CFG (PMU_BASE + 0xb0) ++#define PMU_UART2RX_REQACK_CFG (PMU_BASE + 0xb4) ++#define PMU_SDC_REQACK_CFG (PMU_BASE + 0xb8) ++#define PMU_I2SAC97TX_REQACK_CFG (PMU_BASE + 0xbc) ++#define PMU_I2SAC97RX_REQACK_CFG (PMU_BASE + 0xc4) ++#define PMU_UART3TX_REQACK_CFG (PMU_BASE + 0xc0) ++#define PMU_UART3RX_REQACK_CFG (PMU_BASE + 0xcc) ++#define PMU_USB_REQACK_CFG (PMU_BASE + 0xc8) ++#define PMU_IRDA_REQACK_CFG (PMU_BASE + 0xd0) ++#define PMU_EXT0_REQACK_CFG (PMU_BASE + 0xd4) ++#define PMU_EXT1_REQACK_CFG (PMU_BASE + 0xd8) ++ ++ ++/***************************************************************************** ++ * PMU - AG101 Core APB ++*****************************************************************************/ ++ ++/* Driving capability and slew rate control register 2 (+0x48) */ ++#define PMU_STUART_DCSR_MASK 0x0000000f ++#define PMU_STUART_DCSR_SHIFT 0 ++#define PMU_BTUART_DCSR_MASK 0x00000f00 ++#define PMU_BTUART_DCSR_SHIFT 8 ++/*#define PMU_FFUART_DCSR_MASK 0x0000f000*/ ++/*#define PMU_FFUART_DCSR_SHIFT 12 */ ++#define PMU_PMU_DCSR_MASK 0x000f0000 ++#define PMU_PMU_DCSR_SHIFT 16 ++#define PMU_I2SAC97_DCSR_MASK 0x00f00000 ++#define PMU_I2SAC97_DCSR_SHIFT 20 ++#define PMU_SSP_DCSR_MASK 0x0f000000 ++#define PMU_SSP_DCSR_SHIFT 24 ++#define PMU_SD_DCSR_MASK 0xf0000000 ++#define PMU_SD_DCSR_SHIFT 28 ++ ++/* AHB DMA REQ/ACK connection configuration status register (+0x90) */ ++#define PMU_CH0_REQACK_MASK 0x0000000f ++#define PMU_CH0_REQACK_SHIFT 0 ++#define PMU_CH1_REQACK_MASK 0x000000f0 ++#define PMU_CH1_REQACK_SHIFT 4 ++#define PMU_CH2_REQACK_MASK 0x00000f00 ++#define PMU_CH2_REQACK_SHIFT 8 ++#define PMU_CH3_REQACK_MASK 0x0000f000 ++#define PMU_CH3_REQACK_SHIFT 12 ++#define PMU_CH4_REQACK_MASK 0x000f0000 ++#define PMU_CH4_REQACK_SHIFT 16 ++#define PMU_CH5_REQACK_MASK 0x00f00000 ++#define PMU_CH5_REQACK_SHIFT 20 ++#define PMU_CH6_REQACK_MASK 0x0f000000 ++#define PMU_CH6_REQACK_SHIFT 24 ++#define PMU_CH7_REQACK_MASK 0xf0000000 ++#define PMU_CH7_REQACK_SHIFT 28 ++ ++ #define PMU_REQN_NONE 0 ++ #define PMU_REQN_CFC 1 ++ #define PMU_REQN_SSP 2 ++ #define PMU_REQN_UART1TX 3 ++ #define PMU_REQN_UART1RX 4 ++ #define PMU_REQN_UART2TX 5 ++ #define PMU_REQN_UART2RX 6 ++ #define PMU_REQN_SDC 7 ++ #define PMU_REQN_I2SAC97TX 8 ++ #define PMU_REQN_I2SAC97RX 10 ++/* for amerald ac97 ssp2 */ ++ #define PMU_REQN_I2SAC97TX_AMERALD 8 ++ #define PMU_REQN_I2SAC97RX_AMERALD 9 ++ #define PMU_REQN_USB 11 ++ #define PMU_REQN_EXT0 14 ++ #define PMU_REQN_EXT1 15 ++ #define PMU_REQN_MAX 15 ++ ++/* CFC ..., etc, REQ/ACK connection configuration registers (0xa0 ~ 0xd8) */ ++#define PMU_CHANNEL_MASK 0x00000007 ++#define PMU_CHANNEL_SHIFT 0 ++#define PMU_DMACUSED_MASK 0x00000008 ++#define PMU_DMACUSED_BIT 3 ++ ++#endif /* CONFIG_PLAT_AG102 */ ++ ++ ++/***************************************************************************** ++ * DMAD globals section ++ */ ++ ++enum DMAD_DMAC_CORE { ++ DMAD_DMAC_AHB_CORE, ++ DMAD_DMAC_APB_CORE ++}; ++ ++enum DMAD_CHREG_FLAGS { ++ DMAD_FLAGS_NON_BLOCK = 0x00000000, ++ DMAD_FLAGS_SLEEP_BLOCK = 0x00000001, ++ DMAD_FLAGS_SPIN_BLOCK = 0x00000002, ++ DMAD_FLAGS_RING_MODE = 0x00000008, /* ring submission mode */ ++ DMAD_FLAGS_BIDIRECTION = 0x00000010, /* indicates both tx and rx */ ++}; ++ ++enum DMAD_CHDIR ++{ ++ DMAD_DIR_A0_TO_A1 = 0, ++ DMAD_DIR_A1_TO_A0 = 1, ++}; ++ ++/* AHB Channel Request ++ * ++ * Notes for developers: ++ * These should be channel-only properties. Controller-specific properties ++ * should be separated as other driver structure or driver buildin-hardcode. ++ * If controller properties are embeded in this union, request for a channel ++ * may unexpectedly override the controller setting of the request of other ++ * channels. ++ */ ++typedef struct dmad_ahb_chreq ++{ ++ /* channel property */ ++ u32 sync; /* (in) different clock domain */ ++ u32 priority; /* (in) DMAC_CSR_CHPRI_xxx */ ++ u32 hw_handshake; /* (in) hardware handshaking on/off */ ++ u32 burst_size; /* (in) DMAC_CSR_SIZE_xxx */ ++ ++ /* source property */ ++ union { ++ u32 src_width; /* (in) DMAC_CSR_WIDTH_xxx */ ++ u32 addr0_width; /* (in) bi-direction mode alias */ ++ u32 ring_width; /* (in) ring-mode alias */ ++ }; ++ union { ++ u32 src_ctrl; /* (in) DMAC_CSR_AD_xxx */ ++ u32 addr0_ctrl; /* (in) bi-direction mode alias */ ++ u32 ring_ctrl; /* (in) ring-mode alias */ ++ }; ++ union { ++ u32 src_reqn; /* (in) DMAC_REQN_xxx */ ++ u32 addr0_reqn; /* (in) bi-direction mode alias */ ++ u32 ring_reqn; /* (in) ring-mode alias */ ++ }; ++ ++ /* destination property */ ++ union { ++ u32 dst_width; /* (in) DMAC_CSR_WIDTH_xxx */ ++ u32 addr1_width; /* (in) bi-direction mode alias */ ++ u32 dev_width; /* (in) ring-mode alias */ ++ }; ++ union { ++ u32 dst_ctrl; /* (in) DMAC_CSR_AD_xxx */ ++ u32 addr1_ctrl; /* (in) bi-direction mode alias */ ++ u32 dev_ctrl; /* (in) ring-mode alias */ ++ }; ++ union { ++ u32 dst_reqn; /* (in) DMAC_REQN_xxx */ ++ u32 addr1_reqn; /* (in) bi-direction mode alias */ ++ u32 dev_reqn; /* (in) ring-mode alias */ ++ }; ++ ++ /* (in) transfer direction, valid only if following flags were set ... ++ * DMAD_FLAGS_BIDIRECTION or ++ * DMAD_FLAGS_RING_MODE ++ * value: ++ * 0 (addr0 -> addr1, or ring-buff to device) ++ * 1 (addr0 <- addr1, or device to ring-buff) ++ */ ++ u32 tx_dir; ++ ++} dmad_ahb_chreq; ++ ++/* APB Channel Request ++ * ++ * Notes for developers: ++ * These should be channel-only properties. Controller-specific properties ++ * should be separated as other driver structure or driver buildin-hardcode. ++ * If controller properties are embeded in this union, request for a channel ++ * may unexpectedly override the controller setting of the request of other ++ * channels. ++ */ ++typedef struct dmad_apb_chreq ++{ ++ /* controller property (removed! should not exist in this struct) */ ++ ++ /* channel property */ ++ u32 burst_mode; /* (in) Burst mode (0/1) */ ++ u32 data_width; /* (in) APBBR_DATAWIDTH_xxx */ ++ ++ /* source property */ ++ union { ++ u32 src_ctrl; /* (in) APBBR_ADDRINC_xxx */ ++ u32 addr0_ctrl; /* (in) bi-direction mode alias */ ++ u32 ring_ctrl; /* (in) ring-mode alias */ ++ }; ++ union { ++ u32 src_reqn; /* (in) APBBR_REQN_xxx */ ++ u32 addr0_reqn; /* (in) bi-direction mode alias */ ++ u32 ring_reqn; /* (in) ring-mode alias */ ++ }; ++ ++ /* destination property */ ++ union { ++ u32 dst_ctrl; /* (in) APBBR_ADDRINC_xxx */ ++ u32 addr1_ctrl; /* (in) bi-direction mode alias */ ++ u32 dev_ctrl; /* (in) ring-mode alias */ ++ }; ++ union { ++ u32 dst_reqn; /* (in) APBBR_REQN_xxx */ ++ u32 addr1_reqn; /* (in) bi-direction mode alias */ ++ u32 dev_reqn; /* (in) ring-mode alias */ ++ }; ++ ++ /* (in) transfer direction, valid only if following flags were set ... ++ * DMAD_FLAGS_BIDIRECTION or ++ * DMAD_FLAGS_RING_MODE ++ * value: ++ * 0 (addr0 -> addr1, or ring-buff to device) ++ * 1 (addr0 <- addr1, or device to ring-buff) ++ */ ++ u32 tx_dir; ++ ++} dmad_apb_chreq; ++ ++/* Channel Request Descriptor */ ++typedef struct dmad_chreq ++{ ++ /* common fields */ ++ u32 controller; /* (in) enum DMAD_DMAC_CORE */ ++ u32 flags; /* (in) enum DMAD_CHREQ_FLAGS */ ++ ++ /********************************************************************** ++ * ring mode specific fields (valid only for DMAD_FLAGS_RING_MODE) ++ * note: ++ * - size fields are in unit of data width ++ * * for AHB, ring size is limited to 4K * data_width of data if ++ * hw-LLP is not used ++ * * for AHB, ring size is limited to 4K * data_width * LLP-count ++ * hw-if LLP is used ++ * * for APB, ring size is limited to 16M * data_width of data ++ * - currently sw ring mode dma supports only fixed or incremental ++ * src/dst addressing ++ * - ring_size shoule >= periods * period_size ++ */ ++ dma_addr_t ring_base; /* (in) ring buffer base (pa) */ ++ dma_addr_t ring_size; /* (in) unit of data width */ ++ addr_t dev_addr; /* (in) device data port address */ ++ dma_addr_t periods; /* (in) number of ints per ring */ ++ dma_addr_t period_size; /* (in) size per int, data-width */ ++ ++ ++ /* channel-wise completion callback - called when hw-ptr catches sw-ptr ++ * (i.e., channel stops) ++ * ++ * completion_cb: (in) client supplied callback function, executed in ++ * interrupt context. ++ * completion_data: (in) client private data to be passed to data ++ * argument of completion_cb(). ++ */ ++ void (*completion_cb)(int channel, u16 status, void *data); ++ void *completion_data; ++ /*********************************************************************/ ++ ++ /* channel allocation output */ ++ u32 channel; /* (out) allocated channel */ ++ void *drq; /* (out) internal use (DMAD_DRQ *)*/ ++ ++ /* channel-alloc parameters (channel-wise properties) */ ++ union { ++#ifdef CONFIG_PLATFORM_AHBDMA ++ dmad_ahb_chreq ahb_req; /* (in) for AHB DMA parameters */ ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ dmad_apb_chreq apb_req; /* (in) APB Bridge DMA params */ ++#endif ++ }; ++ ++} dmad_chreq; ++ ++/* drb states are mutual exclusive */ ++enum DMAD_DRB_STATE ++{ ++ DMAD_DRB_STATE_FREE = 0, ++ DMAD_DRB_STATE_READY = 0x00000001, ++ DMAD_DRB_STATE_SUBMITTED = 0x00000002, ++ DMAD_DRB_STATE_EXECUTED = 0x00000004, ++ DMAD_DRB_STATE_COMPLETED = 0x00000008, ++ //DMAD_DRB_STATE_ERROR = 0x00000010, ++ DMAD_DRB_STATE_ABORT = 0x00000020, ++}; ++ ++/* DMA request block ++ * todo: replaced link with kernel struct list_head ?? ++ */ ++typedef struct dmad_drb ++{ ++ u32 prev; /* (internal) previous node */ ++ u32 next; /* (internal) next node */ ++ u32 node; /* (internal) this node */ ++ ++ u32 state; /* (out) DRB's current state */ ++ ++ union { ++ dma_addr_t src_addr; /* (in) source pa */ ++ dma_addr_t addr0; /* (in) bi-direction mode alias */ ++ }; ++ ++ union { ++ dma_addr_t dst_addr; /* (in) destination pa */ ++ dma_addr_t addr1; /* (in) bi-direction mode alias */ ++ }; ++ ++ /* (in) AHB DMA (22 bits): 0 ~ 4M-1, unit is "data width" ++ * APB DMA (24 bits): 0 ~ 16M-1, unit is "data width * burst size" ++ * => for safe without mistakes, use dmad_make_req_cycles() to ++ * compose this value if the addressing mode is incremental ++ * mode (not working yet for decremental mode). ++ */ ++ dma_addr_t req_cycle; ++ ++ /* (in) if non-null, this sync object will be signaled upon dma ++ * completion (for blocked-waiting dma completion) ++ */ ++ struct completion *sync; ++ ++} dmad_drb; ++ ++ ++/****************************************************************************** ++ * Debug Trace Mechanism ++ */ ++#if (DMAD_ERROR_TRACE) ++#define dmad_err(format, arg...) printk(KERN_ERR format , ## arg) ++#else ++#define dmad_err(format, arg...) (void)(0) ++#endif ++ ++#if (DMAD_DEBUG_TRACE) ++#define dmad_dbg(format, arg...) printk(KERN_INFO format , ## arg) ++#else ++#define dmad_dbg(format, arg...) (void)(0) ++#endif ++ ++#if (defined(CONFIG_PLATFORM_AHBDMA) || defined(CONFIG_PLATFORM_APBDMA)) ++ ++/****************************************************************************** ++ * DMAD Driver Interface ++******************************************************************************/ ++ ++extern int dmad_channel_alloc(dmad_chreq *ch_req); ++extern int dmad_channel_free(dmad_chreq *ch_req); ++extern int dmad_channel_enable(const dmad_chreq *ch_req, u8 enable); ++extern u32 dmad_max_size_per_drb(dmad_chreq *ch_req); ++extern u32 dmad_bytes_to_cycles(dmad_chreq *ch_req, u32 byte_size); ++ ++extern int dmad_kickoff_requests(dmad_chreq *ch_req); ++extern int dmad_drain_requests(dmad_chreq *ch_req, u8 shutdown); ++ ++/* for performance reason, these two functions are platform-specific */ ++#ifdef CONFIG_PLATFORM_AHBDMA ++extern int dmad_probe_irq_source_ahb(void); ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++extern int dmad_probe_irq_source_apb(void); ++#endif ++ ++/* note: hw_ptr here is phyical address of dma source or destination */ ++extern dma_addr_t dmad_probe_hw_ptr_src(dmad_chreq *ch_req); ++extern dma_addr_t dmad_probe_hw_ptr_dst(dmad_chreq *ch_req); ++ ++/***************************************************************************** ++ * routines only valid in discrete (non-ring) mode ++ */ ++extern int dmad_config_channel_dir(dmad_chreq *ch_req, u8 dir); ++extern int dmad_alloc_drb(dmad_chreq *ch_req, dmad_drb **drb); ++extern int dmad_free_drb(dmad_chreq *ch_req, dmad_drb *drb); ++extern int dmad_submit_request(dmad_chreq *ch_req, ++ dmad_drb *drb, u8 keep_fired); ++extern int dmad_withdraw_request(dmad_chreq *ch_req, dmad_drb *drb); ++/****************************************************************************/ ++ ++/***************************************************************************** ++ * routines only valid in ring mode ++ * note: sw_ptr and hw_ptr are values offset from the ring buffer base ++ * unit of sw_ptr is data-width ++ * unit of hw_ptr returned is byte ++ */ ++extern int dmad_update_ring(dmad_chreq *ch_req); ++extern int dmad_update_ring_sw_ptr(dmad_chreq *ch_req, ++ dma_addr_t sw_ptr, u8 keep_fired); ++extern dma_addr_t dmad_probe_ring_hw_ptr(dmad_chreq *ch_req); ++/****************************************************************************/ ++ ++#else /* CONFIG_PLATFORM_AHBDMA || CONFIG_PLATFORM_APBDMA */ ++ ++static inline int dmad_channel_alloc(dmad_chreq *ch_req) { return -EFAULT; } ++static inline int dmad_channel_free(dmad_chreq *ch_req) { return -EFAULT; } ++static inline int dmad_channel_enable(const dmad_chreq *ch_req, u8 enable) ++ { return -EFAULT; } ++static inline u32 dmad_max_size_per_drb(dmad_chreq *ch_req) { return 0; } ++static inline u32 dmad_bytes_to_cycles(dmad_chreq *ch_req, u32 byte_size) ++ { return 0; } ++static inline int dmad_kickoff_requests(dmad_chreq *ch_req) { return -EFAULT; } ++static inline int dmad_drain_requests(dmad_chreq *ch_req, u8 shutdown) ++ { return -EFAULT; } ++static inline int dmad_probe_irq_source_ahb(void) { return -EFAULT; } ++static inline int dmad_probe_irq_source_apb(void) { return -EFAULT; } ++static inline dma_addr_t dmad_probe_hw_ptr_src(dmad_chreq *ch_req) ++ { return (dma_addr_t)NULL; } ++static inline dma_addr_t dmad_probe_hw_ptr_dst(dmad_chreq *ch_req) ++ { return (dma_addr_t)NULL; } ++static inline int dmad_config_channel_dir(dmad_chreq *ch_req, u8 dir) ++ { return -EFAULT; } ++static inline int dmad_alloc_drb(dmad_chreq *ch_req, dmad_drb **drb) ++ { return -EFAULT; } ++static inline int dmad_free_drb(dmad_chreq *ch_req, dmad_drb *drb) ++ { return -EFAULT; } ++static inline int dmad_submit_request(dmad_chreq *ch_req, ++ dmad_drb *drb, u8 keep_fired) { return -EFAULT; } ++static inline int dmad_withdraw_request(dmad_chreq *ch_req, dmad_drb *drb) ++ { return -EFAULT; } ++static inline int dmad_update_ring(dmad_chreq *ch_req) ++ { return -EFAULT; } ++static inline int dmad_update_ring_sw_ptr(dmad_chreq *ch_req, ++ dma_addr_t sw_ptr, u8 keep_fired) { return -EFAULT; } ++static inline dma_addr_t dmad_probe_ring_hw_ptr(dmad_chreq *ch_req) ++ { return (dma_addr_t)NULL; } ++ ++#endif /* CONFIG_PLATFORM_AHBDMA || CONFIG_PLATFORM_APBDMA */ ++ ++#endif /* __NDS_DMAD_INC__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/dma.h linux-3.4.110/arch/nds32/include/asm/dma.h +--- linux-3.4.110.orig/arch/nds32/include/asm/dma.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/dma.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,17 @@ ++/* ++ * linux/arch/nds32/include/asm/dma.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_DMA_H__ ++#define __NDS32_DMA_H__ ++ ++#define MAX_DMA_ADDRESS 0xffffffff ++ ++#ifdef CONFIG_PCI ++extern int isa_dma_bridge_buggy; ++#else ++#define isa_dma_bridge_buggy (0) ++#endif ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/dma-mapping.h linux-3.4.110/arch/nds32/include/asm/dma-mapping.h +--- linux-3.4.110.orig/arch/nds32/include/asm/dma-mapping.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/dma-mapping.h 2016-04-07 10:20:50.894079168 +0200 +@@ -0,0 +1,453 @@ ++/* ++ * linux/arch/nds32/include/asm/dma-mapping.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef ASMNDS32_DMA_MAPPING_H ++#define ASMNDS32_DMA_MAPPING_H ++ ++#ifdef __KERNEL__ ++ ++#include <linux/mm.h> /* need struct page */ ++#include <linux/highmem.h> ++ ++#include <asm/scatterlist.h> ++ ++/* ++ * DMA-consistent mapping functions. These allocate/free a region of ++ * uncached, unwrite-buffered mapped memory space for use with DMA ++ * devices. This is the "generic" version. The PCI specific version ++ * is in pci.h ++ */ ++extern void consistent_sync(void *kaddr, size_t size, int rw); ++ ++/* ++ * Return whether the given device DMA address mask can be supported ++ * properly. For example, if your device can only drive the low 24-bits ++ * during bus mastering, then you would pass 0x00ffffff as the mask ++ * to this function. ++ */ ++static inline int dma_supported(struct device *dev, u64 mask) ++{ ++ return dev->dma_mask && *dev->dma_mask != 0; ++} ++ ++static inline int dma_set_mask(struct device *dev, u64 dma_mask) ++{ ++ if (!dev->dma_mask || !dma_supported(dev, dma_mask)) ++ return -EIO; ++ ++ *dev->dma_mask = dma_mask; ++ ++ return 0; ++} ++ ++static inline int dma_is_consistent(dma_addr_t handle) ++{ ++ return 0; ++} ++ ++/* ++ * DMA errors are defined by all-bits-set in the DMA address. ++ */ ++static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) ++{ ++ return dma_addr == ~0; ++} ++ ++/* ++ * Dummy noncoherent implementation. We don't provide a dma_cache_sync ++ * function so drivers using this API are highlighted with build warnings. ++ */ ++static inline void * ++dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) ++{ ++ return NULL; ++} ++ ++static inline void ++dma_free_noncoherent(struct device *dev, size_t size, void *cpu_addr, ++ dma_addr_t handle) ++{ ++} ++ ++/** ++ * dma_alloc_coherent - allocate consistent memory for DMA ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @size: required memory size ++ * @handle: bus-specific DMA address ++ * ++ * Allocate some uncached, unbuffered memory for a device for ++ * performing DMA. This function allocates pages, and will ++ * return the CPU-viewed address, and sets @handle to be the ++ * device-viewed address. ++ */ ++extern void * ++dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp); ++ ++/** ++ * dma_free_coherent - free memory allocated by dma_alloc_coherent ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @size: size of memory originally requested in dma_alloc_coherent ++ * @cpu_addr: CPU-view address returned from dma_alloc_coherent ++ * @handle: device-view address returned from dma_alloc_coherent ++ * ++ * Free (and unmap) a DMA buffer previously allocated by ++ * dma_alloc_coherent(). ++ * ++ * References to memory and mappings associated with cpu_addr/handle ++ * during and after this call executing are illegal. ++ */ ++extern void ++dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, ++ dma_addr_t handle); ++ ++/** ++ * dma_mmap_coherent - map a coherent DMA allocation into user space ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @vma: vm_area_struct describing requested user mapping ++ * @cpu_addr: kernel CPU-view address returned from dma_alloc_coherent ++ * @handle: device-view address returned from dma_alloc_coherent ++ * @size: size of memory originally requested in dma_alloc_coherent ++ * ++ * Map a coherent DMA buffer previously allocated by dma_alloc_coherent ++ * into user space. The coherent DMA buffer must not be freed by the ++ * driver until the user space mapping has been released. ++ */ ++int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t handle, size_t size); ++ ++ ++/** ++ * dma_alloc_writecombine - allocate writecombining memory for DMA ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @size: required memory size ++ * @handle: bus-specific DMA address ++ * ++ * Allocate some uncached, buffered memory for a device for ++ * performing DMA. This function allocates pages, and will ++ * return the CPU-viewed address, and sets @handle to be the ++ * device-viewed address. ++ */ ++extern void * ++dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp); ++ ++#define dma_free_writecombine(dev,size,cpu_addr,handle) \ ++ dma_free_coherent(dev,size,cpu_addr,handle) ++ ++int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t handle, size_t size); ++ ++ ++/** ++ * dma_map_single - map a single buffer for streaming DMA ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @cpu_addr: CPU direct mapped address of buffer ++ * @size: size of buffer to map ++ * @dir: DMA transfer direction ++ * ++ * Ensure that any data held in the cache is appropriately discarded ++ * or written back. ++ * ++ * The device owns this memory once this call has completed. The CPU ++ * can regain ownership by calling dma_unmap_single() or ++ * dma_sync_single_for_cpu(). ++ */ ++#ifndef CONFIG_DMABOUNCE ++static inline dma_addr_t ++dma_map_single(struct device *dev, void *cpu_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ consistent_sync(cpu_addr, size, dir); ++ return virt_to_dma(dev, (unsigned long)cpu_addr); ++} ++#else ++extern dma_addr_t dma_map_single(struct device *,void *, size_t, enum dma_data_direction); ++#endif ++ ++/** ++ * dma_map_page - map a portion of a page for streaming DMA ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @page: page that buffer resides in ++ * @offset: offset into page for start of buffer ++ * @size: size of buffer to map ++ * @dir: DMA transfer direction ++ * ++ * Ensure that any data held in the cache is appropriately discarded ++ * or written back. ++ * ++ * The device owns this memory once this call has completed. The CPU ++ * can regain ownership by calling dma_unmap_page() or ++ * dma_sync_single_for_cpu(). ++ */ ++static inline dma_addr_t ++dma_map_page(struct device *dev, struct page *page, ++ unsigned long offset, size_t size, ++ enum dma_data_direction dir) ++{ ++ return dma_map_single(dev, page_address(page) + offset, size, (int)dir); ++} ++ ++/** ++ * dma_unmap_single - unmap a single buffer previously mapped ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @handle: DMA address of buffer ++ * @size: size of buffer to map ++ * @dir: DMA transfer direction ++ * ++ * Unmap a single streaming mode DMA translation. The handle and size ++ * must match what was provided in the previous dma_map_single() call. ++ * All other usages are undefined. ++ * ++ * After this call, reads by the CPU to the buffer are guaranteed to see ++ * whatever the device wrote there. ++ */ ++#ifndef CONFIG_DMABOUNCE ++static inline void ++dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, ++ enum dma_data_direction dir) ++{ ++ /* nothing to do */ ++} ++#else ++extern void dma_unmap_single(struct device *, dma_addr_t, size_t, enum dma_data_direction); ++#endif ++ ++/** ++ * dma_unmap_page - unmap a buffer previously mapped through dma_map_page() ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @handle: DMA address of buffer ++ * @size: size of buffer to map ++ * @dir: DMA transfer direction ++ * ++ * Unmap a single streaming mode DMA translation. The handle and size ++ * must match what was provided in the previous dma_map_single() call. ++ * All other usages are undefined. ++ * ++ * After this call, reads by the CPU to the buffer are guaranteed to see ++ * whatever the device wrote there. ++ */ ++static inline void ++dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, ++ enum dma_data_direction dir) ++{ ++ dma_unmap_single(dev, handle, size, (int)dir); ++} ++ ++/** ++ * dma_map_sg - map a set of SG buffers for streaming mode DMA ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @sg: list of buffers ++ * @nents: number of buffers to map ++ * @dir: DMA transfer direction ++ * ++ * Map a set of buffers described by scatterlist in streaming ++ * mode for DMA. This is the scatter-gather version of the ++ * above dma_map_single interface. Here the scatter gather list ++ * elements are each tagged with the appropriate dma address ++ * and length. They are obtained via sg_dma_{address,length}(SG). ++ * ++ * NOTE: An implementation may be able to use a smaller number of ++ * DMA address/length pairs than there are SG table elements. ++ * (for example via virtual mapping capabilities) ++ * The routine returns the number of addr/length pairs actually ++ * used, at most nents. ++ * ++ * Device ownership issues as mentioned above for dma_map_single are ++ * the same here. ++ */ ++#ifndef CONFIG_DMABOUNCE ++static inline int ++dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ int i; ++ ++ for (i = 0; i < nents; i++, sg++) { ++ void *virt; ++ unsigned long pfn; ++ struct page *page = sg_page(sg); ++ ++ sg->dma_address = page_to_dma(dev, page) + sg->offset; ++ pfn = page_to_pfn(page) + sg->offset / PAGE_SIZE; ++ page = pfn_to_page(pfn); ++ if (PageHighMem(page)) { ++ virt = kmap_atomic(page); ++ consistent_sync(virt, sg->length, dir); ++ kunmap_atomic(virt); ++ } else { ++ if (sg->offset > PAGE_SIZE) ++ panic("sg->offset:%08x > PAGE_SIZE\n", sg->offset); ++ virt = page_address(page) + sg->offset; ++ consistent_sync(virt, sg->length, dir); ++ } ++ } ++ return nents; ++} ++#else ++extern int dma_map_sg(struct device *, struct scatterlist *, int, enum dma_data_direction); ++#endif ++ ++/** ++ * dma_unmap_sg - unmap a set of SG buffers mapped by dma_map_sg ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @sg: list of buffers ++ * @nents: number of buffers to map ++ * @dir: DMA transfer direction ++ * ++ * Unmap a set of streaming mode DMA translations. ++ * Again, CPU read rules concerning calls here are the same as for ++ * dma_unmap_single() above. ++ */ ++#ifndef CONFIG_DMABOUNCE ++static inline void ++dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ ++ /* nothing to do */ ++} ++#else ++extern void dma_unmap_sg(struct device *, struct scatterlist *, int, enum dma_data_direction); ++#endif ++ ++ ++/** ++ * dma_sync_single_for_cpu ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @handle: DMA address of buffer ++ * @size: size of buffer to map ++ * @dir: DMA transfer direction ++ * ++ * Make physical memory consistent for a single streaming mode DMA ++ * translation after a transfer. ++ * ++ * If you perform a dma_map_single() but wish to interrogate the ++ * buffer using the cpu, yet do not wish to teardown the PCI dma ++ * mapping, you must call this function before doing so. At the ++ * next point you give the PCI dma address back to the card, you ++ * must first the perform a dma_sync_for_device, and then the ++ * device again owns the buffer. ++ */ ++#ifndef CONFIG_DMABOUNCE ++static inline void ++dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size, ++ enum dma_data_direction dir) ++{ ++ consistent_sync((void *)dma_to_virt(dev, handle), size, dir); ++} ++ ++static inline void ++dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size, ++ enum dma_data_direction dir) ++{ ++ consistent_sync((void *)dma_to_virt(dev, handle), size, dir); ++} ++#else ++extern void dma_sync_single_for_cpu(struct device*, dma_addr_t, size_t, enum dma_data_direction); ++extern void dma_sync_single_for_device(struct device*, dma_addr_t, size_t, enum dma_data_direction); ++#endif ++ ++ ++/** ++ * dma_sync_sg_for_cpu ++ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices ++ * @sg: list of buffers ++ * @nents: number of buffers to map ++ * @dir: DMA transfer direction ++ * ++ * Make physical memory consistent for a set of streaming ++ * mode DMA translations after a transfer. ++ * ++ * The same as dma_sync_single_for_* but for a scatter-gather list, ++ * same rules and usage. ++ */ ++#ifndef CONFIG_DMABOUNCE ++static inline void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ int i; ++ ++ for (i = 0; i < nents; i++, sg++) { ++ char *virt = page_address( (struct page *)sg->page_link) + sg->offset; ++ consistent_sync(virt, sg->length, dir); ++ } ++} ++ ++static inline void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ int i; ++ ++ for (i = 0; i < nents; i++, sg++) { ++ char *virt = page_address( (struct page *)sg->page_link) + sg->offset; ++ consistent_sync(virt, sg->length, dir); ++ } ++} ++#else ++extern void dma_sync_sg_for_cpu(struct device*, struct scatterlist*, int, enum dma_data_direction); ++extern void dma_sync_sg_for_device(struct device*, struct scatterlist*, int, enum dma_data_direction); ++#endif ++ ++#ifdef CONFIG_DMABOUNCE ++/* ++ * For SA-1111, IXP425, and ADI systems the dma-mapping functions are "magic" ++ * and utilize bounce buffers as needed to work around limited DMA windows. ++ * ++ * On the SA-1111, a bug limits DMA to only certain regions of RAM. ++ * On the IXP425, the PCI inbound window is 64MB (256MB total RAM) ++ * On some ADI engineering systems, PCI inbound window is 32MB (12MB total RAM) ++ * ++ * The following are helper functions used by the dmabounce subystem ++ * ++ */ ++ ++/** ++ * dmabounce_register_dev ++ * ++ * @dev: valid struct device pointer ++ * @small_buf_size: size of buffers to use with small buffer pool ++ * @large_buf_size: size of buffers to use with large buffer pool (can be 0) ++ * ++ * This function should be called by low-level platform code to register ++ * a device as requireing DMA buffer bouncing. The function will allocate ++ * appropriate DMA pools for the device. ++ * ++ */ ++extern int dmabounce_register_dev(struct device *, unsigned long, unsigned long); ++ ++/** ++ * dmabounce_unregister_dev ++ * ++ * @dev: valid struct device pointer ++ * ++ * This function should be called by low-level platform code when device ++ * that was previously registered with dmabounce_register_dev is removed ++ * from the system. ++ * ++ */ ++extern void dmabounce_unregister_dev(struct device *); ++ ++/** ++ * dma_needs_bounce ++ * ++ * @dev: valid struct device pointer ++ * @dma_handle: dma_handle of unbounced buffer ++ * @size: size of region being mapped ++ * ++ * Platforms that utilize the dmabounce mechanism must implement ++ * this function. ++ * ++ * The dmabounce routines call this function whenever a dma-mapping ++ * is requested to determine whether a given buffer needs to be bounced ++ * or not. The function must return 0 if the buffer is OK for ++ * DMA access and 1 if the buffer needs to be bounced. ++ * ++ */ ++extern int dma_needs_bounce(struct device*, dma_addr_t, size_t); ++#endif /* CONFIG_DMABOUNCE */ ++ ++#endif /* __KERNEL__ */ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/elf.h linux-3.4.110/arch/nds32/include/asm/elf.h +--- linux-3.4.110.orig/arch/nds32/include/asm/elf.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/elf.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,145 @@ ++/* ++ * linux/arch/nds32/include/asm/elf.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ASMNDS32_ELF_H ++#define __ASMNDS32_ELF_H ++ ++/* ++ * ELF register definitions.. ++ */ ++ ++#include <asm/ptrace.h> ++#include <asm/user.h> ++ ++typedef unsigned long elf_greg_t; ++typedef unsigned long elf_freg_t[3]; ++ ++extern unsigned int elf_hwcap; ++ ++#define EM_NDS32 167 ++ ++ ++#define R_NDS32_NONE 0 ++#define R_NDS32_16_RELA 19 ++#define R_NDS32_32_RELA 20 ++#define R_NDS32_9_PCREL_RELA 22 ++#define R_NDS32_15_PCREL_RELA 23 ++#define R_NDS32_17_PCREL_RELA 24 ++#define R_NDS32_25_PCREL_RELA 25 ++#define R_NDS32_HI20_RELA 26 ++#define R_NDS32_LO12S3_RELA 27 ++#define R_NDS32_LO12S2_RELA 28 ++#define R_NDS32_LO12S1_RELA 29 ++#define R_NDS32_LO12S0_RELA 30 ++#define R_NDS32_SDA15S3_RELA 31 ++#define R_NDS32_SDA15S2_RELA 32 ++#define R_NDS32_SDA15S1_RELA 33 ++#define R_NDS32_SDA15S0_RELA 34 ++#define R_NDS32_GOT20 37 ++#define R_NDS32_25_PLTREL 38 ++#define R_NDS32_COPY 39 ++#define R_NDS32_GLOB_DAT 40 ++#define R_NDS32_JMP_SLOT 41 ++#define R_NDS32_RELATIVE 42 ++#define R_NDS32_GOTOFF 43 ++#define R_NDS32_GOTPC20 44 ++#define R_NDS32_GOT_HI20 45 ++#define R_NDS32_GOT_LO12 46 ++#define R_NDS32_GOTPC_HI20 47 ++#define R_NDS32_GOTPC_LO12 48 ++#define R_NDS32_GOTOFF_HI20 49 ++#define R_NDS32_GOTOFF_LO12 50 ++#define R_NDS32_INSN16 51 ++#define R_NDS32_LABEL 52 ++#define R_NDS32_LONGCALL1 53 ++#define R_NDS32_LONGCALL2 54 ++#define R_NDS32_LONGCALL3 55 ++#define R_NDS32_LONGJUMP1 56 ++#define R_NDS32_LONGJUMP2 57 ++#define R_NDS32_LONGJUMP3 58 ++#define R_NDS32_LOADSTORE 59 ++#define R_NDS32_9_FIXED_RELA 60 ++#define R_NDS32_15_FIXED_RELA 61 ++#define R_NDS32_17_FIXED_RELA 62 ++#define R_NDS32_25_FIXED_RELA 63 ++#define R_NDS32_PLTREL_HI20 64 ++#define R_NDS32_PLTREL_LO12 65 ++#define R_NDS32_PLT_GOTREL_HI20 66 ++#define R_NDS32_PLT_GOTREL_LO12 67 ++#define R_NDS32_LO12S0_ORI_RELA 72 ++#define R_NDS32_DWARF2_OP1_RELA 77 ++#define R_NDS32_DWARF2_OP2_RELA 78 ++#define R_NDS32_DWARF2_LEB_RELA 79 ++#define R_NDS32_WORD_9_PCREL_RELA 94 ++#define R_NDS32_LONGCALL4 107 ++#define R_NDS32_RELA_NOP_MIX 192 ++#define R_NDS32_RELA_NOP_MAX 255 ++ ++#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) ++typedef elf_greg_t elf_gregset_t[ELF_NGREG]; ++ ++typedef struct user_fp elf_fpregset_t; ++ ++struct elf32_hdr; ++extern int elf_check_arch(const struct elf32_hdr *hdr); ++ ++/* ++ * These are used to set parameters in the core dumps. ++ */ ++#define ELF_CLASS ELFCLASS32 ++#ifdef __NDS32_EB__ ++#define ELF_DATA ELFDATA2MSB; ++#else ++#define ELF_DATA ELFDATA2LSB; ++#endif ++#define ELF_ARCH EM_NDS32 ++#define USE_ELF_CORE_DUMP ++#define ELF_EXEC_PAGESIZE PAGE_SIZE ++ ++/* This is the location that an ET_DYN program is loaded if exec'ed. Typical ++ use of this is to invoke "./ld.so someprog" to test out a new version of ++ the loader. We need to make sure that it is out of the way of the program ++ that it will "exec", and that there is sufficient room for the brk. */ ++ ++#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) ++ ++/* When the program starts, a1 contains a pointer to a function to be ++ registered with atexit, as per the SVR4 ABI. A value of 0 means we ++ have no such handler. */ ++#define ELF_PLAT_INIT(_r, load_addr) (_r)->NDS32_r0 = 0 ++ ++/* This yields a mask that user programs can use to figure out what ++ instruction set this cpu supports. */ ++ ++#define ELF_HWCAP (elf_hwcap) ++ ++/* This yields a string that ld.so will use to load implementation ++ specific libraries for optimization. This is more specific in ++ intent than poking at uname or /proc/cpuinfo. */ ++ ++/* For now we just provide a fairly general string that describes the ++ processor family. This could be made more specific later if someone ++ implemented optimisations that require it. 26-bit CPUs give you ++ "v1l" for ARM2 (no SWP) and "v2l" for anything else (ARM1 isn't ++ supported). 32-bit CPUs give you "v3[lb]" for anything based on an ++ ARM6 or ARM7 core and "armv4[lb]" for anything based on a StrongARM-1 ++ core. */ ++ ++#define ELF_PLATFORM_SIZE 16 ++extern char elf_platform[]; ++#define ELF_PLATFORM (elf_platform) ++ ++#ifdef __KERNEL__ ++ ++/* Old NetWinder binaries were compiled in such a way that the iBCS ++ heuristic always trips on them. Until these binaries become uncommon ++ enough not to care, don't trust the `ibcs' flag here. In any case ++ there is no other ELF system currently supported by iBCS. ++ @@ Could print a warning message to encourage users to upgrade. */ ++#define SET_PERSONALITY(ex) set_personality(PER_LINUX) ++ ++#endif ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/emergency-restart.h linux-3.4.110/arch/nds32/include/asm/emergency-restart.h +--- linux-3.4.110.orig/arch/nds32/include/asm/emergency-restart.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/emergency-restart.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/emergency-restart.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_EMERGENCY_RESTART_H__ ++#define __NDS32_EMERGENCY_RESTART_H__ ++ ++#include <asm-generic/emergency-restart.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/errno.h linux-3.4.110/arch/nds32/include/asm/errno.h +--- linux-3.4.110.orig/arch/nds32/include/asm/errno.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/errno.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/errno.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_ERRNO_H__ ++#define __NDS32_ERRNO_H__ ++ ++#include <asm-generic/errno.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/exec.h linux-3.4.110/arch/nds32/include/asm/exec.h +--- linux-3.4.110.orig/arch/nds32/include/asm/exec.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/exec.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,6 @@ ++#ifndef __ASM_NDS32_EXEC_H ++#define __ASM_NDS32_EXEC_H ++ ++#define arch_align_stack(x) (x) ++ ++#endif /* __ASM_ARM_EXEC_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/fb.h linux-3.4.110/arch/nds32/include/asm/fb.h +--- linux-3.4.110.orig/arch/nds32/include/asm/fb.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/fb.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,25 @@ ++/* ++ * linux/arch/nds32/include/asm/fb.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_FB_H__ ++#define __NDS32_FB_H__ ++ ++ ++#include <linux/fb.h> ++#include <linux/fs.h> ++#include <asm/page.h> ++ ++static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, ++ unsigned long off) ++{ ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++} ++ ++static inline int fb_is_primary_device(struct fb_info *info) ++{ ++ return 0; ++} ++ ++#endif /* __NDS32_FB_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/fcntl.h linux-3.4.110/arch/nds32/include/asm/fcntl.h +--- linux-3.4.110.orig/arch/nds32/include/asm/fcntl.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/fcntl.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,37 @@ ++/* ++ * 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) 1995, 96, 97, 98, 99, 2003, 05 Ralf Baechle ++ */ ++#ifndef _ASM_FCNTL_H ++#define _ASM_FCNTL_H ++ ++/* ++ * The flavours of struct flock. "struct flock" is the ABI compliant ++ * variant. Finally struct flock64 is the LFS variant of struct flock. As ++ * a historic accident and inconsistence with the ABI definition it doesn't ++ * contain all the same fields as struct flock. ++ */ ++ ++#ifdef CONFIG_32BIT ++#include <linux/types.h> ++ ++struct flock { ++ short l_type; ++ short l_whence; ++ off_t l_start; ++ off_t l_len; ++ long l_sysid; ++ __kernel_pid_t l_pid; ++ long pad[4]; ++}; ++ ++#define HAVE_ARCH_STRUCT_FLOCK ++ ++#endif /* CONFIG_32BIT */ ++ ++#include <asm-generic/fcntl.h> ++ ++#endif /* _ASM_FCNTL_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/fixmap.h linux-3.4.110/arch/nds32/include/asm/fixmap.h +--- linux-3.4.110.orig/arch/nds32/include/asm/fixmap.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/fixmap.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,88 @@ ++/* ++ * fixmap.h: compile-time virtual memory allocation ++ * ++ * 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) 1998 Ingo Molnar ++ * ++ * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 ++ */ ++ ++#ifndef __ASM_NDS32_FIXMAP_H ++#define __ASM_NDS32_FIXMAP_H ++ ++#ifdef CONFIG_HIGHMEM ++#include <linux/threads.h> ++#include <asm/kmap_types.h> ++#endif ++ ++/* ++ * Here we define all the compile-time 'special' virtual ++ * addresses. The point is to have a constant address at ++ * compile time, but to set the physical address only ++ * in the boot process. We allocate these special addresses ++ * from the end of the consistent memory region backwards. ++ * Also this lets us do fail-safe vmalloc(), we ++ * can guarantee that these special addresses and ++ * vmalloc()-ed addresses never overlap. ++ * ++ * these 'compile-time allocated' memory buffers are ++ * fixed-size 4k pages. (or larger if used with an increment ++ * higher than 1) use fixmap_set(idx,phys) to associate ++ * physical memory with fixmap indices. ++ * ++ * TLB entries of such buffers will not be flushed across ++ * task switches. ++ */ ++enum fixed_addresses { ++ FIX_KMAP_RESERVED, ++ FIX_KMAP_BEGIN, ++#ifdef CONFIG_HIGHMEM ++ FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS), ++#endif ++#ifdef CONFIG_EARLY_PRINTK ++ FIX_EARLY_DEBUG, ++#endif ++ FIX_RETURN_SYSCALL, ++ __end_of_fixed_addresses ++}; ++#define FIXADDR_TOP ((unsigned long) (-(16 * PAGE_SIZE))) ++#define FIXADDR_SIZE ((__end_of_fixed_addresses) << PAGE_SHIFT) ++#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) ++ ++#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) ++#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) ++ ++#define __this_fixmap_does_not_exist() WARN_ON(1) ++/* ++ * 'index to address' translation. If anyone tries to use the idx ++ * directly without tranlation, we catch the bug with a NULL-deference ++ * kernel oops. Illegal ranges of incoming indices are caught too. ++ */ ++ ++static inline unsigned long fix_to_virt(const unsigned int idx) ++{ ++ /* ++ * this branch gets completely eliminated after inlining, ++ * except when someone tries to use fixaddr indices in an ++ * illegal way. (such as mixing up address types or using ++ * out-of-range indices). ++ * ++ * If it doesn't get removed, the linker will complain ++ * loudly with a reasonably clear error message.. ++ */ ++ if (idx >= __end_of_fixed_addresses) ++ __this_fixmap_does_not_exist(); ++ ++ return __fix_to_virt(idx); ++} ++ ++static inline unsigned long virt_to_fix(const unsigned long vaddr) ++{ ++ BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START); ++ return __virt_to_fix(vaddr); ++} ++ ++#endif /* __ASM_NDS32_FIXMAP_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/fpu.h linux-3.4.110/arch/nds32/include/asm/fpu.h +--- linux-3.4.110.orig/arch/nds32/include/asm/fpu.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/fpu.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,100 @@ ++/* ++ * linux/arch/nds32/include/asm/fpu.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ASM_NDS32_FPU_H ++#define __ASM_NDS32_FPU_H ++ ++#ifndef __ASSEMBLY__ ++#include <linux/preempt.h> ++#include <asm/ptrace.h> ++ ++extern void save_fpu(struct task_struct *__tsk); ++extern void fpload(struct fpu_struct *fpregs); ++extern void do_fpu_exception(unsigned long error_code, struct pt_regs *regs); ++extern int do_fpu_inst(unsigned short, struct pt_regs *); ++ ++#ifdef CONFIG_FPU ++ ++#define test_tsk_fpu(regs) (regs->NDS32_FUCOP_CTL & FUCOP_CTL_mskCP0EN) ++ ++struct task_struct; ++ ++static inline void release_fpu(struct pt_regs *regs) ++{ ++ regs->NDS32_FUCOP_CTL &= ~FUCOP_CTL_mskCP0EN; ++} ++ ++static inline void grab_fpu(struct pt_regs *regs) ++{ ++ regs->NDS32_FUCOP_CTL |= FUCOP_CTL_mskCP0EN; ++} ++ ++static inline void enable_fpu(void) ++{ ++ SET_FUCOP_CTL(GET_FUCOP_CTL() | FUCOP_CTL_mskCP0EN); ++} ++ ++static inline void disable_fpu(void) ++{ ++ SET_FUCOP_CTL(GET_FUCOP_CTL() & ~FUCOP_CTL_mskCP0EN); ++} ++ ++static inline void lose_fpu(int save) ++{ ++ preempt_disable(); ++ if (test_tsk_fpu(task_pt_regs(current))) { ++ if (save) ++ { ++ save_fpu(current); ++# ifndef CONFIG_UNLAZY_FPU ++ last_task_used_math=NULL; ++# endif ++ } ++ release_fpu(task_pt_regs(current)); ++ } ++ preempt_enable(); ++} ++ ++static inline void own_fpu(int restore) ++{ ++ preempt_disable(); ++ if (!test_tsk_fpu(task_pt_regs(current))) { ++ if (restore) ++ { ++# ifdef CONFIG_UNLAZY_FPU ++ fpload(¤t->thread.fpu); ++# else ++ if((last_task_used_math!=NULL) ++ &&(last_task_used_math!=current)) ++ save_fpu(last_task_used_math); ++ fpload(¤t->thread.fpu); ++ last_task_used_math=current; ++#endif ++ } ++ grab_fpu(task_pt_regs(current)); ++ } ++ preempt_enable(); ++} ++# ifdef CONFIG_UNLAZY_FPU ++static inline void unlazy_fpu(struct task_struct *tsk) ++{ ++ preempt_disable(); ++ if (test_tsk_fpu(task_pt_regs(tsk))) ++ save_fpu(tsk); ++ preempt_enable(); ++} ++# endif /* CONFIG_UNLAZY_FPU */ ++static inline void clear_fpu(struct pt_regs *regs) ++{ ++ preempt_disable(); ++ if (test_tsk_fpu(regs)) { ++ release_fpu(regs); ++ } ++ preempt_enable(); ++} ++#endif /* CONFIG_FPU */ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* __ASM_NDS32_FPU_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/ftpci.h linux-3.4.110/arch/nds32/include/asm/ftpci.h +--- linux-3.4.110.orig/arch/nds32/include/asm/ftpci.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/ftpci.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,30 @@ ++/* ++ * linux/arch/nds32/include/asm/ftpci.h ++ * ++ * Faraday FTPCI010 PCI Bridge Device Driver Interface ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * ChangeLog ++ * ++ * Peter Liao 09/26/2005 Created, heavily modified from Faraday A320 platform code. ++ */ ++ ++#ifndef __FARADAY_PLATFORM_PCI_HEADER__ ++#define __FARADAY_PLATFORM_PCI_HEADER__ ++ ++ ++#define PCI_BRIDGE_DEVID 0x4321 ++#define PCI_BRIDGE_VENID 0x159b ++ ++extern int ftpci_probed; ++extern void ftpci_clear_irq(unsigned int irq); ++extern void ftpci_mask_irq(unsigned int irq); ++extern void ftpci_unmask_irq(unsigned int irq); ++extern int ftpci_get_irq(void); ++#endif /* __FARADAY_PLATFORM_PCI_HEADER__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/ftrace.h linux-3.4.110/arch/nds32/include/asm/ftrace.h +--- linux-3.4.110.orig/arch/nds32/include/asm/ftrace.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/ftrace.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,17 @@ ++#ifndef _ASM_POWERPC_FTRACE ++#define _ASM_POWERPC_FTRACE ++ ++#ifdef CONFIG_FUNCTION_TRACER ++#define MCOUNT_ADDR ((long)(_mcount)) ++#define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ ++ ++#ifdef __ASSEMBLY__ ++ ++#else /* !__ASSEMBLY__ */ ++extern void _mcount(void); ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif ++ ++#endif /* _ASM_POWERPC_FTRACE */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/futex.h linux-3.4.110/arch/nds32/include/asm/futex.h +--- linux-3.4.110.orig/arch/nds32/include/asm/futex.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/futex.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/futex.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_FUTEX_H__ ++#define __NDS32_FUTEX_H__ ++ ++#include <asm-generic/futex.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/glue.h linux-3.4.110/arch/nds32/include/asm/glue.h +--- linux-3.4.110.orig/arch/nds32/include/asm/glue.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/glue.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,26 @@ ++/* ++ * linux/arch/nds32/include/asm/glue.h ++ * ++ * Copyright (C) 1997-1999 Russell King ++ * Copyright (C) 2000-2002 Deep Blue Solutions Ltd. ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This file provides the glue to stick the processor-specific bits ++ * into the kernel in an efficient manner. The idea is to use branches ++ * when we're only targetting one class of TLB, or indirect calls ++ * when we're targetting multiple classes of TLBs. ++ */ ++#ifdef __KERNEL__ ++ ++#ifdef __STDC__ ++#define ____glue(name,fn) name##fn ++#else ++#define ____glue(name,fn) name/**/fn ++#endif ++#define __glue(name,fn) ____glue(name,fn) ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/gpio.h linux-3.4.110/arch/nds32/include/asm/gpio.h +--- linux-3.4.110.orig/arch/nds32/include/asm/gpio.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/gpio.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,10 @@ ++#ifndef _ARCH_NDS32_GPIO_H ++#define _ARCH_NDS32_GPIO_H ++ ++#include <asm-generic/gpio.h> ++#define gpio_get_value __gpio_get_value ++#define gpio_set_value __gpio_set_value ++#define gpio_cansleep __gpio_cansleep ++#define gpio_to_irq __gpio_to_irq ++ ++#endif /* _ARCH_NDS32_GPIO_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/hardirq.h linux-3.4.110/arch/nds32/include/asm/hardirq.h +--- linux-3.4.110.orig/arch/nds32/include/asm/hardirq.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/hardirq.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,36 @@ ++/* ++ * linux/arch/nds32/include/asm/hardirq.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++#ifndef __ASM_HARDIRQ_H ++#define __ASM_HARDIRQ_H ++ ++#include <linux/cache.h> ++#include <linux/threads.h> ++#include <asm/irq.h> ++ ++typedef struct { ++ unsigned int __softirq_pending; ++} ____cacheline_aligned irq_cpustat_t; ++ ++#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ ++ ++#if NR_IRQS > 256 ++#define HARDIRQ_BITS 9 ++#else ++#define HARDIRQ_BITS 8 ++#endif ++ ++/* ++ * The hardirq mask has to be large enough to have space ++ * for potentially all IRQ sources in the system nesting ++ * on a single CPU: ++ */ ++#if (1 << HARDIRQ_BITS) < NR_IRQS ++# error HARDIRQ_BITS is too low! ++#endif ++ ++#define __ARCH_IRQ_EXIT_IRQS_DISABLED 1 ++ ++extern void ack_bad_irq(unsigned int irq); ++#endif /* __ASM_HARDIRQ_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/hardware.h linux-3.4.110/arch/nds32/include/asm/hardware.h +--- linux-3.4.110.orig/arch/nds32/include/asm/hardware.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/hardware.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,61 @@ ++/* ++ * linux/arch/nds32/include/asm/hardware.h ++ * ++ * Faraday Platform Independent Hardware Configuration ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ChangeLog ++ * ++ * Luke Lee 09/16/2005 Created. ++ * Peter Liao 10/04/2005 Modified for uClinux ++ * Harry Pan 11/02/2007 Added REGxx macros. ++ */ ++ ++#ifndef __FARADAY_PLATFORM_HARDWARE_HEADER__ ++#define __FARADAY_PLATFORM_HARDWARE_HEADER__ ++ ++#include <asm/spec.h> ++ ++#ifndef PCIBIOS_MIN_IO ++/* the mini io address is 0x6000,that is IO will allocate from 0-0x6000 offset*/ ++#define PCIBIOS_MIN_IO 0x0 ++#endif ++ ++#ifndef PCIBIOS_MIN_MEM ++/* the mini MEM address is 0x100000,that is MEM will allocate from 0-0x100000 offset*/ ++#define PCIBIOS_MIN_MEM 0x0 ++#endif ++ ++#define pcibios_assign_all_busses() 1 ++ ++/* Pliauo add 5 to resolve __alloc_bootmem_core return NULL pointer in bootmem.c */ ++#if defined(CPU_MEM_PA_BASE) && defined(CPU_MEM_PA_SIZE) ++ #define PA_SDRAM_BASE (CPU_MEM_PA_BASE) ++#else ++ #define PA_SDRAM_BASE (0x00000000) ++#endif ++ ++/* ++ * Define a simple register accessing method by Harry@Nov.02.2007 ++ */ ++#define REG32(a) (*(volatile unsigned int *)(a)) ++#define REG16(a) (*(volatile unsigned short *)(a)) ++#define REG8(a) (*(volatile unsigned char *)(a)) ++ ++#endif /* __FARADAY_PLATFORM_HARDWARE_HEADER__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/highmem.h linux-3.4.110/arch/nds32/include/asm/highmem.h +--- linux-3.4.110.orig/arch/nds32/include/asm/highmem.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/highmem.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,61 @@ ++#ifndef _ASM_HIGHMEM_H ++#define _ASM_HIGHMEM_H ++ ++#include <asm/kmap_types.h> ++#include <asm/fixmap.h> ++#include <asm/pgtable.h> ++ ++/* ++ * Right now we initialize only a single pte table. It can be extended ++ * easily, subsequent pte tables have to be allocated in one physical ++ * chunk of RAM. ++ */ ++/* ++ * Ordering is (from lower to higher memory addresses): ++ * ++ * high_memory ++ * Persistent kmap area ++ * PKMAP_BASE ++ * fixed_addresses ++ * FIXADDR_START ++ * FIXADDR_TOP ++ * Vmalloc area ++ * VMALLOC_START ++ * VMALLOC_END ++ */ ++#define PKMAP_BASE ((FIXADDR_START - PGDIR_SIZE) & (PGDIR_MASK)) ++#define LAST_PKMAP PTRS_PER_PTE ++#define LAST_PKMAP_MASK (LAST_PKMAP - 1) ++#define PKMAP_NR(virt) (((virt) - (PKMAP_BASE)) >> PAGE_SHIFT) ++#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) ++#define kmap_prot PAGE_KERNEL ++ ++static inline void flush_cache_kmaps(void) ++{ ++ cpu_dcache_wbinval_all(); ++} ++ ++/* declarations for highmem.c */ ++extern unsigned long highstart_pfn, highend_pfn; ++ ++extern pte_t *pkmap_page_table; ++ ++extern void *kmap_high(struct page *page); ++extern void kunmap_high(struct page *page); ++ ++extern void kmap_init(void); ++ ++/* ++ * The following functions are already defined by <linux/highmem.h> ++ * when CONFIG_HIGHMEM is not set. ++ */ ++#ifdef CONFIG_HIGHMEM ++extern void *kmap(struct page *page); ++extern void kunmap(struct page *page); ++extern void *kmap_atomic(struct page *page); ++extern void __kunmap_atomic(void *kvaddr); ++extern void *kmap_atomic_pfn(unsigned long pfn); ++extern struct page *kmap_atomic_to_page(void *ptr); ++#endif ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/hw_irq.h linux-3.4.110/arch/nds32/include/asm/hw_irq.h +--- linux-3.4.110.orig/arch/nds32/include/asm/hw_irq.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/hw_irq.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/hw_irq.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_HW_IRQ_H__ ++#define __NDS32_HW_IRQ_H__ ++ ++ ++#endif /* __NDS32_HW_IRQ_H__ */ ++ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/intc.h linux-3.4.110/arch/nds32/include/asm/intc.h +--- linux-3.4.110.orig/arch/nds32/include/asm/intc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/intc.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,45 @@ ++/* ++ * linux/arch/nds32/include/asm/intc.h ++ * ++ * Faraday FTINTC010 Interrupt Controller Device Driver Interface ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ChangeLog ++ * ++ * Luke Lee 09/14/2005 Created, heavily modified from Faraday CPE platform code. ++ */ ++ ++#ifndef __FARADAY_INTC_FTINTC010_HEADER__ ++#define __FARADAY_INTC_FTINTC010_HEADER__ ++ ++#define IRQ_SOURCE_REG 0 ++#define IRQ_MASK_REG 0x04 ++#define IRQ_CLEAR_REG 0x08 ++#define IRQ_MODE_REG 0x0c ++#define IRQ_LEVEL_REG 0x10 ++#define IRQ_STATUS_REG 0x14 ++ ++#define FIQ_SOURCE_REG 0x20 ++#define FIQ_MASK_REG 0x24 ++#define FIQ_CLEAR_REG 0x28 ++#define FIQ_MODE_REG 0x2c ++#define FIQ_LEVEL_REG 0x30 ++#define FIQ_STATUS_REG 0x34 ++ ++#endif /* __FARADAY_INTC_FTINTC010_HEADER__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/ioctl.h linux-3.4.110/arch/nds32/include/asm/ioctl.h +--- linux-3.4.110.orig/arch/nds32/include/asm/ioctl.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/ioctl.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/ioctl.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_IOCTL_H__ ++#define __NDS32_IOCTL_H__ ++ ++#include <asm-generic/ioctl.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/ioctls.h linux-3.4.110/arch/nds32/include/asm/ioctls.h +--- linux-3.4.110.orig/arch/nds32/include/asm/ioctls.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/ioctls.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,13 @@ ++/* ++ * linux/arch/nds32/include/asm/ioctls.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ASM_NDS32_IOCTLS_H ++#define __ASM_NDS32_IOCTLS_H ++ ++#define FIOQSIZE 0x545E ++ ++#include <asm-generic/ioctls.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/io.h linux-3.4.110/arch/nds32/include/asm/io.h +--- linux-3.4.110.orig/arch/nds32/include/asm/io.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/io.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,343 @@ ++/* ++ * linux/arch/nds32/include/asm/io.h ++ * ++ * Copyright (C) 1996-2000 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Modifications: ++ * 16-Sep-1996 RMK Inlined the inx/outx functions & optimised for both ++ * constant addresses and variable addresses. ++ * 04-Dec-1997 RMK Moved a lot of this stuff to the new architecture ++ * specific IO header files. ++ * 27-Mar-1999 PJB Second parameter of memcpy_toio is const.. ++ * 04-Apr-1999 PJB Added check_signature. ++ * 12-Dec-1999 RMK More cleanups ++ * 18-Jun-2000 RMK Removed virt_to_* and friends definitions ++ * 05-Oct-2004 BJD Moved memory string functions to use void __iomem ++ */ ++#ifndef __ASM_NDS32_IO_H ++#define __ASM_NDS32_IO_H ++ ++#ifdef __KERNEL__ ++ ++#include <linux/types.h> ++#include <asm/byteorder.h> ++#include <asm/memory.h> ++#include <asm/hardware.h> ++#include <asm-generic/iomap.h> ++ ++ ++/* ++ * ISA I/O bus memory addresses are 1:1 with the physical address. ++ */ ++#define isa_virt_to_bus virt_to_phys ++#define isa_page_to_bus page_to_phys ++#define isa_bus_to_virt phys_to_virt ++ ++/* ++ * Generic IO read/write. These perform native-endian accesses. Note ++ * that some architectures will want to re-define __raw_{read,write}w. ++ */ ++ ++#define __raw_writeb(v,a) (*(volatile unsigned char __force *)(a) = (v)) ++#define __raw_writew(v,a) (*(volatile unsigned short __force *)(a) = (v)) ++#define __raw_writel(v,a) (*(volatile unsigned int __force *)(a) = (v)) ++ ++#define __raw_readb(a) (*(volatile unsigned char __force *)(a)) ++#define __raw_readw(a) (*(volatile unsigned short __force *)(a)) ++#define __raw_readl(a) (*(volatile unsigned int __force *)(a)) ++ ++/* ++ * Bad read/write accesses... ++ */ ++extern void __readwrite_bug(const char *fn); ++ ++/* ++ * Now, pick up the machine-defined IO definitions ++ */ ++#ifndef __FARADAY_PLATFORM_IO_HEADER__ ++#define __FARADAY_PLATFORM_IO_HEADER__ ++ ++#include <linux/compiler.h> ++#include <asm/spec.h> ++ ++#ifndef IO_SPACE_LIMIT ++#define IO_SPACE_LIMIT 0xffffffff ++#endif ++ ++#ifndef __io ++#define __io(a) ((void __iomem *)(a)) ++#endif ++#define IO_ADDRESS(a) __io(a) ++#ifndef __mem_pci ++#define __mem_pci(a) (a) ++#endif ++ ++#endif ++ ++#ifdef __io_pci ++#warning machine class uses buggy __io_pci ++#endif ++#if defined(__arch_putb) || defined(__arch_putw) || defined(__arch_putl) || \ ++ defined(__arch_getb) || defined(__arch_getw) || defined(__arch_getl) ++//-Tom for debug ++//#warning machine class uses old __arch_putw or __arch_getw ++#endif ++ ++/* ++ * IO port access primitives ++ * ------------------------- ++ * ++ * The ARM doesn't have special IO access instructions; all IO is memory ++ * mapped. Note that these are defined to perform little endian accesses ++ * only. Their primary purpose is to access PCI and ISA peripherals. ++ * ++ * Note that for a big endian machine, this implies that the following ++ * big endian mode connectivity is in place, as described by numerious ++ * ARM documents: ++ * ++ * PCI: D0-D7 D8-D15 D16-D23 D24-D31 ++ * ARM: D24-D31 D16-D23 D8-D15 D0-D7 ++ * ++ * The machine specific io.h include defines __io to translate an "IO" ++ * address to a memory address. ++ * ++ * Note that we prevent GCC re-ordering or caching values in expressions ++ * by introducing sequence points into the in*() definitions. Note that ++ * __raw_* do not guarantee this behaviour. ++ * ++ * The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space. ++ */ ++#ifdef __io ++#ifdef __NDS32_EB__ ++#define inw(p) ({ unsigned int __v = be16_to_cpu(__raw_readw(__io(p))); __v; }) ++#define inl(p) ({ unsigned int __v = be32_to_cpu(__raw_readl(__io(p))); __v; }) ++#define outw(v,p) __raw_writew(cpu_to_be16(v),__io(p)) ++#define outl(v,p) __raw_writel(cpu_to_be32(v),__io(p)) ++#else ++#define inw(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(__io(p))); __v; }) ++#define inl(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(__io(p))); __v; }) ++#define outw(v,p) __raw_writew(cpu_to_le16(v),__io(p)) ++#define outl(v,p) __raw_writel(cpu_to_le32(v),__io(p)) ++#endif ++ ++#define inb(p) ({ unsigned int __v = __raw_readb(__io(p)); __v; }) ++#define outb(v,p) __raw_writeb(v,__io(p)) ++ ++#endif ++ ++#define outb_p(val,port) outb((val),(port)) ++#define outw_p(val,port) outw((val),(port)) ++#define outl_p(val,port) outl((val),(port)) ++#define inb_p(port) inb((port)) ++#define inw_p(port) inw((port)) ++#define inl_p(port) inl((port)) ++ ++/* ++ * String version of IO memory access ops: ++ */ ++extern void _memcpy_fromio(void *, const volatile void __iomem *, size_t); ++extern void _memcpy_toio(volatile void __iomem *, const void *, size_t); ++extern void _memset_io(volatile void __iomem *, int, size_t); ++ ++#define mmiowb() ++ ++/* ++ * Memory access primitives ++ * ------------------------ ++ * ++ * These perform PCI memory accesses via an ioremap region. They don't ++ * take an address as such, but a cookie. ++ * ++ * Again, this are defined to perform little endian accesses. See the ++ * IO port primitives for more information. ++ */ ++#ifdef __mem_pci ++#ifdef __NDS32_EB__ ++#define readw(c) ({ unsigned int __v = be16_to_cpu(__raw_readw(__mem_pci(c))); __v; }) ++#define readl(c) ({ unsigned int __v = be32_to_cpu(__raw_readl(__mem_pci(c))); __v; }) ++#define writew(v,c) __raw_writew(cpu_to_be16(v),__mem_pci(c)) ++#define writel(v,c) __raw_writel(cpu_to_be32(v),__mem_pci(c)) ++#else ++#define readw(c) ({ unsigned int __v = le16_to_cpu(__raw_readw(__mem_pci(c))); __v; }) ++#define readl(c) ({ unsigned int __v = le32_to_cpu(__raw_readl(__mem_pci(c))); __v; }) ++#define writew(v,c) __raw_writew(cpu_to_le16(v),__mem_pci(c)) ++#define writel(v,c) __raw_writel(cpu_to_le32(v),__mem_pci(c)) ++#endif ++ ++#define readb(c) ({ unsigned int __v = __raw_readb(__mem_pci(c)); __v; }) ++#define writeb(v,c) __raw_writeb(v,__mem_pci(c)) ++ ++#define readb_relaxed(addr) readb(addr) ++#define readw_relaxed(addr) readw(addr) ++#define readl_relaxed(addr) readl(addr) ++ ++#define memset_io(c,v,l) _memset_io(__mem_pci(c),(v),(l)) ++#define memcpy_fromio(a,c,l) _memcpy_fromio((a),__mem_pci(c),(l)) ++#define memcpy_toio(c,a,l) _memcpy_toio(__mem_pci(c),(a),(l)) ++ ++#define eth_io_copy_and_sum(s,c,l,b) \ ++ eth_copy_and_sum((s),__mem_pci(c),(l),(b)) ++ ++#elif !defined(readb) ++ ++#define readb(c) (__readwrite_bug("readb"),0) ++#define readw(c) (__readwrite_bug("readw"),0) ++#define readl(c) (__readwrite_bug("readl"),0) ++#define writeb(v,c) __readwrite_bug("writeb") ++#define writew(v,c) __readwrite_bug("writew") ++#define writel(v,c) __readwrite_bug("writel") ++ ++#define eth_io_copy_and_sum(s,c,l,b) __readwrite_bug("eth_io_copy_and_sum") ++ ++#endif /* __mem_pci */ ++ ++/* ++ * If this architecture has ISA IO, then define the isa_read/isa_write ++ * macros. ++ */ ++#ifdef __mem_isa ++ ++#define isa_readb(addr) __raw_readb(__mem_isa(addr)) ++#define isa_readw(addr) __raw_readw(__mem_isa(addr)) ++#define isa_readl(addr) __raw_readl(__mem_isa(addr)) ++#define isa_writeb(val,addr) __raw_writeb(val,__mem_isa(addr)) ++#define isa_writew(val,addr) __raw_writew(val,__mem_isa(addr)) ++#define isa_writel(val,addr) __raw_writel(val,__mem_isa(addr)) ++#define isa_memset_io(a,b,c) _memset_io(__mem_isa(a),(b),(c)) ++#define isa_memcpy_fromio(a,b,c) _memcpy_fromio((a),__mem_isa(b),(c)) ++#define isa_memcpy_toio(a,b,c) _memcpy_toio(__mem_isa((a)),(b),(c)) ++ ++#define isa_eth_io_copy_and_sum(a,b,c,d) \ ++ eth_copy_and_sum((a),__mem_isa(b),(c),(d)) ++ ++#else /* __mem_isa */ ++ ++#define isa_readb(addr) (__readwrite_bug("isa_readb"),0) ++#define isa_readw(addr) (__readwrite_bug("isa_readw"),0) ++#define isa_readl(addr) (__readwrite_bug("isa_readl"),0) ++#define isa_writeb(val,addr) __readwrite_bug("isa_writeb") ++#define isa_writew(val,addr) __readwrite_bug("isa_writew") ++#define isa_writel(val,addr) __readwrite_bug("isa_writel") ++#define isa_memset_io(a,b,c) __readwrite_bug("isa_memset_io") ++#define isa_memcpy_fromio(a,b,c) __readwrite_bug("isa_memcpy_fromio") ++#define isa_memcpy_toio(a,b,c) __readwrite_bug("isa_memcpy_toio") ++ ++#define isa_eth_io_copy_and_sum(a,b,c,d) \ ++ __readwrite_bug("isa_eth_io_copy_and_sum") ++ ++#endif /* __mem_isa */ ++ ++/* ++ * ioremap and friends. ++ * ++ * ioremap takes a PCI memory address, as specified in ++ * Documentation/IO-mapping.txt. ++ */ ++extern void __iomem * __ioremap(unsigned long, size_t, unsigned long, unsigned long); ++extern void __iounmap(void __iomem *addr); ++ ++#ifndef __arch_ioremap ++#define ioremap(cookie,size) __ioremap(cookie,size,0,1) ++#define ioremap_nocache(cookie,size) __ioremap(cookie,size,0,1) ++#define iounmap(cookie) __iounmap(cookie) ++#else ++#define ioremap(cookie,size) __arch_ioremap((cookie),(size),0,1) ++#define ioremap_nocache(cookie,size) __arch_ioremap((cookie),(size),0,1) ++#define iounmap(cookie) __arch_iounmap(cookie) ++#endif ++ ++/* ++ * can the hardware map this into one segment or not, given no other ++ * constraints. ++ */ ++#define BIOVEC_MERGEABLE(vec1, vec2) \ ++ ((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2))) ++ ++/* ++ * Convert a physical pointer to a virtual kernel pointer for /dev/mem ++ * access ++ */ ++#define xlate_dev_mem_ptr(p) __va(p) ++ ++/* ++ * Convert a virtual cached pointer to an uncached pointer ++ */ ++#define xlate_dev_kmem_ptr(p) p ++static inline void readsb(const void __iomem *addr, void * data, int bytelen) ++{ ++ unsigned char *ptr = (unsigned char *)addr; ++ unsigned char *ptr2 = (unsigned char *)data; ++ while(bytelen) { ++ *ptr2 = *ptr; ++ ptr2++; ++ bytelen--; ++ } ++} ++ ++static inline void readsw(const void __iomem *addr, void * data, int wordlen) ++{ ++ unsigned short *ptr = (unsigned short *)addr; ++ unsigned short *ptr2 = (unsigned short *)data; ++ while(wordlen) { ++ *ptr2 = *ptr; ++ ptr2++; ++ wordlen--; ++ } ++} ++ ++static inline void readsl(const void __iomem *addr, void * data, int longlen) ++{ ++ unsigned int *ptr = (unsigned int *)addr; ++ unsigned int *ptr2 = (unsigned int *)data; ++ while(longlen) { ++ *ptr2 = *ptr; ++ ptr2++; ++ longlen--; ++ } ++} ++static inline void writesb(void __iomem *addr, const void * data, int bytelen) ++{ ++ unsigned char *ptr = (unsigned char *)addr; ++ unsigned char *ptr2 = (unsigned char *)data; ++ while(bytelen) { ++ *ptr = *ptr2; ++ ptr2++; ++ bytelen--; ++ } ++} ++static inline void writesw(void __iomem *addr, const void * data, int wordlen) ++{ ++ unsigned short *ptr = (unsigned short *)addr; ++ unsigned short *ptr2 = (unsigned short *)data; ++ while(wordlen) { ++ *ptr = *ptr2; ++ ptr2++; ++ wordlen--; ++ } ++} ++static inline void writesl(void __iomem *addr, const void * data, int longlen) ++{ ++ unsigned int *ptr = (unsigned int *)addr; ++ unsigned int *ptr2 = (unsigned int *)data; ++ while(longlen) { ++ *ptr = *ptr2; ++ ptr2++; ++ longlen--; ++ } ++} ++ ++ ++#define insb(p,d,l) BUG() ++#define insw(p,d,l) BUG() ++#define insl(p,d,l) BUG() ++#define outsb(p,d,l) BUG() ++#define outsw(p,d,l) BUG() ++#define outsl(p,d,l) BUG() ++ ++#endif /* __KERNEL__ */ ++#endif /* __ASM_NDS32_IO_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/ipcbuf.h linux-3.4.110/arch/nds32/include/asm/ipcbuf.h +--- linux-3.4.110.orig/arch/nds32/include/asm/ipcbuf.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/ipcbuf.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,34 @@ ++/* ++ * linux/arch/nds32/include/asm/ipcbuf.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ASMNDS32_IPCBUF_H ++#define __ASMNDS32_IPCBUF_H ++ ++/* ++ * The ipc64_perm structure for arm architecture. ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 32-bit mode_t and seq ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct ipc64_perm ++{ ++ __kernel_key_t key; ++ __kernel_uid32_t uid; ++ __kernel_gid32_t gid; ++ __kernel_uid32_t cuid; ++ __kernel_gid32_t cgid; ++ __kernel_mode_t mode; ++ unsigned short __pad1; ++ unsigned short seq; ++ unsigned short __pad2; ++ unsigned long __unused1; ++ unsigned long __unused2; ++}; ++ ++#endif /* __ASMNDS32_IPCBUF_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/irqflags.h linux-3.4.110/arch/nds32/include/asm/irqflags.h +--- linux-3.4.110.orig/arch/nds32/include/asm/irqflags.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/irqflags.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,65 @@ ++/* ++ * linux/arch/nds32/include/asm/irqflags.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#include <asm/nds32.h> ++#include <asm/assembler.h> ++ ++#define arch_local_irq_disable() \ ++ GIE_DISABLE(); ++ ++#define arch_local_irq_enable() \ ++ GIE_ENABLE(); ++static inline unsigned long arch_local_irq_save(void) ++{ ++ unsigned long flags; ++ __asm__ __volatile__( ++ "mfsr %0, $PSW\n" ++ "andi %0, %0, #0x1\n" ++ "gie_disable\n" ++ : "=r" (flags) ); ++ return flags; ++} ++static inline unsigned long arch_local_save_flags(void) ++{ ++ unsigned long flags; ++ __asm__ __volatile__( ++ "mfsr %0, $PSW\n" ++ "andi %0, %0, #0x1" ++ : "=r" (flags) ); ++ return flags; ++} ++static inline void arch_local_irq_restore(unsigned long flags) ++{ ++ __asm__ __volatile__( ++ "beqz %0, 1f\n" ++ "gie_enable\n" ++ "1:" ++ :: "r" (flags) ); ++} ++static inline int arch_irqs_disabled_flags(unsigned long flags) ++{ ++ return !flags; ++} ++#if 0 ++#define raw_local_irq_save(x) \ ++ __asm__ __volatile__( \ ++ "mfsr %0, $PSW\n" \ ++ "andi %0, %0, #0x1\n" \ ++ "gie_disable\n" \ ++ : "=r" (x) ) ++#define raw_local_save_flags(x) \ ++ __asm__ __volatile__( \ ++ "mfsr %0, $PSW\n" \ ++ "andi %0, %0, #0x1" \ ++ : "=r" (x) ) ++#define raw_local_irq_restore(x) \ ++ __asm__ __volatile__( \ ++ "beqz %0, 1f\n" \ ++ "gie_enable\n" \ ++ "1:" \ ++ :: "r" (x) ) ++ ++#define raw_irqs_disabled_flags(x) !(x) ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/irq.h linux-3.4.110/arch/nds32/include/asm/irq.h +--- linux-3.4.110.orig/arch/nds32/include/asm/irq.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/irq.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,50 @@ ++/* ++ * linux/arch/nds32/include/asm/irq.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ASM_NDS32_IRQ_H ++#define __ASM_NDS32_IRQ_H ++ ++#include <asm/spec.h> ++ ++#ifndef irq_canonicalize ++#define irq_canonicalize(i) (i) ++#endif ++ ++#ifndef NR_IRQS ++#define NR_IRQS 128 ++#endif ++ ++/* ++ * Use this value to indicate lack of interrupt ++ * capability ++ */ ++#ifndef NO_IRQ ++#define NO_IRQ ((unsigned int)(-1)) ++#endif ++ ++struct irqaction; ++ ++extern void disable_irq_nosync(unsigned int); ++extern void disable_irq(unsigned int); ++extern void enable_irq(unsigned int); ++ ++#define __IRQT_FALEDGE IRQ_TYPE_EDGE_FALLING ++#define __IRQT_RISEDGE IRQ_TYPE_EDGE_RISING ++#define __IRQT_LOWLVL IRQ_TYPE_LEVEL_LOW ++#define __IRQT_HIGHLVL IRQ_TYPE_LEVEL_HIGH ++ ++#define IRQT_NOEDGE (0) ++#define IRQT_RISING (__IRQT_RISEDGE) ++#define IRQT_FALLING (__IRQT_FALEDGE) ++#define IRQT_BOTHEDGE (__IRQT_RISEDGE|__IRQT_FALEDGE) ++#define IRQT_LOW (__IRQT_LOWLVL) ++#define IRQT_HIGH (__IRQT_HIGHLVL) ++#define IRQT_PROBE IRQ_TYPE_PROBE ++ ++struct irqaction; ++struct pt_regs; ++ ++#endif ++ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/irq_regs.h linux-3.4.110/arch/nds32/include/asm/irq_regs.h +--- linux-3.4.110.orig/arch/nds32/include/asm/irq_regs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/irq_regs.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,9 @@ ++/* ++ * linux/arch/nds32/include/asm/irq_regs.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_IRQ_REGS_H__ ++#define __NDS32_IRQ_REGS_H__ ++#include <asm-generic/irq_regs.h> ++#endif /* __NDS32_IRQ_REGS_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/Kbuild linux-3.4.110/arch/nds32/include/asm/Kbuild +--- linux-3.4.110.orig/arch/nds32/include/asm/Kbuild 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/Kbuild 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,3 @@ ++include include/asm-generic/Kbuild.asm ++ ++header-y += pfm.h +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/kdebug.h linux-3.4.110/arch/nds32/include/asm/kdebug.h +--- linux-3.4.110.orig/arch/nds32/include/asm/kdebug.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/kdebug.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,14 @@ ++/* ++ * linux/arch/nds32/include/asm/kdebug.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_KDEBUG_H__ ++#define __NDS32_KDEBUG_H__ ++ ++enum die_val { ++ DIE_OOPS = 1, ++ DIE_DEBUG, ++}; ++ ++#endif /* __NDS32_KDEBUG_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/kexec.h linux-3.4.110/arch/nds32/include/asm/kexec.h +--- linux-3.4.110.orig/arch/nds32/include/asm/kexec.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/kexec.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,31 @@ ++#ifndef _NDS32_KEXEC_H ++#define _NDS32_KEXEC_H ++ ++#ifdef CONFIG_KEXEC ++ ++/* Maximum physical address we can use pages from */ ++#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) ++/* Maximum address we can reach in physical address mode */ ++#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) ++/* Maximum address we can use for the control code buffer */ ++#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL) ++ ++#define KEXEC_CONTROL_PAGE_SIZE 4096 ++ ++#define KEXEC_ARCH KEXEC_ARCH_NDS32 ++ ++#define KEXEC_NDS32_ATAGS_OFFSET 0x1000 ++#define KEXEC_NDS32_ZIMAGE_OFFSET 0x500000 ++ ++#ifndef __ASSEMBLY__ ++ ++struct kimage; ++/* Provide a dummy definition to avoid build failures. */ ++static inline void crash_setup_regs(struct pt_regs *newregs, ++ struct pt_regs *oldregs) { } ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif /* CONFIG_KEXEC */ ++ ++#endif /* _NDS32_KEXEC_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/kgdb.h linux-3.4.110/arch/nds32/include/asm/kgdb.h +--- linux-3.4.110.orig/arch/nds32/include/asm/kgdb.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/kgdb.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,90 @@ ++/* ============================================================================ ++ * ++ * linux/arch/nds32/include/asm/kgdb.h ++ * ++ * Copyright (C) 2007 Andes Technology Corporation ++ * This file is part of Linux and should be licensed under the GPL. ++ * See the file COPYING for conditions for redistribution. ++ * ++ * Abstract: ++ * ++ * This program is for NDS32 KGDB support. ++ * ++ * Author: Harry Pan ++ * ++ * Revision History: ++ * ++ * Jul.14.2007 Initial ported by Harry. ++ * ++ * Note: ++ * ++ * ============================================================================ ++ */ ++#ifndef __ASM_NDS32_KGDB_H__ ++#define __ASM_NDS32_KGDB_H__ ++ ++#include <asm/ptrace.h> ++ ++#define BREAK_INSTR_SIZE 2 ++#define CACHE_FLUSH_IS_SAFE 1 ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * Define numbers of registers we have in NDS32 arch ++ */ ++#define NDS32_NUM_GR 32 // general registers. ++#define NDS32_NUM_SPR 5 // special registers. (PC, D0, D1) ++#define NDS32_NUM_CR 6 // ctrl registers. ++#define NDS32_NUM_IR 16 // interruption registers. ++#define NDS32_NUM_MR 11 // MMU registers. ++#define NDS32_NUM_DR 48 // debug registers. ++#define NDS32_NUM_PFR 4 // performance monitoring registers. ++#define NDS32_NUM_DMAR 11 // local memory DMA registers ++#define NDS32_NUM_RACR 1 // resource access control registers. ++#define NDS32_NUM_IDR 2 // implementation dependent registers. ++#define NDS32_NUM_SR (NDS32_NUM_CR + NDS32_NUM_IR + NDS32_NUM_MR + \ ++ NDS32_NUM_DR + NDS32_NUM_PFR + NDS32_NUM_DMAR + \ ++ NDS32_NUM_RACR + NDS32_NUM_IDR) ++#define NDS32_NUM_REGS (NDS32_NUM_GR + NDS32_NUM_SPR + NDS32_NUM_SR) ++ ++#define KGDB_MAX_NO_CPUS 1 ++#define BUFMAX 2048 ++#define NUMREGBYTES (NDS32_NUM_REGS << 2) ++ ++/* ++ * NDS32 virtual registers layout for GDB. ++ */ ++enum nds32_regnum ++{ ++ NDS32_R0_REGNUM = 0, // first integer-like argument. ++ NDS32_R5_REGNUM = 5, // last integer-like argument. ++ NDS32_FP_REGNUM = 28, // frame register ++ NDS32_LP_REGNUM = 30, // link pointer ++ NDS32_SP_REGNUM = 31, // address of stack top. ++ NDS32_PC_REGNUM = 32, ++ NDS32_D0LO_REGNUM = 33, ++ NDS32_D0HI_REGNUM = 34, ++ NDS32_D1LO_REGNUM = 35, ++ NDS32_D1HI_REGNUM = 36, ++ NDS32_CR0_REGNUM = 37, ++ NDS32_IR0_REGNUM = (NDS32_CR0_REGNUM + NDS32_NUM_CR), ++ NDS32_MR0_REGNUM = (NDS32_IR0_REGNUM + NDS32_NUM_IR), ++ NDS32_DR0_REGNUM = (NDS32_MR0_REGNUM + NDS32_NUM_MR), ++ NDS32_PFR0_REGNUM = (NDS32_DR0_REGNUM + NDS32_NUM_DR), ++ NDS32_DMAR0_REGNUM = (NDS32_PFR0_REGNUM + NDS32_NUM_PFR), ++ NDS32_RACR0_REGNUM = (NDS32_DMAR0_REGNUM + NDS32_NUM_DMAR), ++ NDS32_IDR0_REGNUM = (NDS32_RACR0_REGNUM + NDS32_NUM_RACR), ++ /* nds32 calling convention. */ ++ NDS32_ARG0_REGNUM = NDS32_R0_REGNUM, ++ NDS32_ARGN_REGNUM = NDS32_R5_REGNUM, ++ NDS32_RET_REGNUM = NDS32_R0_REGNUM, ++}; ++ ++static inline void arch_kgdb_breakpoint(void) ++{ ++ asm __volatile__ ( "break 0x1ff\n" ); ++} ++ ++#endif /* !__ASSEMBLY__ */ ++#endif /* __ASM_NDS32_KGDB_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/kmap_types.h linux-3.4.110/arch/nds32/include/asm/kmap_types.h +--- linux-3.4.110.orig/arch/nds32/include/asm/kmap_types.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/kmap_types.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,29 @@ ++/* ++ * linux/arch/nds32/include/asm/kmap-types.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_KMAP_TYPES_H ++#define __NDS32_KMAP_TYPES_H ++ ++/* ++ * This is the "bare minimum". AIO seems to require this. ++ */ ++enum km_type { ++ KM_BOUNCE_READ, ++ KM_SKB_SUNRPC_DATA, ++ KM_SKB_DATA_SOFTIRQ, ++ KM_USER0, ++ KM_USER1, ++ KM_BIO_SRC_IRQ, ++ KM_BIO_DST_IRQ, ++ KM_PTE0, ++ KM_PTE1, ++ KM_IRQ0, ++ KM_IRQ1, ++ KM_SOFTIRQ0, ++ KM_SOFTIRQ1, ++ KM_TYPE_NR ++}; ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/kprobes.h linux-3.4.110/arch/nds32/include/asm/kprobes.h +--- linux-3.4.110.orig/arch/nds32/include/asm/kprobes.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/kprobes.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,86 @@ ++#ifndef _ASM_ANDES_KPROBES_H ++#define _ASM_ANDES_KPROBES_H ++/* ++ * Kernel Probes (KProbes) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) IBM Corporation, 2002, 2004 ++ * ++ * See arch/x86/kernel/kprobes.c for x86 kprobes history. ++ */ ++#include <linux/types.h> ++#include <linux/ptrace.h> ++#include <linux/percpu.h> ++ ++#define __ARCH_WANT_KPROBES_INSN_SLOT ++ ++struct pt_regs; ++struct kprobe; ++ ++typedef unsigned short kprobe_opcode_t; ++ ++#define MAX_INSN_SIZE 2 ++#define MAX_STACK_SIZE 64 ++#define MIN_STACK_SIZE(ADDR) \ ++ (((MAX_STACK_SIZE) < (((unsigned long)current_thread_info()) + \ ++ THREAD_SIZE - (unsigned long)(ADDR))) \ ++ ? (MAX_STACK_SIZE) \ ++ : (((unsigned long)current_thread_info()) + \ ++ THREAD_SIZE - (unsigned long)(ADDR))) ++#define regs_return_value(regs) ((regs)->NDS32_r0) ++#define flush_insn_slot(p) do { } while (0) ++#define kretprobe_blacklist_size 0 ++ ++void arch_remove_kprobe(struct kprobe *p); ++void kretprobe_trampoline(void); ++ ++/* Architecture specific copy of original instruction*/ ++struct arch_specific_insn { ++ /* copy of the original instruction */ ++ kprobe_opcode_t *insn; ++ /* ++ * boostable = -1: This instruction type is not boostable. ++ * boostable = 0: This instruction type is boostable. ++ * boostable = 1: This instruction has been boosted: we have ++ * added a relative jump after the instruction copy in insn, ++ * so no single-step and fixup are needed (unless there's ++ * a post_handler or break_handler). ++ */ ++ int boostable; ++}; ++ ++struct prev_kprobe { ++ struct kprobe *kp; ++ unsigned long status; ++ unsigned long old_flags; ++ unsigned long saved_flags; ++}; ++ ++/* per-cpu kprobe control block */ ++struct kprobe_ctlblk { ++ unsigned long kprobe_status; ++ unsigned long kprobe_old_flags; ++ unsigned long kprobe_saved_flags; ++ unsigned long *jprobe_saved_sp; ++ struct pt_regs jprobe_saved_regs; ++ kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE]; ++ struct prev_kprobe prev_kprobe; ++}; ++ ++extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); ++extern int kprobe_exceptions_notify(struct notifier_block *self, ++ unsigned long val, void *data); ++#endif /* _ASM_ANDES_KPROBES_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/kvm.h linux-3.4.110/arch/nds32/include/asm/kvm.h +--- linux-3.4.110.orig/arch/nds32/include/asm/kvm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/kvm.h 2016-04-07 10:20:50.898079322 +0200 +@@ -0,0 +1,9 @@ ++/* ++ * linux/arch/nds32/include/asm/kvm.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_KVM_H__ ++#define __NDS32_KVM_H__ ++ ++#endif /* __NDS32_KVM_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/l2_cache.h linux-3.4.110/arch/nds32/include/asm/l2_cache.h +--- linux-3.4.110.orig/arch/nds32/include/asm/l2_cache.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/l2_cache.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,134 @@ ++/* ++ * linux/arch/nds32/include/asm/l2_cache.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef L2_CACHE_H ++#define L2_CACHE_H ++ ++// CCTL_CMD_OP ++#define L2_CA_CONF_OFF 0x0 ++#define L2_IF_CONF_OFF 0x4 ++#define L2CC_SETUP_OFF 0x8 ++#define L2CC_PROT_OFF 0xC ++#define L2CC_CTRL_OFF 0x10 ++#define L2_INT_EN_OFF 0x20 ++#define L2_STA_OFF 0x24 ++#define RDERR_ADDR_OFF 0x28 ++#define WRERR_ADDR_OFF 0x2c ++#define EVDPTERR_ADDR_OFF 0x30 ++#define IMPL3ERR_ADDR_OFF 0x34 ++#define L2_CNT0_CTRL_OFF 0x40 ++#define L2_EVNT_CNT0_OFF 0x44 ++#define L2_CNT1_CTRL_OFF 0x48 ++#define L2_EVNT_CNT1_OFF 0x4c ++#define L2_CCTL_CMD_OFF 0x60 ++#define L2_CCTL_STATUS_OFF 0x64 ++#define L2_LINE_TAG_OFF 0x68 ++#define L2_LINE_DPT_OFF 0x70 ++ ++#define CCTL_CMD_L2_IX_INVAL 0x0 ++#define CCTL_CMD_L2_PA_INVAL 0x1 ++#define CCTL_CMD_L2_IX_WB 0x2 ++#define CCTL_CMD_L2_PA_WB 0x3 ++#define CCTL_CMD_L2_PA_WBINVAL 0x5 ++#define CCTL_CMD_L2_SYNC 0xa ++// CCTL_CMD_TYPE ++#define CCTL_SINGLE_CMD 0 ++#define CCTL_BLOCK_CMD 0x10 ++#define CCTL_ALL_CMD 0x10 ++ ++/****************************************************************************** ++ * L2_CA_CONF (Cache architecture configuration) ++ *****************************************************************************/ ++#define L2_CA_CONF_offL2SET 0 ++#define L2_CA_CONF_offL2WAY 4 ++#define L2_CA_CONF_offL2CLSZ 8 ++#define L2_CA_CONF_offL2DW 11 ++#define L2_CA_CONF_offL2PT 14 ++#define L2_CA_CONF_offL2VER 16 ++ ++#define L2_CA_CONF_mskL2SET (0xFUL << L2_CA_CONF_offL2SET) ++#define L2_CA_CONF_mskL2WAY (0xFUL << L2_CA_CONF_offL2WAY) ++#define L2_CA_CONF_mskL2CLSZ (0x7UL << L2_CA_CONF_offL2CLSZ) ++#define L2_CA_CONF_mskL2DW (0x7UL << L2_CA_CONF_offL2DW) ++#define L2_CA_CONF_mskL2PT (0x3UL << L2_CA_CONF_offL2PT) ++#define L2_CA_CONF_mskL2VER (0xFFFFUL << L2_CA_CONF_offL2VER) ++ ++/****************************************************************************** ++ * L2CC_SETUP (L2CC Setup register) ++ *****************************************************************************/ ++#define L2CC_SETUP_offPART 0 ++#define L2CC_SETUP_mskPART (0x3UL << L2CC_SETUP_offPART) ++#define L2CC_SETUP_offDDLATC 4 ++#define L2CC_SETUP_mskDDLATC (0x3UL << L2CC_SETUP_offDDLATC) ++#define L2CC_SETUP_offTDLATC 8 ++#define L2CC_SETUP_mskTDLATC (0x3UL << L2CC_SETUP_offTDLATC) ++ ++/****************************************************************************** ++ * L2CC_PROT (L2CC Protect register) ++ *****************************************************************************/ ++#define L2CC_PROT_offMRWEN 31 ++#define L2CC_PROT_mskMRWEN (0x1UL << L2CC_PROT_offMRWEN) ++//TODO finish this table ++// ++/****************************************************************************** ++ * L2_CCTL_STATUS_Mn (The L2CCTL command working status for Master n) ++ *****************************************************************************/ ++#define L2CC_CTRL_offEN 31 ++#define L2CC_CTRL_mskEN (0x1UL << L2CC_CTRL_offEN) ++ ++/****************************************************************************** ++ * L2_CCTL_STATUS_Mn (The L2CCTL command working status for Master n) ++ *****************************************************************************/ ++#define L2_CCTL_STATUS_offCMD_COMP 31 ++#define L2_CCTL_STATUS_mskCMD_COMP (0x1 << L2_CCTL_STATUS_offCMD_COMP) ++//TODO finish this table ++ ++#ifndef __ASSEMBLY__ ++ ++#include <linux/smp.h> ++#include <asm/io.h> ++#include <asm/bitfield.h> ++ ++#define L2C_R_REG(offset) inl(L2CC_VA_BASE + offset) ++#define L2C_W_REG(offset, value) outl(value, L2CC_VA_BASE + offset) ++ ++#define L2_CMD_RDY() \ ++ do{;}while((L2C_R_REG(L2_CCTL_STATUS_OFF) & L2_CCTL_STATUS_mskCMD_COMP) == 0) ++ ++static inline unsigned long L2_CACHE_SET(void){ ++ return 64 << ( ( L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2SET) >> L2_CA_CONF_offL2SET); ++} ++ ++static inline unsigned long L2_CACHE_WAY(void){ ++ return 1 + ( ( L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2WAY) >> L2_CA_CONF_offL2WAY); ++} ++ ++static inline unsigned long L2_CACHE_LINE_SIZE(void){ ++ ++ return 4 << ( ( L2C_R_REG(L2_CA_CONF_OFF) & L2_CA_CONF_mskL2CLSZ) >> L2_CA_CONF_offL2CLSZ); ++} ++ ++static inline unsigned long GET_L2CC_CTRL_CPU(unsigned long cpu){ ++ if(cpu == smp_processor_id()) ++ return L2C_R_REG(L2CC_CTRL_OFF); ++ return L2C_R_REG(L2CC_CTRL_OFF+(cpu<<8)); ++} ++ ++static inline void SET_L2CC_CTRL_CPU(unsigned long cpu , unsigned long val){ ++ if(cpu == smp_processor_id()) ++ L2C_W_REG(L2CC_CTRL_OFF,val); ++ else ++ L2C_W_REG(L2CC_CTRL_OFF+(cpu<<8),val); ++} ++ ++static inline unsigned long GET_L2CC_STATUS_CPU(unsigned long cpu){ ++ if(cpu == smp_processor_id()) ++ return L2C_R_REG(L2_CCTL_STATUS_OFF); ++ return L2C_R_REG(L2_CCTL_STATUS_OFF+(cpu<<8)); ++} ++ ++#endif ++ ++#endif //L2_CACHE_H +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/leds.h linux-3.4.110/arch/nds32/include/asm/leds.h +--- linux-3.4.110.orig/arch/nds32/include/asm/leds.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/leds.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,51 @@ ++/* ++ * linux/arch/nds32/include/asm/leds.h ++ * ++ * Copyright (C) 1998 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Event-driven interface for LEDs on machines ++ * Added led_start and led_stop- Alex Holden, 28th Dec 1998. ++ */ ++#ifndef ASM_NDS32_LEDS_H ++#define ASM_NDS32_LEDS_H ++ ++ ++typedef enum { ++ led_idle_start, ++ led_idle_end, ++ led_timer, ++ led_start, ++ led_stop, ++ led_claim, /* override idle & timer leds */ ++ led_release, /* restore idle & timer leds */ ++ led_start_timer_mode, ++ led_stop_timer_mode, ++ led_green_on, ++ led_green_off, ++ led_amber_on, ++ led_amber_off, ++ led_red_on, ++ led_red_off, ++ led_blue_on, ++ led_blue_off, ++ /* ++ * I want this between led_timer and led_start, but ++ * someone has decided to export this to user space ++ */ ++ led_halted ++} led_event_t; ++ ++/* Use this routine to handle LEDs */ ++ ++#ifdef CONFIG_LEDS ++extern void (*leds_event)(led_event_t); ++#else ++#define leds_event(e) ++#endif ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/limits.h linux-3.4.110/arch/nds32/include/asm/limits.h +--- linux-3.4.110.orig/arch/nds32/include/asm/limits.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/limits.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,16 @@ ++/* ++ * linux/arch/nds32/include/asm/limits.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ASM_PIPE_H ++#define __ASM_PIPE_H ++ ++#ifndef PAGE_SIZE ++#include <asm/page.h> ++#endif ++ ++#define PIPE_BUF PAGE_SIZE ++ ++#endif ++ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/linkage.h linux-3.4.110/arch/nds32/include/asm/linkage.h +--- linux-3.4.110.orig/arch/nds32/include/asm/linkage.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/linkage.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,12 @@ ++/* ++ * linux/arch/nds32/include/asm/linkage.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_LINKAGE_H__ ++#define __NDS32_LINKAGE_H__ ++ ++#define __ALIGN .align 2 ++#define __ALIGN_STR ".align 2" ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/local.h linux-3.4.110/arch/nds32/include/asm/local.h +--- linux-3.4.110.orig/arch/nds32/include/asm/local.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/local.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/local.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_LOCAL_H__ ++#define __NDS32_LOCAL_H__ ++ ++#include <asm-generic/local.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mach/arch.h linux-3.4.110/arch/nds32/include/asm/mach/arch.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mach/arch.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mach/arch.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,86 @@ ++/* ++ * linux/arch/nds32/include/asm/mach/arch.h ++ * ++ * Copyright (C) 2000 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#ifndef __ASSEMBLY__ ++ ++struct tag; ++struct meminfo; ++struct sys_timer; ++ ++struct machine_desc { ++ /* ++ * Note! The first four elements are used ++ * by assembler code in head-armv.S ++ */ ++ unsigned int nr; /* architecture number */ ++ ++ const char *name; /* architecture name */ ++ unsigned int param_offset; /* parameter page */ ++ ++ unsigned int video_start; /* start of video RAM */ ++ unsigned int video_end; /* end of video RAM */ ++ ++ unsigned int reserve_lp0 :1; /* never has lp0 */ ++ unsigned int reserve_lp1 :1; /* never has lp1 */ ++ unsigned int reserve_lp2 :1; /* never has lp2 */ ++ unsigned int soft_reboot :1; /* soft reboot */ ++ void (*fixup)(struct machine_desc *, ++ struct tag *, char **, ++ struct meminfo *); ++ void (*map_io)(void);/* IO mapping function */ ++ void (*init_irq)(void); ++ struct sys_timer *timer; /* system tick timer */ ++ void (*init_machine)(void); ++}; ++ ++/* ++ * * Current machine - only accessible during boot. ++ * */ ++extern struct machine_desc *machine_desc; ++ ++/* ++ * Set of macros to define architecture features. This is built into ++ * a table by the linker. ++ */ ++#define MACHINE_START(_type,_name) \ ++const struct machine_desc __mach_desc_##_type \ ++ __attribute__((__section__(".arch.info"))) = { \ ++ .nr = MACH_TYPE_##_type, \ ++ .name = _name, ++ ++#define MAINTAINER(n) ++ ++#define BOOT_PARAMS(_params) \ ++ .param_offset = _params, ++ ++#define VIDEO(_start,_end) \ ++ .video_start = _start, \ ++ .video_end = _end, ++ ++#define DISABLE_PARPORT(_n) \ ++ .reserve_lp##_n = 1, ++ ++#define SOFT_REBOOT \ ++ .soft_reboot = 1, ++ ++#define MAPIO(_func) \ ++ .map_io = _func, ++ ++#define INITIRQ(_func) \ ++ .init_irq = _func, ++ ++#define INIT_MACHINE(_func) \ ++ .init_machine = _func, ++ ++#define MACHINE_END \ ++}; ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mach/dma.h linux-3.4.110/arch/nds32/include/asm/mach/dma.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mach/dma.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mach/dma.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,56 @@ ++/* ++ * linux/arch/nds32/include/asm/mach/dma.h ++ * ++ * Copyright (C) 1998-2000 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This header file describes the interface between the generic DMA handler ++ * (dma.c) and the architecture-specific DMA backends (dma-*.c) ++ */ ++ ++struct dma_struct; ++typedef struct dma_struct dma_t; ++ ++struct dma_ops { ++ int (*request)(dmach_t, dma_t *); /* optional */ ++ void (*free)(dmach_t, dma_t *); /* optional */ ++ void (*enable)(dmach_t, dma_t *); /* mandatory */ ++ void (*disable)(dmach_t, dma_t *); /* mandatory */ ++ int (*residue)(dmach_t, dma_t *); /* optional */ ++ int (*setspeed)(dmach_t, dma_t *, int); /* optional */ ++ char *type; ++}; ++ ++struct dma_struct { ++ struct scatterlist buf; /* single DMA */ ++ int sgcount; /* number of DMA SG */ ++ struct scatterlist *sg; /* DMA Scatter-Gather List */ ++ ++ unsigned int active:1; /* Transfer active */ ++ unsigned int invalid:1; /* Address/Count changed */ ++ unsigned int using_sg:1; /* using scatter list? */ ++ dmamode_t dma_mode; /* DMA mode */ ++ int speed; /* DMA speed */ ++ ++ unsigned int lock; /* Device is allocated */ ++ const char *device_id; /* Device name */ ++ ++ unsigned int dma_base; /* Controller base address */ ++ int dma_irq; /* Controller IRQ */ ++ struct scatterlist cur_sg; /* Current controller buffer */ ++ unsigned int state; ++ ++ struct dma_ops *d_ops; ++}; ++ ++/* Prototype: void arch_dma_init(dma) ++ * Purpose : Initialise architecture specific DMA ++ * Params : dma - pointer to array of DMA structures ++ */ ++extern void arch_dma_init(dma_t *dma); ++ ++extern void isa_init_dma(dma_t *dma); +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mach/flash.h linux-3.4.110/arch/nds32/include/asm/mach/flash.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mach/flash.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mach/flash.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,35 @@ ++/* ++ * linux/arch/nds32/include/asm/mach/flash.h ++ * ++ * Copyright (C) 2003 Russell King, All Rights Reserved. ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef ASMNDS32_MACH_FLASH_H ++#define ASMNDS32_MACH_FLASH_H ++ ++struct mtd_partition; ++ ++/* ++ * map_name: the map probe function name ++ * width: width of mapped device ++ * init: method called at driver/device initialisation ++ * exit: method called at driver/device removal ++ * set_vpp: method called to enable or disable VPP ++ * parts: optional array of mtd_partitions for static partitioning ++ * nr_parts: number of mtd_partitions for static partitoning ++ */ ++struct flash_platform_data { ++ const char *map_name; ++ unsigned int width; ++ int (*init)(void); ++ void (*exit)(void); ++ void (*set_vpp)(int on); ++ struct mtd_partition *parts; ++ unsigned int nr_parts; ++}; ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mach/irda.h linux-3.4.110/arch/nds32/include/asm/mach/irda.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mach/irda.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mach/irda.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,21 @@ ++/* ++ * linux/arch/nds32/include/asm/mach/irda.h ++ * ++ * Copyright (C) 2004 Russell King. ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __ASM_NDS32_MACH_IRDA_H ++#define __ASM_NDS32_MACH_IRDA_H ++ ++struct irda_platform_data { ++ int (*startup)(struct device *); ++ void (*shutdown)(struct device *); ++ int (*set_power)(struct device *, unsigned int state); ++ void (*set_speed)(struct device *, unsigned int speed); ++}; ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mach/map.h linux-3.4.110/arch/nds32/include/asm/mach/map.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mach/map.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mach/map.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,37 @@ ++/* ++ * linux/arch/nds32/include/asm/mach/map.h ++ * ++ * Copyright (C) 1999-2000 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Page table mapping constructs and function prototypes ++ */ ++struct map_desc { ++ unsigned long virtual; ++ unsigned long physical; ++ unsigned long length; ++ unsigned int type; ++}; ++ ++struct meminfo; ++ ++#define MT_DEVICE_NCB MT_DEVICE ++#define MT_DEVICE_NCNB MT_DEVICE ++#define MT_DEVICE 0 ++#define MT_CACHECLEAN 1 ++#define MT_MINICLEAN 2 ++#define MT_CACHE_L1 3 ++#define MT_UXKRWX_V1 4 ++#define MT_UXKRWX_V2 5 ++#define MT_MEMORY 6 ++#define MT_ROM 7 ++#define MT_ILM 8 ++#define MT_DLM 9 ++ ++extern void create_memmap_holes(struct meminfo *); ++extern void iotable_init(struct map_desc *, int); ++extern void setup_io_desc(void); +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mach/mmc.h linux-3.4.110/arch/nds32/include/asm/mach/mmc.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mach/mmc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mach/mmc.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,16 @@ ++/* ++ * linux/arch/nds32/include/asm/mach/mmc.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++#ifndef ASMNDS32_MACH_MMC_H ++#define ASMNDS32_MACH_MMC_H ++ ++#include <linux/mmc/protocol.h> ++ ++struct mmc_platform_data { ++ unsigned int ocr_mask; /* available voltages */ ++ u32 (*translate_vdd)(struct device *, unsigned int); ++ unsigned int (*status)(struct device *); ++}; ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mach/pci.h linux-3.4.110/arch/nds32/include/asm/mach/pci.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mach/pci.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mach/pci.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,76 @@ ++/* ++ * linux/arch/nds32/include/asm/mach/pci.h ++ * ++ * Copyright (C) 2000 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++struct pci_sys_data; ++struct pci_bus; ++ ++struct hw_pci { ++ struct list_head buses; ++ int nr_controllers; ++ int (*setup)(int nr, struct pci_sys_data *); ++ struct pci_bus *(*scan)(int nr, struct pci_sys_data *); ++ void (*preinit)(void); ++ void (*postinit)(void); ++ u8 (*swizzle)(struct pci_dev *dev, u8 *pin); ++ int (*map_irq)(struct pci_dev *dev, u8 slot, u8 pin); ++}; ++ ++/* ++ * Per-controller structure ++ */ ++struct pci_sys_data { ++ struct list_head node; ++ int busnr; /* primary bus number */ ++ unsigned long mem_offset; /* bus->cpu memory mapping offset */ ++ unsigned long io_offset; /* bus->cpu IO mapping offset */ ++ struct pci_bus *bus; /* PCI bus */ ++ struct resource *resource[3]; /* Primary PCI bus resources */ ++ /* Bridge swizzling */ ++ u8 (*swizzle)(struct pci_dev *, u8 *); ++ /* IRQ mapping */ ++ int (*map_irq)(struct pci_dev *, u8, u8); ++ struct hw_pci *hw; ++}; ++ ++/* ++ * This is the standard PCI-PCI bridge swizzling algorithm. ++ */ ++u8 pci_std_swizzle(struct pci_dev *dev, u8 *pinp); ++ ++/* ++ * Call this with your hw_pci struct to initialise the PCI system. ++ */ ++void pci_common_init(struct hw_pci *); ++ ++/* ++ * PCI controllers ++ */ ++extern int iop321_setup(int nr, struct pci_sys_data *); ++extern struct pci_bus *iop321_scan_bus(int nr, struct pci_sys_data *); ++extern void iop321_init(void); ++ ++extern int iop331_setup(int nr, struct pci_sys_data *); ++extern struct pci_bus *iop331_scan_bus(int nr, struct pci_sys_data *); ++extern void iop331_init(void); ++ ++extern int dc21285_setup(int nr, struct pci_sys_data *); ++extern struct pci_bus *dc21285_scan_bus(int nr, struct pci_sys_data *); ++extern void dc21285_preinit(void); ++extern void dc21285_postinit(void); ++ ++extern int via82c505_setup(int nr, struct pci_sys_data *); ++extern struct pci_bus *via82c505_scan_bus(int nr, struct pci_sys_data *); ++extern void via82c505_init(void *sysdata); ++ ++extern int pci_v3_setup(int nr, struct pci_sys_data *); ++extern struct pci_bus *pci_v3_scan_bus(int nr, struct pci_sys_data *); ++extern void pci_v3_preinit(void); ++extern void pci_v3_postinit(void); +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mach/serial_sa1100.h linux-3.4.110/arch/nds32/include/asm/mach/serial_sa1100.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mach/serial_sa1100.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mach/serial_sa1100.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,31 @@ ++/* ++ * linux/include/asm-arm/mach/serial_sa1100.h ++ * ++ * Author: Nicolas Pitre ++ * ++ * Moved to include/asm-arm/mach and changed lots, Russell King ++ * ++ * Low level machine dependent UART functions. ++ */ ++ ++struct uart_port; ++struct uart_info; ++ ++/* ++ * This is a temporary structure for registering these ++ * functions; it is intended to be discarded after boot. ++ */ ++struct sa1100_port_fns { ++ void (*set_mctrl)(struct uart_port *, u_int); ++ u_int (*get_mctrl)(struct uart_port *); ++ void (*pm)(struct uart_port *, u_int, u_int); ++ int (*set_wake)(struct uart_port *, u_int); ++}; ++ ++#ifdef CONFIG_SERIAL_SA1100 ++void sa1100_register_uart_fns(struct sa1100_port_fns *fns); ++void sa1100_register_uart(int idx, int port); ++#else ++#define sa1100_register_uart_fns(fns) do { } while (0) ++#define sa1100_register_uart(idx,port) do { } while (0) ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mach/time.h linux-3.4.110/arch/nds32/include/asm/mach/time.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mach/time.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mach/time.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,62 @@ ++/* ++ * linux/arch/nds32/include/asm/mach/time.h ++ * ++ * Copyright (C) 2004 MontaVista Software, Inc. ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __ASM_NDS32_MACH_TIME_H ++#define __ASM_NDS32_MACH_TIME_H ++ ++//#include <linux/sysdev.h> ++ ++/* ++ * This is our kernel timer structure. ++ * ++ * - init ++ * Initialise the kernels jiffy timer source, claim interrupt ++ * using setup_irq. This is called early on during initialisation ++ * while interrupts are still disabled on the local CPU. ++ * - suspend ++ * Suspend the kernel jiffy timer source, if necessary. This ++ * is called with interrupts disabled, after all normal devices ++ * have been suspended. If no action is required, set this to ++ * NULL. ++ * - resume ++ * Resume the kernel jiffy timer source, if necessary. This ++ * is called with interrupts disabled before any normal devices ++ * are resumed. If no action is required, set this to NULL. ++ * - offset ++ * Return the timer offset in microseconds since the last timer ++ * interrupt. Note: this must take account of any unprocessed ++ * timer interrupt which may be pending. ++ */ ++ ++/* + Tom from newlib ++ * Have the 32 bit jiffies value wrap 5 minutes after boot ++ * so jiffies wrap bugs show up earlier. ++ */ ++//#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) ++ ++struct sys_timer { ++// struct sys_device dev; ++ void (*init)(void); ++ void (*suspend)(void); ++ void (*resume)(void); ++ unsigned long (*offset)(void); ++}; ++ ++extern struct sys_timer *system_timer; ++extern void timer_tick( void); ++ ++/* ++ * Kernel time keeping support. ++ */ ++extern int (*set_rtc)(void); ++extern void save_time_delta(struct timespec *delta, struct timespec *rtc); ++extern void restore_time_delta(struct timespec *delta, struct timespec *rtc); ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mach-types.h linux-3.4.110/arch/nds32/include/asm/mach-types.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mach-types.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mach-types.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,14 @@ ++#ifndef __ASSEMBLY__ ++/* The type of machine we're running on */ ++extern unsigned int __machine_arch_type; ++#endif ++ ++#define MACH_TYPE_FARADAY 758 ++ ++# ifdef machine_arch_type ++# undef machine_arch_type ++# define machine_arch_type __machine_arch_type ++# else ++# define machine_arch_type MACH_TYPE_FARADAY ++# endif ++# define machine_is_faraday() (machine_arch_type == MACH_TYPE_FARADAY) +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/memory.h linux-3.4.110/arch/nds32/include/asm/memory.h +--- linux-3.4.110.orig/arch/nds32/include/asm/memory.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/memory.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,218 @@ ++/* ++ * linux/arch/nds32/include/asm/memory.h ++ * ++ * Copyright (C) 2000-2002 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Note: this file should not be included by non-asm/.h files ++ */ ++#ifndef __ASM_NDS32_MEMORY_H ++#define __ASM_NDS32_MEMORY_H ++ ++#include <linux/compiler.h> ++#ifndef __FARADAY_PLATFORM_INDEPENDENT_MEMORY_HEADER__ ++#define __FARADAY_PLATFORM_INDEPENDENT_MEMORY_HEADER__ ++ ++#include <asm/spec.h> ++ ++#ifndef __ASSEMBLY__ ++#include <asm/page.h> ++#endif ++ ++#ifndef PHYS_OFFSET ++#define PHYS_OFFSET CPU_MEM_PA_BASE ++#endif ++ ++#ifndef PAGE_OFFSET ++#define PAGE_OFFSET (0xC0000000) ++#endif ++ ++#ifndef END_MEM ++#define END_MEM (CPU_MEM_PA_LIMIT) ++#endif ++ ++#ifndef __virt_to_bus ++#define __virt_to_bus __virt_to_phys ++#endif ++ ++#ifndef __bus_to_virt ++#define __bus_to_virt __phys_to_virt ++#endif ++ ++#endif /* __FARADAY_PLATFORM_INDEPENDENT_MEMORY_HEADER__ */ ++ ++#ifndef TASK_SIZE ++/* ++ * TASK_SIZE - the maximum size of a user space task. ++ * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area ++ */ ++#define TASK_SIZE (0xbf000000UL) ++#define TASK_UNMAPPED_BASE (0x40000000UL) ++#endif ++ ++/* ++ * Page offset: 3GB ++ */ ++#ifndef PAGE_OFFSET ++#define PAGE_OFFSET (0xc0000000) ++#endif ++ ++/* ++ * Physical vs virtual RAM address space conversion. These are ++ * private definitions which should NOT be used outside memory.h ++ * files. Use virt_to_phys/phys_to_virt/__pa/__va instead. ++ */ ++#ifndef __virt_to_phys ++#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET) ++#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) ++#endif ++ ++/* ++ * The module space lives between the addresses given by TASK_SIZE ++ * and PAGE_OFFSET - it must be within 32MB of the kernel text. ++ */ ++#define MODULES_END (PAGE_OFFSET) ++#define MODULES_VADDR (MODULES_END - 16*1048576) ++ ++#if TASK_SIZE > MODULES_VADDR ++#error Top of user space clashes with start of module space ++#endif ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * The DMA mask corresponding to the maximum bus address allocatable ++ * using GFP_DMA. The default here places no restriction on DMA ++ * allocations. This must be the smallest DMA mask in the system, ++ * so a successful GFP_DMA allocation will always satisfy this. ++ */ ++#ifndef ISA_DMA_THRESHOLD ++#define ISA_DMA_THRESHOLD (0xffffffffULL) ++#endif ++ ++#ifndef arch_adjust_zones ++#define arch_adjust_zones(node,size,holes) do { } while (0) ++#endif ++ ++/* ++ * PFNs are used to describe any physical page; this means ++ * PFN 0 == physical address 0. ++ * ++ * This is the PFN of the first RAM page in the kernel ++ * direct-mapped view. We assume this is the first page ++ * of RAM in the mem_map as well. ++ */ ++#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT) ++ ++/* ++ * These are *only* valid on the kernel direct mapped RAM memory. ++ * Note: Drivers should NOT use these. They are the wrong ++ * translation for translating DMA addresses. Use the driver ++ * DMA support - see dma-mapping.h. ++ */ ++static inline unsigned long virt_to_phys(void *x) ++{ ++ return __virt_to_phys((unsigned long)(x)); ++} ++ ++static inline void *phys_to_virt(unsigned long x) ++{ ++ return (void *)(__phys_to_virt((unsigned long)(x))); ++} ++ ++/* ++ * Drivers should NOT use these either. ++ */ ++#define __pa(x) __virt_to_phys((unsigned long)(x)) ++#define __va(x) ((void *)__phys_to_virt((unsigned long)(x))) ++ ++/* ++ * Virtual <-> DMA view memory address translations ++ * Again, these are *only* valid on the kernel direct mapped RAM ++ * memory. Use of these is *deprecated* (and that doesn't mean ++ * use the __ prefixed forms instead.) See dma-mapping.h. ++ */ ++static inline __deprecated unsigned long virt_to_bus(void *x) ++{ ++ return __virt_to_bus((unsigned long)x); ++} ++ ++static inline __deprecated void *bus_to_virt(unsigned long x) ++{ ++ return (void *)__bus_to_virt(x); ++} ++ ++/* ++ * Conversion between a struct page and a physical address. ++ * ++ * Note: when converting an unknown physical address to a ++ * struct page, the resulting pointer must be validated ++ * using VALID_PAGE(). It must return an invalid struct page ++ * for any physical address not corresponding to a system ++ * RAM address. ++ * ++ * pfn_valid(pfn) indicates whether a PFN number is valid ++ * ++ * virt_to_page(k) convert a _valid_ virtual address to struct page * ++ * virt_addr_valid(k) indicates whether a virtual address is valid ++ */ ++#ifndef CONFIG_DISCONTIGMEM ++ ++#define ARCH_PFN_OFFSET PHYS_PFN_OFFSET ++#define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr)) ++ ++#define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)) ++#define virt_addr_valid(kaddr) ((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory) ++ ++#define PHYS_TO_NID(addr) (0) ++ ++#else /* CONFIG_DISCONTIGMEM */ ++ ++/* ++ * This is more complex. We have a set of mem_map arrays spread ++ * around in memory. ++ */ ++#include <linux/numa.h> ++ ++#define pfn_valid(pfn) (PFN_TO_NID(pfn) < MAX_NUMNODES) ++ ++#define virt_to_page(kaddr) \ ++ (ADDR_TO_MAPBASE(kaddr) + LOCAL_MAP_NR(kaddr)) ++#define virt_addr_valid(kaddr) (KVADDR_TO_NID(kaddr) < MAX_NUMNODES) ++ ++/* ++ * Common discontigmem stuff. ++ * PHYS_TO_NID is used by the NDS32 kernel/setup.c ++ */ ++#define PHYS_TO_NID(addr) PFN_TO_NID((addr) >> PAGE_SHIFT) ++ ++#endif /* !CONFIG_DISCONTIGMEM */ ++ ++/* ++ * For BIO. "will die". Kill me when bio_to_phys() and bvec_to_phys() die. ++ */ ++#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) ++ ++/* ++ * Optional device DMA address remapping. Do _not_ use directly! ++ * We should really eliminate virt_to_bus() here - it's deprecated. ++ */ ++#ifndef __arch_page_to_dma ++#define page_to_dma(dev, page) ((dma_addr_t)__virt_to_bus((unsigned long)page_address(page))) ++#define dma_to_virt(dev, addr) ((void *)__bus_to_virt(addr)) ++#define virt_to_dma(dev, addr) ((dma_addr_t)__virt_to_bus((unsigned long)(addr))) ++#else ++#define page_to_dma(dev, page) (__arch_page_to_dma(dev, page)) ++#define dma_to_virt(dev, addr) (__arch_dma_to_virt(dev, addr)) ++#define virt_to_dma(dev, addr) (__arch_virt_to_dma(dev, addr)) ++#endif ++ ++#endif ++ ++#include <asm-generic/memory_model.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/misc_spec.h linux-3.4.110/arch/nds32/include/asm/misc_spec.h +--- linux-3.4.110.orig/arch/nds32/include/asm/misc_spec.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/misc_spec.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,75 @@ ++/* ++ * linux/arch/nds32/include/asm/misc_spec.h ++ * ++ * Faraday A320D platform dependent definitions ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ChangeLog ++ * ++ * Luke Lee 09/14/2005 Created ++ * Luke Lee 10/06/2005 Modified for automatic system clock rate ++ */ ++ ++#ifndef __A320_PLATFORM_MANUAL_DEFINITION__ ++#define __A320_PLATFORM_MANUAL_DEFINITION__ ++ ++#define BOOT_PARAMETER_PA_BASE (PHYS_OFFSET + 0x400) ++ ++#ifdef CONFIG_AUTO_SYS_CLK ++ ++#ifndef __ASSEMBLY__ ++extern int ag101_get_ahb_clk(void); ++extern int ag102_get_ahb_clk(void); ++ ++#if defined(CONFIG_PLAT_AG101) ++#define AHB_CLK_IN ag101_get_ahb_clk() ++#elif defined(CONFIG_PLAT_AG102) ++#define AHB_CLK_IN ag102_get_ahb_clk() ++ ++#endif ++ ++#endif ++#define TIMER_CLK_IN (CONFIG_SYS_CLK/2) ++ ++#else ++ ++/* Timer clock input is APB CLOCK */ ++#define TIMER_CLK_IN (CONFIG_SYS_CLK/2) ++#define AHB_CLK_IN (CONFIG_SYS_CLK) ++ ++#endif ++ ++#ifndef __ASSEMBLY__ ++#include <linux/init.h> ++ ++#ifdef CONFIG_PLATFORM_INTC ++extern void __init intc_ftintc010_init_irq(void); ++#define platform_init_irq intc_ftintc010_init_irq ++#endif ++ ++#ifdef CONFIG_PLATFORM_NOINTC ++extern void __init nointc_init_irq(void); ++#define platform_init_irq nointc_init_irq ++#endif ++ ++#endif ++ ++#define daughter_platform_init_irq(x) /* NOP */ ++ ++#endif /*__A320_PLATFORM_MANUAL_DEFINITION__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mman.h linux-3.4.110/arch/nds32/include/asm/mman.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mman.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mman.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,22 @@ ++/* ++ * linux/arch/nds32/include/asm/mman.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_MMAN_H__ ++#define __NDS32_MMAN_H__ ++ ++#include <asm-generic/mman.h> ++ ++#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ ++#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ ++#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ ++#define MAP_LOCKED 0x2000 /* pages are locked */ ++#define MAP_NORESERVE 0x4000 /* don't check for reservations */ ++#define MAP_POPULATE 0x8000 /* populate (prefault) page tables */ ++#define MAP_NONBLOCK 0x10000 /* do not block on IO */ ++ ++#define MCL_CURRENT 1 /* lock all current mappings */ ++#define MCL_FUTURE 2 /* lock all future mappings */ ++ ++#endif /* __NDS32_MMAN_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mmu_context.h linux-3.4.110/arch/nds32/include/asm/mmu_context.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mmu_context.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mmu_context.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,84 @@ ++/* ++ * linux/arch/nds32/include/asm/mmu_context.h ++ * ++ * Copyright (C) 1996 Russell King. ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Changelog: ++ * 27-06-1996 RMK Created ++ */ ++#ifndef __ASM_NDS32_MMU_CONTEXT_H ++#define __ASM_NDS32_MMU_CONTEXT_H ++ ++#include <linux/spinlock.h> ++#include <asm/tlbflush.h> ++#include <asm-generic/mm_hooks.h> ++ ++static inline int ++init_new_context(struct task_struct *tsk, struct mm_struct *mm) ++{ ++ mm->context.id = 0; ++ return 0; ++} ++ ++#define destroy_context(mm) do { } while(0) ++ ++#ifndef CONFIG_CPU_NO_CONTEXT_ID ++#define CID_BITS 9 ++extern spinlock_t cid_lock; ++extern unsigned int cpu_last_cid; ++ ++static inline void ++__new_context(struct mm_struct *mm) ++{ ++ unsigned int cid; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&cid_lock, flags); ++ cid = cpu_last_cid; ++ cpu_last_cid += 1 << TLB_MISC_offCID; ++ if (cpu_last_cid == 0) ++ cpu_last_cid = 1 << TLB_MISC_offCID << CID_BITS; ++ spin_unlock_irqrestore(&cid_lock, flags); ++ ++ if ((cid & TLB_MISC_mskCID ) == 0) ++ flush_tlb_all(); ++ ++ mm->context.id = cid; ++} ++ ++static inline void ++check_context(struct mm_struct *mm) ++{ ++ if (unlikely((mm->context.id ^ cpu_last_cid) >> TLB_MISC_offCID >> CID_BITS)) ++ __new_context(mm); ++} ++#else ++#define check_context(m) ++#endif ++ ++static inline void ++enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) ++{ ++} ++ ++static inline void ++switch_mm(struct mm_struct *prev, struct mm_struct *next, ++ struct task_struct *tsk) ++{ ++ unsigned int cpu = smp_processor_id(); ++ ++ if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) { ++ check_context(next); ++ cpu_switch_mm(next); ++ } ++} ++ ++#define deactivate_mm(tsk,mm) do { } while (0) ++#define activate_mm(prev,next) switch_mm(prev, next, NULL) ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mmu.h linux-3.4.110/arch/nds32/include/asm/mmu.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mmu.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mmu.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,42 @@ ++/* ++ * linux/arch/nds32/include/asm/mmu.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_MMU_H ++#define __NDS32_MMU_H ++ ++typedef struct { ++ unsigned int id; ++} mm_context_t; ++ ++#define ASID(mm) ((mm)->context.id & (TLB_MISC_mskCID >> TLB_MISC_offCID)) ++inline static unsigned long ACC_PSZ(unsigned long page_size) ++{ ++ switch(page_size) { ++ case(1<<12): ++ return 0; ++ case(1<<13): ++ return 1; ++ case(1<<14): ++ return 2; ++ case(1<<16): ++ return 3; ++ case(1<<18): ++ return 4; ++ case(1<<20): ++ return 5; ++ case(1<<22): ++ return 6; ++ case(1<<24): ++ return 7; ++ case(1<<26): ++ return 8; ++ case(1<<28): ++ return 9; ++ default: ++ printk("Huge Page Size is not supported \n"); ++ return 0xffffffff; ++ } ++} ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/module.h linux-3.4.110/arch/nds32/include/asm/module.h +--- linux-3.4.110.orig/arch/nds32/include/asm/module.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/module.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,23 @@ ++/* ++ * linux/arch/nds32/include/asm/module.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASM_NDS32_MODULE_H ++#define _ASM_NDS32_MODULE_H ++ ++struct mod_arch_specific ++{ ++ int foo; ++}; ++ ++#define Elf_Shdr Elf32_Shdr ++#define Elf_Sym Elf32_Sym ++#define Elf_Ehdr Elf32_Ehdr ++ ++/* ++ * Include the ARM architecture version. ++ */ ++#define MODULE_ARCH_VERMAGIC "NDS32vN10" __stringify(__LINUX_NDS32_ARCH__) " " ++ ++#endif /* _ASM_NDS32_MODULE_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/msgbuf.h linux-3.4.110/arch/nds32/include/asm/msgbuf.h +--- linux-3.4.110.orig/arch/nds32/include/asm/msgbuf.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/msgbuf.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,36 @@ ++/* ++ * linux/arch/nds32/include/asm/msgbuf.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_MSGBUF_H ++#define _ASMNDS32_MSGBUF_H ++ ++/* ++ * The msqid64_ds structure for arm architecture. ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 64-bit time_t to solve y2038 problem ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct msqid64_ds { ++ struct ipc64_perm msg_perm; ++ __kernel_time_t msg_stime; /* last msgsnd time */ ++ unsigned long __unused1; ++ __kernel_time_t msg_rtime; /* last msgrcv time */ ++ unsigned long __unused2; ++ __kernel_time_t msg_ctime; /* last change time */ ++ unsigned long __unused3; ++ unsigned long msg_cbytes; /* current number of bytes on queue */ ++ unsigned long msg_qnum; /* number of messages in queue */ ++ unsigned long msg_qbytes; /* max number of bytes on queue */ ++ __kernel_pid_t msg_lspid; /* pid of last msgsnd */ ++ __kernel_pid_t msg_lrpid; /* last receive pid */ ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++ ++#endif /* _ASMNDS32_MSGBUF_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/mutex.h linux-3.4.110/arch/nds32/include/asm/mutex.h +--- linux-3.4.110.orig/arch/nds32/include/asm/mutex.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/mutex.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/mutex.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_MUTEX_H__ ++#define __NDS32_MUTEX_H__ ++ ++#include <asm-generic/mutex-dec.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/namei.h linux-3.4.110/arch/nds32/include/asm/namei.h +--- linux-3.4.110.orig/arch/nds32/include/asm/namei.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/namei.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/namei.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_NAMEI_H__ ++#define __NDS32_NAMEI_H__ ++ ++#define __emul_prefix() NULL ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/nds32.h linux-3.4.110/arch/nds32/include/asm/nds32.h +--- linux-3.4.110.orig/arch/nds32/include/asm/nds32.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/nds32.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,90 @@ ++/* ++ * linux/arch/nds32/include/asm/nds32.h -- Andes NDS32 processor register interface ++ * ++ * 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) 2006 Andes Technology Corporation ++ * ++ */ ++#ifndef _ASM_NDS32_NDS32_H_ ++#define _ASM_NDS32_NDS32_H_ ++ ++#include <asm/bitfield.h> ++#include <asm/reg_access.h> ++ ++#define MSYNC( subtype) __asm__ ("\n\tmsync "#subtype); ++#define STANDBY( cond) __asm__ ("\n\tstandby "#cond); ++ ++#ifndef __ASSEMBLY__ ++ ++static inline void ISB( void) { __asm__ ("\n\tisb"); } ++static inline void DSB( void) { __asm__ ("\n\tdsb"); } ++ ++static inline void GIE_ENABLE( void) ++{ ++ __asm__ ("gie_enable\n\t"); ++} ++ ++static inline void GIE_DISABLE( void) ++{ ++ __asm__ ("gie_disable\n\t"); ++} ++ ++enum cache_t{ ICACHE, DCACHE}; ++ ++static inline unsigned long CACHE_SET( enum cache_t cache){ ++ ++ if( cache == ICACHE) ++ return 64 << ( ( GET_ICM_CFG() & ICM_CFG_mskISET) >> ICM_CFG_offISET); ++ else ++ return 64 << ( ( GET_DCM_CFG() & DCM_CFG_mskDSET) >> DCM_CFG_offDSET); ++} ++ ++static inline unsigned long CACHE_WAY( enum cache_t cache){ ++ ++ if( cache == ICACHE) ++ return 1 + ( ( GET_ICM_CFG() & ICM_CFG_mskIWAY) >> ICM_CFG_offIWAY); ++ else ++ return 1 + ( ( GET_DCM_CFG() & DCM_CFG_mskDWAY) >> DCM_CFG_offDWAY); ++} ++ ++static inline unsigned long CACHE_LINE_SIZE( enum cache_t cache){ ++ ++ if( cache == ICACHE) ++ return 8 << ( ( ( GET_ICM_CFG() & ICM_CFG_mskISZ) >> ICM_CFG_offISZ) - 1); ++ else ++ return 8 << ( ( ( GET_DCM_CFG() & DCM_CFG_mskDSZ) >> DCM_CFG_offDSZ) - 1); ++} ++ ++static inline void GIE_SAVE( unsigned long *var){ ++ ++ *var = GET_PSW(); ++ GIE_DISABLE(); ++} ++ ++static inline void GIE_RESTORE( unsigned long var){ ++ ++ if( var & PSW_mskGIE){ ++ GIE_ENABLE(); ++ } ++} ++ ++#endif /* __ASSEMBLY__ */ ++ ++#define IVB_BASE PHYS_OFFSET /* in user space for intr/exc/trap/break table base, 64KB aligned ++ * We defined at the start of the physical memory */ ++ ++/* The following dispatching entry */ ++#define ENTRY_TLB_MISC (IVB_BASE + nrTLB_MISC*vENTRY_SZ) /* TLB misc eh# */ ++/* dispatched sub-entry exception handler numbering */ ++#define RD_PROT 0 /* read protrection */ ++#define WRT_PROT 1 /* write protection */ ++#define NOEXEC 2 /* non executable */ ++#define PAGE_MODIFY 3 /* page modified */ ++#define ACC_BIT 4 /* access bit */ ++#define RESVED_PTE 5 /* reserved PTE attribute */ ++/* reserved 6 ~ 16 */ ++ ++#endif /* _ASM_NDS32_NDS32_H_ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/numnodes.h linux-3.4.110/arch/nds32/include/asm/numnodes.h +--- linux-3.4.110.orig/arch/nds32/include/asm/numnodes.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/numnodes.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,25 @@ ++/* ++ * linux/arch/nds32/include/asm/numnodes.h ++ * ++ * Copyright (C) 2002 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++/* This declaration for the size of the NUMA (CONFIG_DISCONTIGMEM) ++ * memory node table is the default. ++ * ++ * A good place to override this value is include/asm/arch/memory.h. ++ */ ++ ++#ifndef __ASM_NDS32_NUMNODES_H ++#define __ASM_NDS32_NUMNODES_H ++ ++#ifndef NODES_SHIFT ++# define NODES_SHIFT 2 /* Normally, Max 4 Nodes */ ++#endif ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/page.h linux-3.4.110/arch/nds32/include/asm/page.h +--- linux-3.4.110.orig/arch/nds32/include/asm/page.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/page.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,153 @@ ++/* ++ * linux/arch/nds32/include/asm/page.h ++ * ++ * Copyright (C) 1995-2003 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef _ASMNDS32_PAGE_H ++#define _ASMNDS32_PAGE_H ++ ++ ++#ifdef CONFIG_ANDES_PAGE_SIZE_4KB ++#define PAGE_SHIFT 12 ++#endif ++#ifdef CONFIG_ANDES_PAGE_SIZE_8KB ++#define PAGE_SHIFT 13 ++#endif ++#include <linux/const.h> ++#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) ++#define PAGE_MASK (~(PAGE_SIZE-1)) ++#define PTE_MASK PAGE_MASK ++ ++/* PAGE_SHIFT determines the page size */ ++#define EXEC_PAGESIZE PAGE_SIZE ++ ++#ifdef CONFIG_ANDES_HUGETLB_PAGE_SIZE_16KB ++#define LARGE_PAGE_SHIFT 14 ++#define HPAGE_SHIFT 14 ++#endif ++ ++#ifdef CONFIG_ANDES_HUGETLB_PAGE_SIZE_64KB ++#define LARGE_PAGE_SHIFT 16 ++#define HPAGE_SHIFT 16 ++#endif ++ ++#ifdef CONFIG_ANDES_HUGETLB_PAGE_SIZE_256KB ++#define LARGE_PAGE_SHIFT 18 ++#define HPAGE_SHIFT 18 ++#endif ++#ifdef CONFIG_ANDES_HUGETLB_PAGE_SIZE_1MB ++#define LARGE_PAGE_SHIFT 20 ++#define HPAGE_SHIFT 20 ++#endif ++ ++#ifdef CONFIG_ANDES_HUGETLB_PAGE_SIZE_4MB ++#define LARGE_PAGE_SHIFT 22 ++#define HPAGE_SHIFT 22 ++#endif ++ ++#ifdef CONFIG_ANDES_HUGETLB_PAGE_SIZE_16MB ++#define LARGE_PAGE_SHIFT 24 ++#define HPAGE_SHIFT 24 ++#endif ++ ++#ifdef CONFIG_ANDES_HUGETLB_PAGE_SIZE_64MB ++#define LARGE_PAGE_SHIFT 26 ++#define HPAGE_SHIFT 26 ++#endif ++ ++#ifdef CONFIG_ANDES_HUGETLB_PAGE_SIZE_256MB ++#define LARGE_PAGE_SHIFT 28 ++#define HPAGE_SHIFT 28 ++#endif ++ ++#ifdef CONFIG_HUGETLB_PAGE ++// taken for i386 style ++#define LARGE_PAGE_SIZE (1UL << LARGE_PAGE_SHIFT) ++#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1)) ++// taken for SH style ++#define HPAGE_SIZE (1UL << HPAGE_SHIFT) ++#define HPAGE_MASK (~(HPAGE_SIZE-1)) ++#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT-PAGE_SHIFT) ++#endif ++ ++ ++#ifdef __KERNEL__ ++ ++#ifndef __ASSEMBLY__ ++ ++struct page; ++struct vm_area_struct; ++#ifndef CONFIG_CPU_CACHE_NONALIASING ++extern void copy_user_highpage(struct page *to, struct page *from, ++ unsigned long vaddr, struct vm_area_struct *vma); ++extern void clear_user_highpage(struct page *page, unsigned long vaddr); ++ ++#define __HAVE_ARCH_COPY_USER_HIGHPAGE ++#define clear_user_highpage clear_user_highpage ++#else ++#define clear_user_page(page, vaddr, pg) clear_page(page) ++#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) ++#endif ++ ++void clear_page(void *page); ++void copy_page(void *to, void *from); ++ ++#undef STRICT_MM_TYPECHECKS ++ ++#ifdef STRICT_MM_TYPECHECKS ++/* ++ * These are used to make use of C type-checking.. ++ */ ++typedef struct { unsigned long pte; } pte_t; ++typedef struct { unsigned long pmd; } pmd_t; ++typedef struct { unsigned long pgd; } pgd_t; ++typedef struct { unsigned long pgprot; } pgprot_t; ++ ++#define pte_val(x) ((x).pte) ++#define pmd_val(x) ((x).pmd) ++#define pgd_val(x) ((x).pgd) ++#define pgprot_val(x) ((x).pgprot) ++ ++#define __pte(x) ((pte_t) { (x) } ) ++#define __pmd(x) ((pmd_t) { (x) } ) ++#define __pgd(x) ((pgd_t) { (x) } ) ++#define __pgprot(x) ((pgprot_t) { (x) } ) ++ ++#else ++/* ++ * .. while these make it easier on the compiler ++ */ ++typedef unsigned long pte_t; ++typedef unsigned long pmd_t; ++typedef unsigned long pgd_t; ++typedef unsigned long pgprot_t; ++ ++#define pte_val(x) (x) ++#define pmd_val(x) (x) ++#define pgd_val(x) (x) ++#define pgprot_val(x) (x) ++ ++#define __pte(x) (x) ++#define __pmd(x) (x) ++#define __pgd(x) (x) ++#define __pgprot(x) (x) ++ ++#endif /* STRICT_MM_TYPECHECKS */ ++typedef struct page *pgtable_t; ++ ++#include <asm/memory.h> ++#include <asm-generic/getorder.h> ++ ++#endif /* !__ASSEMBLY__ */ ++ ++#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ ++ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) ++ ++#endif /* __KERNEL__ */ ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/param.h linux-3.4.110/arch/nds32/include/asm/param.h +--- linux-3.4.110.orig/arch/nds32/include/asm/param.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/param.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,36 @@ ++/* ++ * linux/arch/nds32/include/asm/param.h ++ * ++ * Copyright (C) 1995-1999 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __ASM_PARAM_H ++#define __ASM_PARAM_H ++ ++#ifdef __KERNEL__ ++ ++# ifndef HZ ++# define HZ CONFIG_HZ /* Internal kernel timer frequency */ ++# endif ++ ++# define USER_HZ HZ /* User interfaces are in "ticks" */ ++# define CLOCKS_PER_SEC (USER_HZ) /* like times() */ ++#else ++# define HZ 100 ++#endif ++ ++//#define EXEC_PAGESIZE 4096 ++ ++#ifndef NOGROUP ++#define NOGROUP (-1) ++#endif ++ ++/* max length of hostname */ ++#define MAXHOSTNAMELEN 64 ++ ++#endif ++ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/parport.h linux-3.4.110/arch/nds32/include/asm/parport.h +--- linux-3.4.110.orig/arch/nds32/include/asm/parport.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/parport.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,19 @@ ++/* ++ * linux/arch/nds32/include/asm/parport.h: NDS32-specific parport initialisation ++ * ++ * Copyright (C) 1999, 2000 Tim Waugh <tim@cyberelk.demon.co.uk> ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This file should only be included by drivers/parport/parport_pc.c. ++ */ ++ ++#ifndef __ASMNDS32_PARPORT_H ++#define __ASMNDS32_PARPORT_H ++ ++static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma); ++static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma) ++{ ++ return parport_pc_find_isa_ports (autoirq, autodma); ++} ++ ++#endif /* !(_ASMNDS32_PARPORT_H) */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/pci.h linux-3.4.110/arch/nds32/include/asm/pci.h +--- linux-3.4.110.orig/arch/nds32/include/asm/pci.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/pci.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,77 @@ ++/* ++ * linux/arch/nds32/include/asm/pci.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef ASMNDS32_PCI_H ++#define ASMNDS32_PCI_H ++ ++#ifdef __KERNEL__ ++#include <asm-generic/pci-dma-compat.h> ++ ++#include <asm/hardware.h> /* for PCIBIOS_MIN_* */ ++ ++#define pcibios_scan_all_fns(a, b) 0 ++ ++static inline void pcibios_set_master(struct pci_dev *dev) ++{ ++ /* No special bus mastering setup handling */ ++} ++ ++static inline void pcibios_penalize_isa_irq(int irq) ++{ ++ /* We don't do dynamic PCI IRQ allocation */ ++} ++ ++/* ++ * The PCI address space does equal the physical memory address space. ++ * The networking and block device layers use this boolean for bounce ++ * buffer decisions. ++ */ ++#define PCI_DMA_BUS_IS_PHYS (0) ++ ++/* ++ * Whether pci_unmap_{single,page} is a nop depends upon the ++ * configuration. ++ */ ++#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME; ++#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) __u32 LEN_NAME; ++#define pci_unmap_addr(PTR, ADDR_NAME) ((PTR)->ADDR_NAME) ++#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) (((PTR)->ADDR_NAME) = (VAL)) ++#define pci_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME) ++#define pci_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL)) ++ ++#define HAVE_PCI_MMAP ++extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, ++ enum pci_mmap_state mmap_state, int write_combine); ++ ++extern void ++pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, ++ struct resource *res); ++ ++extern void ++pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, ++ struct pci_bus_region *region); ++ ++static inline struct resource * ++pcibios_select_root(struct pci_dev *pdev, struct resource *res) ++{ ++ struct resource *root = NULL; ++ ++ if (res->flags & IORESOURCE_IO) ++ root = &ioport_resource; ++ if (res->flags & IORESOURCE_MEM) ++ root = &iomem_resource; ++ ++ return root; ++} ++ ++#endif /* __KERNEL__ */ ++ ++/* Chances are this interrupt is wired PC-style ... */ ++static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) ++{ ++ return channel ? 15 : 14; ++} ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/percpu.h linux-3.4.110/arch/nds32/include/asm/percpu.h +--- linux-3.4.110.orig/arch/nds32/include/asm/percpu.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/percpu.h 2016-04-07 10:20:50.902079477 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/percpu.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_PERCPU ++#define __NDS32_PERCPU ++ ++#include <asm-generic/percpu.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/pfm.h linux-3.4.110/arch/nds32/include/asm/pfm.h +--- linux-3.4.110.orig/arch/nds32/include/asm/pfm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/pfm.h 2016-04-07 10:20:50.906079632 +0200 +@@ -0,0 +1,16 @@ ++#ifndef __PFM_H_ ++#define __PFM_H_ ++ ++struct pcounter { ++ unsigned long long pfm0; /* value of $PFMC0 */ ++ unsigned long long pfm1; /* value of $PFMC1 */ ++ unsigned long long pfm2; /* value of $PFMC2 */ ++}; ++ ++#ifdef __KERNEL__ ++void sys_pfmctl(int event0, int event1, int event2, int start); ++int sys_getpfm(struct pcounter __user *p); ++int sys_setpfm(int pfm0, int pfm1, int pfm2, struct pcounter __user *p); ++#endif ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/pgalloc.h linux-3.4.110/arch/nds32/include/asm/pgalloc.h +--- linux-3.4.110.orig/arch/nds32/include/asm/pgalloc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/pgalloc.h 2016-04-07 10:20:50.906079632 +0200 +@@ -0,0 +1,104 @@ ++/* ++ * linux/arch/nds32/include/asm/pgalloc.h ++ * ++ * Copyright (C) 2000-2001 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef _ASMNDS32_PGALLOC_H ++#define _ASMNDS32_PGALLOC_H ++ ++#include <asm/processor.h> ++#include <asm/cacheflush.h> ++#include <asm/tlbflush.h> ++ ++/* ++ * Since we have only two-level page tables, these are trivial ++ */ ++#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) ++#define pmd_free(mm, pmd) do { } while (0) ++#define pgd_populate(mm, pmd, pte) BUG() ++#define pmd_pgtable(pmd) pmd_page(pmd) ++ ++extern pgd_t *get_pgd_slow(struct mm_struct *mm); ++extern void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd); ++ ++#define pgd_alloc(mm) get_pgd_slow(mm) ++#define pgd_free(mm, pgd) free_pgd_slow(mm, pgd) ++ ++#define check_pgt_cache() do { } while (0) ++ ++static inline pte_t * ++pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr) ++{ ++ pte_t *pte; ++ ++ pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO); ++ ++ return pte; ++} ++ ++static inline pgtable_t ++pte_alloc_one(struct mm_struct *mm, unsigned long addr) ++{ ++ pgtable_t pte; ++ ++ pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0); ++ if (pte) ++ cpu_dcache_wb_page((unsigned long)page_address(pte)); ++ ++ return pte; ++} ++ ++/* ++ * Free one PTE table. ++ */ ++static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) ++{ ++ if (pte) { ++ free_page((unsigned long)pte); ++ } ++} ++ ++static inline void pte_free(struct mm_struct *mm, pgtable_t pte) ++{ ++ __free_page(pte); ++} ++ ++/* ++ * Populate the pmdp entry with a pointer to the pte. This pmd is part ++ * of the mm address space. ++ * ++ * Ensure that we always set both PMD entries. ++ */ ++static inline void ++pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) ++{ ++ unsigned long pte_ptr = (unsigned long)ptep; ++ unsigned long pmdval; ++ ++ BUG_ON(mm != &init_mm); ++ ++ /* ++ * The pmd must be loaded with the physical ++ * address of the PTE table ++ */ ++ pmdval = __pa(pte_ptr) | _PAGE_KERNEL_TABLE; ++ set_pmd(pmdp, __pmd(pmdval)); ++} ++ ++static inline void ++pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep) ++{ ++ unsigned long pmdval; ++ ++ BUG_ON(mm == &init_mm); ++ ++ pmdval = page_to_pfn(ptep) << PAGE_SHIFT | _PAGE_USER_TABLE; ++ set_pmd(pmdp, __pmd(pmdval)); ++} ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/pgtable.h linux-3.4.110/arch/nds32/include/asm/pgtable.h +--- linux-3.4.110.orig/arch/nds32/include/asm/pgtable.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/pgtable.h 2016-04-07 10:20:50.910079787 +0200 +@@ -0,0 +1,429 @@ ++/* ++ * linux/arch/nds32/include/asm/pgtable.h ++ * ++ * Copyright (C) 1995-2002 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef _ASMNDS32_PGTABLE_H ++#define _ASMNDS32_PGTABLE_H ++ ++#include <asm-generic/4level-fixup.h> ++#include <asm-generic/sizes.h> ++ ++#include <asm/memory.h> ++#include <asm/vmalloc.h> ++#include <asm/nds32.h> ++#ifndef __ASSEMBLY__ ++#include <asm/fixmap.h> ++#endif ++ ++#ifdef CONFIG_CACHE_L2 ++#include <asm/l2_cache.h> ++#endif ++ ++#ifdef CONFIG_ANDES_PAGE_SIZE_4KB ++#define PGDIR_SHIFT 22 ++#define PTRS_PER_PGD 1024 ++#define PMD_SHIFT 22 ++#define PTRS_PER_PMD 1 ++#define PTRS_PER_PTE 1024 ++#endif ++ ++#ifdef CONFIG_ANDES_PAGE_SIZE_8KB ++#define PGDIR_SHIFT 24 ++#define PTRS_PER_PGD 256 ++#define PMD_SHIFT 24 ++#define PTRS_PER_PMD 1 ++#define PTRS_PER_PTE 2048 ++#endif ++ ++#ifndef __ASSEMBLY__ ++extern void __pte_error(const char *file, int line, unsigned long val); ++extern void __pmd_error(const char *file, int line, unsigned long val); ++extern void __pgd_error(const char *file, int line, unsigned long val); ++ ++#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte)) ++#define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd)) ++#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd)) ++#endif /* !__ASSEMBLY__ */ ++ ++#define PMD_SIZE (1UL << PMD_SHIFT) ++#define PMD_MASK (~(PMD_SIZE-1)) ++#define PGDIR_SIZE (1UL << PGDIR_SHIFT) ++#define PGDIR_MASK (~(PGDIR_SIZE-1)) ++ ++/* ++ * This is the lowest virtual address we can permit any user space ++ * mapping to be mapped at. This is particularly important for ++ * non-high vector CPUs. ++ */ ++#define FIRST_USER_ADDRESS 0x8000 ++ ++#define VMALLOC_OFFSET (8 * 1024 * 1024) ++#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) ++#define VMALLOC_VMADDR(x) ((unsigned long)(x)) ++ ++ ++#ifdef CONFIG_HIGHMEM ++#define CONSISTENT_BASE ((PKMAP_BASE) - (SZ_2M)) ++#define CONSISTENT_END (PKMAP_BASE) ++#else ++#define CONSISTENT_BASE (FIXADDR_START - SZ_2M) ++#define CONSISTENT_END (FIXADDR_START) ++#endif ++#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT) ++ ++#ifdef CONFIG_HIGHMEM ++#ifndef __ASSEMBLY__ ++#include <asm/highmem.h> ++#endif ++#endif ++ ++//# define VMALLOC_END (CONSISTENT_START - PAGE_SIZE) ++# define VMALLOC_END (0xf9000000) ++ ++#define VMALLOC_RESERVE (128 << 20) ++#define MAXMEM (VMALLOC_END - PAGE_OFFSET - VMALLOC_RESERVE) ++#define MAXMEM_PFN PFN_DOWN(MAXMEM) ++ ++#define FIRST_USER_PGD_NR 0 ++#define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) + FIRST_USER_PGD_NR) ++ ++/* L2 PTE */ ++#define _PAGE_V (1UL << 0) ++ ++#define _PAGE_M_XKRW (0UL << 1) ++#define _PAGE_M_UR_KR (1UL << 1) ++#define _PAGE_M_UR_KRW (2UL << 1) ++#define _PAGE_M_URW_KRW (3UL << 1) ++#define _PAGE_M_KR (5UL << 1) ++#define _PAGE_M_KRW (7UL << 1) ++ ++#define _PAGE_D (1UL << 4) ++#define _PAGE_E (1UL << 5) ++#define _PAGE_A (1UL << 6) ++#define _PAGE_G (1UL << 7) ++ ++#define _PAGE_C_DEV (0UL << 8) ++#define _PAGE_C_DEV_WB (1UL << 8) ++#define _PAGE_C_MEM (2UL << 8) ++#define _PAGE_C_MEM_SHRD_WB (4UL << 8) ++#define _PAGE_C_MEM_SHRD_WT (5UL << 8) ++#define _PAGE_C_MEM_WB (6UL << 8) ++#define _PAGE_C_MEM_WT (7UL << 8) ++ ++#define _PAGE_L (1UL << 11) ++ ++#ifndef CONFIG_NO_KERNEL_LARGE_PAGE ++#define _HAVE_PAGE_L (_PAGE_L) ++#else ++#define _HAVE_PAGE_L 0 ++#endif ++#define _PAGE_FILE (1UL << 1) ++#define _PAGE_YOUNG 0 ++#define _PAGE_M_MASK _PAGE_M_KRW ++#define _PAGE_C_MASK _PAGE_C_MEM_WT ++ ++#ifdef CONFIG_SMP ++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH ++#define _PAGE_CACHE_SHRD _PAGE_C_MEM_SHRD_WT ++#else ++#define _PAGE_CACHE_SHRD _PAGE_C_MEM_SHRD_WB ++#endif ++#else ++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH ++#define _PAGE_CACHE_SHRD _PAGE_C_MEM_WT ++#else ++#define _PAGE_CACHE_SHRD _PAGE_C_MEM_WB ++#endif ++#endif ++ ++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH ++#define _PAGE_CACHE _PAGE_C_MEM_WT ++#else ++#define _PAGE_CACHE _PAGE_C_MEM_WB ++#endif ++ ++/* ++ * + Level 1 descriptor (PMD) ++ */ ++#define PMD_TYPE_TABLE 0 ++ ++#ifndef __ASSEMBLY__ ++ ++#define _PAGE_USER_TABLE PMD_TYPE_TABLE ++#define _PAGE_KERNEL_TABLE PMD_TYPE_TABLE ++ ++#define PAGE_EXEC __pgprot(_PAGE_V | _PAGE_M_XKRW | _PAGE_E) ++#define PAGE_NONE __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_A) ++#define PAGE_READ __pgprot(_PAGE_V | _PAGE_M_UR_KR) ++#define PAGE_RDWR __pgprot(_PAGE_V | _PAGE_M_URW_KRW | _PAGE_D) ++#define PAGE_COPY __pgprot(_PAGE_V | _PAGE_M_UR_KR) ++ ++#define PAGE_UXKRWX_V1 __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD) ++#define PAGE_UXKRWX_V2 __pgprot(_PAGE_V | _PAGE_M_XKRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD) ++#define PAGE_CACHE_L1 __pgprot(_HAVE_PAGE_L | _PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE) ++#define PAGE_MEMORY __pgprot(_HAVE_PAGE_L | _PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD) ++#define PAGE_KERNEL __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_E | _PAGE_G | _PAGE_CACHE_SHRD) ++#define PAGE_DEVICE __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D | _PAGE_G | _PAGE_C_DEV) ++#endif /* __ASSEMBLY__ */ ++ ++/* xwr */ ++#define __P000 (PAGE_NONE | _PAGE_CACHE_SHRD) ++#define __P001 (PAGE_READ | _PAGE_CACHE_SHRD) ++#define __P010 (PAGE_COPY | _PAGE_CACHE_SHRD) ++#define __P011 (PAGE_COPY | _PAGE_CACHE_SHRD) ++#define __P100 (PAGE_EXEC | _PAGE_CACHE_SHRD) ++#define __P101 (PAGE_READ | _PAGE_E | _PAGE_CACHE_SHRD) ++#define __P110 (PAGE_COPY | _PAGE_E | _PAGE_CACHE_SHRD) ++#define __P111 (PAGE_COPY | _PAGE_E | _PAGE_CACHE_SHRD) ++ ++#define __S000 (PAGE_NONE | _PAGE_CACHE_SHRD) ++#define __S001 (PAGE_READ | _PAGE_CACHE_SHRD) ++#define __S010 (PAGE_RDWR | _PAGE_CACHE_SHRD) ++#define __S011 (PAGE_RDWR | _PAGE_CACHE_SHRD) ++#define __S100 (PAGE_EXEC | _PAGE_CACHE_SHRD) ++#define __S101 (PAGE_READ | _PAGE_E | _PAGE_CACHE_SHRD) ++#define __S110 (PAGE_RDWR | _PAGE_E | _PAGE_CACHE_SHRD) ++#define __S111 (PAGE_RDWR | _PAGE_E | _PAGE_CACHE_SHRD) ++ ++#ifndef __ASSEMBLY__ ++/* ++ * ZERO_PAGE is a global shared page that is always zero: used ++ * for zero-mapped memory areas etc.. ++ */ ++extern struct page *empty_zero_page; ++#define ZERO_PAGE(vaddr) (empty_zero_page) ++ ++#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) ++#define pfn_pte(pfn,prot) (__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))) ++ ++#define pte_none(pte) !(pte_val(pte)) ++#define pte_clear(mm,addr,ptep) set_pte_at((mm),(addr),(ptep), __pte(0)) ++#define pte_page(pte) (pfn_to_page(pte_pfn(pte))) ++ ++#define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) ++#define pte_offset_kernel(dir, address) ((pte_t *)pmd_page_kernel(*(dir)) + pte_index(address)) ++#define pte_offset_map(dir, address) ((pte_t *)page_address(pmd_page(*(dir))) + pte_index(address)) ++#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address) ++#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) ++ ++#define pte_unmap(pte) do { } while (0) ++#define pte_unmap_nested(pte) do { } while (0) ++ ++#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) ++ ++static inline pgd_t *get_pgd( void){ ++ ++ return ( pgd_t *)phys_to_virt( GET_L1_PPTB() & L1_PPTB_mskBASE); ++} ++ ++static inline void set_pgd( pgd_t *pgdp, pgd_t pgd){ ++ ++ /* TODO */ ++} ++/* ++ * Set a level 1 translation table entry, and clean it out of ++ * any caches such that the MMUs can load it correctly. ++ */ ++static inline void set_pmd( pmd_t *pmdp, pmd_t pmd){ ++ ++ *pmdp = pmd; ++#if !defined(CONFIG_CPU_DCACHE_DISABLE) && !defined(CONFIG_CPU_DCACHE_WRITETHROUGH) ++ __asm__ volatile ( "\n\tcctl %0, L1D_VA_WB" ::"r" ( pmdp) :"memory"); ++ MSYNC( all); ++ DSB(); ++#endif ++} ++ ++/* ++ * Set a PTE and flush it out ++ */ ++static inline void set_pte( pte_t *ptep, pte_t pte){ ++ ++ *ptep = pte; ++#if !defined(CONFIG_CPU_DCACHE_DISABLE) && !defined(CONFIG_CPU_DCACHE_WRITETHROUGH) ++ __asm__ volatile ( "\n\tcctl %0, L1D_VA_WB" ::"r" ( ptep) :"memory"); ++ MSYNC( all); ++ DSB(); ++#endif ++} ++ ++ ++/* ++ * The following only work if pte_present() is true. ++ * Undefined behaviour if not.. ++ */ ++ ++/* ++ * pte_write: this page is writeable for user mode ++ * pte_read: this page is readable for user mode ++ * pte_kernel_write: this page is writeable for kernel mode ++ * ++ * We don't have pte_kernel_read because kernel always can read. ++ * ++ * */ ++ ++#define pte_present(pte) (pte_val(pte) & _PAGE_V) ++#define pte_write(pte) ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_URW_KRW) ++#define pte_read(pte) (((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_UR_KR) || \ ++ ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_UR_KRW) || \ ++ ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_URW_KRW)) ++#define pte_kernel_write(pte) (((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_URW_KRW) || \ ++ ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_UR_KRW) || \ ++ ((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_KRW) || \ ++ (((pte_val(pte) & _PAGE_M_MASK) == _PAGE_M_XKRW) && pte_exec(pte))) ++#define pte_exec(pte) (pte_val(pte) & _PAGE_E) ++#define pte_dirty(pte) (pte_val(pte) & _PAGE_D) ++#define pte_young(pte) (pte_val(pte) & _PAGE_YOUNG) ++ ++/* ++ * The following only works if pte_present() is not true. ++ */ ++#define pte_file(pte) (pte_val(pte) & _PAGE_FILE) ++#define pte_to_pgoff(x) (pte_val(x) >> 2) ++#define pgoff_to_pte(x) __pte(((x) << 2) | _PAGE_FILE) ++ ++#define PTE_FILE_MAX_BITS 29 ++ ++#define PTE_BIT_FUNC(fn,op) \ ++static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } ++ ++static inline pte_t pte_wrprotect(pte_t pte) ++{ ++ pte_val(pte) = pte_val(pte) & ~_PAGE_M_MASK; ++ pte_val(pte) = pte_val(pte) | _PAGE_M_UR_KR; ++ return pte; ++} ++ ++static inline pte_t pte_mkwrite(pte_t pte) ++{ ++ pte_val(pte) = pte_val(pte) & ~_PAGE_M_MASK; ++ pte_val(pte) = pte_val(pte) | _PAGE_M_URW_KRW; ++ return pte; ++} ++ ++PTE_BIT_FUNC(exprotect, &= ~_PAGE_E); ++PTE_BIT_FUNC(mkexec, |= _PAGE_E); ++PTE_BIT_FUNC(mkclean, &= ~_PAGE_D); ++PTE_BIT_FUNC(mkdirty, |= _PAGE_D); ++PTE_BIT_FUNC(mkold, &= ~_PAGE_YOUNG); ++PTE_BIT_FUNC(mkyoung, |= _PAGE_YOUNG); ++static inline int pte_special(pte_t pte) { return 0; } ++static inline pte_t pte_mkspecial(pte_t pte) { return pte; } ++ ++/* ++ * Mark the prot value as uncacheable and unbufferable. ++ */ ++#define pgprot_noncached(prot) __pgprot((pgprot_val(prot)&~_PAGE_C_MASK) | _PAGE_C_DEV) ++#define pgprot_writecombine(prot) __pgprot((pgprot_val(prot)&~_PAGE_C_MASK) | _PAGE_C_DEV_WB) ++ ++#define pmd_none(pmd) (pmd_val(pmd)&0x1) ++#define pmd_present(pmd) (!pmd_none(pmd)) ++#define pmd_bad(pmd) pmd_none(pmd) ++ ++#define copy_pmd(pmdpd,pmdps) set_pmd((pmdpd), *(pmdps)) ++#define pmd_clear(pmdp) set_pmd((pmdp), __pmd(1)) ++ ++static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) ++{ ++ unsigned long ptr = (unsigned long)ptep; ++ pmd_t pmd; ++ ++ /* ++ * The pmd must be loaded with the physical ++ * address of the PTE table ++ */ ++ ++ pmd_val(pmd) = __virt_to_phys(ptr) | prot; ++ return pmd; ++} ++ ++ ++#define pmd_page(pmd) virt_to_page(__va(pmd_val(pmd))) ++ ++/* ++ * Permanent address of a page. We never have highmem, so this is trivial. ++ */ ++#define pages_to_mb(x) ((x) >> (20 - PAGE_SHIFT)) ++ ++/* ++ * Conversion functions: convert a page and protection to a page entry, ++ * and a page entry and page directory to the page they refer to. ++ */ ++#define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot) ++ ++/* ++ * The "pgd_xxx()" functions here are trivial for a folded two-level ++ * setup: the pgd is never bad, and a pmd always exists (as it's folded ++ * into the pgd entry) ++ */ ++#define pgd_none(pgd) (0) ++#define pgd_bad(pgd) (0) ++#define pgd_present(pgd) (1) ++#define pgd_clear(pgdp) do { } while (0) ++ ++#define page_pte_prot(page,prot) mk_pte(page, prot) ++#define page_pte(page) mk_pte(page, __pgprot(0)) ++/* Tom: ++ * L1PTE = $mr1 + ((virt >> PMD_SHIFT) << 2); ++ * L2PTE = (((virt >> PAGE_SHIFT) & (PTRS_PER_PTE -1 )) << 2); ++ * PPN = (phys & 0xfffff000); ++ * ++*/ ++ ++/* to find an entry in a page-table-directory */ ++#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) ++#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) ++/* to find an entry in a kernel page-table-directory */ ++#define pgd_offset_k(addr) pgd_offset(&init_mm, addr) ++ ++/* Find an entry in the second-level page table.. */ ++#define pmd_offset(dir, addr) ((pmd_t *)(dir)) ++ ++static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) ++{ ++ const unsigned long mask = 0xfff; ++ pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); ++ return pte; ++} ++ ++extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; ++ ++/* Encode and decode a swap entry. ++ * ++ * We support up to 32GB of swap on 4k machines ++ */ ++#define __swp_type(x) (((x).val >> 2) & 0x7f) ++#define __swp_offset(x) ((x).val >> 9) ++#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 2) | ((offset) << 9) }) ++#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) ++#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) ++ ++/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ ++/* FIXME: this is not correct */ ++#define kern_addr_valid(addr) (1) ++ ++#include <asm-generic/pgtable.h> ++ ++/* ++ * We provide our own arch_get_unmapped_area to cope with VIPT caches. ++ */ ++#define HAVE_ARCH_UNMAPPED_AREA ++ ++/* ++ * remap a physical address `phys' of size `size' with page protection `prot' ++ * into virtual address `from' ++ */ ++#define io_remap_pfn_range(vma,from,pfn,size,prot) \ ++ remap_pfn_range(vma, from, pfn, size, prot) ++ ++#define pgtable_cache_init() do { } while (0) ++ ++#endif /* !__ASSEMBLY__ */ ++ ++#endif /* _ASMNDS32_PGTABLE_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/poll.h linux-3.4.110/arch/nds32/include/asm/poll.h +--- linux-3.4.110.orig/arch/nds32/include/asm/poll.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/poll.h 2016-04-07 10:20:50.910079787 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/poll.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ASMNDS32_POLL_H ++#define __ASMNDS32_POLL_H ++ ++#include <asm-generic/poll.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/posix_types.h linux-3.4.110/arch/nds32/include/asm/posix_types.h +--- linux-3.4.110.orig/arch/nds32/include/asm/posix_types.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/posix_types.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,40 @@ ++/* ++ * arch/arm/include/asm/posix_types.h ++ * ++ * Copyright (C) 1996-1998 Russell King. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Changelog: ++ * 27-06-1996 RMK Created ++ */ ++#ifndef __ARCH_NDS32_POSIX_TYPES_H ++#define __ARCH_NDS32_POSIX_TYPES_H ++ ++/* ++ * This file is generally used by user-level software, so you need to ++ * be a little careful about namespace pollution etc. Also, we cannot ++ * assume GCC is being used. ++ */ ++ ++typedef unsigned short __kernel_mode_t; ++#define __kernel_mode_t __kernel_mode_t ++ ++typedef unsigned short __kernel_nlink_t; ++#define __kernel_nlink_t __kernel_nlink_t ++ ++typedef unsigned short __kernel_ipc_pid_t; ++#define __kernel_ipc_pid_t __kernel_ipc_pid_t ++ ++typedef unsigned short __kernel_uid_t; ++typedef unsigned short __kernel_gid_t; ++#define __kernel_uid_t __kernel_uid_t ++ ++typedef unsigned short __kernel_old_dev_t; ++#define __kernel_old_dev_t __kernel_old_dev_t ++ ++#include <asm-generic/posix_types.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/processor.h linux-3.4.110/arch/nds32/include/asm/processor.h +--- linux-3.4.110.orig/arch/nds32/include/asm/processor.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/processor.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,133 @@ ++/* ++ * linux/arch/nds32/include/asm/processor.h ++ */ ++/* Copyright (C) 1995-1999 Russell King ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++/* ============================================================================ ++ * Copyright (C) 2007 Andes Technology Corporation ++ * This file is part of Linux and should be licensed under the GPL. ++ * See the file COPYING for conditions for redistribution. ++ * ++ * Abstract: ++ * ++ * This program is ptrace relative code for Andes NDS32 architecture. ++ * Original referred from ARM, fit to NDS32. ++ * ++ * Revision History: ++ * ++ * Oct.03.2007 Original from Tom, Shawn and Steven, refined by Harry. ++ * ++ * Note: ++ * ++ * ============================================================================ ++ */ ++#ifndef __ASM_NDS32_PROCESSOR_H ++#define __ASM_NDS32_PROCESSOR_H ++ ++/* ++ * Default implementation of macro that returns current ++ * instruction pointer ("program counter"). ++ */ ++#define current_text_addr() ({ __label__ _l; _l: &&_l;}) ++ ++#ifdef __KERNEL__ ++ ++#include <asm/ptrace.h> ++#include <asm/procinfo.h> ++#include <asm/types.h> ++#include <asm/cpuver.h> ++#include <asm/sigcontext.h> ++ ++#define KERNEL_STACK_SIZE PAGE_SIZE ++#define STACK_TOP TASK_SIZE ++#define STACK_TOP_MAX TASK_SIZE ++ ++struct debug_info { ++ u32 address; ++ u16 insn; ++ u8 valid; ++}; ++ ++struct thread_struct { ++ /* fault info */ ++ unsigned long address; ++ unsigned long trap_no; ++ unsigned long error_code; ++ ++ struct fpu_struct fpu; /* Saved fpu/fpu emulator stuff. */ ++ struct audio_struct audio; ++ struct debug_info debug; /* debugging */ ++}; ++ ++#define INIT_THREAD { } ++ ++#ifdef __NDS32_EB__ ++#define PSW_DE PSW_mskBE ++#else ++#define PSW_DE 0x0 ++#endif ++ ++#ifdef CONFIG_WBNA ++#define PSW_valWBNA PSW_mskWBNA ++#else ++#define PSW_valWBNA 0x0 ++#endif ++ ++#define start_thread(regs,pc,sp) \ ++({ \ ++ unsigned long *stack = (unsigned long *)sp; \ ++ set_fs(USER_DS); \ ++ memzero(regs->uregs, sizeof(regs->uregs)); \ ++ regs->NDS32_ipsw = (PSW_CPL_ANY | PSW_valWBNA | PSW_mskDT | PSW_mskIT | PSW_DE | PSW_mskGIE); \ ++ regs->NDS32_ir0 = (PSW_CPL_ANY | PSW_valWBNA | PSW_mskDT | PSW_mskIT | PSW_DE | PSW_SYSTEM | PSW_INTL_1); \ ++ regs->NDS32_ipc = pc; /* pc */ \ ++ regs->NDS32_sp = sp; /* $sp */ \ ++ regs->NDS32_r2 = stack[4]; /* $r2 (envp) */ \ ++ regs->NDS32_r1 = stack[1]; /* $r1 (argv) */ \ ++ regs->NDS32_r0 = stack[0]; /* $r0 (argc) */ \ ++}) ++ ++ ++/* Forward declaration, a strange C thing */ ++struct task_struct; ++ ++/* Free all resources held by a thread. */ ++extern void release_thread(struct task_struct *); ++#ifdef CONFIG_FPU ++#ifndef CONFIG_UNLAZU_FPU //lazy fpu ++extern struct task_struct *last_task_used_math; ++#endif ++#endif ++#ifdef CONFIG_AUDIO ++#ifndef CONFIG_UNLAZY_AUDIO //lazy audio ++extern struct task_struct *last_task_used_audio; ++#endif ++#endif ++ ++/* Prepare to copy thread state - unlazy all lazy status */ ++#define prepare_to_copy(tsk) do { } while (0) ++ ++unsigned long get_wchan(struct task_struct *p); ++ ++#define cpu_relax() barrier() ++ ++#define task_pt_regs(task) \ ++ ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE \ ++ - 8) - 1) ++ ++/* ++ * Create a new kernel thread ++ */ ++extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); ++ ++#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)task_thread_info(tsk)))[1019]) ++#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)task_thread_info(tsk)))[1017]) ++ ++ ++#endif ++ ++#endif /* __ASM_NDS32_PROCESSOR_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/proc-fns.h linux-3.4.110/arch/nds32/include/asm/proc-fns.h +--- linux-3.4.110.orig/arch/nds32/include/asm/proc-fns.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/proc-fns.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,88 @@ ++/* ++ * linux/arch/nds32/include/asm/proc-fns.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_PROCFNS_H__ ++#define __NDS32_PROCFNS_H__ ++ ++#define CPU_NAME n12 ++ ++#ifdef __KERNEL__ ++ ++#ifdef __STDC__ ++#define ____cpu_fn(name,fn) name##fn ++#else ++#define ____cpu_fn(name,fn) name/**/fn ++#endif ++#define __cpu_fn(name,fn) ____cpu_fn(name,fn) ++ ++#define cpu_proc_init __cpu_fn( CPU_NAME, _proc_init) ++#define cpu_proc_fin __cpu_fn( CPU_NAME, _proc_fin) ++#define cpu_do_idle __cpu_fn( CPU_NAME, _do_idle) ++#define cpu_reset __cpu_fn( CPU_NAME, _reset) ++#define cpu_switch_mm __cpu_fn( CPU_NAME, _switch_mm) ++ ++#define cpu_dcache_inval_all __cpu_fn( CPU_NAME, _dcache_inval_all) ++#define cpu_dcache_wbinval_all __cpu_fn( CPU_NAME, _dcache_wbinval_all) ++#define cpu_dcache_inval_page __cpu_fn( CPU_NAME, _dcache_inval_page) ++#define cpu_dcache_wb_page __cpu_fn( CPU_NAME, _dcache_wb_page) ++#define cpu_dcache_wbinval_page __cpu_fn( CPU_NAME, _dcache_wbinval_page) ++#define cpu_dcache_inval_range __cpu_fn( CPU_NAME, _dcache_inval_range) ++#define cpu_dcache_wb_range __cpu_fn( CPU_NAME, _dcache_wb_range) ++#define cpu_dcache_wbinval_range __cpu_fn( CPU_NAME, _dcache_wbinval_range) ++ ++#define cpu_icache_inval_all __cpu_fn( CPU_NAME, _icache_inval_all) ++#define cpu_icache_inval_page __cpu_fn( CPU_NAME, _icache_inval_page) ++#define cpu_icache_inval_range __cpu_fn( CPU_NAME, _icache_inval_range) ++ ++#define cpu_cache_wbinval_page __cpu_fn( CPU_NAME, _cache_wbinval_page) ++#define cpu_cache_wbinval_range __cpu_fn( CPU_NAME, _cache_wbinval_range) ++#define cpu_cache_wbinval_range_check __cpu_fn( CPU_NAME, _cache_wbinval_range_check) ++ ++#define cpu_dma_wb_range __cpu_fn( CPU_NAME, _dma_wb_range) ++#define cpu_dma_inval_range __cpu_fn( CPU_NAME, _dma_inval_range) ++#define cpu_dma_wbinval_range __cpu_fn( CPU_NAME, _dma_wbinval_range) ++ ++#include <asm/page.h> ++ ++struct mm_struct; ++struct vm_area_struct; ++extern void cpu_proc_init(void); ++extern void cpu_proc_fin(void); ++extern void cpu_do_idle(void); ++extern void cpu_reset(unsigned long reset); ++extern void cpu_switch_mm(struct mm_struct *mm); ++ ++extern void cpu_dcache_inval_all(void); ++extern void cpu_dcache_wbinval_all(void); ++extern void cpu_dcache_inval_page(unsigned long page); ++extern void cpu_dcache_wb_page(unsigned long page); ++extern void cpu_dcache_wbinval_page(unsigned long page); ++extern void cpu_dcache_inval_range(unsigned long start, unsigned long end); ++extern void cpu_dcache_wb_range(unsigned long start, unsigned long end); ++extern void cpu_dcache_wbinval_range(unsigned long start, unsigned long end); ++ ++extern void cpu_icache_inval_all(void); ++extern void cpu_icache_inval_page(unsigned long page); ++extern void cpu_icache_inval_range(unsigned long start, unsigned long end); ++ ++extern void cpu_cache_wbinval_page(unsigned long page, int flushi); ++extern void cpu_cache_wbinval_range(unsigned long start, ++ unsigned long end, int flushi); ++extern void cpu_cache_wbinval_range_check(struct vm_area_struct *vma, ++ unsigned long start, unsigned long end); ++ ++extern void cpu_dma_wb_range(unsigned long start, unsigned long end); ++extern void cpu_dma_inval_range(unsigned long start, unsigned long end); ++extern void cpu_dma_wbinval_range(unsigned long start, unsigned long end); ++ ++#ifdef CONFIG_CACHE_L2 ++#define cpu_L2cache_inval __cpu_fn(CPU_NAME, _L2cache_inval) ++#define cpu_L2cache_wb __cpu_fn(CPU_NAME, _L2cache_wb) ++extern void cpu_L2cache_inval(void); ++extern void cpu_L2cache_wb(void); ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __NDS32_PROCFNS_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/procinfo.h linux-3.4.110/arch/nds32/include/asm/procinfo.h +--- linux-3.4.110.orig/arch/nds32/include/asm/procinfo.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/procinfo.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,71 @@ ++/* ++ * linux/arch/nds32/include/asm/procinfo.h ++ * ++ * Copyright (C) 1996-1999 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __ASM_PROCINFO_H ++#define __ASM_PROCINFO_H ++ ++#ifndef __ASSEMBLY__ ++ ++/* ++ * These structure are defined in assembly ++ * ( nds32/mm/proc-nds32.S) ++ */ ++struct proc_info_item { ++ ++ const char *manufacturer; ++ const char *cpu_name; ++}; ++ ++/* ++ * Note! struct processor is always defined if we're ++ * using MULTI_CPU, otherwise this entry is unused, ++ * but still exists. ++ * ++ * NOTE! The following structure is defined by assembly ++ * language, NOT C code. For more information, check: ++ * arch/arm/mm/proc-*.S and arch/arm/kernel/head.S ++ */ ++struct proc_info_list { ++ ++ unsigned int cpu_val; ++ unsigned int cpu_mask; ++ const char *arch_name; ++ const char *elf_name; ++ unsigned int elf_hwcap; ++ struct proc_info_item *info; ++}; ++ ++extern unsigned int elf_hwcap; ++ ++#endif /* __ASSEMBLY__ */ ++ ++#define HWCAP_MFUSR_PC 0x000001 ++#define HWCAP_EXT 0x000002 ++#define HWCAP_EXT2 0x000004 ++#define HWCAP_FPU 0x000008 ++#define HWCAP_AUDIO 0x000010 ++#define HWCAP_BASE16 0x000020 ++#define HWCAP_STRING 0x000040 ++#define HWCAP_REDUCED_REGS 0x000080 ++#define HWCAP_VIDEO 0x000100 ++#define HWCAP_ENCRYPT 0x000200 ++#define HWCAP_EDM 0x000400 ++#define HWCAP_LMDMA 0x000800 ++#define HWCAP_PFM 0x001000 ++#define HWCAP_HSMP 0x002000 ++#define HWCAP_TRACE 0x004000 ++#define HWCAP_DIV 0x008000 ++#define HWCAP_MAC 0x010000 ++#define HWCAP_L2C 0x020000 ++#define HWCAP_FPU_DP 0x040000 ++#define HWCAP_V2 0x080000 ++#define HWCAP_DX_REGS 0x100000 ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/ptrace.h linux-3.4.110/arch/nds32/include/asm/ptrace.h +--- linux-3.4.110.orig/arch/nds32/include/asm/ptrace.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/ptrace.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,119 @@ ++/* ++ * linux/arch/nds32/include/asm/ptrace.h ++ * ++ * Copyright (C) 1996-2003 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __ASM_NDS32_PTRACE_H ++#define __ASM_NDS32_PTRACE_H ++ ++#define PTRACE_GETREGS 12 ++#define PTRACE_SETREGS 13 ++#define PTRACE_GETFPREGS 14 ++#define PTRACE_SETFPREGS 15 ++#define PTRACE_GETAUREGS 18 ++#define PTRACE_SETAUREGS 19 ++ ++#define PTRACE_OLDSETOPTIONS 21 ++ ++#define PTRACE_GET_THREAD_AREA 22 ++ ++#ifndef __ASSEMBLY__ ++/* this struct defines the way the registers are stored on the ++ stack during a system call. */ ++ ++struct pt_regs { ++#if defined(CONFIG_ABI1) ++ long dummy[6]; ++#endif ++ long uregs[44]; ++}; ++#define NDS32_osp uregs[43] ++#define NDS32_FUCOP_CTL uregs[42] ++#define NDS32_lp uregs[41] ++#define NDS32_gp uregs[40] ++#define NDS32_fp uregs[39] ++#define NDS32_r25 uregs[38] ++#define NDS32_r24 uregs[37] ++#define NDS32_r23 uregs[36] ++#define NDS32_r22 uregs[35] ++#define NDS32_r21 uregs[34] ++#define NDS32_r20 uregs[33] ++#define NDS32_r19 uregs[32] ++#define NDS32_r18 uregs[31] ++#define NDS32_r17 uregs[30] ++#define NDS32_r16 uregs[29] ++#define NDS32_r15 uregs[28] ++#define NDS32_r14 uregs[27] ++#define NDS32_r13 uregs[26] ++#define NDS32_r12 uregs[25] ++#define NDS32_r11 uregs[24] ++#define NDS32_r10 uregs[23] ++#define NDS32_r9 uregs[22] ++#define NDS32_r8 uregs[21] ++#define NDS32_r7 uregs[20] ++#define NDS32_r6 uregs[19] ++#define NDS32_r5 uregs[18] ++#define NDS32_r4 uregs[17] ++#define NDS32_r3 uregs[16] ++#define NDS32_r2 uregs[15] ++#define NDS32_r1 uregs[14] ++#define NDS32_r0 uregs[13] ++#if defined(CONFIG_HWZOL) ++#define NDS32_lc uregs[11] ++#define NDS32_le uregs[10] ++#define NDS32_lb uregs[9] ++#endif ++#define NDS32_pp1 uregs[8] ++#define NDS32_pp0 uregs[7] ++#define NDS32_pipc uregs[6] ++#define NDS32_pipsw uregs[5] ++#define NDS32_ORIG_r0 uregs[4] ++#define NDS32_sp uregs[3] ++#define NDS32_ipc uregs[2] ++#define NDS32_ipsw uregs[1] ++#define NDS32_ir0 uregs[0] ++ ++#ifdef __KERNEL__ ++#include <asm/bitfield.h> ++ ++#define arch_has_single_step() (1) ++struct task_struct; ++extern void user_enable_single_step(struct task_struct *); ++extern void user_disable_single_step(struct task_struct *); ++ ++#define user_mode(regs) (((regs)->NDS32_ipsw & PSW_mskPOM) == 0) ++ ++#define interrupts_enabled(regs) (!((regs)->NDS32_ipsw & ~PSW_mskGIE)) ++ ++extern void show_regs(struct pt_regs *); ++ ++/* Are the current registers suitable for user mode? ++ * (used to maintain security in signal handlers) ++ */ ++static inline int valid_user_regs(struct pt_regs *regs) ++{ ++ return user_mode(regs) && ((regs->NDS32_ipsw & PSW_mskGIE) == 1); ++} ++ ++static inline unsigned long regs_return_value(struct pt_regs *regs) ++{ ++ return regs->NDS32_r0; ++} ++ ++ ++#define instruction_pointer(regs) ((regs)->NDS32_ipc) ++ ++#ifdef CONFIG_SMP ++extern unsigned long profile_pc(struct pt_regs *regs); ++#else ++#define profile_pc(regs) instruction_pointer(regs) ++#endif ++ ++#endif /* __KERNEL__ */ ++#endif /* __ASSEMBLY__ */ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/reg_access.h linux-3.4.110/arch/nds32/include/asm/reg_access.h +--- linux-3.4.110.orig/arch/nds32/include/asm/reg_access.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/reg_access.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,153 @@ ++/* ++ * linux/arch/nds32/include/asm/reg_access.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_REG_ACCESS_H__ ++#define __NDS32_REG_ACCESS_H__ ++ ++#ifndef __ASSEMBLY__ ++#define DEFINE_GET_SYS_REG( reg) \ ++inline static unsigned long GET_##reg( void){ \ ++ unsigned long val; \ ++ __asm__ volatile ( "mfsr %0, $"#reg :"=&r" (val) ::"memory"); \ ++ return val; \ ++} ++ ++#define DEFINE_PUT_SYS_REG( reg) \ ++inline static void SET_##reg( unsigned long val){ \ ++ __asm__ volatile ( "\n\tmtsr %0, $"#reg \ ++ "\n\tdsb" ::"r" ( val) :"memory"); \ ++} ++ ++#define DEFINE_PUT_SYS_REG_i( reg) \ ++inline static void SET_##reg( unsigned long val){ \ ++ __asm__ volatile ( "\n\tmtsr %0, $"#reg \ ++ "\n\tisb" ::"r" ( val) :"memory"); \ ++} ++#define DEFINE_SYS_REG_OP( reg) \ ++DEFINE_GET_SYS_REG( reg); \ ++DEFINE_PUT_SYS_REG( reg); ++ ++#define DEFINE_SYS_REG_OP_i( reg) \ ++DEFINE_GET_SYS_REG( reg); \ ++DEFINE_PUT_SYS_REG_i( reg); ++ ++DEFINE_SYS_REG_OP( CPU_VER); ++DEFINE_SYS_REG_OP( ICM_CFG); ++DEFINE_SYS_REG_OP( DCM_CFG); ++DEFINE_SYS_REG_OP( MMU_CFG); ++DEFINE_SYS_REG_OP( MSC_CFG); ++DEFINE_SYS_REG_OP( CORE_ID); ++DEFINE_SYS_REG_OP( FUCOP_EXIST); ++ ++DEFINE_SYS_REG_OP_i( PSW); ++DEFINE_SYS_REG_OP( IPSW); ++DEFINE_SYS_REG_OP( P_IPSW); ++DEFINE_SYS_REG_OP( IVB); ++DEFINE_SYS_REG_OP( EVA); ++DEFINE_SYS_REG_OP( P_EVA); ++DEFINE_SYS_REG_OP( ITYPE); ++DEFINE_SYS_REG_OP( P_ITYPE); ++DEFINE_SYS_REG_OP( MERR); ++DEFINE_SYS_REG_OP( IPC); ++DEFINE_SYS_REG_OP( P_IPC); ++DEFINE_SYS_REG_OP( OIPC); ++DEFINE_SYS_REG_OP( P_P0); ++DEFINE_SYS_REG_OP( P_P1); ++DEFINE_SYS_REG_OP( INT_MASK); ++DEFINE_SYS_REG_OP( INT_PEND); ++DEFINE_SYS_REG_OP( INT_MASK2); ++DEFINE_SYS_REG_OP( INT_PEND2); ++DEFINE_SYS_REG_OP( INT_TRIGGER); ++ ++DEFINE_SYS_REG_OP( MMU_CTL); ++DEFINE_SYS_REG_OP( L1_PPTB); ++DEFINE_SYS_REG_OP( TLB_VPN); ++DEFINE_SYS_REG_OP( TLB_DATA); ++DEFINE_SYS_REG_OP( TLB_MISC); ++DEFINE_SYS_REG_OP( VLPT_IDX); ++DEFINE_SYS_REG_OP( ILMB); ++DEFINE_SYS_REG_OP( DLMB); ++DEFINE_SYS_REG_OP( CACHE_CTL); ++DEFINE_SYS_REG_OP( HSMP_SADDR); ++DEFINE_SYS_REG_OP( HSMP_EADDR); ++ ++DEFINE_SYS_REG_OP( EDM_CFG); ++DEFINE_SYS_REG_OP( EDMSW); ++DEFINE_SYS_REG_OP( EDM_CTL); ++DEFINE_SYS_REG_OP( EDM_DTR); ++DEFINE_SYS_REG_OP( BPMTC); ++DEFINE_SYS_REG_OP( DIMBR); ++DEFINE_SYS_REG_OP( TECR0); ++DEFINE_SYS_REG_OP( TECR1); ++ ++DEFINE_SYS_REG_OP( BPC0); ++DEFINE_SYS_REG_OP( BPA0); ++DEFINE_SYS_REG_OP( BPAM0); ++DEFINE_SYS_REG_OP( BPV0); ++DEFINE_SYS_REG_OP( BPCID0); ++DEFINE_SYS_REG_OP( BPC1); ++DEFINE_SYS_REG_OP( BPA1); ++DEFINE_SYS_REG_OP( BPAM1); ++DEFINE_SYS_REG_OP( BPV1); ++DEFINE_SYS_REG_OP( BPCID1); ++DEFINE_SYS_REG_OP( BPC2); ++DEFINE_SYS_REG_OP( BPA2); ++DEFINE_SYS_REG_OP( BPAM2); ++DEFINE_SYS_REG_OP( BPV2); ++DEFINE_SYS_REG_OP( BPCID2); ++DEFINE_SYS_REG_OP( BPC3); ++DEFINE_SYS_REG_OP( BPA3); ++DEFINE_SYS_REG_OP( BPAM3); ++DEFINE_SYS_REG_OP( BPV3); ++DEFINE_SYS_REG_OP( BPCID3); ++DEFINE_SYS_REG_OP( BPC4); ++DEFINE_SYS_REG_OP( BPA4); ++DEFINE_SYS_REG_OP( BPAM4); ++DEFINE_SYS_REG_OP( BPV4); ++DEFINE_SYS_REG_OP( BPCID4); ++DEFINE_SYS_REG_OP( BPC5); ++DEFINE_SYS_REG_OP( BPA5); ++DEFINE_SYS_REG_OP( BPAM5); ++DEFINE_SYS_REG_OP( BPV5); ++DEFINE_SYS_REG_OP( BPCID5); ++DEFINE_SYS_REG_OP( BPC6); ++DEFINE_SYS_REG_OP( BPA6); ++DEFINE_SYS_REG_OP( BPAM6); ++DEFINE_SYS_REG_OP( BPV6); ++DEFINE_SYS_REG_OP( BPCID6); ++DEFINE_SYS_REG_OP( BPC7); ++DEFINE_SYS_REG_OP( BPA7); ++DEFINE_SYS_REG_OP( BPAM7); ++DEFINE_SYS_REG_OP( BPV7); ++DEFINE_SYS_REG_OP( BPCID7); ++ ++DEFINE_SYS_REG_OP( PFMC0); ++DEFINE_SYS_REG_OP( PFMC1); ++DEFINE_SYS_REG_OP( PFMC2); ++DEFINE_SYS_REG_OP( PFM_CTL); ++ ++DEFINE_SYS_REG_OP( SDZ_CTL); ++DEFINE_SYS_REG_OP( N12MISC_CTL); ++DEFINE_SYS_REG_OP( PRUSR_ACC_CTL); ++ ++DEFINE_SYS_REG_OP( DMA_CFG); ++DEFINE_SYS_REG_OP( DMA_GCSW); ++DEFINE_SYS_REG_OP( DMA_CHNSEL); ++DEFINE_SYS_REG_OP( DMA_ACT); ++DEFINE_SYS_REG_OP( DMA_SETUP); ++DEFINE_SYS_REG_OP( DMA_ISADDR); ++DEFINE_SYS_REG_OP( DMA_ESADDR); ++DEFINE_SYS_REG_OP( DMA_TCNT); ++DEFINE_SYS_REG_OP( DMA_STATUS); ++DEFINE_SYS_REG_OP( DMA_2DSET); ++DEFINE_SYS_REG_OP( DMA_2DSCTL); ++ ++DEFINE_SYS_REG_OP( FPCSR); ++DEFINE_SYS_REG_OP( FPCFG); ++DEFINE_SYS_REG_OP( FUCOP_CTL); ++ ++#endif /* !__ASSEMBLY__ */ ++ ++#endif /* __NDS32_REG_ACCESS_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/resource.h linux-3.4.110/arch/nds32/include/asm/resource.h +--- linux-3.4.110.orig/arch/nds32/include/asm/resource.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/resource.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/resource.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_RESOURCE_H__ ++#define __NDS32_RESOURCE_H__ ++ ++#include <asm-generic/resource.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/rtc.h linux-3.4.110/arch/nds32/include/asm/rtc.h +--- linux-3.4.110.orig/arch/nds32/include/asm/rtc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/rtc.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,43 @@ ++/* ++ * linux/arch/nds32/include/asm/rtc.h ++ * ++ * Copyright (C) 2003 Deep Blue Solutions Ltd. ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef ASMNDS32_RTC_H ++#define ASMNDS32_RTC_H ++ ++struct module; ++ ++struct rtc_ops { ++ struct module *owner; ++ int (*open)(void); ++ void (*release)(void); ++ int (*ioctl)(unsigned int, unsigned long); ++ ++ int (*read_time)(struct rtc_time *); ++ int (*set_time)(struct rtc_time *); ++ int (*read_alarm)(struct rtc_wkalrm *); ++ int (*set_alarm)(struct rtc_wkalrm *); ++ int (*proc)(char *buf); ++}; ++ ++void rtc_update(unsigned long, unsigned long); ++int register_rtc(struct rtc_ops *); ++void unregister_rtc(struct rtc_ops *); ++ ++static inline int rtc_periodic_alarm(struct rtc_time *tm) ++{ ++ return (tm->tm_year == -1) || ++ ((unsigned)tm->tm_mon >= 12) || ++ ((unsigned)(tm->tm_mday - 1) >= 31) || ++ ((unsigned)tm->tm_hour > 23) || ++ ((unsigned)tm->tm_min > 59) || ++ ((unsigned)tm->tm_sec > 59); ++} ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/scatterlist.h linux-3.4.110/arch/nds32/include/asm/scatterlist.h +--- linux-3.4.110.orig/arch/nds32/include/asm/scatterlist.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/scatterlist.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,35 @@ ++/* ++ * linux/arch/nds32/include/asm/scatterlist.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_SCATTERLIST_H ++#define _ASMNDS32_SCATTERLIST_H ++ ++#include <asm/memory.h> ++#include <asm/types.h> ++#include <asm-generic/scatterlist.h> ++ ++#if 0 ++struct scatterlist { ++#ifdef CONFIG_DEBUG_SG ++ unsigned long sg_magic; ++#endif ++ unsigned long page_link; ++ unsigned int offset; /* buffer offset */ ++ dma_addr_t dma_address; /* dma address */ ++ unsigned int length; /* length */ ++}; ++ ++/* ++ * These macros should be used after a pci_map_sg call has been done ++ * to get bus addresses of each of the SG entries and their lengths. ++ * You should only work with the number of sg entries pci_map_sg ++ * returns, or alternatively stop on the first sg_dma_len(sg) which ++ * is 0. ++ */ ++#define sg_dma_address(sg) ((sg)->dma_address) ++#define sg_dma_len(sg) ((sg)->length) ++#endif ++ ++#endif /* _ASMNDS32_SCATTERLIST_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/sections.h linux-3.4.110/arch/nds32/include/asm/sections.h +--- linux-3.4.110.orig/arch/nds32/include/asm/sections.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/sections.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/sections.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __NDS32_SECTIONS_H__ ++#define __NDS32_SECTIONS_H__ ++ ++#include <asm-generic/sections.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/segment.h linux-3.4.110/arch/nds32/include/asm/segment.h +--- linux-3.4.110.orig/arch/nds32/include/asm/segment.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/segment.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,16 @@ ++/* ++ * linux/arch/nds32/include/asm/segment.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ASM_NDS32_SEGMENT_H ++#define __ASM_NDS32_SEGMENT_H ++ ++#define __KERNEL_CS 0x0 ++#define __KERNEL_DS 0x0 ++ ++#define __USER_CS 0x1 ++#define __USER_DS 0x1 ++ ++#endif /* __ASM_NDS32_SEGMENT_H */ ++ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/semaphore.h linux-3.4.110/arch/nds32/include/asm/semaphore.h +--- linux-3.4.110.orig/arch/nds32/include/asm/semaphore.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/semaphore.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,6 @@ ++/* ++ * linux/arch/nds32/include/asm/semaphore.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#include <linux/semaphore.h> +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/semaphore-helper.h linux-3.4.110/arch/nds32/include/asm/semaphore-helper.h +--- linux-3.4.110.orig/arch/nds32/include/asm/semaphore-helper.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/semaphore-helper.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,89 @@ ++/* ++ * linux/arch/nds32/include/asm/semaphore-helper.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef ASMNDS32_SEMAPHORE_HELPER_H ++#define ASMNDS32_SEMAPHORE_HELPER_H ++ ++/* ++ * These two _must_ execute atomically wrt each other. ++ */ ++static inline void wake_one_more(struct semaphore * sem) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ if (atomic_read(&sem->count) <= 0) ++ sem->waking++; ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++} ++ ++static inline int waking_non_zero(struct semaphore *sem) ++{ ++ unsigned long flags; ++ int ret = 0; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ if (sem->waking > 0) { ++ sem->waking--; ++ ret = 1; ++ } ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++ return ret; ++} ++ ++/* ++ * waking non zero interruptible ++ * 1 got the lock ++ * 0 go to sleep ++ * -EINTR interrupted ++ * ++ * We must undo the sem->count down_interruptible() increment while we are ++ * protected by the spinlock in order to make this atomic_inc() with the ++ * atomic_read() in wake_one_more(), otherwise we can race. -arca ++ */ ++static inline int waking_non_zero_interruptible(struct semaphore *sem, ++ struct task_struct *tsk) ++{ ++ unsigned long flags; ++ int ret = 0; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ if (sem->waking > 0) { ++ sem->waking--; ++ ret = 1; ++ } else if (signal_pending(tsk)) { ++ atomic_inc(&sem->count); ++ ret = -EINTR; ++ } ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++ return ret; ++} ++ ++/* ++ * waking_non_zero_try_lock: ++ * 1 failed to lock ++ * 0 got the lock ++ * ++ * We must undo the sem->count down_interruptible() increment while we are ++ * protected by the spinlock in order to make this atomic_inc() with the ++ * atomic_read() in wake_one_more(), otherwise we can race. -arca ++ */ ++static inline int waking_non_zero_trylock(struct semaphore *sem) ++{ ++ unsigned long flags; ++ int ret = 1; ++ ++ spin_lock_irqsave(&semaphore_wake_lock, flags); ++ if (sem->waking <= 0) ++ atomic_inc(&sem->count); ++ else { ++ sem->waking--; ++ ret = 0; ++ } ++ spin_unlock_irqrestore(&semaphore_wake_lock, flags); ++ return ret; ++} ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/sembuf.h linux-3.4.110/arch/nds32/include/asm/sembuf.h +--- linux-3.4.110.orig/arch/nds32/include/asm/sembuf.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/sembuf.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,30 @@ ++/* ++ * linux/arch/nds32/include/asm/sembuf.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_SEMBUF_H ++#define _ASMNDS32_SEMBUF_H ++ ++/* ++ * The semid64_ds structure for arm architecture. ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 64-bit time_t to solve y2038 problem ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct semid64_ds { ++ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ ++ __kernel_time_t sem_otime; /* last semop time */ ++ unsigned long __unused1; ++ __kernel_time_t sem_ctime; /* last change time */ ++ unsigned long __unused2; ++ unsigned long sem_nsems; /* no. of semaphores in array */ ++ unsigned long __unused3; ++ unsigned long __unused4; ++}; ++ ++#endif /* _ASMNDS32_SEMBUF_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/serial.h linux-3.4.110/arch/nds32/include/asm/serial.h +--- linux-3.4.110.orig/arch/nds32/include/asm/serial.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/serial.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,20 @@ ++/* ++ * linux/arch/nds32/include/asm/serial.h ++ * ++ * Copyright (C) 1996 Russell King. ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Changelog: ++ * 15-10-1996 RMK Created ++ */ ++ ++#ifndef __ASM_SERIAL_H ++#define __ASM_SERIAL_H ++ ++#define BASE_BAUD (CONFIG_UART_CLK / 16) ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/setup.h linux-3.4.110/arch/nds32/include/asm/setup.h +--- linux-3.4.110.orig/arch/nds32/include/asm/setup.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/setup.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,232 @@ ++/* ++ * linux/arch/nds32/include/asm/setup.h ++ * ++ * Copyright (C) 1997-1999 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Structure passed to kernel to tell it about the ++ * hardware it's running on. See Documentation/arm/Setup ++ * for more info. ++ */ ++#ifndef __ASMNDS32_SETUP_H ++#define __ASMNDS32_SETUP_H ++ ++#define COMMAND_LINE_SIZE 256 ++ ++/* The list ends with an ATAG_NONE node. */ ++#define ATAG_NONE 0x00000000 ++ ++struct tag_header { ++ u32 size; ++ u32 tag; ++}; ++ ++/* The list must start with an ATAG_CORE node */ ++#define ATAG_CORE 0x54410001 ++ ++struct tag_core { ++ u32 flags; /* bit 0 = read-only */ ++ u32 pagesize; ++ u32 rootdev; ++}; ++ ++/* it is allowed to have multiple ATAG_MEM nodes */ ++#define ATAG_MEM 0x54410002 ++ ++struct tag_mem32 { ++ u32 size; ++ u32 start; /* physical start address */ ++}; ++ ++/* VGA text type displays */ ++#define ATAG_VIDEOTEXT 0x54410003 ++ ++struct tag_videotext { ++ u8 x; ++ u8 y; ++ u16 video_page; ++ u8 video_mode; ++ u8 video_cols; ++ u16 video_ega_bx; ++ u8 video_lines; ++ u8 video_isvga; ++ u16 video_points; ++}; ++ ++/* describes how the ramdisk will be used in kernel */ ++#define ATAG_RAMDISK 0x54410004 ++ ++struct tag_ramdisk { ++ u32 flags; /* bit 0 = load, bit 1 = prompt */ ++ u32 size; /* decompressed ramdisk size in _kilo_ bytes */ ++ u32 start; /* starting block of floppy-based RAM disk image */ ++}; ++ ++/*M Tom ++ * this one accidentally used virtual addresses - as such, ++ * it's deprecated. ++ * describes where the compressed ramdisk image lives (virtual address) ++ */ ++#define ATAG_INITRD 0x54410005 ++ ++/* describes where the compressed ramdisk image lives (physical address) */ ++#define ATAG_INITRD2 0x54420005 ++ ++struct tag_initrd { ++ u32 start; //M Tom va of start addr /* physical start address */ ++ u32 size; //M Tom unzipped size /* size of compressed ramdisk image in bytes */ ++}; ++ ++/* board serial number. "64 bits should be enough for everybody" */ ++#define ATAG_SERIAL 0x54410006 ++ ++struct tag_serialnr { ++ u32 low; ++ u32 high; ++}; ++ ++/* board revision */ ++#define ATAG_REVISION 0x54410007 ++ ++struct tag_revision { ++ u32 rev; ++}; ++ ++/* initial values for vesafb-type framebuffers. see struct screen_info ++ * in include/linux/tty.h ++ */ ++#define ATAG_VIDEOLFB 0x54410008 ++ ++struct tag_videolfb { ++ u16 lfb_width; ++ u16 lfb_height; ++ u16 lfb_depth; ++ u16 lfb_linelength; ++ u32 lfb_base; ++ u32 lfb_size; ++ u8 red_size; ++ u8 red_pos; ++ u8 green_size; ++ u8 green_pos; ++ u8 blue_size; ++ u8 blue_pos; ++ u8 rsvd_size; ++ u8 rsvd_pos; ++}; ++ ++/* command line: \0 terminated string */ ++#define ATAG_CMDLINE 0x54410009 ++ ++struct tag_cmdline { ++ char cmdline[COMMAND_LINE_SIZE];//M Tom ++}; ++ ++/* acorn RiscPC specific information */ ++/*-d Tom ++#define ATAG_ACORN 0x41000101 ++ ++struct tag_acorn { ++ u32 memc_control_reg; ++ u32 vram_pages; ++ u8 sounddefault; ++ u8 adfsdrives; ++}; ++*/ ++#define ATAG_CPE 0x41000101 ++struct tag_cpe { ++ u32 memc_control_reg; ++ u32 vram_pages; ++ u8 sounddefault; ++ u8 adfsdrives; ++}; ++ ++ ++/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */ ++#define ATAG_MEMCLK 0x41000402 ++ ++struct tag_memclk { ++ u32 fmemclk; ++}; ++ ++struct tag { ++ struct tag_header hdr; ++ union { ++ struct tag_core core; ++ struct tag_mem32 mem; ++ struct tag_videotext videotext; ++ struct tag_ramdisk ramdisk; ++ struct tag_initrd initrd; ++ struct tag_serialnr serialnr; ++ struct tag_revision revision; ++ struct tag_videolfb videolfb; ++ struct tag_cmdline cmdline; ++ ++ /* ++ * Andes specific ++ */ ++ struct tag_cpe cpe; ++ ++ /* ++ * DC21285 specific ++ */ ++ struct tag_memclk memclk; ++ } u; ++}; ++ ++struct tagtable { ++ u32 tag; ++ int (*parse)(const struct tag *); ++}; ++ ++#define tag_member_present(tag,member) \ ++ ((unsigned long)(&((struct tag *)0L)->member + 1) \ ++ <= (tag)->hdr.size * 4) ++ ++#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)) ++#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2) ++ ++#define for_each_tag(t,base) \ ++ for (t = base; t->hdr.size; t = tag_next(t)) ++ ++#ifdef __KERNEL__ ++ ++#define __tag __used __attribute__((__section__(".taglist"))) ++#define __tagtable(tag, fn) \ ++static struct tagtable __tagtable_##fn __tag = { tag, fn } ++ ++/* ++ * Memory map description ++ */ ++#ifdef CONFIG_ARCH_LH7A40X ++# define NR_BANKS 16 ++#else ++# define NR_BANKS 8 ++#endif ++ ++struct meminfo { ++ int nr_banks; ++ struct { ++ unsigned long start; ++ unsigned long size; ++ int node; ++ } bank[NR_BANKS]; ++}; ++ ++/* ++ * Early command line parameters. ++ */ ++struct early_params { ++ const char *arg; ++ void (*fn)(char **p); ++}; ++ ++#define __early_param(name,fn) \ ++static struct early_params __early_##fn __used \ ++__attribute__((__section__("__early_param"))) = { name, fn } ++ ++#endif ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/shmbuf.h linux-3.4.110/arch/nds32/include/asm/shmbuf.h +--- linux-3.4.110.orig/arch/nds32/include/asm/shmbuf.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/shmbuf.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,47 @@ ++/* ++ * linux/arch/nds32/include/asm/shmbuf.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_SHMBUF_H ++#define _ASMNDS32_SHMBUF_H ++ ++/* ++ * The shmid64_ds structure for arm architecture. ++ * Note extra padding because this structure is passed back and forth ++ * between kernel and user space. ++ * ++ * Pad space is left for: ++ * - 64-bit time_t to solve y2038 problem ++ * - 2 miscellaneous 32-bit values ++ */ ++ ++struct shmid64_ds { ++ struct ipc64_perm shm_perm; /* operation perms */ ++ size_t shm_segsz; /* size of segment (bytes) */ ++ __kernel_time_t shm_atime; /* last attach time */ ++ unsigned long __unused1; ++ __kernel_time_t shm_dtime; /* last detach time */ ++ unsigned long __unused2; ++ __kernel_time_t shm_ctime; /* last change time */ ++ unsigned long __unused3; ++ __kernel_pid_t shm_cpid; /* pid of creator */ ++ __kernel_pid_t shm_lpid; /* pid of last operator */ ++ unsigned long shm_nattch; /* no. of current attaches */ ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++ ++struct shminfo64 { ++ unsigned long shmmax; ++ unsigned long shmmin; ++ unsigned long shmmni; ++ unsigned long shmseg; ++ unsigned long shmall; ++ unsigned long __unused1; ++ unsigned long __unused2; ++ unsigned long __unused3; ++ unsigned long __unused4; ++}; ++ ++#endif /* _ASMNDS32_SHMBUF_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/shmparam.h linux-3.4.110/arch/nds32/include/asm/shmparam.h +--- linux-3.4.110.orig/arch/nds32/include/asm/shmparam.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/shmparam.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,27 @@ ++/* ++ * linux/arch/nds32/include/asm/shmparam.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_SHMPARAM_H ++#define _ASMNDS32_SHMPARAM_H ++ ++/* ++ * This should be the size of the virtually indexed cache/ways, ++ * whichever is greater since the cache aliases every size/ways ++ * bytes. ++ */ ++/* ++ * Reference ARM architecture, retain the previous code ++ * #define SHMLBA 0x4000 ++ * #define REALSHMLBA (CACHE_SET( DCACHE) * CACHE_LINE_SIZE( DCACHE)) ++ */ ++#define SHMLBA (4 * PAGE_SIZE) /* attach addr a multiple of this */ ++#define REALSHMLBA SHMLBA ++ ++/* ++ * Enforce SHMLBA in shmat ++ */ ++#define __ARCH_FORCE_SHMLBA ++ ++#endif /* _ASMNDS32_SHMPARAM_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/sigcontext.h linux-3.4.110/arch/nds32/include/asm/sigcontext.h +--- linux-3.4.110.orig/arch/nds32/include/asm/sigcontext.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/sigcontext.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,81 @@ ++/* ++ * linux/arch/nds32/include/asm/sigcontext.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_SIGCONTEXT_H ++#define _ASMNDS32_SIGCONTEXT_H ++ ++/* ++ * Signal context structure - contains all info to do with the state ++ * before the signal handler was invoked. Note: only add new entries ++ * to the end of the structure. ++ */ ++struct fpu_struct { ++ unsigned long fs_regs[32]; ++ unsigned long long fd_regs[16]; ++ unsigned long fpcsr; ++}; ++ ++struct audio_struct { ++ unsigned long auregs[32]; ++}; ++ ++struct zol_struct { ++ unsigned long nds32_lc; /* $LC */ ++ unsigned long nds32_le; /* $LE */ ++ unsigned long nds32_lb; /* $LB */ ++}; ++ ++struct sigcontext { ++ unsigned long trap_no; ++ unsigned long error_code; ++ unsigned long oldmask; ++ unsigned long nds32_r0; ++ unsigned long nds32_r1; ++ unsigned long nds32_r2; ++ unsigned long nds32_r3; ++ unsigned long nds32_r4; ++ unsigned long nds32_r5; ++ unsigned long nds32_r6; ++ unsigned long nds32_r7; ++ unsigned long nds32_r8; ++ unsigned long nds32_r9; ++ unsigned long nds32_r10; ++ unsigned long nds32_r11; ++ unsigned long nds32_r12; ++ unsigned long nds32_r13; ++ unsigned long nds32_r14; ++ unsigned long nds32_r15; ++ unsigned long nds32_r16; ++ unsigned long nds32_r17; ++ unsigned long nds32_r18; ++ unsigned long nds32_r19; ++ unsigned long nds32_r20; ++ unsigned long nds32_r21; ++ unsigned long nds32_r22; ++ unsigned long nds32_r23; ++ unsigned long nds32_r24; ++ unsigned long nds32_r25; ++ unsigned long nds32_fp; /* $r28 */ ++ unsigned long nds32_gp; /* $r29 */ ++ unsigned long nds32_lr; /* $r30 */ ++ unsigned long nds32_sp; /* $r31 */ ++ unsigned long nds32_ipc; ++ unsigned long fault_address; ++#if defined(CONFIG_FPU) ++ unsigned long used_math_flag; ++ /* FPU Registers */ ++ struct fpu_struct fpu; ++#endif ++ /* Audio Registers */ ++#if defined(CONFIG_AUDIO) ++ unsigned long used_audio_flag; ++ struct audio_struct audio; ++#endif ++#if defined(CONFIG_HWZOL) ++ struct zol_struct zol; ++#endif ++}; ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/siginfo.h linux-3.4.110/arch/nds32/include/asm/siginfo.h +--- linux-3.4.110.orig/arch/nds32/include/asm/siginfo.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/siginfo.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/siginfo.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_SIGINFO_H ++#define _ASMNDS32_SIGINFO_H ++ ++#include <asm-generic/siginfo.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/signal.h linux-3.4.110/arch/nds32/include/asm/signal.h +--- linux-3.4.110.orig/arch/nds32/include/asm/signal.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/signal.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,173 @@ ++/* ++ * linux/arch/nds32/include/asm/signal.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_SIGNAL_H ++#define _ASMNDS32_SIGNAL_H ++ ++#include <linux/types.h> ++ ++/* Avoid too many header ordering problems. */ ++struct siginfo; ++ ++#ifdef __KERNEL__ ++/* Most things should be clean enough to redefine this at will, if care ++ is taken to make libc match. */ ++ ++#define _NSIG 64 ++#define _NSIG_BPW 32 ++#define _NSIG_WORDS (_NSIG / _NSIG_BPW) ++ ++typedef unsigned long old_sigset_t; /* at least 32 bits */ ++ ++typedef struct { ++ unsigned long sig[_NSIG_WORDS]; ++} sigset_t; ++ ++#else ++/* Here we must cater to libcs that poke about in kernel headers. */ ++ ++#define NSIG 32 ++typedef unsigned long sigset_t; ++ ++#endif /* __KERNEL__ */ ++ ++#define SIGHUP 1 ++#define SIGINT 2 ++#define SIGQUIT 3 ++#define SIGILL 4 ++#define SIGTRAP 5 ++#define SIGABRT 6 ++#define SIGIOT 6 ++#define SIGBUS 7 ++#define SIGFPE 8 ++#define SIGKILL 9 ++#define SIGUSR1 10 ++#define SIGSEGV 11 ++#define SIGUSR2 12 ++#define SIGPIPE 13 ++#define SIGALRM 14 ++#define SIGTERM 15 ++#define SIGSTKFLT 16 ++#define SIGCHLD 17 ++#define SIGCONT 18 ++#define SIGSTOP 19 ++#define SIGTSTP 20 ++#define SIGTTIN 21 ++#define SIGTTOU 22 ++#define SIGURG 23 ++#define SIGXCPU 24 ++#define SIGXFSZ 25 ++#define SIGVTALRM 26 ++#define SIGPROF 27 ++#define SIGWINCH 28 ++#define SIGIO 29 ++#define SIGPOLL SIGIO ++/* ++#define SIGLOST 29 ++*/ ++#define SIGPWR 30 ++#define SIGSYS 31 ++#define SIGUNUSED 31 ++ ++/* These should not be considered constants from userland. */ ++#define SIGRTMIN 32 ++#define SIGRTMAX _NSIG ++ ++#define SIGSWI 32 ++ ++/* ++ * SA_FLAGS values: ++ * ++ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. ++ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. ++ * SA_SIGINFO deliver the signal with SIGINFO structs ++ * SA_THIRTYTWO delivers the signal in 32-bit mode, even if the task ++ * is running in 26-bit. ++ * SA_ONSTACK allows alternate signal stacks (see sigaltstack(2)). ++ * SA_RESTART flag to get restarting signals (which were the default long ago) ++ * SA_NODEFER prevents the current signal from being masked in the handler. ++ * SA_RESETHAND clears the handler when the signal is delivered. ++ * ++ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single ++ * Unix names RESETHAND and NODEFER respectively. ++ */ ++#define SA_NOCLDSTOP 0x00000001 ++#define SA_NOCLDWAIT 0x00000002 ++#define SA_SIGINFO 0x00000004 ++#define SA_THIRTYTWO 0x02000000 ++#define SA_RESTORER 0x04000000 ++#define SA_ONSTACK 0x08000000 ++#define SA_RESTART 0x10000000 ++#define SA_NODEFER 0x40000000 ++#define SA_RESETHAND 0x80000000 ++ ++#define SA_NOMASK SA_NODEFER ++#define SA_ONESHOT SA_RESETHAND ++ ++ ++/* ++ * sigaltstack controls ++ */ ++#define SS_ONSTACK 1 ++#define SS_DISABLE 2 ++ ++#define MINSIGSTKSZ 2048 ++#define SIGSTKSZ 8192 ++ ++#ifdef __KERNEL__ ++#define SA_IRQNOMASK 0x08000000 ++#endif ++ ++#include <asm-generic/signal-defs.h> ++ ++#ifdef __KERNEL__ ++struct old_sigaction { ++ __sighandler_t sa_handler; ++ old_sigset_t sa_mask; ++ unsigned long sa_flags; ++ __sigrestore_t sa_restorer; ++}; ++ ++struct sigaction { ++ __sighandler_t sa_handler; ++ unsigned long sa_flags; ++ __sigrestore_t sa_restorer; ++ sigset_t sa_mask; /* mask last for extensibility */ ++}; ++ ++struct k_sigaction { ++ struct sigaction sa; ++}; ++ ++#else ++/* Here we must cater to libcs that poke about in kernel headers. */ ++ ++struct sigaction { ++ union { ++ __sighandler_t _sa_handler; ++ void (*_sa_sigaction)(int, struct siginfo *, void *); ++ } _u; ++ sigset_t sa_mask; ++ unsigned long sa_flags; ++ void (*sa_restorer)(void); ++}; ++ ++#define sa_handler _u._sa_handler ++#define sa_sigaction _u._sa_sigaction ++ ++#endif /* __KERNEL__ */ ++ ++typedef struct sigaltstack { ++ void __user *ss_sp; ++ int ss_flags; ++ size_t ss_size; ++} stack_t; ++ ++#ifdef __KERNEL__ ++#include <asm/sigcontext.h> ++#define ptrace_signal_deliver(regs, cookie) do { } while (0) ++#endif ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/sizes.h linux-3.4.110/arch/nds32/include/asm/sizes.h +--- linux-3.4.110.orig/arch/nds32/include/asm/sizes.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/sizes.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,53 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++/* DO NOT EDIT!! - this file automatically generated ++ * from .s file by awk -f s2h.awk ++ */ ++/* Size definitions ++ * Copyright (C) ARM Limited 1998. All rights reserved. ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __sizes_h ++#define __sizes_h 1 ++ ++/* handy sizes */ ++#define SZ_1K 0x00000400 ++#define SZ_4K 0x00001000 ++#define SZ_8K 0x00002000 ++#define SZ_16K 0x00004000 ++#define SZ_64K 0x00010000 ++#define SZ_128K 0x00020000 ++#define SZ_256K 0x00040000 ++#define SZ_512K 0x00080000 ++ ++#define SZ_1M 0x00100000 ++#define SZ_2M 0x00200000 ++#define SZ_4M 0x00400000 ++#define SZ_8M 0x00800000 ++#define SZ_16M 0x01000000 ++#define SZ_32M 0x02000000 ++#define SZ_64M 0x04000000 ++#define SZ_128M 0x08000000 ++#define SZ_256M 0x10000000 ++#define SZ_512M 0x20000000 ++ ++#define SZ_1G 0x40000000 ++#define SZ_2G 0x80000000 ++ ++#endif ++ ++/* END */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/smp.h linux-3.4.110/arch/nds32/include/asm/smp.h +--- linux-3.4.110.orig/arch/nds32/include/asm/smp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/smp.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,42 @@ ++/* ++ * linux/arch/nds32/include/asm/smp.h ++ * ++ * Copyright (C) 2004-2005 ARM Ltd. ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __ASM_NDS32_SMP_H ++#define __ASM_NDS32_SMP_H ++ ++#include <linux/threads.h> ++#include <linux/cpumask.h> ++#include <linux/thread_info.h> ++ ++#ifndef CONFIG_SMP ++# error "<asm-nds32/smp.h> included in non-SMP build" ++#endif ++ ++/* ++ * at the moment, there's not a big penalty for changing CPUs ++ * (the >big< penalty is running SMP in the first place) ++ */ ++#define PROC_CHANGE_PENALTY 15 ++ ++struct seq_file; ++ ++/* ++ * Move global data into per-processor storage. ++ */ ++extern void smp_store_cpu_info(unsigned int cpuid); ++ ++#define raw_smp_processor_id() (unsigned int)(GET_CORE_ID()&CORE_ID_mskCOREID) ++ ++extern void smp_init_cpus(void); ++extern void smp_send_timer(void); ++extern void arch_send_call_function_single_ipi(int cpu); ++extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); ++ ++#endif /* ifndef __ASM_NDS32_SMP_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/socket.h linux-3.4.110/arch/nds32/include/asm/socket.h +--- linux-3.4.110.orig/arch/nds32/include/asm/socket.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/socket.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/socket.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_SOCKET_H ++#define _ASMNDS32_SOCKET_H ++ ++#include <asm-generic/socket.h> ++ ++#endif /* _ASMNDS32_SOCKET_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/sockios.h linux-3.4.110/arch/nds32/include/asm/sockios.h +--- linux-3.4.110.orig/arch/nds32/include/asm/sockios.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/sockios.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * linux/arch/nds32/include/asm/sockios.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ARCH_NDS32_SOCKIOS_H ++#define __ARCH_NDS32_SOCKIOS_H ++ ++/* Socket-level I/O control calls. */ ++#define FIOSETOWN 0x8901 ++#define SIOCSPGRP 0x8902 ++#define FIOGETOWN 0x8903 ++#define SIOCGPGRP 0x8904 ++#define SIOCATMARK 0x8905 ++#define SIOCGSTAMP 0x8906 /* Get stamp */ ++#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/spec-ag101.h linux-3.4.110/arch/nds32/include/asm/spec-ag101.h +--- linux-3.4.110.orig/arch/nds32/include/asm/spec-ag101.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/spec-ag101.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,237 @@ ++#ifndef __NDS32_AG101_SPECIFICATION_H__ ++#define __NDS32_AG101_SPECIFICATION_H__ ++ ++#define UART0_PA_BASE 0x99600000 ++#define UART0_VA_BASE 0xF9960000 ++#define UART0_IRQ 7 ++#define UART1_PA_BASE 0x98300000 ++#define UART1_VA_BASE 0xF9830000 ++#define UART1_IRQ 11 ++#define CFC_FTCFC010_0_PA_BASE 0x98D00000 ++#define CFC_FTCFC010_0_VA_BASE 0xF98D0000 ++#define SDC_FTSDC010_0_PA_BASE 0x98e00000 ++#define SDC_FTSDC010_0_VA_BASE 0xF98e0000 ++#define SDMC_FTSDMC021_PA_BASE 0x90300000 ++#define SDMC_FTSDMC021_VA_BASE 0xF9030000 ++#define PCIC_FTPCI100_0_PA_BASE 0x90C00000 ++#define PCIC_FTPCI100_0_VA_BASE 0xF90C0000 ++#define PCIC_FTPCI100_0_VA_LIMIT 0xF90CFFFF ++#define PCIIO_PA_BASE 0x90C01000 ++#define PCIIO_VA_BASE 0xFE901000 ++#define PCIIO_0_PA_BASE 0x90C01000 ++#define PCIIO_0_VA_BASE 0xFE901000 ++#define PCIIO_VA_LIMIT 0xFE9FFFFF ++#define AHB_ATFAHBC020S_0_PA_BASE 0x90100000 ++#define AHB_ATFAHBC020S_0_VA_BASE 0xF9010000 ++ ++/* DMAC */ ++#define DMAC_FTDMAC020_PA_COUNT 1 ++#define DMAC_FTDMAC020_PA_BASE 0x90400000 ++#define DMAC_FTDMAC020_PA_LIMIT 0x90400FFF ++#define DMAC_FTDMAC020_PA_SIZE 0x00001000 ++#define DMAC_FTDMAC020_0_PA_BASE 0x90400000 ++#define DMAC_FTDMAC020_0_PA_LIMIT 0x90400FFF ++#define DMAC_FTDMAC020_0_PA_SIZE 0x00001000 ++#define DMAC_FTDMAC020_VA_COUNT 1 ++#define DMAC_FTDMAC020_VA_BASE 0xF9040000 ++#define DMAC_FTDMAC020_VA_LIMIT 0xF9040FFF ++#define DMAC_FTDMAC020_VA_SIZE 0x00001000 ++#define DMAC_FTDMAC020_0_VA_BASE 0xF9040000 ++#define DMAC_FTDMAC020_0_VA_LIMIT 0xF9040FFF ++#define DMAC_FTDMAC020_0_VA_SIZE 0x00001000 ++ ++/* TIMER */ ++#define TIMER_FTTMR010_PA_COUNT 1 ++#define TIMER_FTTMR010_PA_BASE 0x98400000 ++#define TIMER_FTTMR010_PA_LIMIT 0x98400FFF ++#define TIMER_FTTMR010_PA_SIZE 0x00001000 ++#define TIMER_FTTMR010_0_PA_BASE 0x98400000 ++#define TIMER_FTTMR010_0_PA_LIMIT 0x98400FFF ++#define TIMER_FTTMR010_0_PA_SIZE 0x00001000 ++#define TIMER_FTTMR010_VA_COUNT 1 ++#define TIMER_FTTMR010_VA_BASE 0xF9840000 ++#define TIMER_FTTMR010_VA_LIMIT 0xF9840FFF ++#define TIMER_FTTMR010_VA_SIZE 0x00001000 ++#define TIMER_FTTMR010_0_VA_BASE 0xF9840000 ++#define TIMER_FTTMR010_0_VA_LIMIT 0xF9840FFF ++#define TIMER_FTTMR010_0_VA_SIZE 0x00001000 ++ ++/* RTC */ ++#define RTC_FTRTC010_PA_COUNT 1 ++#define RTC_FTRTC010_PA_BASE 0x98600000 ++#define RTC_FTRTC010_PA_LIMIT 0x98600FFF ++#define RTC_FTRTC010_PA_SIZE 0x00001000 ++#define RTC_FTRTC010_0_PA_BASE 0x98600000 ++#define RTC_FTRTC010_0_PA_LIMIT 0x98600FFF ++#define RTC_FTRTC010_0_PA_SIZE 0x00001000 ++#define RTC_FTRTC010_VA_COUNT 1 ++#define RTC_FTRTC010_VA_BASE 0xF9860000 ++#define RTC_FTRTC010_VA_LIMIT 0xF9860FFF ++#define RTC_FTRTC010_VA_SIZE 0x00001000 ++#define RTC_FTRTC010_0_VA_BASE 0xF9860000 ++#define RTC_FTRTC010_0_VA_LIMIT 0xF9860FFF ++#define RTC_FTRTC010_0_VA_SIZE 0x00001000 ++ ++/* WDT */ ++#define WDT_FTWDT010_PA_COUNT 1 ++#define WDT_FTWDT010_PA_BASE 0x98500000 ++#define WDT_FTWDT010_PA_LIMIT 0x98500FFF ++#define WDT_FTWDT010_PA_SIZE 0x00001000 ++#define WDT_FTWDT010_0_PA_BASE 0x98500000 ++#define WDT_FTWDT010_0_PA_LIMIT 0x98500FFF ++#define WDT_FTWDT010_0_PA_SIZE 0x00001000 ++#define WDT_FTWDT010_VA_COUNT 1 ++#define WDT_FTWDT010_VA_BASE 0xF9850000 ++#define WDT_FTWDT010_VA_LIMIT 0xF9850FFF ++#define WDT_FTWDT010_VA_SIZE 0x00001000 ++#define WDT_FTWDT010_0_VA_BASE 0xF9850000 ++#define WDT_FTWDT010_0_VA_LIMIT 0xF9850FFF ++#define WDT_FTWDT010_0_VA_SIZE 0x00001000 ++ ++/* GPIO */ ++#define GPIO_FTGPIO010_PA_COUNT 1 ++#define GPIO_FTGPIO010_PA_BASE 0x98700000 ++#define GPIO_FTGPIO010_PA_LIMIT 0x98700FFF ++#define GPIO_FTGPIO010_PA_SIZE 0x00001000 ++#define GPIO_FTGPIO010_0_PA_BASE 0x98700000 ++#define GPIO_FTGPIO010_0_PA_LIMIT 0x98700FFF ++#define GPIO_FTGPIO010_0_PA_SIZE 0x00001000 ++#define GPIO_FTGPIO010_VA_COUNT 1 ++#define GPIO_FTGPIO010_VA_BASE 0xF9870000 ++#define GPIO_FTGPIO010_VA_LIMIT 0xF9870FFF ++#define GPIO_FTGPIO010_VA_SIZE 0x00001000 ++#define GPIO_FTGPIO010_0_VA_BASE 0xF9870000 ++#define GPIO_FTGPIO010_0_VA_LIMIT 0xF9870FFF ++#define GPIO_FTGPIO010_0_VA_SIZE 0x00001000 ++ ++ ++/* USB OTG */ ++#define USB_FOTG2XX_0_PA_COUNT 1 ++#define USB_FOTG2XX_0_PA_BASE 0x90B00000 ++#define USB_FOTG2XX_0_PA_LIMIT 0x90B00FFF ++#define USB_FOTG2XX_0_PA_SIZE 0x00001000 ++#define USB_FOTG2XX_0_VA_BASE 0xF90B0000 ++#define USB_FOTG2XX_0_VA_LIMIT 0xF90B0FFF ++#define USB_FOTG2XX_0_VA_SIZE 0x00001000 ++#define USB_FOTG2XX_0_IRQ 26 ++#define USB_FOTG2XX_PA_COUNT 1 ++#define USB_FOTG2XX_PA_BASE 0x90B00000 ++#define USB_FOTG2XX_PA_LIMIT 0x90B00FFF ++#define USB_FOTG2XX_PA_SIZE 0x00001000 ++#define USB_FOTG2XX_VA_BASE 0xF90B0000 ++#define USB_FOTG2XX_VA_LIMIT 0xF90B0FFF ++#define USB_FOTG2XX_VA_SIZE 0x00001000 ++#define USB_FOTG2XX_IRQ 26 ++#define USB_FOTG2XX_IRQ_COUNT 1 ++ ++/* SSP */ ++#define SSP_FTSSP010_PA_COUNT 1 ++#define SSP_FTSSP010_PA_BASE 0x99400000 ++#define SSP_FTSSP010_PA_LIMIT 0x99400FFF ++#define SSP_FTSSP010_PA_SIZE 0x00001000 ++#define SSP_FTSSP010_0_PA_BASE 0x99400000 ++#define SSP_FTSSP010_0_PA_LIMIT 0x99400FFF ++#define SSP_FTSSP010_0_PA_SIZE 0x00001000 ++#define SSP_FTSSP010_VA_COUNT 1 ++#define SSP_FTSSP010_VA_BASE 0xF9940000 ++#define SSP_FTSSP010_VA_LIMIT 0xF9940FFF ++#define SSP_FTSSP010_VA_SIZE 0x00001000 ++#define SSP_FTSSP010_0_VA_BASE 0xF9940000 ++#define SSP_FTSSP010_0_VA_LIMIT 0xF9940FFF ++#define SSP_FTSSP010_0_VA_SIZE 0x00001000 ++ ++/* APBBRG */ ++#define APBBRG_FTAPBBRG020S_PA_COUNT 1 ++#define APBBRG_FTAPBBRG020S_PA_BASE 0x90500000 ++#define APBBRG_FTAPBBRG020S_PA_LIMIT 0x90500FFF ++#define APBBRG_FTAPBBRG020S_PA_SIZE 0x00001000 ++#define APBBRG_FTAPBBRG020S_0_PA_BASE 0x90500000 ++#define APBBRG_FTAPBBRG020S_0_PA_LIMIT 0x90500FFF ++#define APBBRG_FTAPBBRG020S_0_PA_SIZE 0x00001000 ++#define APBBRG_FTAPBBRG020S_1_PA_BASE 0x90E00000 ++#define APBBRG_FTAPBBRG020S_1_PA_LIMIT 0x90E00FFF ++#define APBBRG_FTAPBBRG020S_1_PA_SIZE 0x00001000 ++#define APBBRG_FTAPBBRG020S_VA_COUNT 1 ++#define APBBRG_FTAPBBRG020S_VA_BASE 0xF9050000 ++#define APBBRG_FTAPBBRG020S_VA_LIMIT 0xF9050FFF ++#define APBBRG_FTAPBBRG020S_VA_SIZE 0x00001000 ++#define APBBRG_FTAPBBRG020S_0_VA_BASE 0xF9050000 ++#define APBBRG_FTAPBBRG020S_0_VA_LIMIT 0xF9050FFF ++#define APBBRG_FTAPBBRG020S_0_VA_SIZE 0x00001000 ++#define APBBRG_FTAPBBRG020S_1_VA_BASE 0xF90E0000 ++#define APBBRG_FTAPBBRG020S_1_VA_LIMIT 0xF90E0FFF ++#define APBBRG_FTAPBBRG020S_1_VA_SIZE 0x00001000 ++ ++/* I2C */ ++#define I2C_FTI2C010_PA_COUNT 1 ++#define I2C_FTI2C010_PA_BASE 0x98A00000 ++#define I2C_FTI2C010_PA_LIMIT 0x98A00FFF ++#define I2C_FTI2C010_PA_SIZE 0x00001000 ++#define I2C_FTI2C010_0_PA_BASE 0x98A00000 ++#define I2C_FTI2C010_0_PA_LIMIT 0x98A00FFF ++#define I2C_FTI2C010_0_PA_SIZE 0x00001000 ++#define I2C_FTI2C010_VA_COUNT 1 ++#define I2C_FTI2C010_VA_BASE 0xF98A0000 ++#define I2C_FTI2C010_VA_LIMIT 0xF98A0FFF ++#define I2C_FTI2C010_VA_SIZE 0x00001000 ++#define I2C_FTI2C010_0_VA_BASE 0xF98A0000 ++#define I2C_FTI2C010_0_VA_LIMIT 0xF98A0FFF ++#define I2C_FTI2C010_0_VA_SIZE 0x00001000 ++ ++/* L2CC */ ++#define L2CC_PA_BASE 0x90F00000 /* reserved */ ++#define L2CC_VA_BASE 0xF90F0000 /* FIXME */ ++ ++#define LED_PA_COUNT 1 ++#define LED_PA_BASE 0x902FF000 ++#define LED_PA_LIMIT 0x90200FFF ++#define LED_PA_SIZE 0x00001000 ++#define LED_0_PA_BASE 0x90200000 ++#define LED_0_PA_LIMIT 0x90200FFF ++#define LED_0_PA_SIZE 0x00001000 ++#define LED_VA_COUNT 1 ++#define LED_VA_BASE 0xF9020000 ++#define LED_VA_LIMIT 0xF9020000 ++#define LED_VA_SIZE 0x00001000 ++#define LED_0_VA_BASE 0xF9020000 ++#define LED_0_VA_LIMIT 0xF9020000 ++#define LED_0_VA_SIZE 0x00001000 ++ ++/* MAC */ ++#define MAC_FTMAC100_PA_COUNT 1 ++#define MAC_FTMAC100_PA_BASE 0x90900000 ++#define MAC_FTMAC100_PA_LIMIT 0x90900FFF ++#define MAC_FTMAC100_PA_SIZE 0x00001000 ++#define MAC_FTMAC100_0_PA_BASE 0x90900000 ++#define MAC_FTMAC100_0_PA_LIMIT 0x90900FFF ++#define MAC_FTMAC100_0_PA_SIZE 0x00001000 ++#define MAC_FTMAC100_1_PA_BASE 0x92000000 ++#define MAC_FTMAC100_1_PA_LIMIT 0x92000FFF ++#define MAC_FTMAC100_1_PA_SIZE 0x00001000 ++#define MAC_FTMAC100_VA_COUNT 1 ++#define MAC_FTMAC100_VA_BASE 0xF9090000 ++#define MAC_FTMAC100_VA_LIMIT 0xF9090FFF ++#define MAC_FTMAC100_VA_SIZE 0x00001000 ++#define MAC_FTMAC100_0_VA_BASE 0xF9090000 ++#define MAC_FTMAC100_0_VA_LIMIT 0xF9090FFF ++#define MAC_FTMAC100_0_VA_SIZE 0x00001000 ++#define MAC_FTMAC100_1_VA_BASE 0xF9200000 ++#define MAC_FTMAC100_1_VA_LIMIT 0xF9200FFF ++#define MAC_FTMAC100_1_VA_SIZE 0x00001000 ++ ++/* LCD */ ++#define LCD_FTLCDC100_PA_COUNT 1 ++#define LCD_FTLCDC100_PA_BASE 0x90600000 ++#define LCD_FTLCDC100_PA_LIMIT 0x90600FFF ++#define LCD_FTLCDC100_PA_SIZE 0x00001000 ++#define LCD_FTLCDC100_0_PA_BASE 0x90600000 ++#define LCD_FTLCDC100_0_PA_LIMIT 0x90600FFF ++#define LCD_FTLCDC100_0_PA_SIZE 0x00001000 ++#define LCD_FTLCDC100_VA_COUNT 1 ++#define LCD_FTLCDC100_VA_BASE 0xF9060000 ++#define LCD_FTLCDC100_VA_LIMIT 0xF9060FFF ++#define LCD_FTLCDC100_VA_SIZE 0x00001000 ++#define LCD_FTLCDC100_0_VA_BASE 0xF9060000 ++#define LCD_FTLCDC100_0_VA_LIMIT 0xF9060FFF ++#define LCD_FTLCDC100_0_VA_SIZE 0x00001000 ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/spec-ag102.h linux-3.4.110/arch/nds32/include/asm/spec-ag102.h +--- linux-3.4.110.orig/arch/nds32/include/asm/spec-ag102.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/spec-ag102.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,167 @@ ++#ifndef __NDS32_AG102_SPECIFICATION_H__ ++#define __NDS32_AG102_SPECIFICATION_H__ ++ ++#define UART0_PA_BASE 0x94200000 ++#define UART0_VA_BASE 0xF9420000 ++#define UART0_IRQ 10 ++#define UART1_PA_BASE 0x94600000 ++#define UART1_VA_BASE 0xF9460000 ++#define UART1_IRQ 11 ++#define AMIC_PA_BASE 0x90F00000 ++#define AMIC_VA_BASE 0xF90F0000 ++#define GMAC_PA_BASE 0x90B00000 ++#define GMAC_VA_BASE 0xF90B0000 ++#define APBBR_PA_BASE 0x90D00000 ++#define APBBR_VA_BASE 0xF90D0000 ++#define GMAC_IRQ 25 ++#define TIMER_PA_BASE 0x94900000 ++#define TIMER_VA_BASE 0xF9490000 ++#define L2CC_PA_BASE 0x90900000 ++#define L2CC_VA_BASE 0xF9090000 ++#define CFC_FTCFC010_0_PA_BASE 0x94000000 ++#define CFC_FTCFC010_0_VA_BASE 0xF9400000 ++#define SDC_FTSDC010_0_PA_BASE 0x94400000 ++#define SDC_FTSDC010_0_VA_BASE 0xF9440000 ++#define PCU_PA_BASE 0x94800000 ++#define PCU_VA_BASE 0xF9480000 ++#define PCIC_FTPCI100_0_PA_BASE 0x90000000 ++#define PCIC_FTPCI100_0_VA_BASE 0xF9000000 ++#define PCIC_FTPCI100_0_VA_LIMIT 0xF9000FFF ++#define PCIIO_PA_BASE 0x90001000 ++#define PCIIO_VA_BASE 0xF8901000 ++#define PCIIO_0_PA_BASE 0x90001000 ++#define PCIIO_0_VA_BASE 0xF8901000 ++#define PCIIO_VA_LIMIT 0xF89FFFFF ++#define LPC_IO_PA_BASE 0x90100000 ++#define LPC_IO_VA_BASE 0xF9010000 ++#define LPC_REG_PA_BASE 0x90200000 ++#define LPC_REG_VA_BASE 0xF9020000 ++#define LPC_IRQ 29 ++#define GPU_PA_BASE 0x90A00000 ++#define GPU_VA_BASE 0xFEA00000 ++#define IDE_FTIDE020_VA_BASE 0xF9070000 ++#define IDE_FTIDE020_PA_BASE 0x90700000 ++#define IDE_FTIDE020_IRQ 1 ++#define USB_FOTG2XX_0_PA_BASE 0x90800000 ++#define USB_FOTG2XX_0_VA_BASE 0xF9080000 ++#define USB_FOTG2XX_0_IRQ 26 ++#define DDR2C_PA_BASE 0x90500000 ++#define DDR2C_VA_BASE 0xF9050000 ++#define GPIO_VA_BASE 0xF94C0000 ++#define GPIO_PA_BASE 0x94C00000 ++ ++#define PLATFORM_LPC_IRQ_BASE 180 ++#define PLATFORM_LPC_IRQ_TOTALCOUNT 22 ++ ++/* DMAC */ ++#define DMAC_FTDMAC020_PA_COUNT 1 ++#define DMAC_FTDMAC020_PA_BASE 0x90600000 ++#define DMAC_FTDMAC020_PA_LIMIT 0x90600FFF ++#define DMAC_FTDMAC020_PA_SIZE 0x00001000 ++#define DMAC_FTDMAC020_0_PA_BASE 0x90600000 ++#define DMAC_FTDMAC020_0_PA_LIMIT 0x90600FFF ++#define DMAC_FTDMAC020_0_PA_SIZE 0x00001000 ++#define DMAC_FTDMAC020_VA_COUNT 1 ++#define DMAC_FTDMAC020_VA_BASE 0xF9060000 ++#define DMAC_FTDMAC020_VA_LIMIT 0xF9060FFF ++#define DMAC_FTDMAC020_VA_SIZE 0x00001000 ++#define DMAC_FTDMAC020_0_VA_BASE 0xF9060000 ++#define DMAC_FTDMAC020_0_VA_LIMIT 0xF9060FFF ++#define DMAC_FTDMAC020_0_VA_SIZE 0x00001000 ++ ++/* TIMER */ ++#define TIMER_FTTMR010_PA_COUNT 1 ++#define TIMER_FTTMR010_PA_BASE 0x94900000 ++#define TIMER_FTTMR010_PA_LIMIT 0x94900FFF ++#define TIMER_FTTMR010_PA_SIZE 0x00001000 ++#define TIMER_FTTMR010_0_PA_BASE 0x94900000 ++#define TIMER_FTTMR010_0_PA_LIMIT 0x94900FFF ++#define TIMER_FTTMR010_0_PA_SIZE 0x00001000 ++#define TIMER_FTTMR010_VA_COUNT 1 ++#define TIMER_FTTMR010_VA_BASE 0xF9490000 ++#define TIMER_FTTMR010_VA_LIMIT 0xF9490FFF ++#define TIMER_FTTMR010_VA_SIZE 0x00001000 ++#define TIMER_FTTMR010_0_VA_BASE 0xF9490000 ++#define TIMER_FTTMR010_0_VA_LIMIT 0xF9490FFF ++#define TIMER_FTTMR010_0_VA_SIZE 0x00001000 ++ ++/* WDT */ ++#define WDT_FTWDT010_PA_COUNT 1 ++#define WDT_FTWDT010_PA_BASE 0x94A00000 ++#define WDT_FTWDT010_PA_LIMIT 0x94A00FFF ++#define WDT_FTWDT010_PA_SIZE 0x00001000 ++#define WDT_FTWDT010_0_PA_BASE 0x94A00000 ++#define WDT_FTWDT010_0_PA_LIMIT 0x94A00FFF ++#define WDT_FTWDT010_0_PA_SIZE 0x00001000 ++#define WDT_FTWDT010_VA_COUNT 1 ++#define WDT_FTWDT010_VA_BASE 0xF94A0000 ++#define WDT_FTWDT010_VA_LIMIT 0xF94A0FFF ++#define WDT_FTWDT010_VA_SIZE 0x00001000 ++#define WDT_FTWDT010_0_VA_BASE 0xF94A0000 ++#define WDT_FTWDT010_0_VA_LIMIT 0xF94A0FFF ++#define WDT_FTWDT010_0_VA_SIZE 0x00001000 ++ ++/* RTC */ ++#define RTC_FTRTC010_PA_COUNT 1 ++#define RTC_FTRTC010_PA_BASE 0x94B00000 ++#define RTC_FTRTC010_PA_LIMIT 0x94B00FFF ++#define RTC_FTRTC010_PA_SIZE 0x00001000 ++#define RTC_FTRTC010_0_PA_BASE 0x94B00000 ++#define RTC_FTRTC010_0_PA_LIMIT 0x94B00FFF ++#define RTC_FTRTC010_0_PA_SIZE 0x00001000 ++#define RTC_FTRTC010_VA_COUNT 1 ++#define RTC_FTRTC010_VA_BASE 0xF94B0000 ++#define RTC_FTRTC010_VA_LIMIT 0xF94B0FFF ++#define RTC_FTRTC010_VA_SIZE 0x00001000 ++#define RTC_FTRTC010_0_VA_BASE 0xF94B0000 ++#define RTC_FTRTC010_0_VA_LIMIT 0xF94B0FFF ++#define RTC_FTRTC010_0_VA_SIZE 0x00001000 ++ ++/* GPIO */ ++#define GPIO_FTGPIO010_PA_COUNT 1 ++#define GPIO_FTGPIO010_PA_BASE 0x94C00000 ++#define GPIO_FTGPIO010_PA_LIMIT 0x94C00FFF ++#define GPIO_FTGPIO010_PA_SIZE 0x00001000 ++#define GPIO_FTGPIO010_0_PA_BASE 0x94C00000 ++#define GPIO_FTGPIO010_0_PA_LIMIT 0x94C00FFF ++#define GPIO_FTGPIO010_0_PA_SIZE 0x00001000 ++#define GPIO_FTGPIO010_VA_COUNT 1 ++#define GPIO_FTGPIO010_VA_BASE 0xF94C0000 ++#define GPIO_FTGPIO010_VA_LIMIT 0xF94C0FFF ++#define GPIO_FTGPIO010_VA_SIZE 0x00001000 ++#define GPIO_FTGPIO010_0_VA_BASE 0xF94C0000 ++#define GPIO_FTGPIO010_0_VA_LIMIT 0xF94C0FFF ++#define GPIO_FTGPIO010_0_VA_SIZE 0x00001000 ++ ++/* SSP */ ++#define SSP_FTSSP010_PA_BASE 0x94500000 ++#define SSP_FTSSP010_0_PA_BASE 0x94500000 ++#define SSP_FTSSP010_VA_BASE 0xF9450000 ++#define SSP_FTSSP010_0_VA_BASE 0xF9450000 ++ ++/* SPI */ ++#define SPI_FTSSP010_PA_BASE 0x94100000 ++#define SPI_FTSSP010_0_PA_BASE 0x94100000 ++#define SPI_FTSSP010_VA_BASE 0xF9410000 ++#define SPI_FTSSP010_0_VA_BASE 0xF9410000 ++ ++/* AHB Controller */ ++#define AHB_ATFAHBC020S_0_PA_BASE 0x90C00000 ++#define AHB_ATFAHBC020S_0_VA_BASE 0xF90C0000 ++ ++#define I2C_FTI2C010_PA_COUNT 1 ++#define I2C_FTI2C010_PA_BASE 0x94E00000 ++#define I2C_FTI2C010_PA_LIMIT 0x94E00FFF ++#define I2C_FTI2C010_PA_SIZE 0x00001000 ++#define I2C_FTI2C010_0_PA_BASE 0x94E00000 ++#define I2C_FTI2C010_0_PA_LIMIT 0x94E00FFF ++#define I2C_FTI2C010_0_PA_SIZE 0x00001000 ++#define I2C_FTI2C010_VA_COUNT 1 ++#define I2C_FTI2C010_VA_BASE 0xF94E0000 ++#define I2C_FTI2C010_VA_LIMIT 0xF94E0FFF ++#define I2C_FTI2C010_VA_SIZE 0x00001000 ++#define I2C_FTI2C010_0_VA_BASE 0xF94E0000 ++#define I2C_FTI2C010_0_VA_LIMIT 0xF94E0FFF ++#define I2C_FTI2C010_0_VA_SIZE 0x00001000 ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/spec.h linux-3.4.110/arch/nds32/include/asm/spec.h +--- linux-3.4.110.orig/arch/nds32/include/asm/spec.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/spec.h 2016-04-07 10:20:50.914079941 +0200 +@@ -0,0 +1,510 @@ ++/* ++ * linux/arch/nds32/include/asm/spec.h ++ * ++ * AG101 Platform Independent Specification ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ChangeLog ++ * ++ * Luke Lee 09/14/2005 Created. ++ * 09/15/2005 Completed. ++ */ ++ ++#ifndef __FARADAY_PLATFORM_INDEPENDENT_SPECIFICATION__ ++#define __FARADAY_PLATFORM_INDEPENDENT_SPECIFICATION__ ++ ++#include <asm/glue.h> ++#ifdef CONFIG_PLAT_AG102 ++#include <asm/spec-ag102.h> ++#else ++#include <asm/spec-ag101.h> ++#endif ++ ++/* ++ * Platform dependent specification ++ */ ++#define PLATFORM_NAME "Andes AG101" ++ ++/* ++ * Component counts ++ */ ++ ++/* INTC */ ++#define INTC_COUNT 2 ++#define INTC_FTINTC010_COUNT 2 ++/* TIMER */ ++#define TIMER_COUNT 1 ++#define TIMER_FTTMR010_COUNT 1 ++/* SSP */ ++#define SSP_COUNT 1 ++#define SSP_FTSSP010_COUNT 1 ++/* PMU */ ++#define PMU_COUNT 1 ++#define PMU_FTPMU010_COUNT 1 ++/* MAC */ ++#define MAC_COUNT 1 ++#define MAC_FTMAC100_COUNT 1 ++ ++/* SDC */ ++#define SDC_COUNT 1 ++#define SDC_FTSDC010_COUNT 1 ++/* AHBDMA */ ++#define AHBDMA_COUNT 1 ++/* APBDMA */ ++#define APBDMA_COUNT 1 ++/* RTC */ ++#define RTC_COUNT 1 ++#define RTC_FTRTC010_COUNT 1 ++/* WDT */ ++#define WDT_COUNT 1 ++#define WDT_FTWDT010_COUNT 1 ++/* GPIO */ ++#define GPIO_COUNT 1 ++#define GPIO_FTGPIO010_COUNT 1 ++/* CFC */ ++#define CFC_COUNT 1 ++#define CFC_FTCFC010_COUNT 1 ++/* LCD */ ++#define LCD_COUNT 1 ++#define LCD_FTLCDC100_COUNT 1 ++/* I2C */ ++#define I2C_COUNT 1 ++#define I2C_FTI2C010_COUNT 1 ++/* USB */ ++#define USB_COUNT 3 ++#define USB_FOTG2XX_COUNT 1 ++#define USB_FUSBH200_COUNT 1 ++#define USB_FUSB220_COUNT 1 ++/* DMAC */ ++#define DMAC_COUNT 1 ++#define DMAC_FTDMAC020_COUNT 1 ++/* KMI */ ++#define KMI_COUNT 2 ++#define KMI_FTKBC010_COUNT 2 ++/* PCI */ ++#define PCI_COUNT 1 ++/* PCIMEM */ ++#define PCIMEM_COUNT 1 ++/* PCIIO */ ++#define PCIIO_COUNT 1 ++/* PCIC */ ++#define PCIC_COUNT 1 ++#define PCIC_FTPCI100_COUNT 1 ++ ++/* ++ * Hierarchial Component IDs ++ */ ++ ++#define PLATFORM_AHBDMA_DMAC_FTDMAC020_ID 0 ++#define PLATFORM_APBDMA_APBBRG_FTAPBBRG020S_ID 0 ++ ++/* ++ * Number of interrupts ++ */ ++ ++#define PLATFORM_IRQ_TOTALCOUNT 32 ++#define PLATFORM_AHBDMA_IRQ_TOTALCOUNT 8 ++#define PLATFORM_APBDMA_IRQ_TOTALCOUNT 4 ++ ++#define PLATFORM_IRQ_BASE 0 ++#define PLATFORM_AHBDMA_IRQ_BASE 64 ++#define PLATFORM_APBDMA_IRQ_BASE 72 ++#define PLATFORM_PCI_IRQ_BASE 176 ++#define PLATFORM_INTERRUPTS 202 ++ ++/* ++ * IRQ trigger level and trigger mode ++ */ ++ ++#define PLATFORM_IRQ_TRIGGER_MODE 0x000EC880 ++#define PLATFORM_IRQ_TRIGGER_LEVEL 0x10000000 ++#define PLATFORM_AHBDMA_IRQ_TRIGGER_MODE 0x00000000 ++#define PLATFORM_AHBDMA_IRQ_TRIGGER_LEVEL 0xFFFFFFFF ++#define PLATFORM_APBDMA_IRQ_TRIGGER_MODE 0x00000000 ++#define PLATFORM_APBDMA_IRQ_TRIGGER_LEVEL 0xFFFFFFFF ++ ++/* ++ * Interrupt numbers of Hierarchical Architecture ++ */ ++ ++/* AHBDMA */ ++#define PLATFORM_AHBDMA_IRQ 21 ++ ++/* APBDMA */ ++#define PLATFORM_APBDMA_IRQ 24 ++ ++/* PCI */ ++#ifdef CONFIG_XC5_PCI ++#define PLATFORM_PCI_IRQ 10 ++#else ++#define PLATFORM_PCI_IRQ 28 ++#endif ++ ++ ++/* ++ * Interrrupt numbers ++ */ ++ ++/* TIMER */ ++#define TIMER_FTTMR010_IRQ_COUNT 3 ++#define TIMER_FTTMR010_IRQ0 19 ++#define TIMER_FTTMR010_0_IRQ0 19 ++#define TIMER_FTTMR010_IRQ1 14 ++#define TIMER_FTTMR010_0_IRQ1 14 ++#define TIMER_FTTMR010_IRQ2 15 ++#define TIMER_FTTMR010_0_IRQ2 15 ++ ++/* SSP */ ++#define SSP_FTSSP010_IRQ_COUNT 1 ++#define SSP_FTSSP010_IRQ 6 ++#define SSP_FTSSP010_0_IRQ 6 ++ ++/* MAC */ ++#define MAC_FTMAC100_IRQ_COUNT 1 ++#define MAC_FTMAC100_IRQ 25 ++#define MAC_FTMAC100_0_IRQ 25 ++#define MAC_FTMAC100_1_IRQ 133 ++ ++/* SDC */ ++#define SDC_FTSDC010_IRQ_COUNT 1 ++#define SDC_FTSDC010_IRQ 5 ++#define SDC_FTSDC010_0_IRQ 5 ++ ++/* RTC */ ++#define RTC_FTRTC010_IRQ_COUNT 2 ++#define RTC_FTRTC010_IRQ0 17 ++#define RTC_FTRTC010_0_IRQ0 17 ++#define RTC_FTRTC010_IRQ1 18 ++#define RTC_FTRTC010_0_IRQ1 18 ++ ++/* WDT */ ++#define WDT_FTWDT010_IRQ_COUNT 1 ++#define WDT_FTWDT010_IRQ 16 ++#define WDT_FTWDT010_0_IRQ 16 ++ ++/* GPIO */ ++#define GPIO_FTGPIO010_IRQ_COUNT 1 ++#define GPIO_FTGPIO010_IRQ 13 ++#define GPIO_FTGPIO010_0_IRQ 13 ++ ++/* CFC */ ++#define CFC_FTCFC010_IRQ_COUNT 2 ++#define CFC_FTCFC010_IRQ0 0 ++#define CFC_FTCFC010_0_IRQ0 0 ++#define CFC_FTCFC010_IRQ1 1 ++#define CFC_FTCFC010_0_IRQ1 1 ++ ++/* LCD */ ++#define LCD_FTLCDC100_IRQ_COUNT 1 ++#define LCD_FTLCDC100_IRQ 20 ++#define LCD_FTLCDC100_0_IRQ 20 ++ ++/* I2C */ ++#define I2C_FTI2C010_IRQ_COUNT 1 ++#define I2C_FTI2C010_IRQ 3 ++#define I2C_FTI2C010_0_IRQ 3 ++ ++/* USB */ ++#define USB_FUSBH200_IRQ_COUNT 1 ++#define USB_FUSBH200_IRQ 29 ++#define USB_FUSBH200_0_IRQ 29 ++#define USB_FUSB220_IRQ_COUNT 1 ++#define USB_FUSB220_IRQ 26 ++#define USB_FUSB220_0_IRQ 26 ++ ++/* DMAC */ ++#define DMAC_FTDMAC020_IRQ_COUNT 8 ++#define DMAC_FTDMAC020_IRQ0 64 ++#define DMAC_FTDMAC020_0_IRQ0 64 ++#define DMAC_FTDMAC020_IRQ1 65 ++#define DMAC_FTDMAC020_0_IRQ1 65 ++#define DMAC_FTDMAC020_IRQ2 66 ++#define DMAC_FTDMAC020_0_IRQ2 66 ++#define DMAC_FTDMAC020_IRQ3 67 ++#define DMAC_FTDMAC020_0_IRQ3 67 ++#define DMAC_FTDMAC020_IRQ4 68 ++#define DMAC_FTDMAC020_0_IRQ4 68 ++#define DMAC_FTDMAC020_IRQ5 69 ++#define DMAC_FTDMAC020_0_IRQ5 69 ++#define DMAC_FTDMAC020_IRQ6 70 ++#define DMAC_FTDMAC020_0_IRQ6 70 ++#define DMAC_FTDMAC020_IRQ7 71 ++#define DMAC_FTDMAC020_0_IRQ7 71 ++ ++/* APBBRG */ ++#define APBBRG_FTAPBBRG020S_IRQ_COUNT 4 ++#define APBBRG_FTAPBBRG020S_IRQ0 72 ++#define APBBRG_FTAPBBRG020S_0_IRQ0 72 ++#define APBBRG_FTAPBBRG020S_IRQ1 73 ++#define APBBRG_FTAPBBRG020S_0_IRQ1 73 ++#define APBBRG_FTAPBBRG020S_IRQ2 74 ++#define APBBRG_FTAPBBRG020S_0_IRQ2 74 ++#define APBBRG_FTAPBBRG020S_IRQ3 75 ++#define APBBRG_FTAPBBRG020S_0_IRQ3 75 ++#define APBBRG_FTAPBBRG020S_1_IRQ0 172 ++#define APBBRG_FTAPBBRG020S_1_IRQ1 173 ++#define APBBRG_FTAPBBRG020S_1_IRQ2 174 ++#define APBBRG_FTAPBBRG020S_1_IRQ3 175 ++ ++/* KMI */ ++#define KMI_FTKBC010_IRQ_COUNT 1 ++#define KMI_FTKBC010_IRQ 30 ++#define KMI_FTKBC010_0_IRQ 30 ++#define KMI_FTKBC010_1_IRQ 31 ++ ++/* PCIC */ ++#define PCIC_FTPCI100_IRQ_COUNT 4 ++#define PCIC_FTPCI100_IRQ0 176 ++#define PCIC_FTPCI100_0_IRQ0 176 ++#define PCIC_FTPCI100_IRQ1 177 ++#define PCIC_FTPCI100_0_IRQ1 177 ++#define PCIC_FTPCI100_IRQ2 178 ++#define PCIC_FTPCI100_0_IRQ2 178 ++#define PCIC_FTPCI100_IRQ3 179 ++#define PCIC_FTPCI100_0_IRQ3 179 ++ ++/* ++ * Base addresses ++ */ ++ ++/* CPU */ ++#define CPU_MEM_PA_BASE CONFIG_MEMORY_START ++ ++ ++/* INTC */ ++#define INTC_FTINTC010_PA_COUNT 1 ++#define INTC_FTINTC010_PA_BASE 0x98800000 ++#define INTC_FTINTC010_PA_LIMIT 0x98800FFF ++#define INTC_FTINTC010_PA_SIZE 0x00001000 ++#define INTC_FTINTC010_0_PA_BASE 0x98800000 ++#define INTC_FTINTC010_0_PA_LIMIT 0x98800FFF ++#define INTC_FTINTC010_0_PA_SIZE 0x00001000 ++#define INTC_FTINTC010_1_PA_BASE 0xB0800000 ++#define INTC_FTINTC010_1_PA_LIMIT 0xB0800FFF ++#define INTC_FTINTC010_1_PA_SIZE 0x00001000 ++#define INTC_FTINTC010_VA_COUNT 1 ++#define INTC_FTINTC010_VA_BASE 0xF9880000 ++#define INTC_FTINTC010_VA_LIMIT 0xF9880FFF ++#define INTC_FTINTC010_VA_SIZE 0x00001000 ++#define INTC_FTINTC010_0_VA_BASE 0xF9880000 ++#define INTC_FTINTC010_0_VA_LIMIT 0xF9880FFF ++#define INTC_FTINTC010_0_VA_SIZE 0x00001000 ++#define INTC_FTINTC010_1_VA_BASE 0xFB080000 ++#define INTC_FTINTC010_1_VA_LIMIT 0xFB080FFF ++#define INTC_FTINTC010_1_VA_SIZE 0x00001000 ++ ++/* PMU */ ++#define PMU_FTPMU010_PA_COUNT 1 ++#define PMU_FTPMU010_PA_BASE 0x98100000 ++#define PMU_FTPMU010_PA_LIMIT 0x98100FFF ++#define PMU_FTPMU010_PA_SIZE 0x00001000 ++#define PMU_FTPMU010_0_PA_BASE 0x98100000 ++#define PMU_FTPMU010_0_PA_LIMIT 0x98100FFF ++#define PMU_FTPMU010_0_PA_SIZE 0x00001000 ++#define PMU_FTPMU010_VA_COUNT 1 ++#define PMU_FTPMU010_VA_BASE 0xF9810000 ++#define PMU_FTPMU010_VA_LIMIT 0xF9810FFF ++#define PMU_FTPMU010_VA_SIZE 0x00001000 ++#define PMU_FTPMU010_0_VA_BASE 0xF9810000 ++#define PMU_FTPMU010_0_VA_LIMIT 0xF9810FFF ++#define PMU_FTPMU010_0_VA_SIZE 0x00001000 ++ ++/* USB */ ++#define USB_FUSBH200_PA_COUNT 1 ++#define USB_FUSBH200_PA_BASE 0x92000000 ++#define USB_FUSBH200_PA_LIMIT 0x92000FFF ++#define USB_FUSBH200_PA_SIZE 0x00001000 ++#define USB_FUSBH200_0_PA_BASE 0x92000000 ++#define USB_FUSBH200_0_PA_LIMIT 0x92000FFF ++#define USB_FUSBH200_0_PA_SIZE 0x00001000 ++#define USB_FUSBH200_VA_COUNT 1 ++#define USB_FUSBH200_VA_BASE 0xF9200000 ++#define USB_FUSBH200_VA_LIMIT 0xF9200FFF ++#define USB_FUSBH200_VA_SIZE 0x00001000 ++#define USB_FUSBH200_0_VA_BASE 0xF9200000 ++#define USB_FUSBH200_0_VA_LIMIT 0xF9200FFF ++#define USB_FUSBH200_0_VA_SIZE 0x00001000 ++#define USB_FUSB220_PA_COUNT 1 ++#define USB_FUSB220_PA_BASE 0x90B00000 ++#define USB_FUSB220_PA_LIMIT 0x90B00FFF ++#define USB_FUSB220_PA_SIZE 0x00001000 ++#define USB_FUSB220_0_PA_BASE 0x90B00000 ++#define USB_FUSB220_0_PA_LIMIT 0x90B00FFF ++#define USB_FUSB220_0_PA_SIZE 0x00001000 ++#define USB_FUSB220_VA_COUNT 1 ++#define USB_FUSB220_VA_BASE 0xF90B0000 ++#define USB_FUSB220_VA_LIMIT 0xF90B0FFF ++#define USB_FUSB220_VA_SIZE 0x00001000 ++#define USB_FUSB220_0_VA_BASE 0xF90B0000 ++#define USB_FUSB220_0_VA_LIMIT 0xF90B0FFF ++#define USB_FUSB220_0_VA_SIZE 0x00001000 ++ ++/* KMI */ ++#define KMI_FTKBC010_PA_COUNT 1 ++#define KMI_FTKBC010_PA_BASE 0x97200000 ++#define KMI_FTKBC010_PA_LIMIT 0x97200FFF ++#define KMI_FTKBC010_PA_SIZE 0x00001000 ++#define KMI_FTKBC010_0_PA_BASE 0x97200000 ++#define KMI_FTKBC010_0_PA_LIMIT 0x97200FFF ++#define KMI_FTKBC010_0_PA_SIZE 0x00001000 ++#define KMI_FTKBC010_1_PA_BASE 0x97300000 ++#define KMI_FTKBC010_1_PA_LIMIT 0x97300FFF ++#define KMI_FTKBC010_1_PA_SIZE 0x00001000 ++#define KMI_FTKBC010_VA_COUNT 1 ++#define KMI_FTKBC010_VA_BASE 0xF9720000 ++#define KMI_FTKBC010_VA_LIMIT 0xF9720FFF ++#define KMI_FTKBC010_VA_SIZE 0x00001000 ++#define KMI_FTKBC010_0_VA_BASE 0xF9720000 ++#define KMI_FTKBC010_0_VA_LIMIT 0xF9720FFF ++#define KMI_FTKBC010_0_VA_SIZE 0x00001000 ++#define KMI_FTKBC010_1_VA_BASE 0xF9730000 ++#define KMI_FTKBC010_1_VA_LIMIT 0xF9730FFF ++#define KMI_FTKBC010_1_VA_SIZE 0x00001000 ++ ++/* PCIMEM */ ++#define PCIMEM_PA_COUNT 1 ++#define PCIMEM_PA_BASE 0xA0000000 ++#define PCIMEM_PA_LIMIT 0xAFFFFFFF ++#define PCIMEM_PA_SIZE 0x10000000 ++#define PCIMEM_0_PA_BASE 0xA0000000 ++#define PCIMEM_0_PA_LIMIT 0xAFFFFFFF ++#define PCIMEM_0_PA_SIZE 0x10000000 ++ ++ ++#ifdef CONFIG_PLATFORM_AHBDMA_MODULE ++#define CONFIG_PLATFORM_AHBDMA ++#endif ++ ++#ifdef CONFIG_PLATFORM_APBDMA_MODULE ++#define CONFIG_PLATFORM_APBDMA ++#endif ++ ++#include <asm/misc_spec.h> /* Manual defined spec */ ++ ++/* ++ * Platform independent specification ++ */ ++ ++#define NR_IRQS PLATFORM_INTERRUPTS ++ ++#ifndef TIMER_CLK_IN ++#error Missing platform dependent symbol TIMER_CLK_IN in <asm/arch/platform/misc_spec.h> file. ++#endif ++ ++/* ++ * Macros for retrieving IP related information ++ */ ++#define IP_IDENTIFIER __glue(__glue(IPMODULE,_),__glue(IPNAME,_)) ++ ++#define IP_COUNT __glue(IP_IDENTIFIER,COUNT) ++ ++#define IP_IRQ_COUNT __glue(IP_IDENTIFIER,IRQ_COUNT) ++#define IP_IRQ(n) __glue(__glue(IP_IDENTIFIER,n),_IRQ) ++#define IP_irq __glue(IP_IDENTIFIER,irq) ++ ++#define IP_PA_COUNT __glue(IP_IDENTIFIER,PA_COUNT) ++#define IP_PA_BASE(n) __glue(__glue(IP_IDENTIFIER,n),_PA_BASE) ++#define IP_PA_LIMIT(n) __glue(__glue(IP_IDENTIFIER,n),_PA_LIMIT) ++#define IP_PA_SIZE(n) __glue(__glue(IP_IDENTIFIER,n),_PA_SIZE) ++#define IP_pa_base __glue(IP_IDENTIFIER,pa_base) ++#define IP_pa_limit __glue(IP_IDENTIFIER,pa_limit) ++#define IP_pa_size __glue(IP_IDENTIFIER,pa_size) ++ ++#define IP_VA_COUNT __glue(IP_IDENTIFIER,VA_COUNT) ++#define IP_VA_BASE(n) __glue(__glue(IP_IDENTIFIER,n),_VA_BASE) ++#define IP_VA_LIMIT(n) __glue(__glue(IP_IDENTIFIER,n),_VA_LIMIT) ++#define IP_VA_SIZE(n) __glue(__glue(IP_IDENTIFIER,n),_VA_SIZE) ++#define IP_va_base __glue(IP_IDENTIFIER,va_base) ++#define IP_va_limit __glue(IP_IDENTIFIER,va_limit) ++#define IP_va_size __glue(IP_IDENTIFIER,va_size) ++ ++/* ++ * Facility macros ++ */ ++/* IRQ0~7 */ ++#define IP_IRQ0(n) __glue(__glue(IP_IDENTIFIER,n),_IRQ0) ++#define IP_IRQ1(n) __glue(__glue(IP_IDENTIFIER,n),_IRQ1) ++#define IP_IRQ2(n) __glue(__glue(IP_IDENTIFIER,n),_IRQ2) ++#define IP_IRQ3(n) __glue(__glue(IP_IDENTIFIER,n),_IRQ3) ++#define IP_IRQ4(n) __glue(__glue(IP_IDENTIFIER,n),_IRQ4) ++#define IP_IRQ5(n) __glue(__glue(IP_IDENTIFIER,n),_IRQ5) ++#define IP_IRQ6(n) __glue(__glue(IP_IDENTIFIER,n),_IRQ6) ++#define IP_IRQ7(n) __glue(__glue(IP_IDENTIFIER,n),_IRQ7) ++ ++/* PA_BASE0~7 */ ++#define IP_PA_BASE0(n) __glue(__glue(IP_IDENTIFIER,n),_PA_BASE0) ++#define IP_PA_BASE1(n) __glue(__glue(IP_IDENTIFIER,n),_PA_BASE1) ++#define IP_PA_BASE2(n) __glue(__glue(IP_IDENTIFIER,n),_PA_BASE2) ++#define IP_PA_BASE3(n) __glue(__glue(IP_IDENTIFIER,n),_PA_BASE3) ++#define IP_PA_BASE4(n) __glue(__glue(IP_IDENTIFIER,n),_PA_BASE4) ++#define IP_PA_BASE5(n) __glue(__glue(IP_IDENTIFIER,n),_PA_BASE5) ++#define IP_PA_BASE6(n) __glue(__glue(IP_IDENTIFIER,n),_PA_BASE6) ++#define IP_PA_BASE7(n) __glue(__glue(IP_IDENTIFIER,n),_PA_BASE7) ++ ++/* PA_LIMIT0~7 */ ++#define IP_PA_LIMIT0(n) __glue(__glue(IP_IDENTIFIER,n),_PA_LIMIT0) ++#define IP_PA_LIMIT1(n) __glue(__glue(IP_IDENTIFIER,n),_PA_LIMIT1) ++#define IP_PA_LIMIT2(n) __glue(__glue(IP_IDENTIFIER,n),_PA_LIMIT2) ++#define IP_PA_LIMIT3(n) __glue(__glue(IP_IDENTIFIER,n),_PA_LIMIT3) ++#define IP_PA_LIMIT4(n) __glue(__glue(IP_IDENTIFIER,n),_PA_LIMIT4) ++#define IP_PA_LIMIT5(n) __glue(__glue(IP_IDENTIFIER,n),_PA_LIMIT5) ++#define IP_PA_LIMIT6(n) __glue(__glue(IP_IDENTIFIER,n),_PA_LIMIT6) ++#define IP_PA_LIMIT7(n) __glue(__glue(IP_IDENTIFIER,n),_PA_LIMIT7) ++ ++/* PA_SIZE0~7 */ ++#define IP_PA_SIZE0(n) __glue(__glue(IP_IDENTIFIER,n),_PA_SIZE0) ++#define IP_PA_SIZE1(n) __glue(__glue(IP_IDENTIFIER,n),_PA_SIZE1) ++#define IP_PA_SIZE2(n) __glue(__glue(IP_IDENTIFIER,n),_PA_SIZE2) ++#define IP_PA_SIZE3(n) __glue(__glue(IP_IDENTIFIER,n),_PA_SIZE3) ++#define IP_PA_SIZE4(n) __glue(__glue(IP_IDENTIFIER,n),_PA_SIZE4) ++#define IP_PA_SIZE5(n) __glue(__glue(IP_IDENTIFIER,n),_PA_SIZE5) ++#define IP_PA_SIZE6(n) __glue(__glue(IP_IDENTIFIER,n),_PA_SIZE6) ++#define IP_PA_SIZE7(n) __glue(__glue(IP_IDENTIFIER,n),_PA_SIZE7) ++ ++/* VA_BASE0~7 */ ++#define IP_VA_BASE0(n) __glue(__glue(IP_IDENTIFIER,n),_VA_BASE0) ++#define IP_VA_BASE1(n) __glue(__glue(IP_IDENTIFIER,n),_VA_BASE1) ++#define IP_VA_BASE2(n) __glue(__glue(IP_IDENTIFIER,n),_VA_BASE2) ++#define IP_VA_BASE3(n) __glue(__glue(IP_IDENTIFIER,n),_VA_BASE3) ++#define IP_VA_BASE4(n) __glue(__glue(IP_IDENTIFIER,n),_VA_BASE4) ++#define IP_VA_BASE5(n) __glue(__glue(IP_IDENTIFIER,n),_VA_BASE5) ++#define IP_VA_BASE6(n) __glue(__glue(IP_IDENTIFIER,n),_VA_BASE6) ++#define IP_VA_BASE7(n) __glue(__glue(IP_IDENTIFIER,n),_VA_BASE7) ++ ++/* VA_LIMIT0~7 */ ++#define IP_VA_LIMIT0(n) __glue(__glue(IP_IDENTIFIER,n),_VA_LIMIT0) ++#define IP_VA_LIMIT1(n) __glue(__glue(IP_IDENTIFIER,n),_VA_LIMIT1) ++#define IP_VA_LIMIT2(n) __glue(__glue(IP_IDENTIFIER,n),_VA_LIMIT2) ++#define IP_VA_LIMIT3(n) __glue(__glue(IP_IDENTIFIER,n),_VA_LIMIT3) ++#define IP_VA_LIMIT4(n) __glue(__glue(IP_IDENTIFIER,n),_VA_LIMIT4) ++#define IP_VA_LIMIT5(n) __glue(__glue(IP_IDENTIFIER,n),_VA_LIMIT5) ++#define IP_VA_LIMIT6(n) __glue(__glue(IP_IDENTIFIER,n),_VA_LIMIT6) ++#define IP_VA_LIMIT7(n) __glue(__glue(IP_IDENTIFIER,n),_VA_LIMIT7) ++ ++/* VA_SIZE0~7 */ ++#define IP_VA_SIZE0(n) __glue(__glue(IP_IDENTIFIER,n),_VA_SIZE0) ++#define IP_VA_SIZE1(n) __glue(__glue(IP_IDENTIFIER,n),_VA_SIZE1) ++#define IP_VA_SIZE2(n) __glue(__glue(IP_IDENTIFIER,n),_VA_SIZE2) ++#define IP_VA_SIZE3(n) __glue(__glue(IP_IDENTIFIER,n),_VA_SIZE3) ++#define IP_VA_SIZE4(n) __glue(__glue(IP_IDENTIFIER,n),_VA_SIZE4) ++#define IP_VA_SIZE5(n) __glue(__glue(IP_IDENTIFIER,n),_VA_SIZE5) ++#define IP_VA_SIZE6(n) __glue(__glue(IP_IDENTIFIER,n),_VA_SIZE6) ++#define IP_VA_SIZE7(n) __glue(__glue(IP_IDENTIFIER,n),_VA_SIZE7) ++ ++#endif /* __FARADAY_PLATFORM_INDEPENDENT_SPECIFICATION__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/spinlock.h linux-3.4.110/arch/nds32/include/asm/spinlock.h +--- linux-3.4.110.orig/arch/nds32/include/asm/spinlock.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/spinlock.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,183 @@ ++/* ++ * linux/arch/nds32/include/asm/spinlock.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ASM_SPINLOCK_H ++#define __ASM_SPINLOCK_H ++ ++#include <asm/processor.h> ++ ++#define arch_spin_is_locked(x) ((x)->lock != 0) ++ ++#define arch_spin_unlock_wait(lock) \ ++ do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0) ++ ++#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) ++ ++static inline void arch_spin_lock(arch_spinlock_t *lock) ++{ ++ unsigned long tmp; ++ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%1+$r15]\n" ++ "\tbnez\t%0, 1b\n" ++ "\tmovi\t%0, #0x1\n" ++ "\tscw\t%0, [%1+$r15]\n" ++ "\tbeqz\t%0, 1b\n" ++ : "=&r" (tmp) ++ : "r" (&lock->lock) ++ : "memory"); ++} ++ ++static inline int arch_spin_trylock(arch_spinlock_t *lock) ++{ ++ unsigned long ret, tmp; ++ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%2+$r15]\n" ++ "\tmovi\t%1, #0x1\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ : "=&r" (ret), "=&r" (tmp) ++ : "r" (&lock->lock) ++ : "memory"); ++ ++ return ret == 0; ++} ++ ++static inline void arch_spin_unlock(arch_spinlock_t *lock) ++{ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "\tswi\t$r15, [%0]\n" ++ : ++ : "r" (&lock->lock) ++ : "memory"); ++} ++ ++static inline void arch_write_lock(arch_rwlock_t *rw) ++{ ++ unsigned long tmp; ++ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%1+$r15]\n" ++ "\tbnez\t%0, 1b\n" ++ "\tsethi\t%0, 0x80000\n" ++ "\tscw\t%0, [%1+$r15]\n" ++ "\tbeqz\t%0, 1b\n" ++ : "=&r" (tmp) ++ : "r" (&rw->lock) ++ : "memory"); ++} ++ ++static inline void arch_write_unlock(arch_rwlock_t *rw) ++{ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "\tswi\t$r15, [%0]\n" ++ : ++ : "r" (&rw->lock) ++ : "memory"); ++} ++ ++#define arch_write_can_lock(x) ((x)->lock == 0) ++static inline void arch_read_lock(arch_rwlock_t *rw) ++{ ++ int tmp; ++ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%1+$r15]\n" ++ "\tbltz\t%0, 1b\n" ++ "\taddi\t%0, %0, #1\n" ++ "\tscw\t%0, [%1+$r15]\n" ++ "\tbeqz\t%0, 1b\n" ++ : "=&r" (tmp) ++ : "r" (&rw->lock) ++ : "memory"); ++} ++ ++static inline void arch_read_unlock(arch_rwlock_t *rw) ++{ ++ unsigned long tmp; ++ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "1:\n" ++ "\tllw\t%0, [%1+$r15]\n" ++ "\taddi\t%0, %0, #-1\n" ++ "\tscw\t%0, [%1+$r15]\n" ++ "\tbeqz\t%0, 1b\n" ++ : "=&r" (tmp) ++ : "r" (&rw->lock) ++ : "memory"); ++} ++ ++static inline int arch_read_trylock(arch_rwlock_t *rw) ++{ ++ unsigned long ret, tmp; ++ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "\tmovi\t%0, #0x0\n" ++ "1:\n" ++ "\tllw\t%1, [%2+$r15]\n" ++ "\tbltz\t%1, 2f\n" ++ "\taddi\t%1, %1, #1\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ "\tmovi\t%0, #0x1\n" ++ "\tj\t3f\n" ++ "2:\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "3:\n" ++ : "=&r" (ret), "=&r" (tmp) ++ : "r" (&rw->lock) ++ : "memory"); ++ ++ return ret; ++} ++ ++static inline int arch_write_trylock(arch_rwlock_t *rw) ++{ ++ unsigned long ret, tmp; ++ ++ __asm__ __volatile__( ++ "xor\t$r15, $r15, $r15\n" ++ "\tmovi\t%0, #0x0\n" ++ "1:\n" ++ "\tllw\t%1, [%2+$r15]\n" ++ "\tbnez\t%1, 2f\n" ++ "\tsethi\t%1, 0x80000\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "\tbeqz\t%1, 1b\n" ++ "\tmovi\t%0, #0x1\n" ++ "\tj\t3f\n" ++ "2:\n" ++ "\tscw\t%1, [%2+$r15]\n" ++ "3:\n" ++ : "=&r" (ret), "=&r" (tmp) ++ : "r" (&rw->lock) ++ : "memory"); ++ ++ return ret; ++} ++ ++#define arch_read_lock_flags(lock, flags) arch_read_lock(lock) ++#define arch_write_lock_flags(lock, flags) arch_write_lock(lock) ++ ++#define arch_read_can_lock(x) ((x)->lock < 0x80000000) ++ ++#define arch_spin_relax(lock) cpu_relax() ++#define arch_read_relax(lock) cpu_relax() ++#define arch_write_relax(lock) cpu_relax() ++ ++#endif /* __ASM_SPINLOCK_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/spinlock_types.h linux-3.4.110/arch/nds32/include/asm/spinlock_types.h +--- linux-3.4.110.orig/arch/nds32/include/asm/spinlock_types.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/spinlock_types.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,25 @@ ++/* ++ * linux/arch/nds32/include/asm/spinlock_types.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASM_SPINLOCK_TYPES_H ++#define _ASM_SPINLOCK_TYPES_H ++ ++#ifndef __LINUX_SPINLOCK_TYPES_H ++# error "please don't include this file directly" ++#endif ++ ++typedef struct { ++ volatile unsigned int lock; ++} arch_spinlock_t; ++ ++#define __ARCH_SPIN_LOCK_UNLOCKED { 0 } ++ ++typedef struct { ++ volatile unsigned int lock; ++} arch_rwlock_t; ++ ++#define __ARCH_RW_LOCK_UNLOCKED { 0 } ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/statfs.h linux-3.4.110/arch/nds32/include/asm/statfs.h +--- linux-3.4.110.orig/arch/nds32/include/asm/statfs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/statfs.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/statfs.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_STATFS_H ++#define _ASMNDS32_STATFS_H ++ ++#include <asm-generic/statfs.h> ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/stat.h linux-3.4.110/arch/nds32/include/asm/stat.h +--- linux-3.4.110.orig/arch/nds32/include/asm/stat.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/stat.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,101 @@ ++/* ++ * linux/arch/nds32/include/asm/stat.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_STAT_H ++#define _ASMNDS32_STAT_H ++ ++struct __old_kernel_stat { ++ unsigned short st_dev; ++ unsigned short st_ino; ++ unsigned short st_mode; ++ unsigned short st_nlink; ++ unsigned short st_uid; ++ unsigned short st_gid; ++ unsigned short st_rdev; ++ unsigned long st_size; ++ unsigned long st_atime; ++ unsigned long st_mtime; ++ unsigned long st_ctime; ++}; ++ ++#define STAT_HAVE_NSEC ++ ++struct stat { ++#if defined(__NDS32_EB__) ++ unsigned short st_dev; ++ unsigned short __pad1; ++#else ++ unsigned long st_dev; ++#endif ++ unsigned long st_ino; ++ unsigned short st_mode; ++ unsigned short st_nlink; ++ unsigned short st_uid; ++ unsigned short st_gid; ++#if defined(__NDS32_EB__) ++ unsigned short st_rdev; ++ unsigned short __pad2; ++#else ++ unsigned long st_rdev; ++#endif ++ unsigned long st_size; ++ unsigned long st_blksize; ++ unsigned long st_blocks; ++ unsigned long st_atime; ++ unsigned long st_atime_nsec; ++ unsigned long st_mtime; ++ unsigned long st_mtime_nsec; ++ unsigned long st_ctime; ++ unsigned long st_ctime_nsec; ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++ ++/* This matches struct stat64 in glibc2.1, hence the absolutely ++ * insane amounts of padding around dev_t's. ++ * Note: The kernel zero's the padded region because glibc might read them ++ * in the hope that the kernel has stretched to using larger sizes. ++ */ ++ ++struct stat64 { ++ unsigned long long st_dev; ++ unsigned long __pad0; ++ ++#define STAT64_HAS_BROKEN_ST_INO 1 ++ unsigned long __st_ino; ++ unsigned int st_mode; ++ unsigned int st_nlink; ++ ++ unsigned long st_uid; ++ unsigned long st_gid; ++ ++ unsigned long long st_rdev; ++ unsigned int __pad3; ++ ++ unsigned long long st_size; ++ unsigned long st_blksize; ++ ++//#if defined(__NDS32EB__) ++// unsigned long __pad4; // Future possible st_blocks hi bits ++ unsigned long long st_blocks; // Number 512-byte blocks allocated. ++//#else // Must be little ++// unsigned long st_blocks; // Number 512-byte blocks allocated. ++// unsigned long __pad4; // Future possible st_blocks hi bits ++//#endif ++ ++ unsigned long st_atime; ++ unsigned long st_atime_nsec; ++ ++ unsigned long st_mtime; ++ unsigned long st_mtime_nsec; ++ ++ unsigned long st_ctime; ++ unsigned long st_ctime_nsec; ++ ++ unsigned long long st_ino; ++}; ++ ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/string.h linux-3.4.110/arch/nds32/include/asm/string.h +--- linux-3.4.110.orig/arch/nds32/include/asm/string.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/string.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,45 @@ ++/* ++ * linux/arch/nds32/include/asm/string.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ASM_NDS32_STRING_H ++#define __ASM_NDS32_STRING_H ++ ++/* ++ * We don't do inline string functions, since the ++ * optimised inline asm versions are not small. ++ */ ++ ++#define __HAVE_ARCH_STRRCHR ++extern char * strrchr(const char * s, int c); ++ ++#define __HAVE_ARCH_STRCHR ++extern char * strchr(const char * s, int c); ++ ++#define __HAVE_ARCH_MEMCPY ++extern void * memcpy(void *, const void *, __kernel_size_t); ++ ++#define __HAVE_ARCH_MEMMOVE ++extern void * memmove(void *, const void *, __kernel_size_t); ++ ++#define __HAVE_ARCH_MEMZERO ++#define __HAVE_ARCH_MEMSET ++extern void * memset(void *, int, __kernel_size_t); ++ ++extern void __memzero(void *ptr, __kernel_size_t n); ++ ++#define memset(p,v,n) \ ++ ({ \ ++ if ((n) != 0) { \ ++ if (__builtin_constant_p((v)) && (v) == 0) \ ++ __memzero((p),(n)); \ ++ else \ ++ memset((p),(v),(n)); \ ++ } \ ++ (p); \ ++ }) ++ ++#define memzero(p,n) ({ if ((n) != 0) __memzero((p),(n)); (p); }) ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/suspend.h linux-3.4.110/arch/nds32/include/asm/suspend.h +--- linux-3.4.110.orig/arch/nds32/include/asm/suspend.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/suspend.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,9 @@ ++/* ++ * linux/arch/nds32/include/asm/suspend.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_SUSPEND_H ++#define _ASMNDS32_SUSPEND_H ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/swab.h linux-3.4.110/arch/nds32/include/asm/swab.h +--- linux-3.4.110.orig/arch/nds32/include/asm/swab.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/swab.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,34 @@ ++/* ++ * include/asm/byteorder.h ++ * Copyright (C) 2008 Andes Technology, Inc. ++ */ ++ ++#ifndef __NDS32_SWAB_H__ ++#define __NDS32_SWAB_H__ ++ ++#include <linux/types.h> ++#include <linux/compiler.h> ++ ++static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x) ++{ ++ __asm__("wsbh %0, %0\n\t" /* word swap byte within halfword */ ++ "rotri %0, %0, #16\n" ++ : "=r" (x) : "0" (x)); ++ return x; ++} ++ ++static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x) ++{ ++ __asm__("wsbh %0, %0\n" /* word swap byte within halfword */ ++ : "=r" (x) : "0" (x)); ++ return x; ++} ++#define __arch_swab32(x) ___arch__swab32(x) ++#define __arch_swab16(x) ___arch__swab16(x) ++ ++#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) ++# define __BYTEORDER_HAS_U64__ ++# define __SWAB_64_THRU_32__ ++#endif ++ ++#endif /* __NDS32_SWAB_H__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/switch_to.h linux-3.4.110/arch/nds32/include/asm/switch_to.h +--- linux-3.4.110.orig/arch/nds32/include/asm/switch_to.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/switch_to.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,18 @@ ++#ifndef __ASM_NDS32_SWITCH_TO_H ++#define __ASM_NDS32_SWITCH_TO_H ++ ++#include <linux/thread_info.h> ++ ++/* ++ * switch_to(prev, next) should switch from task `prev' to `next' ++ * `prev' will never be the same as `next'. schedule() itself ++ * contains the memory barrier to tell GCC not to cache `current'. ++ */ ++extern struct task_struct *__switch_to(struct task_struct *, struct thread_info *, struct thread_info *); ++ ++#define switch_to( prev, next, last) \ ++do { \ ++ last = __switch_to( prev, task_thread_info( prev), task_thread_info( next)); \ ++} while (0) ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/system.h linux-3.4.110/arch/nds32/include/asm/system.h +--- linux-3.4.110.orig/arch/nds32/include/asm/system.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/system.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,4 @@ ++/* FILE TO BE DELETED. DO NOT ADD STUFF HERE! */ ++#include <asm/barrier.h> ++#include <asm/switch_to.h> ++ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/termbits.h linux-3.4.110/arch/nds32/include/asm/termbits.h +--- linux-3.4.110.orig/arch/nds32/include/asm/termbits.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/termbits.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,198 @@ ++#ifndef __ASM_NDS32_TERMBITS_H ++#define __ASM_NDS32_TERMBITS_H ++ ++typedef unsigned char cc_t; ++typedef unsigned int speed_t; ++typedef unsigned int tcflag_t; ++ ++#define NCCS 19 ++struct termios { ++ tcflag_t c_iflag; /* input mode flags */ ++ tcflag_t c_oflag; /* output mode flags */ ++ tcflag_t c_cflag; /* control mode flags */ ++ tcflag_t c_lflag; /* local mode flags */ ++ cc_t c_line; /* line discipline */ ++ cc_t c_cc[NCCS]; /* control characters */ ++}; ++ ++struct termios2 { ++ tcflag_t c_iflag; /* input mode flags */ ++ tcflag_t c_oflag; /* output mode flags */ ++ tcflag_t c_cflag; /* control mode flags */ ++ tcflag_t c_lflag; /* local mode flags */ ++ cc_t c_line; /* line discipline */ ++ cc_t c_cc[NCCS]; /* control characters */ ++ speed_t c_ispeed; /* input speed */ ++ speed_t c_ospeed; /* output speed */ ++}; ++ ++struct ktermios { ++ tcflag_t c_iflag; /* input mode flags */ ++ tcflag_t c_oflag; /* output mode flags */ ++ tcflag_t c_cflag; /* control mode flags */ ++ tcflag_t c_lflag; /* local mode flags */ ++ cc_t c_line; /* line discipline */ ++ cc_t c_cc[NCCS]; /* control characters */ ++ speed_t c_ispeed; /* input speed */ ++ speed_t c_ospeed; /* output speed */ ++}; ++ ++ ++/* c_cc characters */ ++#define VINTR 0 ++#define VQUIT 1 ++#define VERASE 2 ++#define VKILL 3 ++#define VEOF 4 ++#define VTIME 5 ++#define VMIN 6 ++#define VSWTC 7 ++#define VSTART 8 ++#define VSTOP 9 ++#define VSUSP 10 ++#define VEOL 11 ++#define VREPRINT 12 ++#define VDISCARD 13 ++#define VWERASE 14 ++#define VLNEXT 15 ++#define VEOL2 16 ++ ++/* c_iflag bits */ ++#define IGNBRK 0000001 ++#define BRKINT 0000002 ++#define IGNPAR 0000004 ++#define PARMRK 0000010 ++#define INPCK 0000020 ++#define ISTRIP 0000040 ++#define INLCR 0000100 ++#define IGNCR 0000200 ++#define ICRNL 0000400 ++#define IUCLC 0001000 ++#define IXON 0002000 ++#define IXANY 0004000 ++#define IXOFF 0010000 ++#define IMAXBEL 0020000 ++#define IUTF8 0040000 ++ ++/* c_oflag bits */ ++#define OPOST 0000001 ++#define OLCUC 0000002 ++#define ONLCR 0000004 ++#define OCRNL 0000010 ++#define ONOCR 0000020 ++#define ONLRET 0000040 ++#define OFILL 0000100 ++#define OFDEL 0000200 ++#define NLDLY 0000400 ++#define NL0 0000000 ++#define NL1 0000400 ++#define CRDLY 0003000 ++#define CR0 0000000 ++#define CR1 0001000 ++#define CR2 0002000 ++#define CR3 0003000 ++#define TABDLY 0014000 ++#define TAB0 0000000 ++#define TAB1 0004000 ++#define TAB2 0010000 ++#define TAB3 0014000 ++#define XTABS 0014000 ++#define BSDLY 0020000 ++#define BS0 0000000 ++#define BS1 0020000 ++#define VTDLY 0040000 ++#define VT0 0000000 ++#define VT1 0040000 ++#define FFDLY 0100000 ++#define FF0 0000000 ++#define FF1 0100000 ++ ++/* c_cflag bit meaning */ ++#define CBAUD 0010017 ++#define B0 0000000 /* hang up */ ++#define B50 0000001 ++#define B75 0000002 ++#define B110 0000003 ++#define B134 0000004 ++#define B150 0000005 ++#define B200 0000006 ++#define B300 0000007 ++#define B600 0000010 ++#define B1200 0000011 ++#define B1800 0000012 ++#define B2400 0000013 ++#define B4800 0000014 ++#define B9600 0000015 ++#define B19200 0000016 ++#define B38400 0000017 ++#define EXTA B19200 ++#define EXTB B38400 ++#define CSIZE 0000060 ++#define CS5 0000000 ++#define CS6 0000020 ++#define CS7 0000040 ++#define CS8 0000060 ++#define CSTOPB 0000100 ++#define CREAD 0000200 ++#define PARENB 0000400 ++#define PARODD 0001000 ++#define HUPCL 0002000 ++#define CLOCAL 0004000 ++#define CBAUDEX 0010000 ++#define BOTHER 0010000 ++#define B57600 0010001 ++#define B115200 0010002 ++#define B230400 0010003 ++#define B460800 0010004 ++#define B500000 0010005 ++#define B576000 0010006 ++#define B921600 0010007 ++#define B1000000 0010010 ++#define B1152000 0010011 ++#define B1500000 0010012 ++#define B2000000 0010013 ++#define B2500000 0010014 ++#define B3000000 0010015 ++#define B3500000 0010016 ++#define B4000000 0010017 ++#define CIBAUD 002003600000 /* input baud rate */ ++#define CMSPAR 010000000000 /* mark or space (stick) parity */ ++#define CRTSCTS 020000000000 /* flow control */ ++ ++#define IBSHIFT 16 ++ ++/* c_lflag bits */ ++#define ISIG 0000001 ++#define ICANON 0000002 ++#define XCASE 0000004 ++#define ECHO 0000010 ++#define ECHOE 0000020 ++#define ECHOK 0000040 ++#define ECHONL 0000100 ++#define NOFLSH 0000200 ++#define TOSTOP 0000400 ++#define ECHOCTL 0001000 ++#define ECHOPRT 0002000 ++#define ECHOKE 0004000 ++#define FLUSHO 0010000 ++#define PENDIN 0040000 ++#define IEXTEN 0100000 ++#define EXTPROC 0200000 ++ ++/* tcflow() and TCXONC use these */ ++#define TCOOFF 0 ++#define TCOON 1 ++#define TCIOFF 2 ++#define TCION 3 ++ ++/* tcflush() and TCFLSH use these */ ++#define TCIFLUSH 0 ++#define TCOFLUSH 1 ++#define TCIOFLUSH 2 ++ ++/* tcsetattr uses these */ ++#define TCSANOW 0 ++#define TCSADRAIN 1 ++#define TCSAFLUSH 2 ++ ++#endif /* __ASM_NDS32_TERMBITS_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/termios.h linux-3.4.110/arch/nds32/include/asm/termios.h +--- linux-3.4.110.orig/arch/nds32/include/asm/termios.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/termios.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,116 @@ ++/* ++ * linux/arch/nds32/include/asm/termios.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ASM_NDS32_TERMIOS_H ++#define __ASM_NDS32_TERMIOS_H ++ ++#include <asm/termbits.h> ++#include <asm/ioctls.h> ++ ++struct winsize { ++ unsigned short ws_row; ++ unsigned short ws_col; ++ unsigned short ws_xpixel; ++ unsigned short ws_ypixel; ++}; ++ ++#define NCC 8 ++struct termio { ++ unsigned short c_iflag; /* input mode flags */ ++ unsigned short c_oflag; /* output mode flags */ ++ unsigned short c_cflag; /* control mode flags */ ++ unsigned short c_lflag; /* local mode flags */ ++ unsigned char c_line; /* line discipline */ ++ unsigned char c_cc[NCC]; /* control characters */ ++}; ++ ++#ifdef __KERNEL__ ++/* intr=^C quit=^| erase=del kill=^U ++ eof=^D vtime=\0 vmin=\1 sxtc=\0 ++ start=^Q stop=^S susp=^Z eol=\0 ++ reprint=^R discard=^U werase=^W lnext=^V ++ eol2=\0 ++*/ ++#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" ++#endif ++ ++/* modem lines */ ++#define TIOCM_LE 0x001 ++#define TIOCM_DTR 0x002 ++#define TIOCM_RTS 0x004 ++#define TIOCM_ST 0x008 ++#define TIOCM_SR 0x010 ++#define TIOCM_CTS 0x020 ++#define TIOCM_CAR 0x040 ++#define TIOCM_RNG 0x080 ++#define TIOCM_DSR 0x100 ++#define TIOCM_CD TIOCM_CAR ++#define TIOCM_RI TIOCM_RNG ++#define TIOCM_OUT1 0x2000 ++#define TIOCM_OUT2 0x4000 ++#define TIOCM_LOOP 0x8000 ++ ++/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ ++ ++/* line disciplines */ ++#define N_TTY 0 ++#define N_SLIP 1 ++#define N_MOUSE 2 ++#define N_PPP 3 ++#define N_STRIP 4 ++#define N_AX25 5 ++#define N_X25 6 /* X.25 async */ ++#define N_6PACK 7 ++#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */ ++#define N_R3964 9 /* Reserved for Simatic R3964 module */ ++#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */ ++#define N_IRDA 11 /* Linux IrDa - http://irda.sourceforge.net/ */ ++#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ ++#define N_HDLC 13 /* synchronous HDLC */ ++#define N_SYNC_PPP 14 ++#define N_HCI 15 /* Bluetooth HCI UART */ ++ ++#ifdef __KERNEL__ ++ ++/* ++ * Translate a "termio" structure into a "termios". Ugh. ++ */ ++#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \ ++ unsigned short __tmp; \ ++ get_user(__tmp,&(termio)->x); \ ++ *(unsigned short *) &(termios)->x = __tmp; \ ++} ++ ++#define user_termio_to_kernel_termios(termios, termio) \ ++({ \ ++ SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \ ++ SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \ ++ SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \ ++ SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \ ++ copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ ++}) ++ ++/* ++ * Translate a "termios" structure into a "termio". Ugh. ++ */ ++#define kernel_termios_to_user_termio(termio, termios) \ ++({ \ ++ put_user((termios)->c_iflag, &(termio)->c_iflag); \ ++ put_user((termios)->c_oflag, &(termio)->c_oflag); \ ++ put_user((termios)->c_cflag, &(termio)->c_cflag); \ ++ put_user((termios)->c_lflag, &(termio)->c_lflag); \ ++ put_user((termios)->c_line, &(termio)->c_line); \ ++ copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ ++}) ++ ++#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) ++#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) ++ ++#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios)) ++#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios)) ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* __ASM_NDS32_TERMIOS_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/thread_info.h linux-3.4.110/arch/nds32/include/asm/thread_info.h +--- linux-3.4.110.orig/arch/nds32/include/asm/thread_info.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/thread_info.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,145 @@ ++/* ++ * linux/arch/nds32/include/asm/thread_info.h ++ * ++ * Copyright (C) 2002 Russell King. ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef __ASM_NDS32_THREAD_INFO_H ++#define __ASM_NDS32_THREAD_INFO_H ++ ++#ifdef __KERNEL__ ++ ++#define THREAD_SHIFT (13) ++#define THREAD_SIZE (1 << THREAD_SHIFT) ++ ++#ifndef __ASSEMBLY__ ++ ++struct task_struct; ++struct exec_domain; ++ ++#include <asm/ptrace.h> ++#include <asm/types.h> ++ ++ ++typedef struct { ++ unsigned long seg; ++} mm_segment_t; ++//typedef unsigned long mm_segment_t; ++ ++struct cpu_context_save { ++ unsigned long r6; ++ unsigned long r7; ++ unsigned long r8; ++ unsigned long r9; ++ unsigned long r10; ++ unsigned long r11; ++ unsigned long r12; ++ unsigned long r13; ++ unsigned long r14; ++ unsigned long fp; ++ unsigned long pc; ++}; ++ ++/* ++ * low level task data that entry.S needs immediate access to. ++ * __switch_to() assumes cpu_context follows immediately after cpu_domain. ++ */ ++struct thread_info { ++ unsigned long flags; /* low level flags */ ++ __s32 preempt_count; /* 0 => preemptable, <0 => bug */ ++ mm_segment_t addr_limit; /* address limit */ ++ struct task_struct *task; /* main task structure */ ++ struct exec_domain *exec_domain; /* execution domain */ ++ __u32 cpu; /* cpu */ ++ struct cpu_context_save* sp_save; /* cpu context */ ++ struct restart_block restart_block; ++}; ++ ++#define INIT_THREAD_INFO(tsk) \ ++{ \ ++ .task = &tsk, \ ++ .exec_domain = &default_exec_domain, \ ++ .flags = 0, \ ++ .cpu = 0, \ ++ .preempt_count = 1, \ ++ .addr_limit = KERNEL_DS, \ ++ .restart_block = { \ ++ .fn = do_no_restart_syscall, \ ++ }, \ ++} ++ ++#define init_thread_info (init_thread_union.thread_info) ++#define init_stack (init_thread_union.stack) ++ ++ ++/* ++ * how to get the thread information struct from C ++ */ ++static inline struct thread_info *current_thread_info(void) __attribute_const__; ++ ++static inline struct thread_info *current_thread_info(void) ++{ ++ register unsigned long sp asm ("$sp"); //M Tom asm -> __asm__ __volatile__ ++ return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); ++} ++ ++#define get_thread_info(ti) get_task_struct((ti)->task) ++#define put_thread_info(ti) put_task_struct((ti)->task) ++ ++#define thread_saved_pc(tsk) \ ++ ((unsigned long)(task_thread_info(tsk)->sp_save->pc)) ++#define thread_saved_fp(tsk) \ ++ ((unsigned long)(task_thread_info(tsk)->sp_save->fp)) ++#endif ++ ++#define THREAD_SIZE_ORDER (1) ++/* ++ * We use bit 30 of the preempt_count to indicate that kernel ++ * preemption is occuring. See include/asm-arm/hardirq.h. ++ */ ++#define PREEMPT_ACTIVE 0x40000000 ++ ++/* ++ * thread information flags: ++ * TIF_SYSCALL_TRACE - syscall trace active ++ * TIF_NOTIFY_RESUME - resumption notification requested ++ * TIF_SIGPENDING - signal pending ++ * TIF_NEED_RESCHED - rescheduling necessary ++ * TIF_USEDFPU - FPU was used by this task this quantum (SMP) ++ * TIF_POLLING_NRFLAG - true if poll_idle() is polling TIF_NEED_RESCHED ++ * TIF_USEDAUDIO - Audio has been used by this task and no need to init the regs ++ */ ++#define TIF_SIGPENDING 1 ++#define TIF_NEED_RESCHED 2 ++#define TIF_SINGLESTEP 3 ++#define TIF_NOTIFY_RESUME 5 ++#define TIF_SYSCALL_TRACE 8 ++#define TIF_RESTORE_SIGMASK 9 ++#define TIF_USEDFPU 16 ++#define TIF_POLLING_NRFLAG 17 ++#define TIF_MEMDIE 18 ++#define TIF_FREEZE 19 ++#define TIF_USEDAUDIO 20 ++ ++#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) ++#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) ++#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) ++#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) ++#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) ++#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) ++#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) ++#define _TIF_FREEZE (1 << TIF_FREEZE) ++ ++/* ++ * Change these and you break ASM code in entry-common.S ++ */ ++#define _TIF_WORK_MASK 0x000000ff ++#define _TIF_WORK_SYSCALL_ENTRY (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP) ++#define _TIF_WORK_SYSCALL_LEAVE (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP) ++ ++#endif /* __KERNEL__ */ ++#endif /* __ASM_NDS32_THREAD_INFO_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/timer.h linux-3.4.110/arch/nds32/include/asm/timer.h +--- linux-3.4.110.orig/arch/nds32/include/asm/timer.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/timer.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,94 @@ ++/* ++ * include/arch/nds32/include/asm/timer.h ++ * ++ * Faraday FTTMR010 Timer Device Driver Interface ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Note ++ * ++ * As IP_COUNT might be greater than one, timer ID is computed as follows: ++ * id=0~2 : Timer 1~3 of the first FTTMR010 IP ++ * id=3~5 : Timer 1~3 of the second FTTMR010 IP ++ * ... ++ * Therefore: ++ * (id / 3) : Compute which IP ++ * (id % 3) : Compute which timer in this IP ++ * Notice: ++ * For simplicity's sake, all code does not check for invalid timer id ++ * ++ * ChangeLog ++ * ++ * Luke Lee 09/14/2005 Created, heavily modified from Faraday CPE platform code. ++ */ ++ ++ ++#ifndef __FARADAY_TIMER_FTTMR010_HEADER__ ++#define __FARADAY_TIMER_FTTMR010_HEADER__ ++ ++/* ++ * Definition of register offsets ++ */ ++ ++#define TIMER1_COUNT 0x0 ++#define TIMER1_LOAD 0x4 ++#define TIMER1_MATCH1 0x8 ++#define TIMER1_MATCH2 0xC ++ ++#define TIMER2_COUNT 0x10 ++#define TIMER2_LOAD 0x14 ++#define TIMER2_MATCH1 0x18 ++#define TIMER2_MATCH2 0x1C ++ ++#define TIMER3_COUNT 0x20 ++#define TIMER3_LOAD 0x24 ++#define TIMER3_MATCH1 0x28 ++#define TIMER3_MATCH2 0x2C ++ ++#define TIMER_TMCR 0x30 ++#define TIMER_INTRSTATE 0x34 ++#define TIMER_INTRMASK 0x38 ++ ++/* Each timer's register address is offset by 0x10 */ ++#define TIMER_OFFSET 0x10 ++ ++/* ++ * Definition of TMCR bits ++ */ ++ ++#define TM1ENABLE 1 ++#define TM1CLOCK (1<<1) ++#define TM1OFENABLE (1<<2) ++ ++#define TM2ENABLE (1<<3) ++#define TM2CLOCK (1<<4) ++#define TM2OFENABLE (1<<5) ++ ++#define TM3ENABLE (1<<6) ++#define TM3CLOCK (1<<7) ++#define TM3OFENABLE (1<<8) ++ ++#define TM1UPDOWN (1<<9) ++#define TM2UPDOWN (1<<10) ++#define TM3UPDOWN (1<<11) ++ ++ ++#define TM1MATCH1 (1 << 0) ++#define TM1MATCH2 (1 << 1) ++#define TM1OVERFLOW (1 << 2) ++#define TM2MATCH1 (1 << 3) ++#define TM2MATCH2 (1 << 4) ++#define TM2OVERFLOW (1 << 5) ++#define TM3MATCH1 (1 << 6) ++#define TM3MATCH2 (1 << 7) ++#define TM3OVERFLOW (1 << 8) ++ ++struct sys_timer; ++extern struct sys_timer platform_timer; ++ ++#endif // __FARADAY_TIMER_FTTMR010_HEADER__ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/timex.h linux-3.4.110/arch/nds32/include/asm/timex.h +--- linux-3.4.110.orig/arch/nds32/include/asm/timex.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/timex.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,36 @@ ++/* ++ * linux/arch/nds32/include/asm/timex.h ++ * ++ * Copyright (C) 1997,1998 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Architecture Specific TIME specifications ++ */ ++#ifndef _ASMNDS32_TIMEX_H ++#define _ASMNDS32_TIMEX_H ++ ++#ifndef __FARADAY_PLATFORM_INDEPENDENT_TIMEX_HEADER__ ++#define __FARADAY_PLATFORM_INDEPENDENT_TIMEX_HEADER__ ++ ++#include <asm/spec.h> ++ ++#ifndef CLOCK_TICK_RATE ++#define CLOCK_TICK_RATE (TIMER_CLK_IN) ++#endif ++ ++#endif /* __FARADAY_PLATFORM_INDEPENDENT_TIMEX_HEADER__ */ ++ ++typedef unsigned long cycles_t; ++ ++extern cycles_t cacheflush_time; ++ ++static inline cycles_t get_cycles (void) ++{ ++ return 0; ++} ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/tlbflush.h linux-3.4.110/arch/nds32/include/asm/tlbflush.h +--- linux-3.4.110.orig/arch/nds32/include/asm/tlbflush.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/tlbflush.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,80 @@ ++/* ++ * linux/arch/nds32/include/asm/tlbflush.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_TLBFLUSH_H ++#define _ASMNDS32_TLBFLUSH_H ++ ++#include <linux/spinlock.h> ++#include <linux/mm.h> ++#include <nds32_intrinsic.h> ++ ++static inline void local_flush_tlb_all(void) ++{ ++ asm("tlbop FLUA\n"); ++ __nds32__isb(); ++} ++static inline void local_flush_tlb_mm(struct mm_struct *mm) ++{ ++ asm("tlbop FLUA\n"); ++ __nds32__isb(); ++} ++static inline void local_flush_tlb_kernel_range(unsigned long start, ++ unsigned long end) ++{ ++ while(start < end) { ++ asm("tlbop %0, INV"::"r" (start)); ++ __nds32__isb(); ++ start += PAGE_SIZE; ++ } ++} ++ ++#ifndef CONFIG_CPU_NO_CONTEXT_ID ++void local_flush_tlb_range(struct vm_area_struct *vma, ++ unsigned long start, unsigned long end); ++void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr); ++#else ++static inline void local_flush_tlb_range(struct vm_area_struct *vma, ++ unsigned long start, unsigned long end) ++{ ++ if ((end - start) > 0x400000) { ++ asm("tlbop FLUA"); ++ __nds32__isb(); ++ return ; ++ } ++ while(start < end) { ++ asm("tlbop %0, INV"::"r" (start)); ++ __nds32__isb(); ++ start += PAGE_SIZE; ++ } ++} ++ ++static inline void local_flush_tlb_page(struct vm_area_struct *vma, ++ unsigned long addr) ++{ ++ asm("tlbop %0, INV"::"r" (addr)); ++ __nds32__isb(); ++} ++#endif ++ ++#ifndef CONFIG_SMP ++#define flush_tlb_all local_flush_tlb_all ++#define flush_tlb_mm local_flush_tlb_mm ++#define flush_tlb_range local_flush_tlb_range ++#define flush_tlb_page local_flush_tlb_page ++#define flush_tlb_kernel_range local_flush_tlb_kernel_range ++#else ++void flush_tlb_all(void); ++void flush_tlb_mm(struct mm_struct *mm); ++void flush_tlb_range(struct vm_area_struct *vma, ++ unsigned long start, unsigned long end); ++void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr); ++void flush_tlb_kernel_range(unsigned long start, unsigned long end); ++#endif ++ ++void update_mmu_cache(struct vm_area_struct *vma, ++ unsigned long address, pte_t* pte); ++void tlb_migrate_finish(struct mm_struct *mm); ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/tlb.h linux-3.4.110/arch/nds32/include/asm/tlb.h +--- linux-3.4.110.orig/arch/nds32/include/asm/tlb.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/tlb.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,30 @@ ++/* ++ * linux/arch/nds32/include/asm/tlb.h ++ * Copyright (C) 2009 Andes Technology Corporation ++ */ ++ ++#ifndef __ASMNDS32_TLB_H ++#define __ASMNDS32_TLB_H ++ ++#define tlb_start_vma(tlb,vma) \ ++ do { \ ++ if (!tlb->fullmm) \ ++ flush_cache_range(vma, vma->vm_start, vma->vm_end); \ ++ } while (0) ++ ++#define tlb_end_vma(tlb,vma) \ ++ do { \ ++ if(!tlb->fullmm) \ ++ flush_tlb_range(vma, vma->vm_start, vma->vm_end); \ ++ } while (0) ++ ++#define __tlb_remove_tlb_entry(tlb, pte, addr) do { } while (0) ++ ++#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) ++ ++#include <asm-generic/tlb.h> ++ ++#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte) ++#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tln)->mm, pmd) ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/topology.h linux-3.4.110/arch/nds32/include/asm/topology.h +--- linux-3.4.110.orig/arch/nds32/include/asm/topology.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/topology.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,11 @@ ++/* ++ * linux/arch/nds32/include/asm/topology.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASM_NDS32_TOPOLOGY_H ++#define _ASM_NDS32_TOPOLOGY_H ++ ++#include <asm-generic/topology.h> ++ ++#endif /* _ASM_NDS32_TOPOLOGY_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/traps.h linux-3.4.110/arch/nds32/include/asm/traps.h +--- linux-3.4.110.orig/arch/nds32/include/asm/traps.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/traps.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,25 @@ ++/* ++ * linux/arch/nds32/include/asm/traps.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_TRAP_H ++#define _ASMNDS32_TRAP_H ++ ++#include <linux/list.h> ++ ++struct undef_hook { ++ struct list_head node; ++ u32 instr_mask; ++ u32 instr_val; ++ u32 cpsr_mask; ++ u32 cpsr_val; ++ int (*fn)(struct pt_regs *regs, unsigned int instr); ++}; ++ ++void register_undef_hook(struct undef_hook *hook); ++void unregister_undef_hook(struct undef_hook *hook); ++ ++extern void __init early_trap_init(void); ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/types.h linux-3.4.110/arch/nds32/include/asm/types.h +--- linux-3.4.110.orig/arch/nds32/include/asm/types.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/types.h 2016-04-07 10:20:50.918080096 +0200 +@@ -0,0 +1,16 @@ ++#ifndef __ASM_NDS32_TYPES_H ++#define __ASM_NDS32_TYPES_H ++ ++#include <asm-generic/int-ll64.h> ++ ++/* ++ * These aren't exported outside the kernel to avoid name space clashes ++ */ ++#ifdef __KERNEL__ ++ ++#define BITS_PER_LONG 32 ++ ++#endif /* __KERNEL__ */ ++ ++#endif ++ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/uaccess.h linux-3.4.110/arch/nds32/include/asm/uaccess.h +--- linux-3.4.110.orig/arch/nds32/include/asm/uaccess.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/uaccess.h 2016-04-07 10:20:50.934080715 +0200 +@@ -0,0 +1,428 @@ ++/* ++ * linux/arch/nds32/include/asm/uaccess.h ++ * ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#ifndef _ASMANDES_UACCESS_H ++#define _ASMANDES_UACCESS_H ++ ++/* ++ * User space memory access functions ++ */ ++#include <linux/sched.h> ++#include <asm/errno.h> ++#include <asm/memory.h> ++#include <asm/system.h> ++#include <asm/types.h> ++#include <linux/mm.h> ++ ++#define VERIFY_READ 0 ++#define VERIFY_WRITE 1 ++ ++/* ++ * The exception table consists of pairs of addresses: the first is the ++ * address of an instruction that is allowed to fault, and the second is ++ * the address at which the program should continue. No registers are ++ * modified, so it is entirely up to the continuation code to figure out ++ * what to do. ++ * ++ * All the routines below use bits of fixup code that are out of line ++ * with the main instruction path. This means when everything is well, ++ * we don't even have to jump over them. Further, they do not intrude ++ * on our cache or tlb entries. ++ */ ++ ++struct exception_table_entry ++{ ++ unsigned long insn, fixup; ++}; ++ ++extern int fixup_exception(struct pt_regs *regs); ++ ++#define KERNEL_DS ((mm_segment_t) { ~0UL }) ++#define USER_DS ((mm_segment_t) {TASK_SIZE - 1}) ++ ++#define get_ds() (KERNEL_DS) ++#define get_fs() (current_thread_info()->addr_limit) ++ ++static inline void set_fs (mm_segment_t fs) ++{ ++ current_thread_info()->addr_limit = fs; ++} ++ ++#define segment_eq(a, b) ((a.seg) == (b.seg)) ++ ++#define __range_ok(addr, size) (size <= get_fs().seg && addr <= (get_fs().seg -size)) ++ ++#define access_ok(type, addr, size) \ ++ __range_ok((unsigned long)addr, (unsigned long)size) ++/* ++ * Single-value transfer routines. They automatically use the right ++ * size if we just have the right pointer type. Note that the functions ++ * which read from user space (*get_*) need to take care not to leak ++ * kernel data even if the calling code is buggy and fails to check ++ * the return value. This means zeroing out the destination variable ++ * or buffer on error. Normally this is done out of line by the ++ * fixup code, but there are a few places where it intrudes on the ++ * main code path. When we only write to user space, there is no ++ * problem. ++ * ++ * The "__xxx" versions of the user access functions do not verify the ++ * address space - it must have been done previously with a separate ++ * "access_ok()" call. ++ * ++ * The "xxx_error" versions set the third argument to EFAULT if an ++ * error occurs, and leave it unchanged on success. Note that these ++ * versions are void (ie, don't return a value as such). ++ */ ++ ++extern int __get_user_1(void *); ++extern int __get_user_2(void *); ++extern int __get_user_4(void *); ++extern int __get_user_8(void *); ++extern int __get_user_bad(void); ++ ++#define __get_user_x(__r2,__p,__e,__s,__i...) \ ++ __asm__ __volatile__ ( \ ++ __asmeq("%0", "$r0") __asmeq("%1", "$r2") \ ++ "bal __get_user_" #__s \ ++ : "=&r" (__e), "=r" (__r2) \ ++ : "0" (__p) \ ++ : __i, "cc") ++ ++#define get_user(x,p) \ ++ ({ \ ++ const register typeof(*(p)) __user *__p asm("$r0") = (p);\ ++ register unsigned long __r2 asm("$r2"); \ ++ register int __e asm("$r0"); \ ++ switch (sizeof(*(__p))) { \ ++ case 1: \ ++ __get_user_x(__r2, __p, __e, 1, "$lp"); \ ++ break; \ ++ case 2: \ ++ __get_user_x(__r2, __p, __e, 2, "$r3", "$lp"); \ ++ break; \ ++ case 4: \ ++ __get_user_x(__r2, __p, __e, 4, "$lp"); \ ++ break; \ ++ case 8: \ ++ __get_user_x(__r2, __p, __e, 8, "$lp"); \ ++ break; \ ++ default: __e = __get_user_bad(); break; \ ++ } \ ++ x = (typeof(*(p))) __r2; \ ++ __e; \ ++ }) ++ ++#define __get_user(x,ptr) \ ++({ \ ++ long __gu_err = 0; \ ++ __get_user_err((x),(ptr),__gu_err); \ ++ __gu_err; \ ++}) ++ ++#define __get_user_error(x,ptr,err) \ ++({ \ ++ __get_user_err((x),(ptr),err); \ ++ (void) 0; \ ++}) ++ ++#define __get_user_err(x,ptr,err) \ ++do { \ ++ unsigned long __gu_addr = (unsigned long)(ptr); \ ++ unsigned long __gu_val; \ ++ __chk_user_ptr(ptr); \ ++ switch (sizeof(*(ptr))) { \ ++ case 1: __get_user_asm_byte(__gu_val,__gu_addr,err); break; \ ++ case 2: __get_user_asm_half(__gu_val,__gu_addr,err); break; \ ++ case 4: __get_user_asm_word(__gu_val,__gu_addr,err); break; \ ++ default: (__gu_val) = __get_user_bad(); \ ++ } \ ++ (x) = (__typeof__(*(ptr)))__gu_val; \ ++} while (0) ++ ++#define __get_user_asm_byte(x,addr,err) \ ++ __asm__ __volatile__( \ ++ "1: lbi %1,[%2]\n" \ ++ "2:\n" \ ++ " .section .fixup,\"ax\"\n" \ ++ " .align 2\n" \ ++ "3: move %0, %3\n" \ ++ " move %1, #0\n" \ ++ " b 2b\n" \ ++ " .previous\n" \ ++ " .section __ex_table,\"a\"\n" \ ++ " .align 3\n" \ ++ " .long 1b, 3b\n" \ ++ " .previous" \ ++ : "+r" (err), "=&r" (x) \ ++ : "r" (addr), "i" (-EFAULT) \ ++ : "cc") ++ ++#ifndef __NDS32_EB__ ++#define __get_user_asm_half(x,__gu_addr,err) \ ++({ \ ++ unsigned long __b1, __b2; \ ++ __get_user_asm_byte(__b1, __gu_addr, err); \ ++ __get_user_asm_byte(__b2, __gu_addr + 1, err); \ ++ (x) = __b1 | (__b2 << 8); \ ++}) ++#else ++#define __get_user_asm_half(x,__gu_addr,err) \ ++({ \ ++ unsigned long __b1, __b2; \ ++ __get_user_asm_byte(__b1, __gu_addr, err); \ ++ __get_user_asm_byte(__b2, __gu_addr + 1, err); \ ++ (x) = (__b1 << 8) | __b2; \ ++}) ++#endif ++ ++#define __get_user_asm_word(x,addr,err) \ ++ __asm__ __volatile__( \ ++ "1: lwi %1,[%2]\n" \ ++ "2:\n" \ ++ " .section .fixup,\"ax\"\n" \ ++ " .align 2\n" \ ++ "3: move %0, %3\n" \ ++ " move %1, #0\n" \ ++ " b 2b\n" \ ++ " .previous\n" \ ++ " .section __ex_table,\"a\"\n" \ ++ " .align 3\n" \ ++ " .long 1b, 3b\n" \ ++ " .previous" \ ++ : "+r" (err), "=&r" (x) \ ++ : "r" (addr), "i" (-EFAULT) \ ++ : "cc") ++ ++extern int __put_user_1(void *, unsigned int); ++extern int __put_user_2(void *, unsigned int); ++extern int __put_user_4(void *, unsigned int); ++extern int __put_user_8(void *, unsigned long long); ++extern int __put_user_bad(void); ++ ++#ifdef _GCC444 ++#define __put_user_x(__r2,__p,__e,__s) \ ++ __asm__ __volatile__ ( \ ++ __asmeq("%0", "$r0") __asmeq("%2", "$r2") \ ++ "bal __put_user_" #__s \ ++ : "=&r" (__e) \ ++ : "0" (__p), "r" (__r2) \ ++ : "$p0", "$lp", "cc") ++#else ++#define __put_user_x(__r2,__p,__e,__s) \ ++ __asm__ __volatile__ ( \ ++ __asmeq("%0", "$r0") __asmeq("%2", "$r2") \ ++ "bal __put_user_" #__s \ ++ : "=&r" (__e) \ ++ : "0" (__p), "r" (__r2) \ ++ : "$r26", "$lp", "cc") ++#endif ++ ++#define put_user(x,p) \ ++ ({ \ ++ const register typeof(*(p)) __r2 asm("$r2") = (x); \ ++ const register typeof(*(p)) __user *__p asm("$r0") = (p);\ ++ register int __e asm("$r0"); \ ++ switch (sizeof(*(__p))) { \ ++ case 1: \ ++ __put_user_x(__r2, __p, __e, 1); \ ++ break; \ ++ case 2: \ ++ __put_user_x(__r2, __p, __e, 2); \ ++ break; \ ++ case 4: \ ++ __put_user_x(__r2, __p, __e, 4); \ ++ break; \ ++ case 8: \ ++ __put_user_x(__r2, __p, __e, 8); \ ++ break; \ ++ default: __e = __put_user_bad(); break; \ ++ } \ ++ __e; \ ++ }) ++ ++#define __put_user(x,ptr) \ ++({ \ ++ long __pu_err = 0; \ ++ __put_user_err((x),(ptr),__pu_err); \ ++ __pu_err; \ ++}) ++ ++#define __put_user_error(x,ptr,err) \ ++({ \ ++ __put_user_err((x),(ptr),err); \ ++ (void) 0; \ ++}) ++ ++#define __put_user_err(x,ptr,err) \ ++do { \ ++ unsigned long __pu_addr = (unsigned long)(ptr); \ ++ __typeof__(*(ptr)) __pu_val = (x); \ ++ __chk_user_ptr(ptr); \ ++ switch (sizeof(*(ptr))) { \ ++ case 1: __put_user_asm_byte(__pu_val,__pu_addr,err); break; \ ++ case 2: __put_user_asm_half(__pu_val,__pu_addr,err); break; \ ++ case 4: __put_user_asm_word(__pu_val,__pu_addr,err); break; \ ++ case 8: __put_user_asm_dword(__pu_val,__pu_addr,err); break; \ ++ default: __put_user_bad(); \ ++ } \ ++} while (0) ++ ++#define __put_user_asm_byte(x,__pu_addr,err) \ ++ __asm__ __volatile__( \ ++ "1: sbi %1,[%2]\n" \ ++ "2:\n" \ ++ " .section .fixup,\"ax\"\n" \ ++ " .align 2\n" \ ++ "3: move %0, %3\n" \ ++ " b 2b\n" \ ++ " .previous\n" \ ++ " .section __ex_table,\"a\"\n" \ ++ " .align 3\n" \ ++ " .long 1b, 3b\n" \ ++ " .previous" \ ++ : "+r" (err) \ ++ : "r" (x), "r" (__pu_addr), "i" (-EFAULT) \ ++ : "cc") ++ ++#ifndef __NDS32_EB__ ++#define __put_user_asm_half(x,__pu_addr,err) \ ++({ \ ++ unsigned long __temp = (unsigned long)(x); \ ++ __put_user_asm_byte(__temp, __pu_addr, err); \ ++ __put_user_asm_byte(__temp >> 8, __pu_addr + 1, err); \ ++}) ++#else ++#define __put_user_asm_half(x,__pu_addr,err) \ ++({ \ ++ unsigned long __temp = (unsigned long)(x); \ ++ __put_user_asm_byte(__temp >> 8, __pu_addr, err); \ ++ __put_user_asm_byte(__temp, __pu_addr + 1, err); \ ++}) ++#endif ++ ++#define __put_user_asm_word(x,__pu_addr,err) \ ++ __asm__ __volatile__( \ ++ "1: swi %1,[%2]\n" \ ++ "2:\n" \ ++ " .section .fixup,\"ax\"\n" \ ++ " .align 2\n" \ ++ "3: move %0, %3\n" \ ++ " b 2b\n" \ ++ " .previous\n" \ ++ " .section __ex_table,\"a\"\n" \ ++ " .align 3\n" \ ++ " .long 1b, 3b\n" \ ++ " .previous" \ ++ : "+r" (err) \ ++ : "r" (x), "r" (__pu_addr), "i" (-EFAULT) \ ++ : "cc") ++ ++#ifdef __NDS32_EB__ ++#define __reg_oper0 "%H2" ++#define __reg_oper1 "%L2" ++#else ++#define __reg_oper0 "%L2" ++#define __reg_oper1 "%H2" ++#endif ++ ++#define __put_user_asm_dword(x, __pu_addr, __pu_err) \ ++ __asm__ __volatile__ ( \ ++ "\n1:\tswi " __reg_oper0 ",[%1]\n" \ ++ "\n2:\tswi " __reg_oper1 ",[%1+4]\n" \ ++ "3:\n" \ ++ " .section .fixup,\"ax\"\n" \ ++ " .align 2\n" \ ++ "4: move %0, %3\n" \ ++ " b 3b\n" \ ++ " .previous\n" \ ++ " .section __ex_table,\"a\"\n" \ ++ " .align 3\n" \ ++ " .long 1b, 4b\n" \ ++ " .long 2b, 4b\n" \ ++ " .previous" \ ++ : "+r"(__pu_err) \ ++ : "r"(__pu_addr), "r"(x), "i"(-EFAULT) \ ++ : "cc") ++extern unsigned long __arch_copy_from_user(void *to, const void __user *from, unsigned long n); ++extern unsigned long __arch_copy_to_user(void __user *to, const void *from, unsigned long n); ++extern unsigned long __arch_clear_user(void __user *addr, unsigned long n); ++extern unsigned long __arch_strncpy_from_user(char *to, const char __user *from, unsigned long count); ++extern unsigned long __arch_strnlen_user(const char __user *s, long n); ++ ++static inline unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) ++{ ++ if (access_ok(VERIFY_READ, from, n)) ++ n = __arch_copy_from_user(to, from, n); ++ else /* security hole - plug it */ ++ memzero(to, n); ++ return n; ++} ++ ++static inline unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n) ++{ ++ return __arch_copy_from_user(to, from, n); ++} ++ ++static inline unsigned long copy_to_user(void __user *to, const void *from, unsigned long n) ++{ ++ if (access_ok(VERIFY_WRITE, to, n)) ++ n = __arch_copy_to_user(to, from, n); ++ return n; ++} ++ ++static inline unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n) ++{ ++ return __arch_copy_to_user(to, from, n); ++} ++ ++#define __copy_to_user_inatomic __copy_to_user ++#define __copy_from_user_inatomic __copy_from_user ++ ++static inline unsigned long clear_user (void __user *to, unsigned long n) ++{ ++ if (access_ok(VERIFY_WRITE, to, n)) ++ n = __arch_clear_user(to, n); ++ return n; ++} ++ ++static inline unsigned long __clear_user (void __user *to, unsigned long n) ++{ ++ return __arch_clear_user(to, n); ++} ++ ++/* ++ * We check the flags of vma here before __arch_strncpy_from_user(). ++ * An alternative way to do it is using lwup instruction in __arch_strncpy_from_user(). ++ * TODO: Should perform performance evaluation of the two. ++ */ ++static inline long strncpy_from_user (char *dst, const char __user *src, long count) ++{ ++ long res = -EFAULT; ++ if (access_ok(VERIFY_READ, src, 1)) ++ res = __arch_strncpy_from_user(dst, src, count); ++ return res; ++} ++ ++static inline long __strncpy_from_user (char *dst, const char __user *src, long count) ++{ ++ return __arch_strncpy_from_user(dst, src, count); ++} ++ ++#define strlen_user(s) strnlen_user(s, ~0UL >> 1) ++ ++static inline long strnlen_user(const char __user *s, long n) ++{ ++ unsigned long res = 0; ++ ++ if (segment_eq(get_fs(),KERNEL_DS) || ((unsigned long)s < get_fs().seg)) ++ res = __arch_strnlen_user(s, n); ++ ++ return res; ++} ++#endif /* _ASMNDS32_UACCESS_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/ucontext.h linux-3.4.110/arch/nds32/include/asm/ucontext.h +--- linux-3.4.110.orig/arch/nds32/include/asm/ucontext.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/ucontext.h 2016-04-07 10:20:50.934080715 +0200 +@@ -0,0 +1,17 @@ ++/* ++ * linux/arch/nds32/include/asm/ucontext.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _ASMNDS32_UCONTEXT_H ++#define _ASMNDS32_UCONTEXT_H ++ ++struct ucontext { ++ unsigned long uc_flags; ++ struct ucontext *uc_link; ++ stack_t uc_stack; ++ struct sigcontext uc_mcontext; ++ sigset_t uc_sigmask; /* mask last for extensibility */ ++}; ++ ++#endif /* !_ASMNDS32_UCONTEXT_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/unaligned.h linux-3.4.110/arch/nds32/include/asm/unaligned.h +--- linux-3.4.110.orig/arch/nds32/include/asm/unaligned.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/unaligned.h 2016-04-07 10:20:50.934080715 +0200 +@@ -0,0 +1,24 @@ ++/* ++ * linux/arch/nds32/include/asm/unaligned.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef __ASM_NDS32_UNALIGNED_H ++#define __ASM_NDS32_UNALIGNED_H ++ ++#include <linux/unaligned/le_byteshift.h> ++#include <linux/unaligned/be_byteshift.h> ++#include <linux/unaligned/generic.h> ++ ++/* ++ * Select endianness ++ */ ++#if defined(__NDS32_EB__) ++#define get_unaligned __get_unaligned_be ++#define put_unaligned __put_unaligned_be ++#else ++#define get_unaligned __get_unaligned_le ++#define put_unaligned __put_unaligned_le ++#endif ++ ++#endif /* __ASM_NDS32_UNALIGNED_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/uncompress.h linux-3.4.110/arch/nds32/include/asm/uncompress.h +--- linux-3.4.110.orig/arch/nds32/include/asm/uncompress.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/uncompress.h 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,65 @@ ++/* ++ * linux/arch/nds32/include/asm/uncompress.h ++ * ++ * Faraday Linux Boot Loader UART (FTUART010) Routines ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * Note ++ * ++ * The first UART (FTUART010) in the system is used for dumping debug messages. ++ * ++ * ChangeLog ++ * ++ * Luke Lee 09/21/2005 Created. Heavily modified from Faraday CPE port. ++ */ ++ ++#include <asm/spec.h> ++ ++#ifdef CONFIG_PLAT_AG102 ++#define UART_PA_BASE 0x94200000 ++#else ++#define UART_PA_BASE 0x99600000 ++#endif ++ ++#define arch_decomp_setup() ++#define arch_decomp_wdog() ++ ++#ifndef STANDALONE_DEBUG ++#define putstr debug_puts ++#endif ++ ++#define SERIAL_THR 0x00 ++#define SERIAL_LSR 0x14 ++#define SERIAL_LSR_THRE 0x20 ++ ++static inline void uncompress_puts(const char *s) ++{ ++ volatile unsigned *status = (volatile unsigned *)(UART_PA_BASE+SERIAL_LSR); ++ while (*s) { ++ while ((*status & SERIAL_LSR_THRE)==0); ++ ++ *(volatile unsigned*)(UART_PA_BASE+SERIAL_THR) = (unsigned)*s; ++ ++ if (*s == '\n') { ++ while ((*status & SERIAL_LSR_THRE)==0); ++ *(volatile unsigned*)(UART_PA_BASE+SERIAL_THR) = '\r'; ++ } ++ s++; ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/unistd.h linux-3.4.110/arch/nds32/include/asm/unistd.h +--- linux-3.4.110.orig/arch/nds32/include/asm/unistd.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/unistd.h 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,468 @@ ++/* ++ * linux/arch/nds32/include/asm/unistd.h ++ * ++ * Copyright (C) 2001-2003 Russell King ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Please forward _all_ changes to this file to rmk@arm.linux.org.uk, ++ * no matter what the change is. Thanks! ++ */ ++/* ============================================================================ ++ * ++ * linux/arch/nds32/include/asm/unistd.h ++ * ++ * Copyright (C) 2007 Andes Technology Corporation ++ * This file is part of Linux and should be licensed under the GPL. ++ * See the file COPYING for conditions for redistribution. ++ * ++ * Abstract: ++ * ++ * This program is syscall scheme for Andes NDS32 architecture. ++ * ++ * Revision History: ++ * ++ * Jul.07.2007 Original from Shawn and Tom, refined by Harry. ++ * ++ * Note: ++ * ++ * ============================================================================ ++ */ ++ ++#ifndef __ASM_NDS32_UNISTD_H ++#define __ASM_NDS32_UNISTD_H ++ ++#define __NR_SYSCALL_BASE 0x5000 ++#define __NR_NDS32_BASE 0x7000 ++/* ++ * This file contains the system call numbers. ++ */ ++ ++#define __NR_restart_syscall (__NR_SYSCALL_BASE+ 0) ++#define __NR_exit (__NR_SYSCALL_BASE+ 1) ++#define __NR_fork (__NR_SYSCALL_BASE+ 2) ++#define __NR_read (__NR_SYSCALL_BASE+ 3) ++#define __NR_write (__NR_SYSCALL_BASE+ 4) ++#define __NR_open (__NR_SYSCALL_BASE+ 5) ++#define __NR_close (__NR_SYSCALL_BASE+ 6) ++#define __NR_waitpid (__NR_SYSCALL_BASE+ 7) ++ /* 7 was sys_waitpid */ ++#define __NR_creat (__NR_SYSCALL_BASE+ 8) ++#define __NR_link (__NR_SYSCALL_BASE+ 9) ++#define __NR_unlink (__NR_SYSCALL_BASE+ 10) ++#define __NR_execve (__NR_SYSCALL_BASE+ 11) ++#define __NR_chdir (__NR_SYSCALL_BASE+ 12) ++#define __NR_time (__NR_SYSCALL_BASE+ 13) ++#define __NR_mknod (__NR_SYSCALL_BASE+ 14) ++#define __NR_chmod (__NR_SYSCALL_BASE+ 15) ++#define __NR_lchown (__NR_SYSCALL_BASE+ 16) ++ /* 17 was sys_break */ ++ /* 18 was sys_oldstat */ ++#define __NR_lseek (__NR_SYSCALL_BASE+ 19) ++#define __NR_getpid (__NR_SYSCALL_BASE+ 20) ++#define __NR_mount (__NR_SYSCALL_BASE+ 21) ++#define __NR_umount (__NR_SYSCALL_BASE+ 22) ++#define __NR_setuid (__NR_SYSCALL_BASE+ 23) ++#define __NR_getuid (__NR_SYSCALL_BASE+ 24) ++#define __NR_stime (__NR_SYSCALL_BASE+ 25) ++#define __NR_ptrace (__NR_SYSCALL_BASE+ 26) ++#define __NR_alarm (__NR_SYSCALL_BASE+ 27) ++ /* 28 was sys_oldfstat */ ++#define __NR_pause (__NR_SYSCALL_BASE+ 29) ++#define __NR_utime (__NR_SYSCALL_BASE+ 30) ++ /* 31 was sys_stty */ ++ /* 32 was sys_gtty */ ++#define __NR_access (__NR_SYSCALL_BASE+ 33) ++#define __NR_nice (__NR_SYSCALL_BASE+ 34) ++ /* 35 was sys_ftime */ ++#define __NR_sync (__NR_SYSCALL_BASE+ 36) ++#define __NR_kill (__NR_SYSCALL_BASE+ 37) ++#define __NR_rename (__NR_SYSCALL_BASE+ 38) ++#define __NR_mkdir (__NR_SYSCALL_BASE+ 39) ++#define __NR_rmdir (__NR_SYSCALL_BASE+ 40) ++#define __NR_dup (__NR_SYSCALL_BASE+ 41) ++#define __NR_pipe (__NR_SYSCALL_BASE+ 42) ++#define __NR_times (__NR_SYSCALL_BASE+ 43) ++ /* 44 was sys_prof */ ++#define __NR_brk (__NR_SYSCALL_BASE+ 45) ++#define __NR_setgid (__NR_SYSCALL_BASE+ 46) ++#define __NR_getgid (__NR_SYSCALL_BASE+ 47) ++ /* 48 was sys_signal */ ++#define __NR_geteuid (__NR_SYSCALL_BASE+ 49) ++#define __NR_getegid (__NR_SYSCALL_BASE+ 50) ++#define __NR_acct (__NR_SYSCALL_BASE+ 51) ++#define __NR_umount2 (__NR_SYSCALL_BASE+ 52) ++ /* 53 was sys_lock */ ++#define __NR_ioctl (__NR_SYSCALL_BASE+ 54) ++#define __NR_fcntl (__NR_SYSCALL_BASE+ 55) ++ /* 56 was sys_mpx */ ++#define __NR_setpgid (__NR_SYSCALL_BASE+ 57) ++ /* 58 was sys_ulimit */ ++ /* 59 was sys_olduname */ ++#define __NR_umask (__NR_SYSCALL_BASE+ 60) ++#define __NR_chroot (__NR_SYSCALL_BASE+ 61) ++#define __NR_ustat (__NR_SYSCALL_BASE+ 62) ++#define __NR_dup2 (__NR_SYSCALL_BASE+ 63) ++#define __NR_getppid (__NR_SYSCALL_BASE+ 64) ++#define __NR_getpgrp (__NR_SYSCALL_BASE+ 65) ++#define __NR_setsid (__NR_SYSCALL_BASE+ 66) ++#define __NR_sigaction (__NR_SYSCALL_BASE+ 67) ++ /* 68 was sys_sgetmask */ ++ /* 69 was sys_ssetmask */ ++#define __NR_setreuid (__NR_SYSCALL_BASE+ 70) ++#define __NR_setregid (__NR_SYSCALL_BASE+ 71) ++#define __NR_sigsuspend (__NR_SYSCALL_BASE+ 72) ++#define __NR_sigpending (__NR_SYSCALL_BASE+ 73) ++#define __NR_sethostname (__NR_SYSCALL_BASE+ 74) ++#define __NR_setrlimit (__NR_SYSCALL_BASE+ 75) ++#define __NR_getrlimit (__NR_SYSCALL_BASE+ 76) /* Back compat 2GB limited rlimit */ ++#define __NR_getrusage (__NR_SYSCALL_BASE+ 77) ++#define __NR_gettimeofday (__NR_SYSCALL_BASE+ 78) ++#define __NR_settimeofday (__NR_SYSCALL_BASE+ 79) ++#define __NR_getgroups (__NR_SYSCALL_BASE+ 80) ++#define __NR_setgroups (__NR_SYSCALL_BASE+ 81) ++#define __NR_select (__NR_SYSCALL_BASE+ 82) ++#define __NR_symlink (__NR_SYSCALL_BASE+ 83) ++ /* 84 was sys_lstat */ ++#define __NR_readlink (__NR_SYSCALL_BASE+ 85) ++#define __NR_uselib (__NR_SYSCALL_BASE+ 86) ++#define __NR_swapon (__NR_SYSCALL_BASE+ 87) ++#define __NR_reboot (__NR_SYSCALL_BASE+ 88) ++#define __NR_readdir (__NR_SYSCALL_BASE+ 89) ++#define __NR_mmap (__NR_SYSCALL_BASE+ 90) ++#define __NR_munmap (__NR_SYSCALL_BASE+ 91) ++#define __NR_truncate (__NR_SYSCALL_BASE+ 92) ++#define __NR_ftruncate (__NR_SYSCALL_BASE+ 93) ++#define __NR_fchmod (__NR_SYSCALL_BASE+ 94) ++#define __NR_fchown (__NR_SYSCALL_BASE+ 95) ++#define __NR_getpriority (__NR_SYSCALL_BASE+ 96) ++#define __NR_setpriority (__NR_SYSCALL_BASE+ 97) ++ /* 98 was sys_profil */ ++#define __NR_statfs (__NR_SYSCALL_BASE+ 99) ++#define __NR_fstatfs (__NR_SYSCALL_BASE+100) ++ /* 101 was sys_ioperm */ ++#define __NR_socketcall (__NR_SYSCALL_BASE+102) ++#define __NR_syslog (__NR_SYSCALL_BASE+103) ++#define __NR_setitimer (__NR_SYSCALL_BASE+104) ++#define __NR_getitimer (__NR_SYSCALL_BASE+105) ++#define __NR_stat (__NR_SYSCALL_BASE+106) ++#define __NR_lstat (__NR_SYSCALL_BASE+107) ++#define __NR_fstat (__NR_SYSCALL_BASE+108) ++ /* 109 was sys_uname */ ++ /* 110 was sys_iopl */ ++#define __NR_vhangup (__NR_SYSCALL_BASE+111) ++ /* 112 was sys_idle */ ++#define __NR_syscall (__NR_SYSCALL_BASE+113) /* syscall to call a syscall! */ ++#define __NR_wait4 (__NR_SYSCALL_BASE+114) ++#define __NR_swapoff (__NR_SYSCALL_BASE+115) ++#define __NR_sysinfo (__NR_SYSCALL_BASE+116) ++#define __NR_ipc (__NR_SYSCALL_BASE+117) ++#define __NR_fsync (__NR_SYSCALL_BASE+118) ++#define __NR_sigreturn (__NR_SYSCALL_BASE+119) ++#define __NR_clone (__NR_SYSCALL_BASE+120) ++#define __NR_setdomainname (__NR_SYSCALL_BASE+121) ++#define __NR_uname (__NR_SYSCALL_BASE+122) ++ /* 123 was sys_modify_ldt */ ++#define __NR_adjtimex (__NR_SYSCALL_BASE+124) ++#define __NR_mprotect (__NR_SYSCALL_BASE+125) ++#define __NR_sigprocmask (__NR_SYSCALL_BASE+126) ++ /* 127 was sys_create_module */ ++#define __NR_init_module (__NR_SYSCALL_BASE+128) ++#define __NR_delete_module (__NR_SYSCALL_BASE+129) ++ /* 130 was sys_get_kernel_syms */ ++#define __NR_quotactl (__NR_SYSCALL_BASE+131) ++#define __NR_getpgid (__NR_SYSCALL_BASE+132) ++#define __NR_fchdir (__NR_SYSCALL_BASE+133) ++#define __NR_bdflush (__NR_SYSCALL_BASE+134) ++#define __NR_sysfs (__NR_SYSCALL_BASE+135) ++#define __NR_personality (__NR_SYSCALL_BASE+136) ++ /* 137 was sys_afs_syscall */ ++#define __NR_setfsuid (__NR_SYSCALL_BASE+138) ++#define __NR_setfsgid (__NR_SYSCALL_BASE+139) ++#define __NR__llseek (__NR_SYSCALL_BASE+140) ++#define __NR_getdents (__NR_SYSCALL_BASE+141) ++#define __NR__newselect (__NR_SYSCALL_BASE+142) ++#define __NR_flock (__NR_SYSCALL_BASE+143) ++#define __NR_msync (__NR_SYSCALL_BASE+144) ++#define __NR_readv (__NR_SYSCALL_BASE+145) ++#define __NR_writev (__NR_SYSCALL_BASE+146) ++#define __NR_getsid (__NR_SYSCALL_BASE+147) ++#define __NR_fdatasync (__NR_SYSCALL_BASE+148) ++#define __NR__sysctl (__NR_SYSCALL_BASE+149) ++#define __NR_mlock (__NR_SYSCALL_BASE+150) ++#define __NR_munlock (__NR_SYSCALL_BASE+151) ++#define __NR_mlockall (__NR_SYSCALL_BASE+152) ++#define __NR_munlockall (__NR_SYSCALL_BASE+153) ++#define __NR_sched_setparam (__NR_SYSCALL_BASE+154) ++#define __NR_sched_getparam (__NR_SYSCALL_BASE+155) ++#define __NR_sched_setscheduler (__NR_SYSCALL_BASE+156) ++#define __NR_sched_getscheduler (__NR_SYSCALL_BASE+157) ++#define __NR_sched_yield (__NR_SYSCALL_BASE+158) ++#define __NR_sched_get_priority_max (__NR_SYSCALL_BASE+159) ++#define __NR_sched_get_priority_min (__NR_SYSCALL_BASE+160) ++#define __NR_sched_rr_get_interval (__NR_SYSCALL_BASE+161) ++#define __NR_nanosleep (__NR_SYSCALL_BASE+162) ++#define __NR_mremap (__NR_SYSCALL_BASE+163) ++#define __NR_setresuid (__NR_SYSCALL_BASE+164) ++#define __NR_getresuid (__NR_SYSCALL_BASE+165) ++#define __NR_getpagesize (__NR_SYSCALL_BASE+166) ++ /* 167 was sys_query_module */ ++#define __NR_poll (__NR_SYSCALL_BASE+168) ++#define __NR_nfsservctl (__NR_SYSCALL_BASE+169) ++#define __NR_setresgid (__NR_SYSCALL_BASE+170) ++#define __NR_getresgid (__NR_SYSCALL_BASE+171) ++#define __NR_prctl (__NR_SYSCALL_BASE+172) ++#define __NR_rt_sigreturn (__NR_SYSCALL_BASE+173) ++#define __NR_rt_sigaction (__NR_SYSCALL_BASE+174) ++#define __NR_rt_sigprocmask (__NR_SYSCALL_BASE+175) ++#define __NR_rt_sigpending (__NR_SYSCALL_BASE+176) ++#define __NR_rt_sigtimedwait (__NR_SYSCALL_BASE+177) ++#define __NR_rt_sigqueueinfo (__NR_SYSCALL_BASE+178) ++#define __NR_rt_sigsuspend (__NR_SYSCALL_BASE+179) ++#define __NR_pread64 (__NR_SYSCALL_BASE+180) ++#define __NR_pwrite64 (__NR_SYSCALL_BASE+181) ++#define __NR_chown (__NR_SYSCALL_BASE+182) ++#define __NR_getcwd (__NR_SYSCALL_BASE+183) ++#define __NR_capget (__NR_SYSCALL_BASE+184) ++#define __NR_capset (__NR_SYSCALL_BASE+185) ++#define __NR_sigaltstack (__NR_SYSCALL_BASE+186) ++#define __NR_sendfile (__NR_SYSCALL_BASE+187) ++ /* 188 reserved */ ++ /* 189 reserved */ ++#define __NR_vfork (__NR_SYSCALL_BASE+190) ++#define __NR_ugetrlimit (__NR_SYSCALL_BASE+191) /* SuS compliant getrlimit */ ++#define __NR_mmap2 (__NR_SYSCALL_BASE+192) ++#define __NR_truncate64 (__NR_SYSCALL_BASE+193) ++#define __NR_ftruncate64 (__NR_SYSCALL_BASE+194) ++#define __NR_stat64 (__NR_SYSCALL_BASE+195) ++#define __NR_lstat64 (__NR_SYSCALL_BASE+196) ++#define __NR_fstat64 (__NR_SYSCALL_BASE+197) ++#define __NR_lchown32 (__NR_SYSCALL_BASE+198) ++#define __NR_getuid32 (__NR_SYSCALL_BASE+199) ++#define __NR_getgid32 (__NR_SYSCALL_BASE+200) ++#define __NR_geteuid32 (__NR_SYSCALL_BASE+201) ++#define __NR_getegid32 (__NR_SYSCALL_BASE+202) ++#define __NR_setreuid32 (__NR_SYSCALL_BASE+203) ++#define __NR_setregid32 (__NR_SYSCALL_BASE+204) ++#define __NR_getgroups32 (__NR_SYSCALL_BASE+205) ++#define __NR_setgroups32 (__NR_SYSCALL_BASE+206) ++#define __NR_fchown32 (__NR_SYSCALL_BASE+207) ++#define __NR_setresuid32 (__NR_SYSCALL_BASE+208) ++#define __NR_getresuid32 (__NR_SYSCALL_BASE+209) ++#define __NR_setresgid32 (__NR_SYSCALL_BASE+210) ++#define __NR_getresgid32 (__NR_SYSCALL_BASE+211) ++#define __NR_chown32 (__NR_SYSCALL_BASE+212) ++#define __NR_setuid32 (__NR_SYSCALL_BASE+213) ++#define __NR_setgid32 (__NR_SYSCALL_BASE+214) ++#define __NR_setfsuid32 (__NR_SYSCALL_BASE+215) ++#define __NR_setfsgid32 (__NR_SYSCALL_BASE+216) ++#define __NR_getdents64 (__NR_SYSCALL_BASE+217) ++#define __NR_pivot_root (__NR_SYSCALL_BASE+218) ++#define __NR_mincore (__NR_SYSCALL_BASE+219) ++#define __NR_madvise (__NR_SYSCALL_BASE+220) ++#define __NR_fcntl64 (__NR_SYSCALL_BASE+221) ++ /* 222 for tux */ ++ /* 223 is unused */ ++#define __NR_gettid (__NR_SYSCALL_BASE+224) ++#define __NR_readahead (__NR_SYSCALL_BASE+225) ++#define __NR_setxattr (__NR_SYSCALL_BASE+226) ++#define __NR_lsetxattr (__NR_SYSCALL_BASE+227) ++#define __NR_fsetxattr (__NR_SYSCALL_BASE+228) ++#define __NR_getxattr (__NR_SYSCALL_BASE+229) ++#define __NR_lgetxattr (__NR_SYSCALL_BASE+230) ++#define __NR_fgetxattr (__NR_SYSCALL_BASE+231) ++#define __NR_listxattr (__NR_SYSCALL_BASE+232) ++#define __NR_llistxattr (__NR_SYSCALL_BASE+233) ++#define __NR_flistxattr (__NR_SYSCALL_BASE+234) ++#define __NR_removexattr (__NR_SYSCALL_BASE+235) ++#define __NR_lremovexattr (__NR_SYSCALL_BASE+236) ++#define __NR_fremovexattr (__NR_SYSCALL_BASE+237) ++#define __NR_tkill (__NR_SYSCALL_BASE+238) ++#define __NR_sendfile64 (__NR_SYSCALL_BASE+239) ++#define __NR_futex (__NR_SYSCALL_BASE+240) ++#define __NR_sched_setaffinity (__NR_SYSCALL_BASE+241) ++#define __NR_sched_getaffinity (__NR_SYSCALL_BASE+242) ++#define __NR_io_setup (__NR_SYSCALL_BASE+243) ++#define __NR_io_destroy (__NR_SYSCALL_BASE+244) ++#define __NR_io_getevents (__NR_SYSCALL_BASE+245) ++#define __NR_io_submit (__NR_SYSCALL_BASE+246) ++#define __NR_io_cancel (__NR_SYSCALL_BASE+247) ++#define __NR_exit_group (__NR_SYSCALL_BASE+248) ++#define __NR_lookup_dcookie (__NR_SYSCALL_BASE+249) ++#define __NR_epoll_create (__NR_SYSCALL_BASE+250) ++#define __NR_epoll_ctl (__NR_SYSCALL_BASE+251) ++#define __NR_epoll_wait (__NR_SYSCALL_BASE+252) ++#define __NR_remap_file_pages (__NR_SYSCALL_BASE+253) ++ /* 254 for set_thread_area */ ++ /* 255 for get_thread_area */ ++#define __NR_set_tid_address (__NR_SYSCALL_BASE+256) ++#define __NR_timer_create (__NR_SYSCALL_BASE+257) ++#define __NR_timer_settime (__NR_SYSCALL_BASE+258) ++#define __NR_timer_gettime (__NR_SYSCALL_BASE+259) ++#define __NR_timer_getoverrun (__NR_SYSCALL_BASE+260) ++#define __NR_timer_delete (__NR_SYSCALL_BASE+261) ++#define __NR_clock_settime (__NR_SYSCALL_BASE+262) ++#define __NR_clock_gettime (__NR_SYSCALL_BASE+263) ++#define __NR_clock_getres (__NR_SYSCALL_BASE+264) ++#define __NR_clock_nanosleep (__NR_SYSCALL_BASE+265) ++#define __NR_statfs64 (__NR_SYSCALL_BASE+266) ++#define __NR_fstatfs64 (__NR_SYSCALL_BASE+267) ++#define __NR_tgkill (__NR_SYSCALL_BASE+268) ++#define __NR_utimes (__NR_SYSCALL_BASE+269) ++#define __NR_fadvise64_64 (__NR_SYSCALL_BASE+270) ++#define __NR_pciconfig_iobase (__NR_SYSCALL_BASE+271) ++#define __NR_pciconfig_read (__NR_SYSCALL_BASE+272) ++#define __NR_pciconfig_write (__NR_SYSCALL_BASE+273) ++#define __NR_mq_open (__NR_SYSCALL_BASE+274) ++#define __NR_mq_unlink (__NR_SYSCALL_BASE+275) ++#define __NR_mq_timedsend (__NR_SYSCALL_BASE+276) ++#define __NR_mq_timedreceive (__NR_SYSCALL_BASE+277) ++#define __NR_mq_notify (__NR_SYSCALL_BASE+278) ++#define __NR_mq_getsetattr (__NR_SYSCALL_BASE+279) ++#define __NR_waitid (__NR_SYSCALL_BASE+280) ++#define __NR_add_key (__NR_SYSCALL_BASE+281) ++#define __NR_request_key (__NR_SYSCALL_BASE+282) ++#define __NR_keyctl (__NR_SYSCALL_BASE+283) ++#define __NR_ioprio_set (__NR_SYSCALL_BASE+284) ++#define __NR_ioprio_get (__NR_SYSCALL_BASE+285) ++#define __NR_inotify_init (__NR_SYSCALL_BASE+286) ++#define __NR_inotify_add_watch (__NR_SYSCALL_BASE+287) ++#define __NR_inotify_rm_watch (__NR_SYSCALL_BASE+288) ++#define __NR_migrate_pages (__NR_SYSCALL_BASE+289) ++#define __NR_openat (__NR_SYSCALL_BASE+290) ++#define __NR_mkdirat (__NR_SYSCALL_BASE+291) ++#define __NR_mknodat (__NR_SYSCALL_BASE+292) ++#define __NR_fchownat (__NR_SYSCALL_BASE+293) ++#define __NR_futimesat (__NR_SYSCALL_BASE+294) ++#define __NR_fstatat64 (__NR_SYSCALL_BASE+295) ++#define __NR_unlinkat (__NR_SYSCALL_BASE+296) ++#define __NR_renameat (__NR_SYSCALL_BASE+297) ++#define __NR_linkat (__NR_SYSCALL_BASE+298) ++#define __NR_symlinkat (__NR_SYSCALL_BASE+299) ++#define __NR_readlinkat (__NR_SYSCALL_BASE+300) ++#define __NR_fchmodat (__NR_SYSCALL_BASE+301) ++#define __NR_faccessat (__NR_SYSCALL_BASE+302) ++#define __NR_pselect6 (__NR_SYSCALL_BASE+303) ++#define __NR_ppoll (__NR_SYSCALL_BASE+304) ++#define __NR_unshare (__NR_SYSCALL_BASE+305) ++#define __NR_set_robust_list (__NR_SYSCALL_BASE+306) ++#define __NR_get_robust_list (__NR_SYSCALL_BASE+307) ++#define __NR_splice (__NR_SYSCALL_BASE+308) ++#define __NR_sync_file_range2 (__NR_SYSCALL_BASE+309) ++#define __NR_tee (__NR_SYSCALL_BASE+310) ++#define __NR_vmsplice (__NR_SYSCALL_BASE+311) ++#define __NR_move_pages (__NR_SYSCALL_BASE+312) ++#define __NR_fadvise64 (__NR_SYSCALL_BASE+313) ++#define __NR_utimensat (__NR_SYSCALL_BASE+314) ++#define __NR_signalfd (__NR_SYSCALL_BASE+315) ++#define __NR_timerfd_create (__NR_SYSCALL_BASE+316) ++#define __NR_eventfd (__NR_SYSCALL_BASE+317) ++#define __NR_fallocate (__NR_SYSCALL_BASE+318) ++#define __NR_timerfd_settime (__NR_SYSCALL_BASE+319) ++#define __NR_timerfd_gettime (__NR_SYSCALL_BASE+320) ++#define __NR_getcpu (__NR_SYSCALL_BASE+321) ++#define __NR_signalfd4 (__NR_SYSCALL_BASE+322) ++#define __NR_eventfd2 (__NR_SYSCALL_BASE+323) ++#define __NR_epoll_create1 (__NR_SYSCALL_BASE+324) ++#define __NR_dup3 (__NR_SYSCALL_BASE+325) ++#define __NR_pipe2 (__NR_SYSCALL_BASE+326) ++#define __NR_inotify_init1 (__NR_SYSCALL_BASE+327) ++#define __NR_kexec_load (__NR_SYSCALL_BASE+328) ++#define __NR_accept (__NR_SYSCALL_BASE+329) ++#define __NR_bind (__NR_SYSCALL_BASE+330) ++#define __NR_connect (__NR_SYSCALL_BASE+331) ++#define __NR_getpeername (__NR_SYSCALL_BASE+332) ++#define __NR_getsockname (__NR_SYSCALL_BASE+333) ++#define __NR_getsockopt (__NR_SYSCALL_BASE+334) ++#define __NR_listen (__NR_SYSCALL_BASE+335) ++#define __NR_recv (__NR_SYSCALL_BASE+336) ++#define __NR_recvfrom (__NR_SYSCALL_BASE+337) ++#define __NR_recvmsg (__NR_SYSCALL_BASE+338) ++#define __NR_send (__NR_SYSCALL_BASE+339) ++#define __NR_sendmsg (__NR_SYSCALL_BASE+340) ++#define __NR_sendto (__NR_SYSCALL_BASE+341) ++#define __NR_setsockopt (__NR_SYSCALL_BASE+342) ++#define __NR_shutdown (__NR_SYSCALL_BASE+343) ++#define __NR_socket (__NR_SYSCALL_BASE+344) ++#define __NR_socketpair (__NR_SYSCALL_BASE+345) ++#define __NR_prlimit64 (__NR_SYSCALL_BASE+346) ++#define __NR_accept4 (__NR_SYSCALL_BASE+347) ++#define __NR_recvmmsg (__NR_SYSCALL_BASE+348) ++#define __NR_sendmmsg (__NR_SYSCALL_BASE+349) ++#define __NR_fanotify_init (__NR_SYSCALL_BASE+350) ++#define __NR_fanotify_mark (__NR_SYSCALL_BASE+351) ++#define __NR_msgget (__NR_SYSCALL_BASE+352) ++#define __NR_msgctl (__NR_SYSCALL_BASE+353) ++#define __NR_msgrcv (__NR_SYSCALL_BASE+354) ++#define __NR_msgsnd (__NR_SYSCALL_BASE+355) ++#define __NR_semget (__NR_SYSCALL_BASE+356) ++#define __NR_semctl (__NR_SYSCALL_BASE+357) ++#define __NR_semtimedop (__NR_SYSCALL_BASE+358) ++#define __NR_semop (__NR_SYSCALL_BASE+359) ++#define __NR_shmget (__NR_SYSCALL_BASE+360) ++#define __NR_shmctl (__NR_SYSCALL_BASE+361) ++#define __NR_shmat (__NR_SYSCALL_BASE+362) ++#define __NR_shmdt (__NR_SYSCALL_BASE+363) ++#define __NR_syncfs (__NR_SYSCALL_BASE+364) ++#define __NR_setns (__NR_SYSCALL_BASE+365) ++#define __NR_name_to_handle_at (__NR_SYSCALL_BASE+366) ++#define __NR_open_by_handle_at (__NR_SYSCALL_BASE+367) ++#define __NR_process_vm_readv (__NR_SYSCALL_BASE+368) ++#define __NR_process_vm_writev (__NR_SYSCALL_BASE+369) ++#define __NR_clock_adjtime (__NR_SYSCALL_BASE+370) ++#define __NR_get_mempolicy (__NR_SYSCALL_BASE+371) ++#define __NR_mbind (__NR_SYSCALL_BASE+372) ++#define __NR_perf_event_open (__NR_SYSCALL_BASE+373) ++#define __NR_preadv (__NR_SYSCALL_BASE+374) ++#define __NR_pwritev (__NR_SYSCALL_BASE+375) ++#define __NR_rt_tgsigqueueinfo (__NR_SYSCALL_BASE+376) ++#define __NR_set_mempolicy (__NR_SYSCALL_BASE+377) ++#define __NR_epoll_pwait (__NR_SYSCALL_BASE+378) ++ ++ ++ ++ ++#define __NR_lmmap (__NR_NDS32_BASE+ 1) ++#define __NR_lmunmap (__NR_NDS32_BASE+ 2) ++#define __NR_lmdma (__NR_NDS32_BASE+ 3) ++#define __NR_pfmctl (__NR_NDS32_BASE+ 4) ++#define __NR_getpfm (__NR_NDS32_BASE+ 5) ++#define __NR_setpfm (__NR_NDS32_BASE+ 6) ++#define __NR_wbna (__NR_NDS32_BASE+ 7) ++ ++ ++ ++#ifdef __KERNEL__ ++ ++#define __ARCH_WANT_IPC_PARSE_VERSION ++#define __ARCH_WANT_OLD_READDIR ++#define __ARCH_WANT_STAT64 ++#define __ARCH_WANT_SYS_ALARM ++#define __ARCH_WANT_SYS_GETHOSTNAME ++#define __ARCH_WANT_SYS_PAUSE ++#define __ARCH_WANT_SYS_TIME ++#define __ARCH_WANT_SYS_UTIME ++#define __ARCH_WANT_SYS_SOCKETCALL ++#define __ARCH_WANT_SYS_FADVISE64 ++#define __ARCH_WANT_SYS_GETPGRP ++#define __ARCH_WANT_SYS_LLSEEK ++#define __ARCH_WANT_SYS_NICE ++#define __ARCH_WANT_SYS_OLD_GETRLIMIT ++#define __ARCH_WANT_SYS_OLD_MMAP ++#define __ARCH_WANT_SYS_OLDUMOUNT ++#define __ARCH_WANT_SYS_SIGPENDING ++#define __ARCH_WANT_SYS_SIGPROCMASK ++#define __ARCH_WANT_SYS_RT_SIGACTION ++ ++/* ++ * "Conditional" syscalls ++ * ++ * What we want is __attribute__((weak,alias("sys_ni_syscall"))), ++ * but it doesn't work on all toolchains, so we just do it by hand ++ */ ++#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); ++ ++#endif ++#endif /* __ASM_NDS32_UNISTD_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/user.h linux-3.4.110/arch/nds32/include/asm/user.h +--- linux-3.4.110.orig/arch/nds32/include/asm/user.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/user.h 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,89 @@ ++/* ++ * linux/arch/nds32/include/asm/user.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef _NDS32_USER_H ++#define _NDS32_USER_H ++ ++#include <asm/page.h> ++#include <asm/ptrace.h> ++/* Core file format: The core file is written in such a way that gdb ++ can understand it and provide useful information to the user (under ++ linux we use the 'trad-core' bfd). There are quite a number of ++ obstacles to being able to view the contents of the floating point ++ registers, and until these are solved you will not be able to view the ++ contents of them. Actually, you can read in the core file and look at ++ the contents of the user struct to find out what the floating point ++ registers contain. ++ The actual file contents are as follows: ++ UPAGE: 1 page consisting of a user struct that tells gdb what is present ++ in the file. Directly after this is a copy of the task_struct, which ++ is currently not used by gdb, but it may come in useful at some point. ++ All of the registers are stored as part of the upage. The upage should ++ always be only one page. ++ DATA: The data area is stored. We use current->end_text to ++ current->brk to pick up all of the user variables, plus any memory ++ that may have been malloced. No attempt is made to determine if a page ++ is demand-zero or if a page is totally unused, we just cover the entire ++ range. All of the addresses are rounded in such a way that an integral ++ number of pages is written. ++ STACK: We need the stack information in order to get a meaningful ++ backtrace. We need to write the data from (esp) to ++ current->start_stack, so we round each of these off in order to be able ++ to write an integer number of pages. ++ The minimum core file size is 3 pages, or 12288 bytes. ++*/ ++ ++struct user_fp { ++ struct fp_reg { ++ unsigned int sign1:1; ++ unsigned int unused:15; ++ unsigned int sign2:1; ++ unsigned int exponent:14; ++ unsigned int j:1; ++ unsigned int mantissa1:31; ++ unsigned int mantissa0:32; ++ } fpregs[8]; ++ unsigned int fpsr:32; ++ unsigned int fpcr:32; ++ unsigned char ftype[8]; ++ unsigned int init_flag; ++}; ++ ++/* When the kernel dumps core, it starts by dumping the user struct - ++ this will be used by gdb to figure out where the data and stack segments ++ are within the file, and what virtual addresses to use. */ ++struct user{ ++/* We start with the registers, to mimic the way that "memory" is returned ++ from the ptrace(3,...) function. */ ++ struct pt_regs regs; /* Where the registers are actually stored */ ++/* ptrace does not yet supply these. Someday.... */ ++ int u_fpvalid; /* True if math co-processor being used. */ ++ /* for this mess. Not yet used. */ ++/* The rest of this junk is to help gdb figure out what goes where */ ++ unsigned long int u_tsize; /* Text segment size (pages). */ ++ unsigned long int u_dsize; /* Data segment size (pages). */ ++ unsigned long int u_ssize; /* Stack segment size (pages). */ ++ unsigned long start_code; /* Starting virtual address of text. */ ++ unsigned long start_stack; /* Starting virtual address of stack area. ++ This is actually the bottom of the stack, ++ the top of the stack is always found in the ++ esp register. */ ++ long int signal; /* Signal that caused the core dump. */ ++ int reserved; /* No longer used */ ++ struct pt_regs * u_ar0; /* Used by gdb to help find the values for */ ++ /* the registers. */ ++ unsigned long magic; /* To uniquely identify a core file */ ++ char u_comm[32]; /* User command that was responsible */ ++ int u_debugreg[8]; ++ struct user_fp u_fp; /* FP state */ ++ struct user_fp_struct * u_fp0;/* Used by gdb to help find the values for */ ++ /* the FP registers. */ ++}; ++#define NBPG PAGE_SIZE ++#define UPAGES 1 ++#define HOST_TEXT_START_ADDR (u.start_code) ++#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) ++ ++#endif /* _NDS32_USER_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/vga.h linux-3.4.110/arch/nds32/include/asm/vga.h +--- linux-3.4.110.orig/arch/nds32/include/asm/vga.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/vga.h 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,17 @@ ++/* ++ * linux/arch/nds32/include/asm/vga.h ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#ifndef ASMNDS32_VGA_H ++#define ASMNDS32_VGA_H ++ ++#include <asm/hardware.h> ++#include <asm/io.h> ++ ++#define VGA_MAP_MEM(x) (PCIMEM_BASE + (x)) ++ ++#define vga_readb(x) (*((volatile unsigned char *)x)) ++#define vga_writeb(x,y) (*((volatile unsigned char *)y) = (x)) ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/vmalloc.h linux-3.4.110/arch/nds32/include/asm/vmalloc.h +--- linux-3.4.110.orig/arch/nds32/include/asm/vmalloc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/vmalloc.h 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,31 @@ ++/* ++ * linux/arch/nds32/include/asm/vmalloc.h ++ * ++ * Faraday Platform Independent Virtual Memory Configuration ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ChangeLog ++ * ++ * Luke Lee 09/16/2005 Copy from Faraday CPE codes. ++ */ ++ ++#ifndef __FARADAY_PLATFORM_INDEPENDENT_VMALLOC_HEADER__ ++#define __FARADAY_PLATFORM_INDEPENDENT_VMALLOC_HEADER__ ++ ++#endif /* __FARADAY_PLATFORM_INDEPENDENT_VMALLOC_HEADER__ */ +diff -Nur linux-3.4.110.orig/arch/nds32/include/asm/xor.h linux-3.4.110/arch/nds32/include/asm/xor.h +--- linux-3.4.110.orig/arch/nds32/include/asm/xor.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/include/asm/xor.h 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,157 @@ ++/* ++ * linux/arch/nds32/include/asm/xor.h ++ * ++ * Copyright (C) 2001 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <asm-generic/xor.h> ++ ++#define __XOR(a1, a2) a1 ^= a2 ++ ++ ++#define GET_BLOCK_2(dst) \ ++ __asm__( \ ++ " lmw.bim %1, [%0], %2 \n"\ ++ : "=r" (dst), "=r" (a1), "=r" (a2) \ ++ : "0" (dst)) ++ ++#define GET_BLOCK_4(dst) \ ++ __asm__( \ ++ " lmw.bim %1, [%0], %1 \n" \ //ldmia %0, {%1, %2, %3, %4} ++ " lmw.bim %2, [%0], %2 \n" \ ++ " lmw.bim %3, [%0], %3 \n" \ ++ " lmw.bim %4, [%0], %4 \n" \ ++ : "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \ ++ : "0" (dst)) ++ ++#define XOR_BLOCK_2(src) \ ++ __asm__(\ ++ " lmw.bim %1, [%0], %2 \n " \ ++ " lmw.bim %2, [%0], %2 \n" \ ++ : "=r" (src), "=r" (b1), "=r" (b2) \ ++ : "0" (src)); \ ++ __XOR(a1, b1); __XOR(a2, b2); ++ ++ ++#define XOR_BLOCK_4(src) \ ++ __asm__(\ ++ "lmw.bim %1, [%0], %1 \n " \ // ldmia %0!, {%1, %2, %3, %4} ++ "lmw.bim %2, [%0], %2 \n " \ ++ "lmw.bim %3, [%0], %3 \n " \ ++ "lmw.bim %4, [%0], %4 \n " \ ++ : "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \ ++ : "0" (src)); \ ++ __XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4) ++ ++#define PUT_BLOCK_2(dst) \ ++ __asm__ __volatile__( \ ++ " smw.bim %2, [%0], %3" \ ++ : "=r" (dst) \ ++ : "0" (dst), "r" (a1), "r" (a2)) ++ ++#define PUT_BLOCK_4(dst) \ ++ __asm__ __volatile__( \ ++ " smw.bim %2, [%0], %5 \n" \ ++ : "=r" (dst) \ ++ : "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4)) ++ ++static void ++xor_nds32regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) ++{ ++ unsigned int lines = bytes / sizeof(unsigned long) / 4; ++ register unsigned int a1 __asm__("r4"); ++ register unsigned int a2 __asm__("r5"); ++ register unsigned int a3 __asm__("r6"); ++ register unsigned int a4 __asm__("r7"); ++ register unsigned int b1 __asm__("r8"); ++ register unsigned int b2 __asm__("r9"); ++ register unsigned int b3 __asm__("p0"); ++ register unsigned int b4 __asm__("ra"); ++ ++ do { ++ GET_BLOCK_4(p1); ++ XOR_BLOCK_4(p2); ++ PUT_BLOCK_4(p1); ++ } while (--lines); ++} ++ ++static void ++xor_nds32regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3) ++{ ++ unsigned int lines = bytes / sizeof(unsigned long) / 4; ++ register unsigned int a1 __asm__("r4"); ++ register unsigned int a2 __asm__("r5"); ++ register unsigned int a3 __asm__("r6"); ++ register unsigned int a4 __asm__("r7"); ++ register unsigned int b1 __asm__("r8"); ++ register unsigned int b2 __asm__("r9"); ++ register unsigned int b3 __asm__("p0"); ++ register unsigned int b4 __asm__("ra"); ++ ++ do { ++ GET_BLOCK_4(p1); ++ XOR_BLOCK_4(p2); ++ XOR_BLOCK_4(p3); ++ PUT_BLOCK_4(p1); ++ } while (--lines); ++} ++ ++static void ++xor_nds32regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4) ++{ ++ unsigned int lines = bytes / sizeof(unsigned long) / 2; ++ register unsigned int a1 __asm__("r8"); ++ register unsigned int a2 __asm__("r9"); ++ register unsigned int b1 __asm__("p0"); ++ register unsigned int b2 __asm__("ra"); ++ ++ do { ++ GET_BLOCK_2(p1); ++ XOR_BLOCK_2(p2); ++ XOR_BLOCK_2(p3); ++ XOR_BLOCK_2(p4); ++ PUT_BLOCK_2(p1); ++ } while (--lines); ++} ++ ++static void ++xor_nds32regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, ++ unsigned long *p3, unsigned long *p4, unsigned long *p5) ++{ ++ unsigned int lines = bytes / sizeof(unsigned long) / 2; ++ register unsigned int a1 __asm__("r8"); ++ register unsigned int a2 __asm__("r9"); ++ register unsigned int b1 __asm__("p0"); ++ register unsigned int b2 __asm__("ra"); ++ ++ do { ++ GET_BLOCK_2(p1); ++ XOR_BLOCK_2(p2); ++ XOR_BLOCK_2(p3); ++ XOR_BLOCK_2(p4); ++ XOR_BLOCK_2(p5); ++ PUT_BLOCK_2(p1); ++ } while (--lines); ++} ++ ++static struct xor_block_template xor_block_nds32regs = { ++ .name = "nds32regs", ++ .do_2 = xor_nds32regs_2, ++ .do_3 = xor_nds32regs_3, ++ .do_4 = xor_nds32regs_4, ++ .do_5 = xor_nds32regs_5, ++}; ++ ++#undef XOR_TRY_TEMPLATES ++#define XOR_TRY_TEMPLATES \ ++ do { \ ++ xor_speed(&xor_block_nds32regs); \ ++ xor_speed(&xor_block_8regs); \ ++ xor_speed(&xor_block_32regs); \ ++ } while (0) +diff -Nur linux-3.4.110.orig/arch/nds32/Kconfig linux-3.4.110/arch/nds32/Kconfig +--- linux-3.4.110.orig/arch/nds32/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/Kconfig 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,249 @@ ++# ++# For a description of the syntax of this configuration file, ++# see Documentation/kbuild/kconfig-language.txt. ++# ++ ++config NDS32 ++ bool ++ default y ++ select RTC_LIB ++ select HAVE_OPROFILE ++ select HAVE_ARCH_KGDB ++ select HAVE_KPROBES ++ select HAVE_KRETPROBES ++ select HAVE_FUNCTION_TRACER ++ select HAVE_FUNCTION_GRAPH_TRACER ++ select HAVE_FUNCTION_TRACE_MCOUNT_TEST ++ select SYS_SUPPORTS_APM_EMULATION ++ select HAVE_IDE ++ select HAVE_MEMBLOCK ++ select HAVE_MEMBLOCK_NODE_MAP ++ ++config GENERIC_GPIO ++ bool ++ default n ++ ++config GENERIC_TIME ++ bool ++ default y ++ ++config GENERIC_CLOCKEVENTS ++ bool ++ default y ++ ++config NO_IOPORT ++ bool ++ default y ++ ++config GENERIC_IOMAP ++ def_bool y ++ ++config GENERIC_LOCKBREAK ++ bool ++ default y ++ depends on SMP && PREEMPT ++ ++config RWSEM_GENERIC_SPINLOCK ++ bool ++ default y ++ ++config RWSEM_XCHGADD_ALGORITHM ++ bool ++ ++config GENERIC_HWEIGHT ++ bool ++ default y ++ ++config GENERIC_FIND_NEXT_BIT ++ bool ++ default y ++ ++config GENERIC_CALIBRATE_DELAY ++ bool ++ default y ++ ++config GENERIC_BUST_SPINLOCK ++ bool ++ ++config GENERIC_HARDIRQS ++ bool ++ default y ++ ++config GENERIC_HARDIRQS_NO__DO_IRQ ++ def_bool y ++ ++config LOCKDEP_SUPPORT ++ bool ++ default y ++ ++config STACKTRACE_SUPPORT ++ bool ++ default y ++ ++config HAVE_LATENCYTOP_SUPPORT ++ def_bool y ++ ++source "init/Kconfig" ++source "kernel/Kconfig.freezer" ++ ++menu "System Type" ++source "arch/nds32/platforms/Kconfig" ++source "arch/nds32/Kconfig.cpu" ++ ++config VECTORS_BASE ++ hex ++ default 0xfeff0000 if MMU || CPU_HIGH_VECTOR ++ default DRAM_BASE if REMAP_VECTORS_TO_RAM ++ default 0x00000000 ++ help ++ The base address of exception vectors. ++ ++config MMU ++ bool ++ default y ++ ++endmenu ++ ++menu "Kernel Features" ++source "kernel/time/Kconfig" ++ ++config SMP ++ bool "Symmetric Multi-Processing" ++ depends on PLATFORM_AMIC ++ select USE_GENERIC_SMP_HELPERS ++ help ++ This enables support for systems with more than one CPU. If you have ++ a system with only one CPU, like most personal computers, say N. If ++ you have a system with more than one CPU, say Y. ++ ++ If you say N here, the kernel will run on single and multiprocessor ++ machines, but will use only one CPU of a multiprocessor machine. If ++ you say Y here, the kernel will run on many, but not all, single ++ processor machines. On a single processor machine, the kernel will ++ run faster if you say N here. ++ ++ See also the <file:Documentation/smp.tex>, ++ <file:Documentation/smp.txt>, <file:Documentation/i386/IO-APIC.txt>, ++ <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at ++ <http://www.linuxdoc.org/docs.html#howto>. ++ ++ If you don't know what to do here, say N. ++ ++config NR_CPUS ++ int "Maximum number of CPUs (2-32)" ++ depends on SMP ++ default "4" ++ ++source "kernel/Kconfig.preempt" ++source "mm/Kconfig" ++ ++config FORCE_MAX_ZONEORDER ++ int "MAX_ORDER for the Page Allocator" ++ default "11" ++ ++source "kernel/Kconfig.hz" ++ ++config CMDLINE ++ string "Default kernel command string" ++ default "mem=64M@0x0 initrd=0x800000,8M root=/dev/ram0 rw console=ttyS0,38400n8 rootfstype=ext2 init=/sbin/init -s" ++ ++endmenu ++ ++menu "Power management options" ++ ++config SYS_SUPPORTS_APM_EMULATION ++ bool ++ ++config ARCH_SUSPEND_POSSIBLE ++ def_bool y ++ ++source "kernel/power/Kconfig" ++ ++if PLAT_AG101 || PLAT_AG102 ++source "drivers/cpufreq/Kconfig" ++ ++if PLAT_AG101 ++choice ++ prompt "Default CPUFreq Implementation" ++ depends on CPU_FREQ ++ default AG101_CPU_FREQ_SCALING_MODE ++ help ++ This option sets which CPUFreq governor shall be loaded at ++ startup. If in doubt, select 'performance'. ++config AG101_CPU_FREQ_SCALING_MODE ++ bool "AG101 Frequency Scaling Mode" ++ help ++ Rescale CPU frequency and Bus clock without changing PLL. ++ ++config AG101_CPU_FREQ_FCS ++ bool "AG101 Frequency Change Sequence (FCS)" ++ help ++ The Frequency Change Sequence (FCS) is used to change the system ++ clock frequency. While in the FCS, the system clocks stop. This ++ mode is intended for setting a different frequency to overwrite ++ the default value at initial boot-up. This can be used as a powr- ++ saving feature that allows the AG101 to run at the minimum required ++ frequency ++endchoice ++endif ++ ++if PLAT_AG102 ++choice ++ prompt "Default CPUFreq Implementation" ++ depends on CPU_FREQ ++ default AG102_CPU_FREQ_SCALING_MODE ++ help ++ This option sets which CPUFreq governor shall be loaded at ++ startup. If in doubt, select 'performance'. ++config AG102_CPU_FREQ_SCALING_MODE ++ bool "AG102 Frequency Scaling Mode" ++ help ++ Rescale CPU frequency and Bus clock without changing PLL. ++ ++config AG102_CPU_FREQ_FCS ++ bool "AG102 Frequency Change Sequence (FCS)" ++ help ++ The Frequency Change Sequence (FCS) is used to change the system ++ clock frequency. While in the FCS, the system clocks stop. This ++ mode is intended for setting a different frequency to overwrite ++ the default value at initial boot-up. This can be used as a powr- ++ saving feature that allows the AG101 to run at the minimum required ++ frequency ++endchoice ++endif ++ ++ ++endif ++ ++endmenu ++ ++menu "Bus options" ++ ++config PCI ++ bool "PCI support" ++ help ++ Find out whether you have a PCI motherboard. PCI is the name of a ++ bus system, i.e. the way the CPU talks to the other stuff inside ++ your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or ++ VESA. If you have PCI, say Y, otherwise N. ++ ++ The PCI-HOWTO, available from ++ <http://www.tldp.org/docs.html#howto>, contains valuable ++ information about which PCI hardware does work under Linux and which ++ doesn't. ++ ++source "drivers/pci/Kconfig" ++ ++endmenu ++ ++menu "Executable file formats" ++source "fs/Kconfig.binfmt" ++endmenu ++ ++source "net/Kconfig" ++source "drivers/Kconfig" ++source "fs/Kconfig" ++source "arch/nds32/Kconfig.debug" ++source "security/Kconfig" ++source "crypto/Kconfig" ++source "lib/Kconfig" +diff -Nur linux-3.4.110.orig/arch/nds32/Kconfig.cpu linux-3.4.110/arch/nds32/Kconfig.cpu +--- linux-3.4.110.orig/arch/nds32/Kconfig.cpu 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/Kconfig.cpu 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,148 @@ ++comment "Processor Features" ++config CPU_N1213 ++ bool ++ ++config CPU_N1213_43U1HA0 ++ bool ++ ++config CPU_N1233F ++ bool ++ ++config CPU_CUSTOM ++ bool ++ ++config FPU ++ bool "fpu support" ++ ++config UNLAZY_FPU ++ bool "Unlazy FPU support" ++ depends on FPU ++ help ++ Say Y here to enable unlazy FPU and disable lazy FPU. ++ ++ ++config AUDIO ++ bool "audio support" if CPU_CUSTOM ++ ++config HWZOL ++ bool "hardware zero overhead loop support" ++ default y ++ ++config UNLAZY_AUDIO ++ bool "Unlazy audio support" ++ depends on AUDIO ++ help ++ Say Y here to enable unlazy audio and disable lazy audio. ++choice ++ prompt "Vector Interrupt Controller mode" ++ default IVIC_INTC ++config IVIC_INTC ++ bool "IVIC mode with Interrupt Controller" ++config IVIC ++ bool "IVIC mode" ++config EVIC ++ bool "EVIC mode" ++endchoice ++ ++config CPU_NO_CONTEXT_ID ++ def_bool CPU_N1213_43U1HA0 || SMP ++ ++config CPU_CACHE_NONALIASING ++ bool "Non-aliasing cache" ++ ++choice ++ prompt "Paging -- page size " ++ default ANDES_PAGE_SIZE_4KB ++config ANDES_PAGE_SIZE_4KB ++ bool "use 4KB page size" ++config ANDES_PAGE_SIZE_8KB ++ bool "use 8KB page size" ++endchoice ++ ++config NO_KERNEL_LARGE_PAGE ++ def_bool CPU_N1213_43U1HA0 || SMP ++ ++config CPU_ICACHE_DISABLE ++ bool "Disable I-Cache" ++ help ++ Say Y here to disable the processor instruction cache. Unless ++ you have a reason not to or are unsure, say N. ++ ++config CPU_DCACHE_DISABLE ++ bool "Disable D-Cache" ++ help ++ Say Y here to disable the processor data cache. Unless ++ you have a reason not to or are unsure, say N. ++ ++config CPU_DCACHE_WRITETHROUGH ++ bool "Force write through D-cache" ++ depends on !CPU_DCACHE_DISABLE ++ help ++ Say Y here to use the data cache in writethrough mode. Unless you ++ specifically require this or are unsure, say N. ++ ++config KEXEC ++ bool "Kexec system call (EXPERIMENTAL)" ++ depends on EXPERIMENTAL ++ help ++ kexec is a system call that implements the ability to shutdown your ++ current kernel, and to start another kernel. It is like a reboot ++ but it is independent of the system firmware. And like a reboot ++ you can start any kernel with it, not just Linux. ++ ++ It is an ongoing process to be certain the hardware in a machine ++ is properly shutdown, so do not be surprised if this code does not ++ initially work for you. It may help to enable device hotplugging ++ support. ++ ++config ABI1 ++ bool "Allow ABI 1 binaries to run with this kernel (EXPERIMENTAL)" ++ depends on EXPERIMENTAL ++ default n ++ help ++ This option preserves the old syscall interface of ABI 1. If ++ you know you'll be using ABI 2 or 2fp then you can say N here. ++ If this option is not selected and you attempt to execute a ++ legacy ABI binary then the result will be UNPREDICTABLE ++ (in fact it can be predicted that it won't work at all). If ++ in doubt say Y. ++ ++config WBNA ++ bool "WBNA" ++ default n ++ help ++ Say Y here to enable write-back memory with no-write-allocation policy. ++ ++config HSS ++ bool "Using Hardware Single-Step (HSS) instead of software breakpoint" ++ default y ++ ++config ALIGNMENT_TRAP ++ tristate "Kernel support unaligned access handling" ++ depends on EXPERIMENTAL ++ default y ++ help ++ Andes processors cannot fetch/store information which is not ++ naturally aligned on the bus, i.e., a 4 byte fetch must start at an ++ address divisible by 4. On 32-bit Andes processors, these non-aligned ++ fetch/store instructions will be emulated in software if you say ++ here, which has a severe performance impact. This is necessary for ++ correct operation of some network protocols. With an IP-only ++ configuration it is safe to say N, otherwise say Y. ++ ++config HIGHMEM ++ bool "High Memory Support" ++ depends on MMU ++ help ++ The address space of ARM processors is only 4 Gigabytes large ++ and it has to accommodate user address space, kernel address ++ space as well as some memory mapped IO. That means that, if you ++ have a large amount of physical memory and/or IO, not all of the ++ memory can be "permanently mapped" by the kernel. The physical ++ memory that is not permanently mapped is called "high memory". ++ ++ Depending on the selected kernel/user memory split, minimum ++ vmalloc space and actual amount of RAM, you may not need this ++ option which should result in a slightly faster kernel. ++ ++ If unsure, say n. +diff -Nur linux-3.4.110.orig/arch/nds32/Kconfig.debug linux-3.4.110/arch/nds32/Kconfig.debug +--- linux-3.4.110.orig/arch/nds32/Kconfig.debug 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/Kconfig.debug 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,82 @@ ++menu "Kernel hacking" ++ ++config TRACE_IRQFLAGS_SUPPORT ++ bool ++ default y ++ ++source "lib/Kconfig.debug" ++ ++config FRAME_POINTER ++ bool ++ default y ++ help ++ If you say N here, the resulting kernel will be slightly smaller and ++ faster. However, when a problem occurs with the kernel, the ++ information that is reported is severely limited. Most people ++ should say Y here. ++ ++config DEBUG_USER ++ bool "Verbose user fault messages" ++ help ++ When a user program crashes due to an exception, the kernel can ++ print a brief message explaining what the problem was. This is ++ sometimes helpful for debugging but serves no purpose on a ++ production system. Most people should say N here. ++ ++ In addition, you need to pass user_debug=N on the kernel command ++ line to enable this feature. N consists of the sum of: ++ ++ 1 - undefined instruction events ++ 2 - system calls ++ 4 - invalid data aborts ++ 8 - SIGSEGV faults ++ 16 - SIGBUS faults ++ ++config DEBUG_ERRORS ++ bool "Verbose kernel error messages" ++ depends on DEBUG_KERNEL ++ help ++ This option controls verbose debugging information which can be ++ printed when the kernel detects an internal error. This debugging ++ information is useful to kernel hackers when tracking down problems, ++ but mostly meaningless to other people. It's safe to say Y unless ++ you are concerned with the code size or don't want to see these ++ messages. ++ ++config DEBUG_LL ++ bool "Kernel low-level debugging functions" ++ depends on DEBUG_KERNEL ++ help ++ Say Y here to include definitions of printascii, printchar, printhex ++ in the kernel. This is helpful if you are debugging code that ++ executes before the console is initialized. ++ ++config CCTL ++ tristate "User space cache control support (EXPERIMENTAL)" ++ depends on EXPERIMENTAL ++ help ++ export cache control to user space via /proc ++ ++ If unsure, say N. ++ ++config ELFCHK_DEFAULT_ENABLE ++ bool "Enable ELF-Core Checking by default" ++ default n ++ select PROC_FS ++ help ++ ELF-Core Checking is a mechanism which prevents ELF binary from ++ being loaded if it requires any feature that the underlying platform ++ doesn't support. ++ ++ If you say Y here, the resulting kernel enables ELF-Core Checking ++ mechanism by default. ++config EARLY_PRINTK ++ bool "Early printk support" ++ default y ++ help ++ Say Y here if you want to have an early console using the ++ earlyprintk=<name>[,<addr>][,<options>] kernel parameter. It ++ is assumed that the early console device has been initialised ++ by the boot loader prior to starting the Linux kernel. ++ ++endmenu +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/asm-offsets.c linux-3.4.110/arch/nds32/kernel/asm-offsets.c +--- linux-3.4.110.orig/arch/nds32/kernel/asm-offsets.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/asm-offsets.c 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,72 @@ ++/* ++ * Copyright (C) 1995-2003 Russell King ++ * 2001-2002 Keith Owens ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * Generate definitions needed by assembly language modules. ++ * This code generates raw asm output which is post-processed to extract ++ * and format the required data. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/sched.h> ++#include <linux/mm.h> ++#include <asm/mach/arch.h> ++#include <asm/thread_info.h> ++#include <asm/memory.h> ++#include <asm/procinfo.h> ++ ++/* ++ * Make sure that the compiler and target are compatible. ++ */ ++ ++#if __GNUC__ < 3 || \ ++ (__GNUC__ == 3 && __GNUC_MINOR__ < 4) || \ ++ (__GNUC__ == 3 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ != 0 && \ ++ __GNUC_PATCHLEVEL__ < 4) || \ ++ (__GNUC__ == 4 && __GNUC_MINOR__ < 2) ++#error Your compiler is too buggy; it is known to miscompile kernels. ++#error Known good compilers: 3.4.4, 4.2 ++#endif ++ ++/* Use marker if you need to separate the values later */ ++ ++#define DEFINE(sym, val) \ ++ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) ++ ++#define BLANK() asm volatile("\n->" : : ) ++ ++int main(void) ++{ ++ DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); ++ BLANK(); ++ DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); ++ DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); ++ DEFINE(TI_ADDR_LIMIT, offsetof(struct thread_info, addr_limit)); ++ DEFINE(TI_TASK, offsetof(struct thread_info, task)); ++ DEFINE(TI_EXEC_DOMAIN, offsetof(struct thread_info, exec_domain)); ++ DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); ++// DEFINE(TI_TP_VALUE, offsetof(struct thread_info, tp_value)); ++ DEFINE(TI_SP_SAVE, offsetof(struct thread_info, sp_save)); ++ BLANK(); ++ DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); ++ BLANK(); ++ DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id)); ++ BLANK(); ++ DEFINE(VMA_VM_MM, offsetof(struct vm_area_struct, vm_mm)); ++ DEFINE(VMA_VM_FLAGS, offsetof(struct vm_area_struct, vm_flags)); ++ BLANK(); ++ DEFINE(VM_EXEC, VM_EXEC); ++ BLANK(); ++ DEFINE(VIRT_OFFSET, PAGE_OFFSET); ++ BLANK(); ++ DEFINE(SIZEOF_MACHINE_DESC, sizeof(struct machine_desc)); ++ DEFINE(MACHINFO_TYPE, offsetof(struct machine_desc, nr)); ++ DEFINE(MACHINFO_NAME, offsetof(struct machine_desc, name)); ++ BLANK(); ++ DEFINE(PROC_INFO_SZ, sizeof(struct proc_info_list)); ++ ++ return 0; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/audio.c linux-3.4.110/arch/nds32/kernel/audio.c +--- linux-3.4.110.orig/arch/nds32/kernel/audio.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/audio.c 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,218 @@ ++/* ++ * arch/nds32/kernel/audio.c ++ * ++ * Copyright (C) 2001 Manuela Cirronis, Paolo Alberelli ++ * Copyright (C) 2002 STMicroelectronics Limited ++ * Author : Stuart Menefy ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * Started from SH4 version: ++ * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka ++ * ++ * 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. ++ */ ++#include <linux/sched.h> ++#include <linux/signal.h> ++#include <asm/processor.h> ++#include <asm/user.h> ++#include <asm/io.h> ++#include <asm/bitfield.h> ++#include <asm/audio.h> ++#include "audio.h" ++/* ++ * Initially load the audio with signalling NANS. This bit pattern ++ * has the property that no matter whether considered as single or as ++ * double precision, it still represents a signalling NAN. ++ */ ++ ++static struct audio_struct init_audioregs = { ++ .auregs = {[0...31] = NAN32} ++}; ++ ++void save_audio(struct task_struct *tsk) ++{ ++ unsigned int tmp; ++ enable_audio(); ++ asm volatile ("mfsr %0, $MSC_CFG\n\t" ++ "andi %0, %0, %2\n\t" ++ "srli %0, %0, %3\n\t" ++ "slti %0, %0, 2\n\t" ++ "bnez %0, 99f\n\t" ++ "amfar %0, $D0.L24\n\t" ++ "swi %0, [%1+0x0]\n\t" ++ "amfar %0, $D1.L24\n\t" ++ "swi %0, [%1+0x4]\n\t" ++ "99:\n\t" ++ "amfar %0, $I0\n\t" ++ "swi %0, [%1+0x8]\n\t" ++ "amfar %0, $I1\n\t" ++ "swi %0, [%1+0xc]\n\t" ++ "amfar %0, $I2\n\t" ++ "swi %0, [%1+0x10]\n\t" ++ "amfar %0, $I3\n\t" ++ "swi %0, [%1+0x14]\n\t" ++ "amfar %0, $I4\n\t" ++ "swi %0, [%1+0x18]\n\t" ++ "amfar %0, $I5\n\t" ++ "swi %0, [%1+0x1c]\n\t" ++ "amfar %0, $I6\n\t" ++ "swi %0, [%1+0x20]\n\t" ++ "amfar %0, $I7\n\t" ++ "swi %0, [%1+0x24]\n\t" ++ "amfar %0, $M1\n\t" ++ "swi %0, [%1+0x28]\n\t" ++ "amfar %0, $M2\n\t" ++ "swi %0, [%1+0x2c]\n\t" ++ "amfar %0, $M3\n\t" ++ "swi %0, [%1+0x30]\n\t" ++ "amfar %0, $M5\n\t" ++ "swi %0, [%1+0x34]\n\t" ++ "amfar %0, $M6\n\t" ++ "swi %0, [%1+0x38]\n\t" ++ "amfar %0, $M7\n\t" ++ "swi %0, [%1+0x3c]\n\t" ++ "amfar %0, $MOD\n\t" ++ "swi %0, [%1+0x40]\n\t" ++ "amfar %0, $LB\n\t" ++ "swi %0, [%1+0x44]\n\t" ++ "amfar %0, $LE\n\t" ++ "swi %0, [%1+0x48]\n\t" ++ "amfar %0, $LC\n\t" ++ "swi %0, [%1+0x4c]\n\t" ++ "amfar %0, $ADM_VBASE\n\t" ++ "swi %0, [%1+0x50]\n\t" ++ "amfar %0, $SHFT_CTL0\n\t" ++ "swi %0, [%1+0x54]\n\t" ++ "amfar %0, $SHFT_CTL1\n\t" ++ "swi %0, [%1+0x58]\n\t" ++ "amfar2 %0, $CB_CTL\n\t" ++ "swi %0, [%1+0x5c]\n\t" ++ "amfar2 %0, $CBB0\n\t" ++ "swi %0, [%1+0x60]\n\t" ++ "amfar2 %0, $CBB1\n\t" ++ "swi %0, [%1+0x64]\n\t" ++ "amfar2 %0, $CBB2\n\t" ++ "swi %0, [%1+0x68]\n\t" ++ "amfar2 %0, $CBB3\n\t" ++ "swi %0, [%1+0x6c]\n\t" ++ "amfar2 %0, $CBE0\n\t" ++ "swi %0, [%1+0x70]\n\t" ++ "amfar2 %0, $CBE1\n\t" ++ "swi %0, [%1+0x74]\n\t" ++ "amfar2 %0, $CBE2\n\t" ++ "swi %0, [%1+0x78]\n\t" ++ "amfar2 %0, $CBE3\n\t" ++ "swi %0, [%1+0x7c]\n\t":"=&r" (tmp) ++ :"r"(&tsk->thread.audio), "i"(MSC_CFG_mskAUDIO), ++ "i"(MSC_CFG_offAUDIO) ++ :"memory"); ++ disable_audio(); ++} ++ ++void audioload(struct audio_struct *audioregs) ++{ ++ unsigned int tmp; ++ enable_audio(); ++ asm volatile ("mfsr %0, $MSC_CFG\n\t" ++ "andi %0, %0, %2\n\t" ++ "srli %0, %0, %3\n\t" ++ "slti %0, %0, 2\n\t" ++ "bnez %0, 98f\n\t" ++ "lwi %0, [%1+0x0]\n\t" ++ "amtar %0, $D0.L24\n\t" ++ "lwi %0, [%1+0x4]\n\t" ++ "amtar %0, $D1.L24\n\t" ++ "98:\n\t" ++ "lwi %0, [%1+0x8]\n\t" ++ "amtar %0, $I0\n\t" ++ "lwi %0, [%1+0xc]\n\t" ++ "amtar %0, $I1\n\t" ++ "lwi %0, [%1+0x10]\n\t" ++ "amtar %0, $I2\n\t" ++ "lwi %0, [%1+0x14]\n\t" ++ "amtar %0, $I3\n\t" ++ "lwi %0, [%1+0x18]\n\t" ++ "amtar %0, $I4\n\t" ++ "lwi %0, [%1+0x1c]\n\t" ++ "amtar %0, $I5\n\t" ++ "lwi %0, [%1+0x20]\n\t" ++ "amtar %0, $I6\n\t" ++ "lwi %0, [%1+0x24]\n\t" ++ "amtar %0, $I7\n\t" ++ "lwi %0, [%1+0x28]\n\t" ++ "amtar %0, $M1\n\t" ++ "lwi %0, [%1+0x2c]\n\t" ++ "amtar %0, $M2\n\t" ++ "lwi %0, [%1+0x30]\n\t" ++ "amtar %0, $M3\n\t" ++ "lwi %0, [%1+0x34]\n\t" ++ "amtar %0, $M5\n\t" ++ "lwi %0, [%1+0x38]\n\t" ++ "amtar %0, $M6\n\t" ++ "lwi %0, [%1+0x3c]\n\t" ++ "amtar %0, $M7\n\t" ++ "lwi %0, [%1+0x40]\n\t" ++ "amtar %0, $MOD\n\t" ++ "lwi %0, [%1+0x44]\n\t" ++ "amtar %0, $LB\n\t" ++ "lwi %0, [%1+0x48]\n\t" ++ "amtar %0, $LE\n\t" ++ "lwi %0, [%1+0x4c]\n\t" ++ "amtar %0, $LC\n\t" ++ "lwi %0, [%1+0x50]\n\t" ++ "amtar %0, $ADM_VBASE\n\t" ++ "lwi %0, [%1+0x54]\n\t" ++ "amtar %0, $SHFT_CTL0\n\t" ++ "lwi %0, [%1+0x58]\n\t" ++ "amtar %0, $SHFT_CTL1\n\t" ++ "lwi %0, [%1+0x5c]\n\t" ++ "amtar2 %0, $CB_CTL\n\t" ++ "lwi %0, [%1+0x60]\n\t" ++ "amtar2 %0, $CBB0\n\t" ++ "lwi %0, [%1+0x64]\n\t" ++ "amtar2 %0, $CBB1\n\t" ++ "lwi %0, [%1+0x68]\n\t" ++ "amtar2 %0, $CBB2\n\t" ++ "lwi %0, [%1+0x6c]\n\t" ++ "amtar2 %0, $CBB3\n\t" ++ "lwi %0, [%1+0x70]\n\t" ++ "amtar2 %0, $CBE0\n\t" ++ "lwi %0, [%1+0x74]\n\t" ++ "amtar2 %0, $CBE1\n\t" ++ "lwi %0, [%1+0x78]\n\t" ++ "amtar2 %0, $CBE2\n\t" ++ "lwi %0, [%1+0x7c]\n\t" ++ "amtar2 %0, $CBE3\n\t":"=&r" (tmp) ++ :"r"(audioregs), "i"(MSC_CFG_mskAUDIO), ++ "i"(MSC_CFG_offAUDIO)); ++ disable_audio(); ++} ++ ++void do_audio_context_switch(unsigned long error_code, struct pt_regs *regs) ++{ ++ struct task_struct *tsk = current; ++ ++ if (!user_mode(regs)) ++ die("Audio used in kernel", regs, error_code); ++ ++ /* Enable to use audio. */ ++ grab_audio(regs); ++#ifndef CONFIG_UNLAZY_AUDIO //Lazy audio is used ++ if (last_task_used_audio == current) ++ return; ++ ++ if (last_task_used_audio != NULL) ++ /* Other processes audio state, save away */ ++ save_audio(last_task_used_audio); ++ last_task_used_audio = current; ++#endif ++ if (test_tsk_thread_flag(tsk, TIF_USEDAUDIO)) { ++ audioload(¤t->thread.audio); ++ } else { ++ /* First time audio user. */ ++ audioload(&init_audioregs); ++ set_tsk_thread_flag(tsk, TIF_USEDAUDIO); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/audio.h linux-3.4.110/arch/nds32/kernel/audio.h +--- linux-3.4.110.orig/arch/nds32/kernel/audio.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/audio.h 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,2 @@ ++ ++#define NAN32 0x0UL +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/bios32.c linux-3.4.110/arch/nds32/kernel/bios32.c +--- linux-3.4.110.orig/arch/nds32/kernel/bios32.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/bios32.c 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,711 @@ ++/* ++ * linux/arch/nds32/kernel/bios32.c ++ * ++ * PCI bios-type initialisation for PCI machines ++ * ++ * Bits taken from various places. ++ * ++ * Copyright (C) 2009 Andes Technology Corporation ++ */ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/pci.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++ ++#include <asm/io.h> ++#include <asm/mach-types.h> ++#include <asm/mach/pci.h> ++ ++static int debug_pci; ++static int use_firmware; ++ ++/* ++ * We can't use pci_find_device() here since we are ++ * called from interrupt context. ++ */ ++static void pcibios_bus_report_status(struct pci_bus *bus, u_int status_mask, ++ int warn) ++{ ++ struct pci_dev *dev; ++ ++ list_for_each_entry(dev, &bus->devices, bus_list) { ++ u16 status; ++ ++ /* ++ * ignore host bridge - we handle ++ * that separately ++ */ ++ if (dev->bus->number == 0 && dev->devfn == 0) ++ continue; ++ ++ pci_read_config_word(dev, PCI_STATUS, &status); ++ if (status == 0xffff) ++ continue; ++ ++ if ((status & status_mask) == 0) ++ continue; ++ ++ /* clear the status errors */ ++ pci_write_config_word(dev, PCI_STATUS, status & status_mask); ++ ++ if (warn) ++ printk("(%s: %04X) ", pci_name(dev), status); ++ } ++ ++ list_for_each_entry(dev, &bus->devices, bus_list) ++ if (dev->subordinate) ++ pcibios_bus_report_status(dev->subordinate, status_mask, warn); ++} ++ ++void pcibios_report_status(u_int status_mask, int warn) ++{ ++ struct list_head *l; ++ ++ list_for_each(l, &pci_root_buses) { ++ struct pci_bus *bus = pci_bus_b(l); ++ ++ pcibios_bus_report_status(bus, status_mask, warn); ++ } ++} ++ ++/* ++ * We don't use this to fix the device, but initialisation of it. ++ * It's not the correct use for this, but it works. ++ * Note that the arbiter/ISA bridge appears to be buggy, specifically in ++ * the following area: ++ * 1. park on CPU ++ * 2. ISA bridge ping-pong ++ * 3. ISA bridge master handling of target RETRY ++ * ++ * Bug 3 is responsible for the sound DMA grinding to a halt. We now ++ * live with bug 2. ++ */ ++static void __devinit pci_fixup_83c553(struct pci_dev *dev) ++{ ++ /* ++ * Set memory region to start at address 0, and enable IO ++ */ ++ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, ++ PCI_BASE_ADDRESS_SPACE_MEMORY); ++ pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_IO); ++ ++ dev->resource[0].end -= dev->resource[0].start; ++ dev->resource[0].start = 0; ++ ++ /* ++ * All memory requests from ISA to be channelled to PCI ++ */ ++ pci_write_config_byte(dev, 0x48, 0xff); ++ ++ /* ++ * Enable ping-pong on bus master to ISA bridge transactions. ++ * This improves the sound DMA substantially. The fixed ++ * priority arbiter also helps (see below). ++ */ ++ pci_write_config_byte(dev, 0x42, 0x01); ++ ++ /* ++ * Enable PCI retry ++ */ ++ pci_write_config_byte(dev, 0x40, 0x22); ++ ++ /* ++ * We used to set the arbiter to "park on last master" (bit ++ * 1 set), but unfortunately the CyberPro does not park the ++ * bus. We must therefore park on CPU. Unfortunately, this ++ * may trigger yet another bug in the 553. ++ */ ++ pci_write_config_byte(dev, 0x83, 0x02); ++ ++ /* ++ * Make the ISA DMA request lowest priority, and disable ++ * rotating priorities completely. ++ */ ++ pci_write_config_byte(dev, 0x80, 0x11); ++ pci_write_config_byte(dev, 0x81, 0x00); ++ ++ /* ++ * Route INTA input to IRQ 11, and set IRQ11 to be level ++ * sensitive. ++ */ ++ pci_write_config_word(dev, 0x44, 0xb000); ++ outb(0x08, 0x4d1); ++} ++ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_83C553, ++ pci_fixup_83c553); ++ ++static void __devinit pci_fixup_unassign(struct pci_dev *dev) ++{ ++ dev->resource[0].end -= dev->resource[0].start; ++ dev->resource[0].start = 0; ++} ++ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940F, ++ pci_fixup_unassign); ++ ++/* ++ * Prevent the PCI layer from seeing the resources allocated to this device ++ * if it is the host bridge by marking it as such. These resources are of ++ * no consequence to the PCI layer (they are handled elsewhere). ++ */ ++static void __devinit pci_fixup_dec21285(struct pci_dev *dev) ++{ ++ int i; ++ ++ if (dev->devfn == 0) { ++ dev->class &= 0xff; ++ dev->class |= PCI_CLASS_BRIDGE_HOST << 8; ++ for (i = 0; i < PCI_NUM_RESOURCES; i++) { ++ dev->resource[i].start = 0; ++ dev->resource[i].end = 0; ++ dev->resource[i].flags = 0; ++ } ++ } ++} ++ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, ++ pci_fixup_dec21285); ++ ++/* ++ * PCI IDE controllers use non-standard I/O port decoding, respect it. ++ */ ++static void __devinit pci_fixup_ide_bases(struct pci_dev *dev) ++{ ++ struct resource *r; ++ int i; ++ ++ if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) ++ return; ++ ++ for (i = 0; i < PCI_NUM_RESOURCES; i++) { ++ r = dev->resource + i; ++ if ((r->start & ~0x80) == 0x374) { ++ r->start |= 2; ++ r->end = r->start; ++ } ++ } ++} ++ ++DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases); ++ ++/* ++ * Put the DEC21142 to sleep ++ */ ++static void __devinit pci_fixup_dec21142(struct pci_dev *dev) ++{ ++ pci_write_config_dword(dev, 0x40, 0x80000000); ++} ++ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, ++ pci_fixup_dec21142); ++ ++/* ++ * The CY82C693 needs some rather major fixups to ensure that it does ++ * the right thing. Idea from the Alpha people, with a few additions. ++ * ++ * We ensure that the IDE base registers are set to 1f0/3f4 for the ++ * primary bus, and 170/374 for the secondary bus. Also, hide them ++ * from the PCI subsystem view as well so we won't try to perform ++ * our own auto-configuration on them. ++ * ++ * In addition, we ensure that the PCI IDE interrupts are routed to ++ * IRQ 14 and IRQ 15 respectively. ++ * ++ * The above gets us to a point where the IDE on this device is ++ * functional. However, The CY82C693U _does not work_ in bus ++ * master mode without locking the PCI bus solid. ++ */ ++static void __devinit pci_fixup_cy82c693(struct pci_dev *dev) ++{ ++ if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) { ++ u32 base0, base1; ++ ++ if (dev->class & 0x80) { /* primary */ ++ base0 = 0x1f0; ++ base1 = 0x3f4; ++ } else { /* secondary */ ++ base0 = 0x170; ++ base1 = 0x374; ++ } ++ ++ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, ++ base0 | PCI_BASE_ADDRESS_SPACE_IO); ++ pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, ++ base1 | PCI_BASE_ADDRESS_SPACE_IO); ++ ++ dev->resource[0].start = 0; ++ dev->resource[0].end = 0; ++ dev->resource[0].flags = 0; ++ ++ dev->resource[1].start = 0; ++ dev->resource[1].end = 0; ++ dev->resource[1].flags = 0; ++ } else if (PCI_FUNC(dev->devfn) == 0) { ++ /* ++ * Setup IDE IRQ routing. ++ */ ++ pci_write_config_byte(dev, 0x4b, 14); ++ pci_write_config_byte(dev, 0x4c, 15); ++ ++ /* ++ * Disable FREQACK handshake, enable USB. ++ */ ++ pci_write_config_byte(dev, 0x4d, 0x41); ++ ++ /* ++ * Enable PCI retry, and PCI post-write buffer. ++ */ ++ pci_write_config_byte(dev, 0x44, 0x17); ++ ++ /* ++ * Enable ISA master and DMA post write buffering. ++ */ ++ pci_write_config_byte(dev, 0x45, 0x03); ++ } ++} ++ ++DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, ++ pci_fixup_cy82c693); ++ ++void __devinit pcibios_update_irq(struct pci_dev *dev, int irq) ++{ ++ if (debug_pci) ++ printk("PCI: Assigning IRQ %02d to %s\n", irq, pci_name(dev)); ++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); ++} ++ ++/* ++ * If the bus contains any of these devices, then we must not turn on ++ * parity checking of any kind. Currently this is CyberPro 20x0 only. ++ */ ++static inline int pdev_bad_for_parity(struct pci_dev *dev) ++{ ++ return (dev->vendor == PCI_VENDOR_ID_INTERG && ++ (dev->device == PCI_DEVICE_ID_INTERG_2000 || ++ dev->device == PCI_DEVICE_ID_INTERG_2010)); ++} ++ ++/* ++ * Adjust the device resources from bus-centric to Linux-centric. ++ */ ++static void __devinit ++pdev_fixup_device_resources(struct pci_sys_data *root, struct pci_dev *dev) ++{ ++ resource_size_t offset; ++ int i; ++ ++ for (i = 0; i < PCI_NUM_RESOURCES; i++) { ++ if (dev->resource[i].start == 0) ++ continue; ++ if (dev->resource[i].flags & IORESOURCE_MEM) ++ offset = root->mem_offset; ++ else ++ offset = root->io_offset; ++ ++ dev->resource[i].start += offset; ++ dev->resource[i].end += offset; ++ } ++} ++ ++static void __devinit ++pbus_assign_bus_resources(struct pci_bus *bus, struct pci_sys_data *root) ++{ ++ struct pci_dev *dev = bus->self; ++ int i; ++ ++ if (!dev) { ++ /* ++ * Assign root bus resources. ++ */ ++ for (i = 0; i < 3; i++) ++ bus->resource[i] = root->resource[i]; ++ } ++} ++ ++/* ++ * pcibios_fixup_bus - Called after each bus is probed, ++ * but before its children are examined. ++ */ ++void __devinit pcibios_fixup_bus(struct pci_bus *bus) ++{ ++ struct pci_sys_data *root = bus->sysdata; ++ struct pci_dev *dev; ++ u16 features = ++ PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_FAST_BACK; ++ ++ pbus_assign_bus_resources(bus, root); ++ ++ /* ++ * Walk the devices on this bus, working out what we can ++ * and can't support. ++ */ ++ list_for_each_entry(dev, &bus->devices, bus_list) { ++ u16 status; ++ ++ pdev_fixup_device_resources(root, dev); ++ ++ pci_read_config_word(dev, PCI_STATUS, &status); ++ ++ /* ++ * If any device on this bus does not support fast back ++ * to back transfers, then the bus as a whole is not able ++ * to support them. Having fast back to back transfers ++ * on saves us one PCI cycle per transaction. ++ */ ++ if (!(status & PCI_STATUS_FAST_BACK)) ++ features &= ~PCI_COMMAND_FAST_BACK; ++ ++ if (pdev_bad_for_parity(dev)) ++ features &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); ++ ++ switch (dev->class >> 8) { ++#if defined(CONFIG_ISA) || defined(CONFIG_EISA) ++ case PCI_CLASS_BRIDGE_ISA: ++ case PCI_CLASS_BRIDGE_EISA: ++ /* ++ * If this device is an ISA bridge, set isa_bridge ++ * to point at this device. We will then go looking ++ * for things like keyboard, etc. ++ */ ++ isa_bridge = dev; ++ break; ++#endif ++ case PCI_CLASS_BRIDGE_PCI: ++ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &status); ++ status |= ++ PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_MASTER_ABORT; ++ status &= ++ ~(PCI_BRIDGE_CTL_BUS_RESET | ++ PCI_BRIDGE_CTL_FAST_BACK); ++ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, status); ++ break; ++ ++ case PCI_CLASS_BRIDGE_CARDBUS: ++ pci_read_config_word(dev, PCI_CB_BRIDGE_CONTROL, ++ &status); ++ status |= ++ PCI_CB_BRIDGE_CTL_PARITY | ++ PCI_CB_BRIDGE_CTL_MASTER_ABORT; ++ pci_write_config_word(dev, PCI_CB_BRIDGE_CONTROL, ++ status); ++ break; ++ } ++ } ++ ++ /* ++ * Now walk the devices again, this time setting them up. ++ */ ++ list_for_each_entry(dev, &bus->devices, bus_list) { ++ u16 cmd; ++ ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ cmd |= features; ++ pci_write_config_word(dev, PCI_COMMAND, cmd); ++ ++ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, ++ L1_CACHE_BYTES >> 2); ++ } ++ ++ /* ++ * Propagate the flags to the PCI bridge. ++ */ ++ if (bus->self && bus->self->hdr_type == PCI_HEADER_TYPE_BRIDGE) { ++ if (features & PCI_COMMAND_FAST_BACK) ++ bus->bridge_ctl |= PCI_BRIDGE_CTL_FAST_BACK; ++ if (features & PCI_COMMAND_PARITY) ++ bus->bridge_ctl |= PCI_BRIDGE_CTL_PARITY; ++ } ++ ++ /* ++ * Report what we did for this bus ++ */ ++ printk(KERN_INFO "PCI: bus%d: Fast back to back transfers %sabled\n", ++ bus->number, (features & PCI_COMMAND_FAST_BACK) ? "en" : "dis"); ++} ++ ++/* ++ * Convert from Linux-centric to bus-centric addresses for bridge devices. ++ */ ++void ++pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, ++ struct resource *res) ++{ ++ struct pci_sys_data *root = dev->sysdata; ++ unsigned long offset = 0; ++ ++ if (res->flags & IORESOURCE_IO) ++ offset = root->io_offset; ++ if (res->flags & IORESOURCE_MEM) ++ offset = root->mem_offset; ++ ++ region->start = res->start - offset; ++ region->end = res->end - offset; ++} ++ ++void __devinit ++pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, ++ struct pci_bus_region *region) ++{ ++ struct pci_sys_data *root = dev->sysdata; ++ unsigned long offset = 0; ++ ++ if (res->flags & IORESOURCE_IO) ++ offset = root->io_offset; ++ if (res->flags & IORESOURCE_MEM) ++ offset = root->mem_offset; ++ ++ res->start = region->start + offset; ++ res->end = region->end + offset; ++} ++ ++#ifdef CONFIG_HOTPLUG ++EXPORT_SYMBOL(pcibios_fixup_bus); ++EXPORT_SYMBOL(pcibios_resource_to_bus); ++EXPORT_SYMBOL(pcibios_bus_to_resource); ++#endif ++ ++/* ++ * This is the standard PCI-PCI bridge swizzling algorithm: ++ * ++ * Dev: 0 1 2 3 ++ * A A B C D ++ * B B C D A ++ * C C D A B ++ * D D A B C ++ * ^^^^^^^^^^ irq pin on bridge ++ */ ++u8 __devinit pci_std_swizzle(struct pci_dev *dev, u8 * pinp) ++{ ++ int pin = *pinp - 1; ++ ++ while (dev->bus->self) { ++ pin = (pin + PCI_SLOT(dev->devfn)) & 3; ++ /* ++ * move up the chain of bridges, ++ * swizzling as we go. ++ */ ++ dev = dev->bus->self; ++ } ++ *pinp = pin + 1; ++ ++ return PCI_SLOT(dev->devfn); ++} ++ ++/* ++ * Swizzle the device pin each time we cross a bridge. ++ * This might update pin and returns the slot number. ++ */ ++static u8 __devinit pcibios_swizzle(struct pci_dev *dev, u8 * pin) ++{ ++ struct pci_sys_data *sys = dev->sysdata; ++ int slot = 0, oldpin = *pin; ++ ++ if (sys->swizzle) ++ slot = sys->swizzle(dev, pin); ++ ++ if (debug_pci) ++ printk("PCI: %s swizzling pin %d => pin %d slot %d\n", ++ pci_name(dev), oldpin, *pin, slot); ++ ++ return slot; ++} ++ ++/* ++ * Map a slot/pin to an IRQ. ++ */ ++static int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ struct pci_sys_data *sys = dev->sysdata; ++ int irq = -1; ++ ++ if (sys->map_irq) ++ irq = sys->map_irq(dev, slot, pin); ++ ++ if (debug_pci) ++ printk("PCI: %s mapping slot %d pin %d => irq %d\n", ++ pci_name(dev), slot, pin, irq); ++ ++ return irq; ++} ++ ++static void __init pcibios_init_hw(struct hw_pci *hw) ++{ ++ struct pci_sys_data *sys = NULL; ++ int ret; ++ int nr, busnr; ++ ++ for (nr = busnr = 0; nr < hw->nr_controllers; nr++) { ++ sys = kmalloc(sizeof(struct pci_sys_data), GFP_KERNEL); ++ if (!sys) ++ panic("PCI: unable to allocate sys data!"); ++ ++ memset(sys, 0, sizeof(struct pci_sys_data)); ++ ++ sys->hw = hw; ++ sys->busnr = busnr; ++ sys->swizzle = hw->swizzle; ++ sys->map_irq = hw->map_irq; ++ sys->resource[0] = &ioport_resource; ++ sys->resource[1] = &iomem_resource; ++ ++ ret = hw->setup(nr, sys); ++ ++ if (ret > 0) { ++ sys->bus = hw->scan(nr, sys); ++ ++ if (!sys->bus) ++ panic("PCI: unable to scan bus!"); ++ ++ busnr = sys->bus->subordinate + 1; ++ ++ list_add(&sys->node, &hw->buses); ++ } else { ++ kfree(sys); ++ if (ret < 0) ++ break; ++ } ++ } ++} ++ ++void __init pci_common_init(struct hw_pci *hw) ++{ ++ struct pci_sys_data *sys; ++ ++ INIT_LIST_HEAD(&hw->buses); ++ ++ if (hw->preinit) ++ hw->preinit(); ++ pcibios_init_hw(hw); ++ if (hw->postinit) ++ hw->postinit(); ++ ++ pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq); ++ ++ list_for_each_entry(sys, &hw->buses, node) { ++ struct pci_bus *bus = sys->bus; ++ ++ if (!use_firmware) { ++ /* ++ * Size the bridge windows. ++ */ ++ pci_bus_size_bridges(bus); ++ ++ /* ++ * Assign resources. ++ */ ++ pci_bus_assign_resources(bus); ++ } ++ ++ /* ++ * Tell drivers about devices found. ++ */ ++ pci_bus_add_devices(bus); ++ } ++} ++ ++char *__devinit pcibios_setup(char *str) ++{ ++ if (!strcmp(str, "debug")) { ++ debug_pci = 1; ++ return NULL; ++ } else if (!strcmp(str, "firmware")) { ++ use_firmware = 1; ++ return NULL; ++ } ++ return str; ++} ++ ++/* ++ * From arch/i386/kernel/pci-i386.c: ++ * ++ * We need to avoid collisions with `mirrored' VGA ports ++ * and other strange ISA hardware, so we always want the ++ * addresses to be allocated in the 0x000-0x0ff region ++ * modulo 0x400. ++ * ++ * Why? Because some silly external IO cards only decode ++ * the low 10 bits of the IO address. The 0x00-0xff region ++ * is reserved for motherboard devices that decode all 16 ++ * bits, so it's ok to allocate at, say, 0x2800-0x28ff, ++ * but we want to try to avoid allocating at 0x2900-0x2bff ++ * which might be mirrored at 0x0100-0x03ff.. ++ */ ++void pcibios_align_resource(void *data, struct resource *res, ++ resource_size_t size, resource_size_t align) ++{ ++ resource_size_t start = res->start; ++ ++ if (res->flags & IORESOURCE_IO && start & 0x300) ++ start = (start + 0x3ff) & ~0x3ff; ++ ++ res->start = (start + align - 1) & ~(align - 1); ++} ++ ++/** ++ * pcibios_enable_device - Enable I/O and memory. ++ * @dev: PCI device to be enabled ++ */ ++int pcibios_enable_device(struct pci_dev *dev, int mask) ++{ ++ u16 cmd, old_cmd; ++ int idx; ++ struct resource *r; ++ ++ pci_read_config_word(dev, PCI_COMMAND, &cmd); ++ old_cmd = cmd; ++ for (idx = 0; idx < 6; idx++) { ++ /* Only set up the requested stuff */ ++ if (!(mask & (1 << idx))) ++ continue; ++ ++ r = dev->resource + idx; ++ if (!r->start && r->end) { ++ printk(KERN_ERR "PCI: Device %s not available because" ++ " of resource collisions\n", pci_name(dev)); ++ return -EINVAL; ++ } ++ if (r->flags & IORESOURCE_IO) ++ cmd |= PCI_COMMAND_IO; ++ if (r->flags & IORESOURCE_MEM) ++ cmd |= PCI_COMMAND_MEMORY; ++ } ++ ++ /* ++ * Bridges (eg, cardbus bridges) need to be fully enabled ++ */ ++ if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) ++ cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY; ++ ++ if (cmd != old_cmd) { ++ printk("PCI: enabling device %s (%04x -> %04x)\n", ++ pci_name(dev), old_cmd, cmd); ++ pci_write_config_word(dev, PCI_COMMAND, cmd); ++ } ++ return 0; ++} ++ ++int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, ++ enum pci_mmap_state mmap_state, int write_combine) ++{ ++ struct pci_sys_data *root = dev->sysdata; ++ unsigned long phys; ++ ++ if (mmap_state == pci_mmap_io) { ++ return -EINVAL; ++ } else { ++ phys = vma->vm_pgoff + (root->mem_offset >> PAGE_SHIFT); ++ } ++ ++ /* ++ * Mark this as IO ++ */ ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ ++ if (remap_pfn_range(vma, vma->vm_start, phys, ++ vma->vm_end - vma->vm_start, vma->vm_page_prot)) ++ return -EAGAIN; ++ ++ return 0; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/calls.S linux-3.4.110/arch/nds32/kernel/calls.S +--- linux-3.4.110.orig/arch/nds32/kernel/calls.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/calls.S 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,400 @@ ++/* ++ * linux/arch/nds32/kernel/calls.S ++ * ++ * Copyright (C) 1995-2004 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This file is included twice in entry-common.S ++ */ ++ ++/* 0 */ CALL(sys_restart_syscall) ++ CALL(sys_exit) ++ CALL(sys_fork_wrapper) ++ CALL(sys_read) ++ CALL(sys_write) ++/* 5 */ CALL(sys_open) ++ CALL(sys_close) ++ CALL(sys_waitpid) ++ CALL(sys_creat) ++ CALL(sys_link) ++/* 10 */ CALL(sys_unlink) ++ CALL(sys_execve_wrapper) ++ CALL(sys_chdir) ++ CALL(sys_time) /* used by libc4 */ ++ CALL(sys_mknod) ++/* 15 */ CALL(sys_chmod) ++ CALL(sys_lchown16) ++ CALL(sys_ni_syscall) /* was sys_break */ ++ CALL(sys_ni_syscall) /* was sys_stat */ ++ CALL(sys_lseek) ++/* 20 */ CALL(sys_getpid) ++ CALL(sys_mount) ++ CALL(sys_oldumount) /* used by libc4 */ ++ CALL(sys_setuid16) ++ CALL(sys_getuid16) ++/* 25 */ CALL(sys_stime) ++ CALL(sys_ptrace) ++ CALL(sys_alarm) /* used by libc4 */ ++ CALL(sys_ni_syscall) /* was sys_fstat */ ++ CALL(sys_pause) ++/* 30 */ CALL(sys_utime) /* used by libc4 */ ++ CALL(sys_ni_syscall) /* was sys_stty */ ++ CALL(sys_ni_syscall) /* was sys_getty */ ++ CALL(sys_access) ++ CALL(sys_nice) ++/* 35 */ CALL(sys_ni_syscall) /* was sys_ftime */ ++ CALL(sys_sync) ++ CALL(sys_kill) ++ CALL(sys_rename) ++ CALL(sys_mkdir) ++/* 40 */ CALL(sys_rmdir) ++ CALL(sys_dup) ++ CALL(sys_pipe) ++ CALL(sys_times) ++ CALL(sys_ni_syscall) /* was sys_prof */ ++/* 45 */ CALL(sys_brk) ++ CALL(sys_setgid16) ++ CALL(sys_getgid16) ++ CALL(sys_ni_syscall) /* was sys_signal */ ++ CALL(sys_geteuid16) ++/* 50 */ CALL(sys_getegid16) ++ CALL(sys_acct) ++ CALL(sys_umount) ++ CALL(sys_ni_syscall) /* was sys_lock */ ++ CALL(sys_ioctl) ++/* 55 */ CALL(sys_fcntl) ++ CALL(sys_ni_syscall) /* was sys_mpx */ ++ CALL(sys_setpgid) ++ CALL(sys_ni_syscall) /* was sys_ulimit */ ++ CALL(sys_cacheflush) /* was sys_olduname */ ++/* 60 */ CALL(sys_umask) ++ CALL(sys_chroot) ++ CALL(sys_ustat) ++ CALL(sys_dup2) ++ CALL(sys_getppid) ++/* 65 */ CALL(sys_getpgrp) ++ CALL(sys_setsid) ++ CALL(sys_sigaction) ++ CALL(sys_ni_syscall) /* was sys_sgetmask */ ++ CALL(sys_ni_syscall) /* was sys_ssetmask */ ++/* 70 */ CALL(sys_setreuid16) ++ CALL(sys_setregid16) ++ CALL(sys_sigsuspend_wrapper) ++ CALL(sys_sigpending) ++ CALL(sys_sethostname) ++/* 75 */ CALL(sys_setrlimit) ++ CALL(sys_old_getrlimit) /* used by libc4 */ ++ CALL(sys_getrusage) ++ CALL(sys_gettimeofday) ++ CALL(sys_settimeofday) ++/* 80 */ CALL(sys_getgroups16) ++ CALL(sys_setgroups16) ++ CALL(old_select) /* used by libc4 */ ++ CALL(sys_symlink) ++ CALL(sys_ni_syscall) /* was sys_lstat */ ++/* 85 */ CALL(sys_readlink) ++ CALL(sys_uselib) ++ CALL(sys_swapon) ++ CALL(sys_reboot) ++ CALL(sys_old_readdir) /* used by libc4 */ ++/* 90 */ CALL(sys_old_mmap) /* used by libc4 */ ++ CALL(sys_munmap) ++ CALL(sys_truncate) ++ CALL(sys_ftruncate) ++ CALL(sys_fchmod) ++/* 95 */ CALL(sys_fchown16) ++ CALL(sys_getpriority) ++ CALL(sys_setpriority) ++ CALL(sys_ni_syscall) /* was sys_profil */ ++ CALL(sys_statfs) ++/* 100 */ CALL(sys_fstatfs) ++ CALL(sys_ni_syscall) ++ CALL(sys_socketcall) ++ CALL(sys_syslog) ++ CALL(sys_setitimer) ++/* 105 */ CALL(sys_getitimer) ++ CALL(sys_newstat) ++ CALL(sys_newlstat) ++ CALL(sys_newfstat) ++ CALL(sys_ni_syscall) /* was sys_uname */ ++/* 110 */ CALL(sys_ni_syscall) /* was sys_iopl */ ++ CALL(sys_vhangup) ++ CALL(sys_ni_syscall) ++ CALL(sys_syscall) /* call a syscall */ ++ CALL(sys_wait4) ++/* 115 */ CALL(sys_swapoff) ++ CALL(sys_sysinfo) ++ CALL(sys_ipc) ++ CALL(sys_fsync) ++ CALL(sys_sigreturn_wrapper) ++/* 120 */ CALL(sys_clone_wrapper) ++ CALL(sys_setdomainname) ++ CALL(sys_newuname) ++ CALL(sys_ni_syscall) ++ CALL(sys_adjtimex) ++/* 125 */ CALL(sys_mprotect) ++ CALL(sys_sigprocmask) ++ CALL(sys_ni_syscall) /* was sys_create_module */ ++ CALL(sys_init_module) ++ CALL(sys_delete_module) ++/* 130 */ CALL(sys_ni_syscall) /* was sys_get_kernel_syms */ ++ CALL(sys_quotactl) ++ CALL(sys_getpgid) ++ CALL(sys_fchdir) ++ CALL(sys_bdflush) ++/* 135 */ CALL(sys_sysfs) ++ CALL(sys_personality) ++ CALL(sys_ni_syscall) /* was _sys_afs_syscall */ ++ CALL(sys_setfsuid16) ++ CALL(sys_setfsgid16) ++/* 140 */ CALL(sys_llseek) ++ CALL(sys_getdents) ++ CALL(sys_select) ++ CALL(sys_flock) ++ CALL(sys_msync) ++/* 145 */ CALL(sys_readv) ++ CALL(sys_writev) ++ CALL(sys_getsid) ++ CALL(sys_fdatasync) ++ CALL(sys_sysctl) ++/* 150 */ CALL(sys_mlock) ++ CALL(sys_munlock) ++ CALL(sys_mlockall) ++ CALL(sys_munlockall) ++ CALL(sys_sched_setparam) ++/* 155 */ CALL(sys_sched_getparam) ++ CALL(sys_sched_setscheduler) ++ CALL(sys_sched_getscheduler) ++ CALL(sys_sched_yield) ++ CALL(sys_sched_get_priority_max) ++/* 160 */ CALL(sys_sched_get_priority_min) ++ CALL(sys_sched_rr_get_interval) ++ CALL(sys_nanosleep) ++ CALL(sys_nds32_mremap) ++ CALL(sys_setresuid16) ++/* 165 */ CALL(sys_getresuid16) ++ CALL(sys_getpagesize) ++ CALL(sys_ni_syscall) /* was sys_query_module */ ++ CALL(sys_poll) ++ CALL(sys_ni_syscall) /* was nfsservctl */ ++/* 170 */ CALL(sys_setresgid16) ++ CALL(sys_getresgid16) ++ CALL(sys_prctl) ++ CALL(sys_rt_sigreturn_wrapper) ++ CALL(sys_rt_sigaction) ++/* 175 */ CALL(sys_rt_sigprocmask) ++ CALL(sys_rt_sigpending) ++ CALL(sys_rt_sigtimedwait) ++ CALL(sys_rt_sigqueueinfo) ++ CALL(sys_rt_sigsuspend_wrapper) ++/* 180 */ CALL(sys_pread64) ++ CALL(sys_pwrite64) ++ CALL(sys_chown16) ++ CALL(sys_getcwd) ++ CALL(sys_capget) ++/* 185 */ CALL(sys_capset) ++ CALL(sys_sigaltstack_wrapper) ++ CALL(sys_sendfile) ++ CALL(sys_ni_syscall) ++ CALL(sys_ni_syscall) ++/* 190 */ CALL(sys_vfork_wrapper) ++ CALL(sys_getrlimit) ++ CALL(sys_mmap2) ++ CALL(sys_truncate64) ++ CALL(sys_ftruncate64) ++/* 195 */ CALL(sys_stat64) ++ CALL(sys_lstat64) ++ CALL(sys_fstat64) ++ CALL(sys_lchown) ++ CALL(sys_getuid) ++/* 200 */ CALL(sys_getgid) ++ CALL(sys_geteuid) ++ CALL(sys_getegid) ++ CALL(sys_setreuid) ++ CALL(sys_setregid) ++/* 205 */ CALL(sys_getgroups) ++ CALL(sys_setgroups) ++ CALL(sys_fchown) ++ CALL(sys_setresuid) ++ CALL(sys_getresuid) ++/* 210 */ CALL(sys_setresgid) ++ CALL(sys_getresgid) ++ CALL(sys_chown) ++ CALL(sys_setuid) ++ CALL(sys_setgid) ++/* 215 */ CALL(sys_setfsuid) ++ CALL(sys_setfsgid) ++ CALL(sys_getdents64) ++ CALL(sys_pivot_root) ++ CALL(sys_mincore) ++/* 220 */ CALL(sys_madvise) ++ CALL(sys_fcntl64) ++ CALL(sys_ni_syscall) /* TUX */ ++ CALL(sys_ni_syscall) ++ CALL(sys_gettid) ++/* 225 */ CALL(sys_readahead) ++ CALL(sys_setxattr) ++ CALL(sys_lsetxattr) ++ CALL(sys_fsetxattr) ++ CALL(sys_getxattr) ++/* 230 */ CALL(sys_lgetxattr) ++ CALL(sys_fgetxattr) ++ CALL(sys_listxattr) ++ CALL(sys_llistxattr) ++ CALL(sys_flistxattr) ++/* 235 */ CALL(sys_removexattr) ++ CALL(sys_lremovexattr) ++ CALL(sys_fremovexattr) ++ CALL(sys_tkill) ++ CALL(sys_sendfile64) ++/* 240 */ CALL(sys_futex_wrapper) ++ CALL(sys_sched_setaffinity) ++ CALL(sys_sched_getaffinity) ++ CALL(sys_io_setup) ++ CALL(sys_io_destroy) ++/* 245 */ CALL(sys_io_getevents) ++ CALL(sys_io_submit) ++ CALL(sys_io_cancel) ++ CALL(sys_exit_group) ++ CALL(sys_lookup_dcookie) ++/* 250 */ CALL(sys_epoll_create) ++ CALL(sys_epoll_ctl) ++ CALL(sys_epoll_wait) ++ CALL(sys_remap_file_pages) ++ CALL(sys_ni_syscall) /* sys_set_thread_area */ ++/* 255 */ CALL(sys_ni_syscall) /* sys_get_thread_area */ ++ CALL(sys_set_tid_address) ++ CALL(sys_timer_create) ++ CALL(sys_timer_settime) ++ CALL(sys_timer_gettime) ++/* 260 */ CALL(sys_timer_getoverrun) ++ CALL(sys_timer_delete) ++ CALL(sys_clock_settime) ++ CALL(sys_clock_gettime) ++ CALL(sys_clock_getres) ++/* 265 */ CALL(sys_clock_nanosleep) ++ CALL(sys_statfs64) ++ CALL(sys_fstatfs64) ++ CALL(sys_tgkill) ++ CALL(sys_utimes) ++/* 270 */ CALL(sys_fadvise64_64_wrapper) ++ CALL(sys_pciconfig_iobase) ++ CALL(sys_pciconfig_read) ++ CALL(sys_pciconfig_write) ++ CALL(sys_mq_open) ++/* 275 */ CALL(sys_mq_unlink) ++ CALL(sys_mq_timedsend) ++ CALL(sys_mq_timedreceive) ++ CALL(sys_mq_notify) ++ CALL(sys_mq_getsetattr) ++/* 280 */ CALL(sys_waitid) ++ CALL(sys_add_key) ++ CALL(sys_request_key) ++ CALL(sys_keyctl) ++ CALL(sys_ioprio_set) ++/* 285 */ CALL(sys_ioprio_get) ++ CALL(sys_inotify_init) ++ CALL(sys_inotify_add_watch) ++ CALL(sys_inotify_rm_watch) ++ CALL(sys_migrate_pages) ++/* 290 */ CALL(sys_openat) ++ CALL(sys_mkdirat) ++ CALL(sys_mknodat) ++ CALL(sys_fchownat) ++ CALL(sys_futimesat) ++/* 295 */ CALL(sys_fstatat64) ++ CALL(sys_unlinkat) ++ CALL(sys_renameat) ++ CALL(sys_linkat) ++ CALL(sys_symlinkat) ++/* 300 */ CALL(sys_readlinkat) ++ CALL(sys_fchmodat) ++ CALL(sys_faccessat) ++ CALL(sys_pselect6) /* sys_pselect6 */ ++ CALL(sys_ppoll) /* sys_ppoll */ ++/* 305 */ CALL(sys_unshare) ++ CALL(sys_set_robust_list) ++ CALL(sys_get_robust_list) ++ CALL(sys_splice) ++ CALL(sys_sync_file_range2) ++/* 310 */ CALL(sys_tee) ++ CALL(sys_vmsplice) ++ CALL(sys_move_pages) ++ CALL(sys_fadvise64) ++ CALL(sys_utimensat) ++/* 315 */ CALL(sys_signalfd) ++ CALL(sys_timerfd_create) ++ CALL(sys_eventfd) ++ CALL(sys_fallocate) ++ CALL(sys_timerfd_settime) ++/* 320 */ CALL(sys_timerfd_gettime) ++ CALL(sys_getcpu) ++ CALL(sys_signalfd4) ++ CALL(sys_eventfd2) ++ CALL(sys_epoll_create1) ++/* 325 */ CALL(sys_dup3) ++ CALL(sys_pipe2) ++ CALL(sys_inotify_init1) ++ CALL(sys_kexec_load) ++ CALL(sys_accept) ++/* 330 */ CALL(sys_bind) ++ CALL(sys_connect) ++ CALL(sys_getpeername) ++ CALL(sys_getsockname) ++ CALL(sys_getsockopt) ++/* 335 */ CALL(sys_listen) ++ CALL(sys_recv) ++ CALL(sys_recvfrom) ++ CALL(sys_recvmsg) ++ CALL(sys_send) ++/* 340 */ CALL(sys_sendmsg) ++ CALL(sys_sendto) ++ CALL(sys_setsockopt) ++ CALL(sys_shutdown) ++ CALL(sys_socket) ++/* 345 */ CALL(sys_socketpair) ++ CALL(sys_prlimit64) ++ CALL(sys_accept4) ++ CALL(sys_recvmmsg) ++ CALL(sys_sendmmsg) ++/* 350 */ CALL(sys_fanotify_init) ++ CALL(sys_fanotify_mark) ++ CALL(sys_msgget) ++ CALL(sys_msgctl) ++ CALL(sys_msgrcv) ++/* 355 */ CALL(sys_msgsnd) ++ CALL(sys_semget) ++ CALL(sys_semctl) ++ CALL(sys_semtimedop) ++ CALL(sys_semop) ++/* 360 */ CALL(sys_shmget) ++ CALL(sys_shmctl) ++ CALL(sys_shmat) ++ CALL(sys_shmdt) ++ CALL(sys_syncfs) ++/* 365 */ CALL(sys_setns) ++ CALL(sys_name_to_handle_at) ++ CALL(sys_open_by_handle_at) ++ CALL(sys_process_vm_readv) ++ CALL(sys_process_vm_writev) ++/* 370 */ CALL(sys_clock_adjtime) ++ CALL(sys_get_mempolicy) ++ CALL(sys_mbind) ++ CALL(sys_perf_event_open) ++ CALL(sys_preadv) ++/* 375 */ CALL(sys_pwritev) ++ CALL(sys_rt_tgsigqueueinfo) ++ CALL(sys_set_mempolicy) ++ CALL(sys_epoll_pwait) ++ ++#ifndef syscalls_counted ++.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls ++#define syscalls_counted ++#endif ++ .rept syscalls_padding ++ CALL(sys_ni_syscall) ++ .endr +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/early_printk.c linux-3.4.110/arch/nds32/kernel/early_printk.c +--- linux-3.4.110.orig/arch/nds32/kernel/early_printk.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/early_printk.c 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,126 @@ ++/* ++ * Earlyprintk support. ++ * ++ * Copyright (C) 2012 ARM Ltd. ++ * Author: Catalin Marinas <catalin.marinas@arm.com> ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <http://www.gnu.org/licenses/>. ++ */ ++#include <linux/kernel.h> ++#include <linux/console.h> ++#include <linux/init.h> ++#include <linux/string.h> ++#include <linux/mm.h> ++#include <linux/io.h> ++ ++#include <linux/serial_reg.h> ++#include <asm/setup.h> ++ ++extern void __iomem *early_io_map(phys_addr_t phys); ++static void __iomem *early_base; ++static void (*printch) (char ch); ++ ++/* ++ * 8250/16550 (8-bit aligned registers) single character TX. ++ */ ++static void uart8250_8bit_printch(char ch) ++{ ++ while (!(readb(early_base + UART_LSR) & UART_LSR_THRE)) ; ++ writeb(ch, early_base + UART_TX); ++} ++ ++/* ++ * 8250/16550 (32-bit aligned registers) single character TX. ++ */ ++static void uart8250_32bit_printch(char ch) ++{ ++ while (!(readl(early_base + (UART_LSR << 2)) & UART_LSR_THRE)) ; ++ writel(ch, early_base + (UART_TX << 2)); ++} ++ ++struct earlycon_match { ++ const char *name; ++ void (*printch) (char ch); ++}; ++ ++static const struct earlycon_match earlycon_match[] __initconst = { ++ {.name = "uart8250-8bit",.printch = uart8250_8bit_printch,}, ++ {.name = "uart8250-32bit",.printch = uart8250_32bit_printch,}, ++ {} ++}; ++ ++static void early_write(struct console *con, const char *s, unsigned n) ++{ ++ while (n-- > 0) { ++ if (*s == '\n') ++ printch('\r'); ++ printch(*s); ++ s++; ++ } ++} ++ ++static struct console early_console_dev = { ++ .name = "earlycon", ++ .write = early_write, ++ .flags = CON_PRINTBUFFER | CON_BOOT, ++ .index = -1, ++}; ++ ++/* ++ * Parse earlyprintk=... parameter in the format: ++ * ++ * <name>[,<addr>][,<options>] ++ * ++ * and register the early console. It is assumed that the UART has been ++ * initialised by the bootloader already. ++ */ ++static int __init setup_early_printk(char *buf) ++{ ++ const struct earlycon_match *match = earlycon_match; ++ phys_addr_t paddr = 0; ++ ++ if (!buf) { ++ pr_warning("No earlyprintk arguments passed.\n"); ++ return 0; ++ } ++ ++ while (match->name) { ++ size_t len = strlen(match->name); ++ if (!strncmp(buf, match->name, len)) { ++ buf += len; ++ break; ++ } ++ match++; ++ } ++ if (!match->name) { ++ pr_warning("Unknown earlyprintk arguments: %s\n", buf); ++ return 0; ++ } ++ ++ /* I/O address */ ++ if (!strncmp(buf, ",0x", 3)) { ++ char *e; ++ paddr = simple_strtoul(buf + 1, &e, 16); ++ buf = e; ++ } ++ ++ if (paddr) ++ early_base = early_io_map(paddr); ++ printch = match->printch; ++ //early_console = &early_console_dev; ++ register_console(&early_console_dev); ++ ++ return 0; ++} ++ ++early_param("earlyprintk", setup_early_printk); +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/elfchk.c linux-3.4.110/arch/nds32/kernel/elfchk.c +--- linux-3.4.110.orig/arch/nds32/kernel/elfchk.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/elfchk.c 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,190 @@ ++#include <linux/module.h> ++#include <linux/kallsyms.h> ++#include <asm/hardware.h> ++#include <asm/uaccess.h> ++#include <asm/elf.h> ++#include <asm/fpu.h> ++#include <asm/audio.h> ++#include <linux/elf.h> ++#include <linux/proc_fs.h> ++ ++#define ELF_CHECKING_OS ++#include "nds32-elf.h" ++ ++extern struct proc_dir_entry *proc_dir_cpu; ++ ++#ifdef CONFIG_ELFCHK_DEFAULT_ENABLE ++static int elf_check_en = 1; ++#else ++static int elf_check_en = 0; ++#endif ++ ++struct reg_struct { ++ ++ const char *name; ++ int idx; ++}; ++ ++static struct reg_struct regs[] = { ++ ++ {"cpu_ver", CPU_SR_INDEX(0, 0, 0)}, ++ {"icm_cfg", CPU_SR_INDEX(0, 1, 0)}, ++ {"dcm_cfg", CPU_SR_INDEX(0, 2, 0)}, ++ {"mmu_cfg", CPU_SR_INDEX(0, 3, 0)}, ++ {"msc_cfg", CPU_SR_INDEX(0, 4, 0)}, ++#ifdef CONFIG_FPU ++ {"fucop_exist", CPU_SR_INDEX(0, 5, 0)} ++#endif ++}; ++ ++#ifdef CONFIG_FPU ++static unsigned int read_fpu_fpcfg(void) ++{ ++ unsigned int fpcfg = 0; ++ ++ enable_fpu(); ++ asm volatile ("fmfcfg %0\n\t":"=&r" (fpcfg)); ++ disable_fpu(); ++ ++ return fpcfg; ++} ++#endif ++ ++static unsigned int read_cpu_sr(unsigned int idx) ++{ ++ switch (idx) { ++ ++ case CPU_SR_INDEX(0, 0, 0): ++ return GET_CPU_VER(); ++ case CPU_SR_INDEX(0, 1, 0): ++ return GET_ICM_CFG(); ++ case CPU_SR_INDEX(0, 2, 0): ++ return GET_DCM_CFG(); ++ case CPU_SR_INDEX(0, 3, 0): ++ return GET_MMU_CFG(); ++ case CPU_SR_INDEX(0, 4, 0): ++ return GET_MSC_CFG(); ++ case CPU_SR_INDEX(0, 5, 0): ++ return GET_FUCOP_EXIST(); ++ ++ default: ++ printk(KERN_ERR ++ "%s: invalid system register index (%d, %d, %d)\n", ++ __func__, (idx >> 7) & 0x7, (idx >> 3) & 0xf, idx & 0x7); ++ ++ return SR_NOT_EXIST; ++ } ++} ++ ++static unsigned int reg_read_callback(unsigned int idx) ++{ ++ if (HW_IS_CPU(idx)) { ++ ++ return read_cpu_sr(SR_INDEX(idx)); ++ } else if (HW_IS_FPU(idx)) { ++ ++#ifdef CONFIG_FPU ++ if (SR_FPU_FPCFG == SR_INDEX(idx)) ++ return read_fpu_fpcfg(); ++ else ++ return SR_NOT_EXIST; ++#endif ++ } else if (HW_IS_AUDIO(idx)) { ++ ++ return SR_NOT_EXIST; ++ } ++ ++ return SR_NOT_EXIST; ++} ++ ++#define BUFLEN 1024 ++ ++int do_elf_check_arch(const struct elf32_hdr *hdr) ++{ ++ static char msg_buf[BUFLEN]; ++ unsigned int err; ++ int buf_status = 0; ++ ++ if (!elf_check_en) ++ return 1; ++ ++ err = ++ elf_check((void *)hdr, reg_read_callback, msg_buf, BUFLEN, ++ &buf_status); ++ ++ if (err) ++ printk(KERN_WARNING "%s", msg_buf); ++ ++ return !err; ++} ++ ++static int proc_elf_check_read(char *page, char **start, off_t off, int count, ++ int *eof, void *data) ++{ ++ return sprintf(page, "%d\n", elf_check_en); ++} ++ ++#define INPUTLEN 10 ++static int proc_elf_check_write(struct file *file, const char __user * buffer, ++ unsigned long count, void *data) ++{ ++ unsigned long en; ++ char inbuf[INPUTLEN]; ++ ++ if (count > INPUTLEN - 1) ++ count = INPUTLEN - 1; ++ ++ if (copy_from_user(inbuf, buffer, count)) ++ return -EFAULT; ++ ++ inbuf[count] = '\0'; ++ ++ if (!sscanf(inbuf, "%lu", &en) || en > 3) ++ return -EFAULT; ++ ++ elf_check_en = en & 0x01; ++ ++ return count; ++} ++ ++static int proc_elf_check_read_reg(char *page, char **start, ++ off_t off, int count, int *eof, void *data) ++{ ++ unsigned long val = read_cpu_sr(*(int *)data); ++ ++ return sprintf(page, "0x%08lx\n", val); ++} ++ ++int __init elf_check_init(void) ++{ ++ static struct proc_dir_entry *res_elf_check; ++ int i; ++ ++ if (!proc_dir_cpu) { ++ if (!(proc_dir_cpu = proc_mkdir("cpu", NULL))) ++ return -ENOMEM; ++ } ++ ++ res_elf_check = ++ create_proc_entry("elf_core_checking", S_IWUSR | S_IRUGO, ++ proc_dir_cpu); ++ if (!res_elf_check) ++ return -ENOMEM; ++ ++ res_elf_check->read_proc = proc_elf_check_read; ++ res_elf_check->write_proc = proc_elf_check_write; ++ ++ for (i = 0; i < ARRAY_SIZE(regs); i++) { ++ ++ if (!create_proc_read_entry(regs[i].name, S_IWUSR | S_IRUGO, ++ proc_dir_cpu, ++ proc_elf_check_read_reg, ++ ®s[i].idx)) ++ ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++module_init(elf_check_init); +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/ex-entry.S linux-3.4.110/arch/nds32/kernel/ex-entry.S +--- linux-3.4.110.orig/arch/nds32/kernel/ex-entry.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/ex-entry.S 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,294 @@ ++#include <linux/linkage.h> ++#include <asm/memory.h> ++#include <asm/nds32.h> ++#include <asm/assembler.h> ++#include <asm/errno.h> ++#include <asm/asm-offsets.h> ++#include <asm/page.h> ++ ++ .macro push_zol ++#ifdef CONFIG_HWZOL ++ mfusr $r10, $LB ++ mfusr $r11, $LE ++ mfusr $r12, $LC ++#endif ++ .endm ++ .macro save_user_regs ++ /* $p1 is VA of percpu data */ ++ sethi $p0, hi20(PAGE_OFFSET - PHYS_OFFSET) ++ add $p1, $p1, $p0 ++ ++ /* change to kernel stack */ ++ mfsr $p0, $IPSW ++ andi $p0, $p0, #PSW_mskPOM ++ cmovz $sp, $r25, $p0 ++ ++ /* 8 byte aligned */ ++ movi $r25, #~7 ++ and $r25, $sp, $r25 ++ smw.adm $sp, [$r25], $sp, #0x1 ++ move $sp, $r25 ++ ++#if defined(CONFIG_FPU) || defined(CONFIG_AUDIO) ++ mfsr $r25, $FUCOP_CTL ++ push $r25 ++ bclr $r25, $r25, #FUCOP_CTL_offCP0EN ++ mtsr $r25, $FUCOP_CTL ++#else ++ addi $sp, $sp, -4 ++#endif ++ pushm $r28, $r30 ++ ++ /* zero fp if user mode*/ ++ movi $r25, #0x0 ++ cmovz $fp, $r25, $p0 ++ ++ lwi $r25, [$p1+#0x0] ++ pushm $r0, $r25 ++#ifdef CONFIG_HWZOL ++ push_zol ++#endif ++ mfsr $r9, $P_P1 ++ mfsr $r8, $P_P0 ++ mfsr $r7, $P_IPC ++ mfsr $r6, $P_IPSW ++ mfsr $r18, $IPC ++ mfsr $r17, $IPSW ++ mfsr $r16, $PSW ++ pushm $r6, $r13 ++ push $r0 ++ lwi $p0, [$p1+#0x8] ++ push $p0 ++ pushm $r16, $r18 ++ ++ andi $r19, $r16, #PSW_mskINTL ++ slti $r20, $r19, #4 ++ bnez $r20, 1f ++ addi $r21, $r16, #-2 ++ mtsr $r21, $PSW ++ isb ++1: ++ addi $sp, $sp, -S_OFF ++ .endm ++ ++ .text ++ ++/* ++ * Exception Vector ++ */ ++exception_handlers: ++ .long unhandled_exceptions !Reset/NMI ++ .long unhandled_exceptions !TLB fill ++ .long do_page_fault !PTE not present ++ .long do_dispatch_tlb_misc !TLB misc ++ .long unhandled_exceptions !TLB VLPT ++ .long unhandled_exceptions !Machine Error ++ .long do_debug_trap !Debug related ++ .long do_dispatch_general !General exception ++ .long eh_syscall !Syscall ++ .long asm_do_IRQ !IRQ ++ ++common_exception_handler: ++ save_user_regs ++ lwi $p0, [$p1+#0x4] ++ andi $p1, $p0, #0x78 ++ bnez $p1, 1f ++ sethi $lp, hi20(ret_from_exception) ++ ori $lp, $lp, lo12(ret_from_exception) ++ sethi $p1, hi20(exception_handlers) ++ ori $p1, $p1, lo12(exception_handlers) ++ lw $p1, [$p1+$p0<<2] ++ move $r0, $p0 ++ mfsr $r1, $EVA ++ mfsr $r2, $ITYPE ++ move $r3, $sp ++ mfsr $r4, $OIPC ++ /* enable gie if it is enabled in IPSW. */ ++ mfsr $r21, $PSW ++ andi $r17, $r17, #0x1 ++ or $r21, $r21, $r17 ++ mtsr $r21, $PSW ++ dsb ++ jr $p1 ++ ++ /* syscall */ ++1: ++ addi $p1, $p0, #-8 ++ bnez $p1, 2f ++ sethi $lp, hi20(ret_from_exception) ++ ori $lp, $lp, lo12(ret_from_exception) ++ sethi $p1, hi20(exception_handlers) ++ ori $p1, $p1, lo12(exception_handlers) ++ lwi $p1, [$p1+#0x8<<2] ++ jr $p1 ++ ++ /* interrupt */ ++2: ++#ifdef CONFIG_TRACE_IRQFLAGS ++ jal arch_trace_hardirqs_off ++#endif ++#if defined(CONFIG_EVIC) || defined(CONFIG_IVIC) ++ addi $r0, $p0, #-9 ++#else ++# ifdef CONFIG_IVIC_INTC ++ jal get_IntSrc ++# else ++# error "Not configure Vector Interrupt Controller mode" ++# endif ++#endif ++ move $r1, $sp ++ sethi $lp, hi20(ret_from_intr) ++ ori $lp, $lp, lo12(ret_from_intr) ++ sethi $p0, hi20(exception_handlers) ++ ori $p0, $p0, lo12(exception_handlers) ++ lwi $p0, [$p0+#0x9<<2] ++ jr $p0 ++ ++ .macro EXCEPTION_VECTOR, num ++ .align 6 ++ .ifc \num, 6 ++ mfsr $p0, $EDM_CTL ++ andi $p0, $p0, EDM_CTL_mskV3_EDM_MODE ++ tnez $p0, 0x1a ++ .endif ++ /* $p1 is PA of percpu data */ ++#ifdef CONFIG_CPU_N1213_43U1HA0 ++ movi $p1, #0x0 ++#else ++ mfsr $p1, $CORE_ID ++#endif ++ slli $p1, $p1, #0x9 ++ li $p0, #(PHYS_OFFSET+0x6000) ++ or $p1, $p1, $p0 ++ ++ /* ++ * 0x0 saved $r25 ++ * 0x4 vector number ++ * 0x8 user stack pointer ++ * 0xc kernel stack pointer ++ */ ++ swi $r25, [$p1+0x0] ++ movi $p0, \num ++ swi $p0, [$p1+#0x4] ++ swi $sp, [$p1+#0x8] ++ lwi $r25, [$p1+#0xc] ++ sethi $p0, hi20(common_exception_handler) ++ ori $p0, $p0, lo12(common_exception_handler) ++ jral.ton $p0, $p0 ++ .endm ++ ++ .macro IPI_VECTOR, num ++ .align 6 ++#ifdef CONFIG_CPU_N1213_43U1HA0 ++ movi $p1, #0x0 ++#else ++ mfsr $p1, $CORE_ID ++#endif ++ slli $p1, $p1, #0x9 ++ li $p0, #(PHYS_OFFSET+0x6000) ++ or $p1, $p1, $p0 ++ ++ /* ++ * 0x10 indicator of CPU is initialized ++ * 0x14 CPU init function ++ */ ++ swi $r25, [$p1+0x0] ++ movi $p0, \num ++ swi $p0, [$p1+#0x4] ++ swi $sp, [$p1+#0x8] ++ lwi $r25, [$p1+#0xc] ++ lwi $p0, [$p1+#0x10] ++ beqz $p0, 1f ++ sethi $p0, hi20(common_exception_handler) ++ ori $p0, $p0, lo12(common_exception_handler) ++ jral.ton $p0, $p0 ++1: ++ lwi $p0, [$p1+#0x14] ++ jr $p0 ++ ++ .endm ++ ++ .section ".text.init", #alloc, #execinstr ++ .global exception_vector ++exception_vector: ++ EXCEPTION_VECTOR 0 ++ EXCEPTION_VECTOR 1 ++ EXCEPTION_VECTOR 2 ++ EXCEPTION_VECTOR 3 ++ EXCEPTION_VECTOR 4 ++ EXCEPTION_VECTOR 5 ++ EXCEPTION_VECTOR 6 ++ EXCEPTION_VECTOR 7 ++ EXCEPTION_VECTOR 8 ++#ifdef CONFIG_EVIC ++ EXCEPTION_VECTOR 9 ++#else ++ IPI_VECTOR 9 ++#endif ++ EXCEPTION_VECTOR 10 ++ EXCEPTION_VECTOR 11 ++ EXCEPTION_VECTOR 12 ++ EXCEPTION_VECTOR 13 ++ EXCEPTION_VECTOR 14 ++ EXCEPTION_VECTOR 15 ++ EXCEPTION_VECTOR 16 ++ EXCEPTION_VECTOR 17 ++ EXCEPTION_VECTOR 18 ++ EXCEPTION_VECTOR 19 ++ EXCEPTION_VECTOR 20 ++ EXCEPTION_VECTOR 21 ++ EXCEPTION_VECTOR 22 ++ EXCEPTION_VECTOR 23 ++ EXCEPTION_VECTOR 24 ++ EXCEPTION_VECTOR 25 ++ EXCEPTION_VECTOR 26 ++ EXCEPTION_VECTOR 27 ++ EXCEPTION_VECTOR 28 ++ EXCEPTION_VECTOR 29 ++ EXCEPTION_VECTOR 30 ++ EXCEPTION_VECTOR 31 ++ EXCEPTION_VECTOR 32 ++ EXCEPTION_VECTOR 33 ++ EXCEPTION_VECTOR 34 ++ EXCEPTION_VECTOR 35 ++ EXCEPTION_VECTOR 36 ++ EXCEPTION_VECTOR 37 ++ EXCEPTION_VECTOR 38 ++ EXCEPTION_VECTOR 39 ++ EXCEPTION_VECTOR 40 ++#ifdef CONFIG_EVIC ++ IPI_VECTOR 41 ++#else ++ EXCEPTION_VECTOR 41 ++#endif ++ EXCEPTION_VECTOR 42 ++ EXCEPTION_VECTOR 43 ++ EXCEPTION_VECTOR 44 ++ EXCEPTION_VECTOR 45 ++ EXCEPTION_VECTOR 46 ++ EXCEPTION_VECTOR 47 ++ EXCEPTION_VECTOR 48 ++ EXCEPTION_VECTOR 49 ++ EXCEPTION_VECTOR 50 ++ EXCEPTION_VECTOR 51 ++ EXCEPTION_VECTOR 52 ++ EXCEPTION_VECTOR 53 ++ EXCEPTION_VECTOR 54 ++ EXCEPTION_VECTOR 55 ++ EXCEPTION_VECTOR 56 ++ EXCEPTION_VECTOR 57 ++ EXCEPTION_VECTOR 58 ++ EXCEPTION_VECTOR 59 ++ EXCEPTION_VECTOR 60 ++ EXCEPTION_VECTOR 61 ++ EXCEPTION_VECTOR 62 ++ EXCEPTION_VECTOR 63 ++ EXCEPTION_VECTOR 64 ++ EXCEPTION_VECTOR 65 ++ EXCEPTION_VECTOR 66 ++ EXCEPTION_VECTOR 67 ++ EXCEPTION_VECTOR 68 ++ EXCEPTION_VECTOR 69 ++ EXCEPTION_VECTOR 70 ++ EXCEPTION_VECTOR 71 ++ EXCEPTION_VECTOR 72 +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/ex-exit.S linux-3.4.110/arch/nds32/kernel/ex-exit.S +--- linux-3.4.110.orig/arch/nds32/kernel/ex-exit.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/ex-exit.S 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,220 @@ ++#include <linux/linkage.h> ++#include <asm/unistd.h> ++#include <asm/assembler.h> ++#include <asm/nds32.h> ++#include <asm/asm-offsets.h> ++#include <asm/thread_info.h> ++ ++#define why $r8 // Linux syscall (!= 0) ++#define tsk $r9 // current thread_info ++ ++ ++ .macro pop_zol ++#ifdef CONFIG_HWZOL ++ mtusr $r10, $LB ++ mtusr $r11, $LE ++ mtusr $r12, $LC ++#endif ++ .endm ++ ++ .macro restore_user_regs_first ++ setgie.d ++ isb ++ /* $p1 is VA of percpu data */ ++#ifdef CONFIG_CPU_N1213_43U1HA0 ++ movi $p1, #0x0 ++#else ++ mfsr $p1, $CORE_ID ++#endif ++ andi $p1, $p1, #0x3 ++ slli $p1, $p1, #0x9 ++ sethi $p0, #0xc0006 ++ or $p1, $p1, $p0 ++ ++ addi $sp, $sp, S_OFF ++ popm $r16, $r18 ++ mtsr $r16, $PSW ++ pop $r16 ++ swi $r16, [$p1+#0x8] ++ addi $sp, $sp, #4 !pop $r0 ++ popm $r6, $r13 ++ mtsr $r17, $IPSW ++ mtsr $r18, $IPC ++ mtsr $r6, $P_IPSW ++ mtsr $r7, $P_IPC ++ mtsr $r8, $P_P0 ++ mtsr $r9, $P_P1 ++#ifdef CONFIG_HWZOL ++ pop_zol ++#endif ++ .endm ++ ++ .macro restore_user_regs_last ++ popm $r28, $r30 ++#if defined(CONFIG_FPU) || defined(CONFIG_AUDIO) ++ pop $p0 ++ mtsr $p0, $FUCOP_CTL ++#else ++ addi $sp, $sp, 4 ++#endif ++ ++ pop $p0 ++ cmovn $sp, $p0, $p0 ++ ++ mfsr $p0, $IPSW ++ andi $p0, $p0, #PSW_mskPOM ++ bnez $p0, 1f ++ swi $sp, [$p1+#0xc] ++ lwi $sp, [$p1+#0x8] ++1: ++ // This is SW workaround for Bug #6294 ++ li $p0, 0xc0000000 ++ cctl $p0, L1D_VA_INVAL ++ lwi $p1, [$p0] ++ ++ iret ++ nop ++ ++ .endm ++ ++ .macro restore_user_regs ++ restore_user_regs_first ++ popm $r0, $r25 ++ restore_user_regs_last ++ .endm ++ ++ .macro fast_restore_user_regs ++ restore_user_regs_first ++ addi $sp, $sp, #4 ++ popm $r1, $r25 ++ restore_user_regs_last ++ .endm ++ ++#ifdef CONFIG_PREEMPT ++ .macro preempt_stop ++ .endm ++#else ++ .macro preempt_stop ++ setgie.d ++ isb ++ .endm ++#define resume_kernel no_work_pending ++#endif ++ ++ENTRY(ret_from_exception) ++ preempt_stop ++ENTRY(ret_from_intr) ++ get_thread_info tsk ++ move why, #0 ! not system call ++ ++/* ++ * judge Kernel or user mode ++ * ++ */ ++ lwi $p0, [$sp+(#S_IPSW+#S_OFF)] ++! mfsr $p0, $IPSW ! Check if in nested interrupt ++ andi $p0, $p0, #PSW_mskINTL ++ bnez $p0, resume_kernel ! done with iret ++ j resume_userspace ++ ++ ++/* ++ * This is the fast syscall return path. We do as little as ++ * possible here, and this includes saving $r0 back into the SVC ++ * stack. ++ * fixed: tsk - $r9, why - $r8, $r7 - syscall #, $r8 - syscall table pointer ++ */ ++ENTRY(ret_fast_syscall) ++ gie_disable ++ lwi $r1, [tsk+#TI_FLAGS] ++ andi $p1, $r1, #_TIF_WORK_MASK ++ bnez $p1, fast_work_pending ++ fast_restore_user_regs ! iret ++ ++/* ++ * Ok, we need to do extra processing, ++ * enter the slow path returning from syscall, while pending work. ++ */ ++fast_work_pending: ++ swi $r0, [$sp+(#S_R0+#S_OFF)] ! what is different from ret_from_exception ++ ! addi $sp, $sp, S_OFF ++ move why, #1 ! come from a syscall ++work_pending: ++ andi $p1, $r1, #_TIF_NEED_RESCHED ++ bnez $p1, work_resched ++ ++ andi $p1, $r1, #_TIF_SIGPENDING|#_TIF_NOTIFY_RESUME ++ beqz $p1, no_work_pending ++ ++ move $r0, $sp ! 'regs' ++ move $r2, why ++ gie_enable ++ bal do_notify_resume ++ ++ b ret_slow_syscall ! return from slow_restore_user_regs ++ ++work_resched: ++ bal schedule ! path, return to user mode ++ ++/* ++ * "slow" syscall return path. ++ * "why" tells us if this was a real syscall. ++ */ ++ENTRY(resume_userspace) ++ENTRY(ret_slow_syscall) ++ gie_disable ++ lwi $p0, [$sp+(#S_IPSW+#S_OFF)] ++! mfsr $p0, $IPSW ! Check if in nested interrupt ++ andi $p0, $p0, #PSW_mskINTL ++ bnez $p0, no_work_pending ! done with iret ++ lwi $r1, [tsk+#TI_FLAGS] ++ andi $p1, $r1, #_TIF_WORK_MASK ++ bnez $p1, work_pending ! handle work_resched, sig_pend ++ ++no_work_pending: ++#ifdef CONFIG_TRACE_IRQFLAGS ++ lwi $p0, [$sp+(#S_IPSW+#S_OFF)] ++ andi $p0, $p0, #0x1 ++ la $r10, arch_trace_hardirqs_off ++ la $r9, arch_trace_hardirqs_on ++ cmovz $r9, $p0, $r10 ++ jral $r9 ++#endif ++ restore_user_regs ! return from iret ++ ++ ++/* ++ * preemptive kernel ++ */ ++#ifdef CONFIG_PREEMPT ++resume_kernel: ++ gie_disable ++ lwi $t0, [tsk+#TI_PREEMPT] ++ bnez $t0, no_work_pending ++need_resched: ++ lwi $t0, [tsk+#TI_FLAGS] ++ andi $p1, $t0, #_TIF_NEED_RESCHED ++ beqz $p1, no_work_pending ++ ++ lwi $t0, [$sp+(#S_IPSW+#S_OFF)] ! Interrupts off? ++ andi $t0, $t0, #1 ++ beqz $t0, no_work_pending ++ ++ jal preempt_schedule_irq ++ b need_resched ++#endif ++ ++/* ++ * This is how we return from a fork. ++ */ ++ENTRY(ret_from_fork) ++ bal schedule_tail ++ get_thread_info tsk ++ lwi $r1, [tsk+#TI_FLAGS] ! check for syscall tracing ++ move why, #1 ++ andi $p1, $r1, #_TIF_WORK_SYSCALL_LEAVE ! are we tracing syscalls? ++ beqz $p1, ret_slow_syscall ++ move $r0, $sp ++ bal syscall_trace_leave ++ b ret_slow_syscall ++ +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/ex-scall.S linux-3.4.110/arch/nds32/kernel/ex-scall.S +--- linux-3.4.110.orig/arch/nds32/kernel/ex-scall.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/ex-scall.S 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,288 @@ ++#include <linux/linkage.h> ++#include <asm/unistd.h> ++#include <asm/assembler.h> ++#include <asm/nds32.h> ++#include <asm/asm-offsets.h> ++#include <asm/thread_info.h> ++ ++/* ++ * $r0 = previous task_struct, ++ * $r1 = previous thread_info, ++ * $r2 = next thread_info ++ * previous and next are guaranteed not to be the same. ++ */ ++ ++ENTRY(_switch) ++ smw.adm $r6, [$sp], $r14, #0xa ++ swi $sp, [$r1+ TI_SP_SAVE] /* Save $sp to task structure */ ++ lwi $sp, [$r2+ TI_SP_SAVE] /* Get $sp from task structure */ ++ lmw.bim $r6, [$sp], $r14, #0xa ++ ret ++ ++/* ++ * These are the registers used in the syscall handler, and allow us ++ * to have in theory up to 6 arguments to a function - $r0 to $r5. ++ * $r7 is reserved for the system call number for Andes architecture. ++ * ++ * Note that tbl == why is intentional. ++ * We must set at least "tsk" and "why" when calling ret_with_reschedule. ++ */ ++#define tbl $r8 // syscall table pointer ++#define why $r8 // Linux syscall (!= 0) ++#define tsk $r9 // current thread_info ++ ++/* ++ * Get the system call number. let $r7 take a system call nr. ++ * ++ * if it is called from library function, $r7 is filled by library call ++ * when user program make a system call. and swid bitfield of $ir6 will ++ * always be encoded as 0x7fff. ++ * ++ * if it is called from kernel code, $r7 will be writen as syscall nr ++ * by retrieving from $ir6 'swid' bitfiled ++ */ ++ .macro get_scno ++ mfsr $r7, $ITYPE ++#ifdef CONFIG_PLAT_QEMU ++ slli $r7, $r7, #1 ++ srli $r7, $r7, #ITYPE_offSWID+1 ++#else ++ srli $r7, $r7, #ITYPE_offSWID ++#endif ++ .endm ++ ++ .macro updateipc ++ addi $r17, $r18, #4 ++ swi $r17, [$sp + S_OFF + S_IPC] ++ .endm ++ ++ .equ NR_syscalls,0 ++#define CALL(x) .equ NR_syscalls,NR_syscalls+1 ++#include "calls.S" ++#undef CALL ++#define CALL(x) .long x ++ ++ENTRY(eh_syscall) ++ updateipc ++ ++ get_scno ++ gie_enable ++ get_thread_info tsk ++ lwi $p0, [tsk+#TI_FLAGS] ! check for syscall tracing ++ ++ andi $p1, $p0, #_TIF_WORK_SYSCALL_ENTRY ! are we tracing syscalls? ++ bnez $p1, __sys_trace ++ ++ la $lp, ret_fast_syscall ! return address ++ ++ li $p0, __NR_NDS32_BASE ++ addi $p0, $p0, -1 ++ slt $p0, $p0, $r7 ++ beqz $p0, 1f ++ addi $r1, $SP, #0 ++ move $r0, $r7 ++ b nds32_syscall ++1: ++ ! check upper syscall limit, ++ andi $r7, $r7, #0xfff ++ addi $p1, $r7, #-NR_syscalls ! syscall number of syscall instruction is guarded by addembler ++ bgez $p1, _SCNO_EXCEED ! call sys_* routine ++ la tbl, sys_call_table ! load syscall table pointer ++ slli $p1, $r7, #2 ++ add $p1, tbl, $p1 ++ lwi $p1, [$p1] ++ jr $p1 ! no return ++ ++_SCNO_EXCEED: ++ ori $r0, $r7, #0 ++ ori $r1, $sp, #0 ++ b bad_syscall ++ ++/* ++ * This is the really slow path. We're going to be doing ++ * context switches, and waiting for our parent to respond. ++ */ ++__sys_trace: ++ move $r1, $sp ++ move $r0, $r7 ! trace entry [IP = 0] ++ bal syscall_trace_enter ++ move $r7, $r0 ++ la $lp, __sys_trace_return ! return address ++ ++ li $p0, __NR_NDS32_BASE ++ addi $p0, $p0, -1 ++ slt $p0, $p0, $r7 ++ beqz $p0, 1f ++ addi $r1, $SP, #0 ++ b nds32_syscall ++1: ++ andi $r7, $r7, #0xfff ++ addi $p1, $sp, #S_R0+S_OFF ! pointer to regs ++ addi $p0, $r7, -#NR_syscalls ! check upper syscall limit ++ bgez $p0, _SCNO_EXCEED ++ lmw.bi $r0, [$p1], $r5 ! have to reload $r0 - $r5 ++ ++ slli $p0, $r7, #2 ! call sys_* routine ++ la tbl, sys_call_table ! load syscall table pointer ++ add $p0, tbl, $p0 ++ lwi $p0, [$p0] ++ jr $p0 ++ ++__sys_trace_return: ++ swi $r0, [$sp+(#S_R0+S_OFF)] ! T: save returned $r0 ++ bal syscall_trace_leave ++ b ret_slow_syscall ++ ++ .type sys_call_table, #object ++ENTRY(sys_call_table) ++#include "calls.S" ++ ++/* ++ * Special system call wrappers ++ * ++ * $r0 = syscall number ++ * $r8 = syscall table ++ */ ++ .type sys_syscall, #function ++sys_syscall: ++ ++ li $p0, __NR_NDS32_BASE ++ addi $p0, $p0, -1 ++ slt $p0, $p0, $r0 ++ beqz $p0, 1f ++ addi $r1, $SP, #0 ++ b nds32_syscall ++1: ++ bltz $r0, 3f ! Guard whether syscall number is between 0~0x7fff. ++ andi $r0, $r0, #0xfff ++ addi $p1, $r0, #-NR_syscalls ++ bgtz $p1, 3f ++ move $p1, $r0 ++ move $r0, $r1 ++ move $r1, $r2 ++ move $r2, $r3 ++ move $r3, $r4 ++ move $r4, $r5 ++! add for syscall 6 args ++ lwi $r5, [$sp + (#S_SP + #S_OFF) ] ++ lwi $r5, [$r5 + #S_OFF] ++! ~add for syscall 6 args ++ ++ lw $p1, [tbl+$p1<<2] ++ jr $p1 ++3: b sys_ni_syscall ++ ++sys_fork_wrapper: ++ addi $r0, $sp, #0 ++ b sys_fork ++ ++sys_vfork_wrapper: ++ addi $r0, $sp, #0 ++ b sys_vfork ++ ++sys_execve_wrapper: ++ addi $r3, $sp, #0 ++ b sys_execve ++ ++sys_clone_wrapper: ++ addi $r5, $SP, #0 ++ b sys_clone ++ ++sys_sigsuspend_wrapper: ++ addi $r3, $sp, #0 ++ b sys_sigsuspend ++ ++sys_rt_sigsuspend_wrapper: ++ addi $r2, $sp, #0 ++ b sys_rt_sigsuspend ++ ++sys_sigreturn_wrapper: ++ addi $r0, $sp, #0 ++ b sys_sigreturn ++ ++sys_rt_sigreturn_wrapper: ++ addi $r0, $sp, #0 ++ b sys_rt_sigreturn ++ ++sys_sigaltstack_wrapper: ++ lwi $r2, [$sp+(#S_OFF + S_SP)] ++ b do_sigaltstack ++ ++sys_futex_wrapper: ++ b sys_futex ++ ++#ifdef CONFIG_FUNCTION_TRACER ++ .global _mcount ++ .global ftrace_stub ++_mcount: ++ sethi $r15, hi20(function_trace_stop) ++ lwi $r15, [$r15 + lo12(function_trace_stop)] ++ bnez $r15, _ftrace_stub ++ ++ sethi $r15, hi20(ftrace_trace_function) ++ lwi $p0, [$r15 + lo12(ftrace_trace_function)] ++ sethi $r15, hi20(ftrace_stub) ++ ori $r15, $r15, lo12(ftrace_stub) ++ bne $r15, $p0, trace ++ ++#ifdef CONFIG_FUNCTION_GRAPH_TRACER ++ sethi $p0, hi20(ftrace_graph_return) ++ lwi $p0, [$p0 + lo12(ftrace_graph_return)] ++ bne $r15, $p0, _ftrace_graph_caller ++ ++ sethi $r15, hi20(ftrace_graph_entry) ++ lwi $r15, [$r15 + lo12(ftrace_graph_entry)] ++ sethi $p0, hi20(ftrace_graph_entry_stub) ++ ori $p0, $p0, lo12(ftrace_graph_entry_stub) ++ bne $r15, $p0, _ftrace_graph_caller ++#endif ++ ++_ftrace_stub: ++ftrace_stub: ++ ret ++ ++trace: ++ smw.adm $r0, [$sp], $r5, #10 ++ move $r0, $lp ++ sethi $r15, hi20(get_selfpc) ++ ori $r15, $r15, lo12(get_selfpc) ++ jral $r15 ++ move $r1, $r0 ++ lwi $r0, [$sp+36] ++ jral $p0 ++ lmw.bim $r0, [$sp], $r5, #10 ++ ret ++#endif ++ ++#ifdef CONFIG_FUNCTION_GRAPH_TRACER ++ .global ftrace_graph_caller ++ .global return_to_handler ++_ftrace_graph_caller: ++ftrace_graph_caller: ++ sethi $p1, hi20(function_trace_stop) ++ lwi $p1, [$p1 + lo12(function_trace_stop)] ++ bnez $p1, ftrace_stub ++ ++ sethi $p1, hi20(prepare_ftrace_return) ++ ori $p1, $p1, lo12(prepare_ftrace_return) ++ ++ smw.adm $r0, [$sp], $r5, #10 ++ move $r0, $lp ++ sethi $p0, hi20(get_selfpc) ++ ori $p0, $p0, lo12(get_selfpc) ++ jral $p0 ++ move $r1, $r0 ++ addi $r0, $sp, #36 ++ jral $p1 ++ lmw.bim $r0, [$sp], $r5, #10 ++ ret ++ ++return_to_handler: ++ smw.adm $r0, [$sp], $r5, #10 ++ sethi $r15, hi20(ftrace_return_to_handler) ++ ori $r15, $r15, lo12(ftrace_return_to_handler) ++ jral $r15 ++ move $r15, $r0 ++ lmw.bim $r0, [$sp], $r5, #10 ++ jr $r15 ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/fpu.c linux-3.4.110/arch/nds32/kernel/fpu.c +--- linux-3.4.110.orig/arch/nds32/kernel/fpu.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/fpu.c 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,306 @@ ++/* ++ * arch/nds32/kernel/fpu.c ++ * ++ * Copyright (C) 2001 Manuela Cirronis, Paolo Alberelli ++ * Copyright (C) 2002 STMicroelectronics Limited ++ * Author : Stuart Menefy ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * Started from SH4 version: ++ * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka ++ * ++ * 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. ++ */ ++#include <linux/sched.h> ++#include <linux/signal.h> ++#include <asm/processor.h> ++#include <asm/user.h> ++#include <asm/io.h> ++#include <asm/bitfield.h> ++#include <asm/fpu.h> ++#include "fpu.h" ++ ++extern void do_revinsn(struct pt_regs *regs); ++extern int do_fpu_denorm(struct pt_regs *regs, struct fpu_struct *fpu); ++ ++static struct fpu_struct init_fpuregs = { ++ .fs_regs = {[0 ... 31] = sNAN32}, ++ .fd_regs = {[0 ... 15] = sNAN64}, ++ .fpcsr = FPCSR_INIT ++}; ++ ++void save_fpu(struct task_struct *tsk) ++{ ++ unsigned int fpcfg, fpcsr; ++ enable_fpu(); ++ asm volatile ("fmfcfg %0\n\t":"=&r" (fpcfg)); ++ fpcfg = ((fpcfg & FPCFG_mskFREG) >> FPCFG_offFREG); ++ ++ switch (fpcfg) { ++ case 3: ++ asm volatile ("fsdi $fd31, [%0+0xf8]\n\t" ++ "fsdi $fd30, [%0+0xf0]\n\t" ++ "fsdi $fd29, [%0+0xe8]\n\t" ++ "fsdi $fd28, [%0+0xe0]\n\t" ++ "fsdi $fd27, [%0+0xd8]\n\t" ++ "fsdi $fd26, [%0+0xd0]\n\t" ++ "fsdi $fd25, [%0+0xc8]\n\t" ++ "fsdi $fd24, [%0+0xc0]\n\t" ++ "fsdi $fd23, [%0+0xb8]\n\t" ++ "fsdi $fd22, [%0+0xb0]\n\t" ++ "fsdi $fd21, [%0+0xa8]\n\t" ++ "fsdi $fd20, [%0+0xa0]\n\t" ++ "fsdi $fd19, [%0+0x98]\n\t" ++ "fsdi $fd18, [%0+0x90]\n\t" ++ "fsdi $fd17, [%0+0x88]\n\t" ++ "fsdi $fd16, [%0+0x80]\n\t" ++ : /* no output */ ++ :"r" (&tsk->thread.fpu) ++ :"memory"); ++ /* fall through */ ++ case 2: ++ asm volatile ("fssi $fs31, [%0+0x7c]\n\t" ++ "fssi $fs30, [%0+0x78]\n\t" ++ "fssi $fs29, [%0+0x74]\n\t" ++ "fssi $fs28, [%0+0x70]\n\t" ++ "fssi $fs27, [%0+0x6c]\n\t" ++ "fssi $fs26, [%0+0x68]\n\t" ++ "fssi $fs25, [%0+0x64]\n\t" ++ "fssi $fs24, [%0+0x60]\n\t" ++ "fssi $fs23, [%0+0x5c]\n\t" ++ "fssi $fs22, [%0+0x58]\n\t" ++ "fssi $fs21, [%0+0x54]\n\t" ++ "fssi $fs20, [%0+0x50]\n\t" ++ "fssi $fs19, [%0+0x4c]\n\t" ++ "fssi $fs18, [%0+0x48]\n\t" ++ "fssi $fs17, [%0+0x44]\n\t" ++ "fssi $fs16, [%0+0x40]\n\t" ++ : /* no output */ ++ :"r" (&tsk->thread.fpu) ++ :"memory"); ++ /* fall through */ ++ case 1: ++ asm volatile ("fssi $fs15, [%0+0x3c]\n\t" ++ "fssi $fs14, [%0+0x38]\n\t" ++ "fssi $fs13, [%0+0x34]\n\t" ++ "fssi $fs12, [%0+0x30]\n\t" ++ "fssi $fs11, [%0+0x2c]\n\t" ++ "fssi $fs10, [%0+0x28]\n\t" ++ "fssi $fs9, [%0+0x24]\n\t" ++ "fssi $fs8, [%0+0x20]\n\t" ++ : /* no output */ ++ :"r" (&tsk->thread.fpu) ++ :"memory"); ++ /* fall through */ ++ case 0: ++ asm volatile ("fssi $fs7, [%1+0x1c]\n\t" ++ "fssi $fs6, [%1+0x18]\n\t" ++ "fssi $fs5, [%1+0x14]\n\t" ++ "fssi $fs4, [%1+0x10]\n\t" ++ "fssi $fs3, [%1+0xc]\n\t" ++ "fssi $fs2, [%1+0x8]\n\t" ++ "fssi $fs1, [%1+0x4]\n\t" ++ "fssi $fs0, [%1+0x0]\n\t" ++ "fmfcsr %0\n\t" ++ "swi %0, [%1+0x100]\n\t" ++ :"=&r" (fpcsr) ++ :"r"(&tsk->thread.fpu) ++ :"memory"); ++ } ++ disable_fpu(); ++} ++ ++void fpload(struct fpu_struct *fpregs) ++{ ++ unsigned int fpcfg, fpcsr; ++ enable_fpu(); ++ ++ asm volatile ("fmfcfg %0\n\t":"=&r" (fpcfg)); ++ fpcfg = ((fpcfg & FPCFG_mskFREG) >> FPCFG_offFREG); ++ ++ switch (fpcfg) { ++ case 3: ++ asm volatile ("fldi $fd31, [%0+0xf8]\n\t" ++ "fldi $fd30, [%0+0xf0]\n\t" ++ "fldi $fd29, [%0+0xe8]\n\t" ++ "fldi $fd28, [%0+0xe0]\n\t" ++ "fldi $fd27, [%0+0xd8]\n\t" ++ "fldi $fd26, [%0+0xd0]\n\t" ++ "fldi $fd25, [%0+0xc8]\n\t" ++ "fldi $fd24, [%0+0xc0]\n\t" ++ "fldi $fd23, [%0+0xb8]\n\t" ++ "fldi $fd22, [%0+0xb0]\n\t" ++ "fldi $fd21, [%0+0xa8]\n\t" ++ "fldi $fd20, [%0+0xa0]\n\t" ++ "fldi $fd19, [%0+0x98]\n\t" ++ "fldi $fd18, [%0+0x90]\n\t" ++ "fldi $fd17, [%0+0x88]\n\t" ++ "fldi $fd16, [%0+0x80]\n\t" ++ : /* no output */ ++ :"r" (fpregs)); ++ /* fall through */ ++ case 2: ++ asm volatile ("flsi $fs31, [%0+0x7c]\n\t" ++ "flsi $fs30, [%0+0x78]\n\t" ++ "flsi $fs29, [%0+0x74]\n\t" ++ "flsi $fs28, [%0+0x70]\n\t" ++ "flsi $fs27, [%0+0x6c]\n\t" ++ "flsi $fs26, [%0+0x68]\n\t" ++ "flsi $fs25, [%0+0x64]\n\t" ++ "flsi $fs24, [%0+0x60]\n\t" ++ "flsi $fs23, [%0+0x5c]\n\t" ++ "flsi $fs22, [%0+0x58]\n\t" ++ "flsi $fs21, [%0+0x54]\n\t" ++ "flsi $fs20, [%0+0x50]\n\t" ++ "flsi $fs19, [%0+0x4c]\n\t" ++ "flsi $fs18, [%0+0x48]\n\t" ++ "flsi $fs17, [%0+0x44]\n\t" ++ "flsi $fs16, [%0+0x40]\n\t" ++ : /* no output */ ++ :"r" (fpregs)); ++ /* fall through */ ++ case 1: ++ asm volatile ("flsi $fs15, [%0+0x3c]\n\t" ++ "flsi $fs14, [%0+0x38]\n\t" ++ "flsi $fs13, [%0+0x34]\n\t" ++ "flsi $fs12, [%0+0x30]\n\t" ++ "flsi $fs11, [%0+0x2c]\n\t" ++ "flsi $fs10, [%0+0x28]\n\t" ++ "flsi $fs9, [%0+0x24]\n\t" ++ "flsi $fs8, [%0+0x20]\n\t" ++ : /* no output */ ++ :"r" (fpregs)); ++ /* fall through */ ++ case 0: ++ asm volatile ("flsi $fs7, [%1+0x1c]\n\t" ++ "flsi $fs6, [%1+0x18]\n\t" ++ "flsi $fs5, [%1+0x14]\n\t" ++ "flsi $fs4, [%1+0x10]\n\t" ++ "flsi $fs3, [%1+0xc]\n\t" ++ "flsi $fs2, [%1+0x8]\n\t" ++ "flsi $fs1, [%1+0x4]\n\t" ++ "flsi $fs0, [%1+0x0]\n\t" ++ "lwi %0, [%1+0x100]\n\t" ++ "fmtcsr %0\n\t":"=&r" (fpcsr) ++ :"r"(fpregs)); ++ } ++ disable_fpu(); ++} ++ ++void do_fpu_context_switch(unsigned long error_code, struct pt_regs *regs) ++{ ++ /* Enable to use FPU. */ ++ ++ if (!user_mode(regs)) { ++ printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); ++ BUG(); ++ return; ++ } ++ ++ grab_fpu(regs); ++#ifndef CONFIG_UNLAZY_FPU //Lazy FPU is used ++ if (last_task_used_math == current) ++ return; ++ if (last_task_used_math != NULL) ++ /* Other processes fpu state, save away */ ++ save_fpu(last_task_used_math); ++ last_task_used_math = current; ++#endif ++ if (used_math()) { ++ fpload(¤t->thread.fpu); ++ } else { ++ /* First time FPU user. */ ++ fpload(&init_fpuregs); ++ set_used_math(); ++ } ++ ++} ++ ++void do_fpu_exception(unsigned long error_code, struct pt_regs *regs) ++{ ++ unsigned int subtype = ++ ((GET_ITYPE() & ITYPE_mskSTYPE) >> ITYPE_offSTYPE); ++ unsigned int cpid = ((GET_ITYPE() & ITYPE_mskCPID) >> ITYPE_offCPID); ++ ++ /* FPU */ ++ if ((cpid == 0) && (GET_FUCOP_EXIST() & FUCOP_EXIST_mskCP0ISFPU)) { ++ /* Coprocessor disabled exception */ ++ if (subtype == 1) { ++ preempt_disable(); ++ do_fpu_context_switch(error_code, regs); ++ preempt_enable(); ++ } ++ /* Coprocessor exception */ ++ else if (subtype == 2) { ++ siginfo_t si = { 0 }; ++ unsigned int fpcsr; ++ enable_fpu(); ++ asm volatile ("fmfcsr %0\n\t":"=&r" (fpcsr)); ++ disable_fpu(); ++ ++ if (fpcsr & FPCSR_mskALLT) { ++ si.si_signo = SIGFPE; ++ /* Exception handling, denorm input, UDF and OVF */ ++ if (fpcsr & FPCSR_mskDNIT) { ++ unsigned int rfpcsr; ++ lose_fpu(1); ++ si.si_signo = ++ do_fpu_denorm(regs, ++ ¤t->thread.fpu); ++ own_fpu(1); ++ ++ if (si.si_signo == SIGFPE) { ++ rfpcsr = ++ current->thread.fpu.fpcsr; ++ ++ if (rfpcsr & FPCSR_mskIVO) ++ si.si_code = FPE_FLTINV; ++ if (rfpcsr & FPCSR_mskDBZ) ++ si.si_code = FPE_FLTDIV; ++ if (rfpcsr & FPCSR_mskOVF) ++ si.si_code = FPE_FLTOVF; ++ if (rfpcsr & FPCSR_mskUDF) ++ si.si_code = FPE_FLTUND; ++ if (rfpcsr & FPCSR_mskIEX) ++ si.si_code = FPE_FLTRES; ++ } else if (si.si_code == SIGILL) ++ show_regs(regs); ++ else if (si.si_code == SIGBUS) ++ si.si_code = BUS_ADRERR; ++ } else if (fpcsr & FPCSR_mskRIT) { ++ printk("Reserved Instruction\n"); ++ show_regs(regs); ++ if (!user_mode(regs)) ++ do_exit(SIGILL); ++ si.si_signo = SIGILL; ++ } else if (fpcsr & FPCSR_mskUDFT) ++ si.si_code = FPE_FLTUND; ++ else if (fpcsr & FPCSR_mskOVFT) ++ si.si_code = FPE_FLTOVF; ++ else if (fpcsr & FPCSR_mskIVOT) ++ si.si_code = FPE_FLTINV; ++ else if (fpcsr & FPCSR_mskDBZT) ++ si.si_code = FPE_FLTDIV; ++ else if (fpcsr & FPCSR_mskIEXT) ++ si.si_code = FPE_FLTRES; ++ /* If something went wrong, signal */ ++ if (si.si_signo) { ++ if (si.si_code == SIGILL) { ++ force_sig(si.si_signo, current); ++ } else { ++ si.si_addr = ++ (void __user *) ++ instruction_pointer(regs); ++ force_sig_info(si.si_signo, &si, ++ current); ++ } ++ } ++ } else { ++ printk("Bad FPU exception\n"); ++ BUG(); ++ } ++ } ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/fpu.h linux-3.4.110/arch/nds32/kernel/fpu.h +--- linux-3.4.110.orig/arch/nds32/kernel/fpu.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/fpu.h 2016-04-07 10:20:50.938080870 +0200 +@@ -0,0 +1,13 @@ ++ ++ ++/* ++ * Initially load the FPU with signalling NANS. This bit pattern ++ * has the property that no matter whether considered as single or as ++ * double precision, it still represents a signalling NAN. ++ */ ++ ++ #define sNAN64 0xFFFFFFFFFFFFFFFFULL ++ #define sNAN32 0xFFFFFFFFUL ++ ++ #define FPCSR_INIT 0x0 /* Hardware reset value */ ++ +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/ftrace.c linux-3.4.110/arch/nds32/kernel/ftrace.c +--- linux-3.4.110.orig/arch/nds32/kernel/ftrace.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/ftrace.c 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,219 @@ ++/* ++ * Code for replacing ftrace calls with jumps. ++ * ++ * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com> ++ * ++ * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box. ++ * ++ * Added function graph tracer code, taken from x86 that was written ++ * by Frederic Weisbecker, and ported to PPC by Steven Rostedt. ++ * ++ */ ++ ++#include <linux/spinlock.h> ++#include <linux/hardirq.h> ++#include <linux/uaccess.h> ++#include <linux/module.h> ++#include <linux/ftrace.h> ++#include <linux/percpu.h> ++#include <linux/init.h> ++#include <linux/list.h> ++ ++#include <asm/cacheflush.h> ++#include <asm/ftrace.h> ++ ++# define GET_ADDR(addr) (*(unsigned long *)addr) ++ ++#ifdef CONFIG_DYNAMIC_FTRACE ++static unsigned int ftrace_nop_replace(void) ++{ ++// return PPC_INST_NOP; ++ return 0; ++} ++ ++static unsigned int ++ftrace_call_replace(unsigned long ip, unsigned long addr, int link) ++{ ++ unsigned int op; ++ ++ addr = GET_ADDR(addr); ++ ++ /* if (link) set op to 'bl' else 'b' */ ++// op = create_branch((unsigned int *)ip, addr, link ? 1 : 0); ++ ++ return op; ++} ++ ++static int ++ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new) ++{ ++ unsigned int replaced; ++ ++ /* ++ * Note: Due to modules and __init, code can ++ * disappear and change, we need to protect against faulting ++ * as well as code changing. We do this by using the ++ * probe_kernel_* functions. ++ * ++ * No real locking needed, this code is run through ++ * kstop_machine, or before SMP starts. ++ */ ++ ++ /* read the text we want to modify */ ++ if (probe_kernel_read(&replaced, (void *)ip, MCOUNT_INSN_SIZE)) ++ return -EFAULT; ++ ++ /* Make sure it is what we expect it to be */ ++ if (replaced != old) ++ return -EINVAL; ++ ++ /* replace the text with the new text */ ++ if (probe_kernel_write((void *)ip, &new, MCOUNT_INSN_SIZE)) ++ return -EPERM; ++ ++ flush_icache_range(ip, ip + 8); ++ ++ return 0; ++} ++ ++int ftrace_make_nop(struct module *mod, ++ struct dyn_ftrace *rec, unsigned long addr) ++{ ++ unsigned long ip = rec->ip; ++ unsigned int old, new; ++ ++ old = ftrace_call_replace(ip, addr, 1); ++ new = ftrace_nop_replace(); ++ return ftrace_modify_code(ip, old, new); ++} ++ ++int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) ++{ ++ unsigned long ip = rec->ip; ++ unsigned int old, new; ++ ++ old = ftrace_nop_replace(); ++ new = ftrace_call_replace(ip, addr, 1); ++ return ftrace_modify_code(ip, old, new); ++} ++ ++int ftrace_update_ftrace_func(ftrace_func_t func) ++{ ++ unsigned long ip = (unsigned long)(&ftrace_call); ++ unsigned int old, new; ++ int ret; ++ ++ old = *(unsigned int *)&ftrace_call; ++ new = ftrace_call_replace(ip, (unsigned long)func, 1); ++ ret = ftrace_modify_code(ip, old, new); ++ ++ return ret; ++} ++ ++int __init ftrace_dyn_arch_init(void *data) ++{ ++ /* caller expects data to be zero */ ++ unsigned long *p = data; ++ ++ *p = 0; ++ ++ return 0; ++} ++#endif /* CONFIG_DYNAMIC_FTRACE */ ++ ++#ifdef CONFIG_FUNCTION_GRAPH_TRACER ++ ++#ifdef CONFIG_DYNAMIC_FTRACE ++extern void ftrace_graph_call(void); ++extern void ftrace_graph_stub(void); ++ ++int ftrace_enable_ftrace_graph_caller(void) ++{ ++ unsigned long ip = (unsigned long)(&ftrace_graph_call); ++ unsigned long addr = (unsigned long)(&ftrace_graph_caller); ++ unsigned long stub = (unsigned long)(&ftrace_graph_stub); ++ unsigned int old, new; ++ ++ old = ftrace_call_replace(ip, stub, 0); ++ new = ftrace_call_replace(ip, addr, 0); ++ ++ return ftrace_modify_code(ip, old, new); ++} ++ ++int ftrace_disable_ftrace_graph_caller(void) ++{ ++ unsigned long ip = (unsigned long)(&ftrace_graph_call); ++ unsigned long addr = (unsigned long)(&ftrace_graph_caller); ++ unsigned long stub = (unsigned long)(&ftrace_graph_stub); ++ unsigned int old, new; ++ ++ old = ftrace_call_replace(ip, addr, 0); ++ new = ftrace_call_replace(ip, stub, 0); ++ ++ return ftrace_modify_code(ip, old, new); ++} ++#endif /* CONFIG_DYNAMIC_FTRACE */ ++int get_selfpc(unsigned long mcount_lp) ++{ ++ unsigned long symbol_size, offset; ++ kallsyms_lookup_size_offset(mcount_lp, &symbol_size, &offset); ++ return mcount_lp - offset; ++} ++ ++/* ++ * Hook the return address and push it in the stack of return addrs ++ * in current thread info. ++ */ ++void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) ++{ ++ unsigned long old; ++ int faulted; ++ struct ftrace_graph_ent trace; ++ unsigned long return_hooker = (unsigned long)&return_to_handler; ++ ++ if (unlikely(atomic_read(¤t->tracing_graph_pause))) ++ return; ++ ++ /* ++ * Protect against fault, even if it shouldn't ++ * happen. This tool is too much intrusive to ++ * ignore such a protection. ++ */ ++ asm volatile ("1: lwi %[old], [%[parent]]\n" ++ "2: swi %[return_hooker], [%[parent]]\n" ++ " movi %[faulted], 0\n" ++ "3:\n" ++ ".section .fixup, \"ax\"\n" ++ ".align 2 \n" ++ "4: movi %[faulted], 1\n" ++ " b 3b\n" ++ ".previous\n" ++ ".section __ex_table,\"a\"\n" ++ ".align 3 \n" ++ ".long 1b,4b\n" ++ ".long 2b,4b\n" ++ ".previous":[old] "=&r"(old),[faulted] "=r"(faulted) ++ :[parent] "r"(parent),[return_hooker] "r"(return_hooker) ++ :"memory"); ++ ++ if (unlikely(faulted)) { ++ ftrace_graph_stop(); ++ WARN_ON(1); ++ return; ++ } ++ ++ trace.func = self_addr; ++ trace.depth = current->curr_ret_stack + 1; ++ ++ /* Only trace if the calling function expects to */ ++ if (!ftrace_graph_entry(&trace)) { ++ *parent = old; ++ return; ++ } ++ ++ if (ftrace_push_return_trace(old, self_addr, &trace.depth, 0) == -EBUSY) { ++ *parent = old; ++ return; ++ } ++} ++#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/head.S linux-3.4.110/arch/nds32/kernel/head.S +--- linux-3.4.110.orig/arch/nds32/kernel/head.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/head.S 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,350 @@ ++/* ++ * arch/nds32/kernel/head.S ++ * ++ * NDS32 Kernel startup code ++ * ++ * Copyright (C) 2007 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++#include <linux/linkage.h> ++#include <linux/init.h> ++#include <asm/assembler.h> ++#include <asm/mach-types.h> ++#include <asm/procinfo.h> ++#include <asm/ptrace.h> ++#include <asm/asm-offsets.h> ++//#include <asm/system.h> ++#include <asm/page.h> ++#include <asm/pgtable.h> ++#include <asm/l2_cache.h> ++#include <asm/sizes.h> ++ ++/* ++ * We place the page tables 16K below TEXTADDR. Therefore, we must make sure ++ * that TEXTADDR is correctly set. Currently, we expect the least significant ++ * 16 bits to be 0x8000, but we could probably relax this restriction to ++ * TEXTADDR >= PAGE_OFFSET + 0x4000 ++ * ++ * Note that swapper_pg_dir is the virtual address of the page tables, and ++ * pgtbl gives us a position-independent reference to these tables. We can ++ * do this because _stext == TEXTADDR ++ */ ++ ++ .globl swapper_pg_dir ++ .equ swapper_pg_dir, TEXTADDR - 0x4000 ++ ++/* ++ * Kernel startup entry point. ++ * --------------------------- ++ * ++ * This is normally called from the decompressor code. The requirements ++ * are: MMU = off, D-cache = off, I-cache = dont care, $r0 = 0, ++ * $r1 = machine nr. ++ * ++ * This code is mostly position independent, so if you link the kernel at ++ * 0xc0008000, you call this at __pa(0xc0008000). ++ * ++ * See linux/arch/nds32/tools/mach-types for the complete list of machine ++ * numbers for $r1. ++ * ++ * We're trying to keep crap to a minimum; DO NOT add any machine specific ++ * crap here - that's what the boot loader (or in extreme, well justified ++ * circumstances, zImage) is for. ++ */ ++ .section ".head.text", "ax" ++ .type _stext, %function ++ENTRY(_stext) ++ setgie.d ! Disable interrupt ++ isb ++ move $r1, #MACH_TYPE_FARADAY ! Note: as far, we are in the Superuser mode ++ jal __lookup_processor_type ! get processor id, $r5=procinfo, $r9=cpuid, invalid processor $r5=0 ++ li $r2, 'p' ++ beqz $r5, __error ! yes, error 'p' ++ jal __lookup_machine_type ! $r5=machinfo ++ li $r2, 'a' ++ beqz $r5, __error ++ ++/* ++ * Create a temporary mapping area for booting, before start_kernel ++ */ ++ sethi $r4, hi20(swapper_pg_dir) ++ li $p0, (PAGE_OFFSET - PHYS_OFFSET) ++ sub $r4, $r4, $p0 ++ tlbop FlushAll ! invalidate TLB\n" ++ isb ++ mtsr $r4, $L1_PPTB ! load page table pointer\n" ++ ++/* set NTC0 cacheable/writeback, mutliple page size in use */ ++ mfsr $r3, $MMU_CTL ++ li $r0, ~0x6 ++ and $r3, $r3, $r0 ++ ori $r3, $r3, 0x404 ++ mtsr $r3, $MMU_CTL ++ isb ++ ++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH ++ li $r2, #(PHYS_OFFSET + 0x7bf) ++#else ++ li $r2, #(PHYS_OFFSET + 0x6bf) ! to remember here ++#endif ++ movi $r3, #0x5 ++ mtsr $r3, $TLB_MISC ++ ++ sethi $r3, hi20(PAGE_OFFSET) ++ li $r0, #PHYS_OFFSET ++ sethi $r5, hi20(SZ_1M) ! Use 1MB pages ++ sethi $r6, hi20(PHYS_OFFSET+SZ_32M) ! Create 32MB first, leave the rest in paging_init() ++_tlb: ++ mtsr $r3, $TLB_VPN ++ dsb ++ tlbop $r2, RWR ++ isb ++ add $r0, $r0, $r5 ++ add $r3, $r3, $r5 ++ add $r2, $r2, $r5 ++ bne $r0, $r6, _tlb ++ ++ mtsr $r3, $TLB_MISC ! setup access page size ++ li $r2, #~0xf ++ and $r3, $r3, $r2 ++#ifdef CONFIG_ANDES_PAGE_SIZE_8KB ++ ori $r3, $r3, #0x1 ++#endif ++ mtsr $r3, $TLB_MISC ++ ++ mfsr $r0, $MISC_CTL ! Enable BTB and RTP ++ li $r1, #~0x3 ++ and $r0, $r0, $r1 ++ mtsr $r0, $MISC_CTL ++ ++/* ++ * Disable L2CC and wait until L2CC registers are mapped into memory to use L2$. ++ */ ++#ifdef CONFIG_CACHE_L2 ++ li $p0, L2CC_PA_BASE ++ li $p1, 0 ++ swi $p1, [$p0 + L2CC_CTRL_OFF] ++#endif ++ ++#ifdef CONFIG_PLAT_AG102 ++/* ++ * Set GPUBA to 0x0c000006. GPUB 0x1c000000, FB size 64MB. ++ */ ++ li $p0, DDR2C_PA_BASE + 0x02a4 ++ li $p1, 0x0c000006 ++ swi $p1, [$p0] ++#endif ++ ++ mfsr $p1, $PSW ++ li $r15, #~0x43df ! clear WBNA|DME|IME|DT|IT|POM|INTL|GIE ++ and $p1, $p1, $r15 ++#ifdef __NDS32_EB__ ++ #ifdef CONFIG_WBNA ++ ori $p1, $p1, #0x40ea ! set WBNA|DT|IT|BE|POM:super|INTL:1 ++ #else ++ ori $p1, $p1, #0xea ! set ----|DT|IT|BE|POM:super|INTL:1 ++ #endif ++#else ++ #ifdef CONFIG_WBNA ++ ori $p1, $p1, #0x40ca ! set WBNA|DT|IT|--|POM:super|INTL:1 ++ #else ++ ori $p1, $p1, #0xca ! set ----|DT|IT|--|POM:super|INTL:1 ++ #endif ++#endif ++ ++ mtsr $p1, $IPSW ! when iret, it will automatically enable MMU ++ la $lp, __mmap_switched ++ mtsr $lp, $IPC ++ iret ++ nop ++ ++ .type __switch_data, %object ++__switch_data: ++ .long __mmap_switched ++ .long _sdata ! $r5 ++ .long __bss_start ! $r6 ++ .long _end ! $r7 ++ .long __machine_arch_type ! $r5 ++ .long init_thread_union + 8192 ! $sp ++ ++ ++/* ++ * The following fragment of code is executed with the MMU on in MMU mode, ++ * and uses absolute addresses; this is not position independent. ++ * ++ * $r0 ++ * $r10 = points to proc info ++ * $r8 = points to machine info, ++ * $r1 = machine ID, 0x2c8 for Andes AG101 board ++ * $r9 = processor ID of value in version register ++ */ ++ .align ++ .type __mmap_switched, %function ++__mmap_switched: ++ la $r3, __switch_data + 4 ++ lmw.bim $r5, [$r3], $r7 ++ ++ move $fp, #0 ! Clear BSS (and zero $fp) ++ beq $r7, $r6, _RRT ++1: swi.bi $fp, [$r6], #4 ++ bne $r7, $r6, 1b ++ ++_RRT: ++ lmw.bim $r4, [$r3], $r4, #0b0001 ++ sw $r1, [$r4] ! Save machine type to memory ++ b start_kernel ++ ++ ++/* ++ * Read processor ID register (CP#15, $CR0), and look up in the linker-built ++ * supported processor list. Note that we can't use the absolute addresses ++ * for the __proc_info lists since we aren't running with the MMU on ++ * (and therefore, we are not in the correct address space). We have to ++ * calculate the offset. ++ * ++ * $r9 = cpuid, get from $CPU_VER ++ * Returns: ++ * $r3, $r4, $r6 corrupted ++ * $r5 = proc_info pointer in physical address space ++ * $r9 = cpuid ++ */ ++ ++ .type __lookup_processor_type, %function ++__lookup_processor_type: ++ la $r5, __proc_info_begin ++ la $r6, __proc_info_end ++ mfsr $r9, $CPU_VER ! get cpu version ++ li $p0, (PAGE_OFFSET - PHYS_OFFSET) ++1: ++ sub $p1, $r5, $p0 ++ lmw.bi $r3, [$p1], $r4 ! value, mask ++ and $r4, $r4, $r9 ! mask wanted bits ++ xor $p1, $r3, $r4 ++ beqz $p1, 2f ++ addi $r5, $r5, #PROC_INFO_SZ ! sizeof(proc_info_list) ++ bne $r5, $r6, 1b ++ ++ move $r5, #0 ! unknown processor -> exit ++2: ret ++ ++ ++ ++/* ++ * Lookup machine architecture in the linker-build list of architectures. ++ * Note that we can't use the absolute addresses for the __arch_info ++ * lists since we aren't running with the MMU on (and therefore, we are ++ * not in the correct address space). We have to calculate the offset. ++ * ++ * $r1 = machine architecture number ++ * Returns: ++ * $r3, $r4, $r6 corrupted ++ * $r5 = mach_info pointer in physical address space ++ */ ++ .type __lookup_machine_type, %function ++__lookup_machine_type: ++ la $r5, __arch_info_begin ++ la $r6, __arch_info_end ++1: ++ li $p0, (PAGE_OFFSET - PHYS_OFFSET) ++ sub $p1, $r5, $p0 ++ lwi $r3, [$p1] ! use PA to get machine type ++ xor $p1, $r3, $r1 ! matches loader number? ++ beqz $p1, 2f ! found ++ addi $r5, $r5, #SIZEOF_MACHINE_DESC ! next machine_desc ++ bne $r5, $r6, 1b ++ move $r5, #0 ! unknown machine ++2: ret ++ ++ ++/* ++ * Exception handling. Something went wrong and we can't proceed. We ++ * ought to tell the user, but since we don't have any guarantee that ++ * we're even running on the right architecture, we do virtually nothing. ++ * ++ * a = invalid architecture ++ * p = invalid processor ++ * ++ * Generally, only serious errors cause this. ++ */ ++__error: ++ li $r1, UART0_PA_BASE ++ sw $r2, [$r1] ++die: b die ++ ++ ++ ++#ifdef CONFIG_SMP ++ ++ .type secondary_startup, %function ++ENTRY(secondary_startup) ++ /* ++ * Common entry point for secondary CPUs. ++ * ++ * Lookup the processor type - there is no need to check the ++ * machine type as it has already been validated by the ++ * primary processor. ++ */ ++ mfsr $r0, $MMU_CTL ++ ori $r0, $r0, #4 ++#ifndef CONFIG_NO_KERNEL_LARGE_PAGE ++ ori $r0, $r0, #0x400 ++#endif ++ mtsr $r0, $MMU_CTL ++ ++ movi $r15, #0x01 ++ swi $r15, [$p1+#0x10] ++ lwi $sp, [$p1+#0x18] ++ ++ /* ++ * Set stack, L1_PPTB, and enable mmu ++ */ ++ sethi $r4, hi20(swapper_pg_dir) ++ li $p0, (PAGE_OFFSET - PHYS_OFFSET) ++ sub $r4, $r4, $p0 ++ ++ tlbop FlushAll ++ isb ++ mtsr $r4, $L1_PPTB ++ ++#ifdef CONFIG_CACHE_L2 ++ li $r0, #0x1801 ++ mtsr $r0, $HSMP_SADDR ++ isb ++ li $r0, #(L2CC_PA_BASE+0x10) ! L2CC Control ++ lwi $r1, [$r0] ++ li $r2, #~(0xf << 28) ++ and $r1, $r1, $r2 ++ bset $r1, $r1, #29 ++ bset $r1, $r1, #31 ++ swi $r1, [$r0] ++#endif ++ ++ move $fp, #0 ++ ++ mfsr $p1, $PSW ++ li $r15, #~0x43df ! clear WBNA|DME|IME|DT|IT|POM|INTL|GIE ++ and $p1, $p1, $r15 ++#ifdef __NDS32_EB__ ++ #ifdef CONFIG_WBNA ++ ori $p1, $p1, #0x40ea ! set WBNA|DT|IT|BE|POM:super|INTL:1 ++ #else ++ ori $p1, $p1, #0xea ! set ----|DT|IT|BE|POM:super|INTL:1 ++ #endif ++#else ++ #ifdef CONFIG_WBNA ++ ori $p1, $p1, #0x40ca ! set WBNA|DT|IT|--|POM:super|INTL:1 ++ #else ++ ori $p1, $p1, #0xca ! set ----|DT|IT|--|POM:super|INTL:1 ++ #endif ++#endif ++ ++ mtsr $p1, $IPSW ! when iret, it will automatically enable MMU ++ la $lp, secondary_start_kernel ++ mtsr $lp, $IPC ++ iret ++ nop ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/init_task.c linux-3.4.110/arch/nds32/kernel/init_task.c +--- linux-3.4.110.orig/arch/nds32/kernel/init_task.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/init_task.c 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,25 @@ ++/* ++ * linux/arch/nds32/kernel/init_task.c ++ * ++ * Copyright (C) 2009 Andes Technology Corporation ++ */ ++#include <linux/module.h> ++#include <linux/init_task.h> ++#include <linux/mqueue.h> ++#include <linux/fs.h> ++ ++#include <asm/uaccess.h> ++ ++static struct signal_struct init_signals = INIT_SIGNALS(init_signals); ++static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); ++ ++/* Initial task structure */ ++struct task_struct init_task = INIT_TASK(init_task); ++EXPORT_SYMBOL(init_task); ++ ++/* ++ * Initial thread structure. Alignment of this is handled by a special ++ * linker map entry. ++ */ ++union thread_union init_thread_union __init_task_data = ++ { INIT_THREAD_INFO(init_task) }; +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/io.c linux-3.4.110/arch/nds32/kernel/io.c +--- linux-3.4.110.orig/arch/nds32/kernel/io.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/io.c 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,51 @@ ++#include <linux/module.h> ++#include <linux/types.h> ++ ++#include <asm/io.h> ++ ++/* ++ * Copy data from IO memory space to "real" memory space. ++ * This needs to be optimized. ++ */ ++void _memcpy_fromio(void *to, const volatile void __iomem * from, size_t count) ++{ ++ unsigned char *t = to; ++ while (count) { ++ count--; ++ *t = readb(from); ++ t++; ++ from++; ++ } ++} ++ ++/* ++ * Copy data from "real" memory space to IO memory space. ++ * This needs to be optimized. ++ */ ++void _memcpy_toio(volatile void __iomem * to, const void *from, size_t count) ++{ ++ const unsigned char *f = from; ++ while (count) { ++ count--; ++ writeb(*f, to); ++ f++; ++ to++; ++ } ++} ++ ++/* ++ * "memset" on IO memory space. ++ * This needs to be optimized. ++ */ ++void _memset_io(volatile void __iomem * dst, int c, size_t count) ++{ ++ while (count) { ++ count--; ++ writeb(c, dst); ++ dst++; ++ } ++} ++ ++EXPORT_SYMBOL(_memcpy_fromio); ++EXPORT_SYMBOL(_memcpy_toio); ++EXPORT_SYMBOL(_memset_io); +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/irq.c linux-3.4.110/arch/nds32/kernel/irq.c +--- linux-3.4.110.orig/arch/nds32/kernel/irq.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/irq.c 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,122 @@ ++/* ++ * linux/arch/nds32/kernel/irq.c ++ * ++ * Copyright (C) 1992 Linus Torvalds ++ * Modifications for ARM processor Copyright (C) 1995-2000 Russell King. ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This file contains the code used by various IRQ handling routines: ++ * asking for different IRQ's should be done through these routines ++ * instead of just grabbing them. Thus setups with different IRQ numbers ++ * shouldn't result in any weird surprises, and installing new handlers ++ * should be easier. ++ * ++ * IRQ's are in fact implemented a bit like signal handlers for the kernel. ++ * Naturally it's not a 1:1 relation, but there are similarities. ++ */ ++#include <linux/kernel_stat.h> ++#include <linux/module.h> ++#include <linux/interrupt.h> ++#include <linux/irq.h> ++#include <linux/slab.h> ++#include <linux/random.h> ++#include <linux/seq_file.h> ++#include <linux/kallsyms.h> ++ ++void (*init_arch_irq) (void)__initdata = NULL; ++unsigned long irq_err_count; ++ ++void ack_bad_irq(unsigned int irq) ++{ ++ printk("bad IRQ %d\n", irq); ++} ++ ++int show_interrupts(struct seq_file *p, void *v) ++{ ++ int i = *(loff_t *) v, cpu; ++ struct irqaction *action; ++ unsigned long flags; ++ ++ if (i == 0) { ++ char cpuname[12]; ++ ++ seq_printf(p, " "); ++ for_each_present_cpu(cpu) { ++ sprintf(cpuname, "CPU%d", cpu); ++ seq_printf(p, " %10s", cpuname); ++ } ++ seq_putc(p, '\n'); ++ } ++ ++ if (i < NR_IRQS) { ++ raw_spin_lock_irqsave(&irq_desc[i].lock, flags); ++ action = irq_desc[i].action; ++ if (!action) ++ goto unlock; ++ ++ seq_printf(p, "%3d: ", i); ++ for_each_present_cpu(cpu) ++ seq_printf(p, "%10u ", kstat_irqs_cpu(i, cpu)); ++ seq_printf(p, " %s", action->name); ++ for (action = action->next; action; action = action->next) ++ seq_printf(p, ", %s", action->name); ++ ++ seq_putc(p, '\n'); ++unlock: ++ raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); ++ } else if (i == NR_IRQS) { ++ seq_printf(p, "Err: %10lu\n", irq_err_count); ++ } ++ return 0; ++} ++ ++/* ++ * do_IRQ handles all hardware IRQ's. Decoded IRQs should not ++ * come via this function. Instead, they should provide their ++ * own 'handler' ++ */ ++asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) ++{ ++ struct pt_regs *old_regs = set_irq_regs(regs); ++ ++ /* ++ * Some hardware gives randomly wrong interrupts. Rather ++ * than crashing, do something sensible. ++ */ ++ if (unlikely(irq >= NR_IRQS)) { ++ printk(KERN_EMERG "IRQ exceeds NR_IRQS\n"); ++ BUG(); ++ } ++ ++ irq_enter(); ++ generic_handle_irq(irq); ++ irq_exit(); ++ set_irq_regs(old_regs); ++ ++} ++ ++void __init init_IRQ(void) ++{ ++ int irq; ++ ++ for (irq = 0; irq < NR_IRQS; irq++) ++ irq_set_noprobe(irq); ++ ++ init_arch_irq(); ++} ++ ++#ifdef CONFIG_TRACE_IRQFLAGS ++void notrace arch_trace_hardirqs_on(void) ++{ ++ trace_hardirqs_on(); ++} ++ ++void notrace arch_trace_hardirqs_off(void) ++{ ++ trace_hardirqs_off(); ++} ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/kgdb.c linux-3.4.110/arch/nds32/kernel/kgdb.c +--- linux-3.4.110.orig/arch/nds32/kernel/kgdb.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/kgdb.c 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,291 @@ ++/* ============================================================================ ++ * ++ * arch/nds32/kernel/kgdb.c ++ * ++ * Copyright (C) 2007 Andes Technology Corporation ++ * This file is part of Linux and should be licensed under the GPL. ++ * See the file COPYING for conditions for redistribution. ++ * ++ * Abstract: ++ * ++ * This program is for NDS32 KGDB support. ++ * ++ * Author: Harry Pan ++ * ++ * Revision History: ++ * ++ * Nov.23.2007 Initial ported by Harry, ++ * inherited from the KGDB in 2.6.11 and 2.4.35. ++ * ++ * Note: ++ * ++ * ============================================================================ ++ */ ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/signal.h> ++#include <linux/sched.h> ++#include <linux/mm.h> ++#include <linux/spinlock.h> ++#include <linux/personality.h> ++#include <linux/ptrace.h> ++#include <linux/elf.h> ++#include <linux/interrupt.h> ++#include <linux/init.h> ++#include <linux/kgdb.h> ++#include <linux/kdebug.h> ++ ++#include <asm/atomic.h> ++#include <asm/io.h> ++#include <asm/pgtable.h> ++#include <asm/system.h> ++#include <asm/uaccess.h> ++#include <asm/unistd.h> ++#include <asm/ptrace.h> ++#include <asm/traps.h> ++ ++// ============================================================================ ++// regs_to_gdb_regs() ++// ++// Make a local copy of the registers passed into the handler (bletch). ++// ============================================================================ ++void pt_regs_to_gdb_regs(unsigned long *gregs, struct pt_regs *kregs) ++{ ++ int regno; ++ ++ /* Initialize all to zero (??) */ ++ for (regno = 0; regno < NDS32_NUM_REGS; regno++) ++ gregs[regno] = 0; ++ ++ gregs[0] = kregs->NDS32_r0; ++ gregs[1] = kregs->NDS32_r1; ++ gregs[2] = kregs->NDS32_r2; ++ gregs[3] = kregs->NDS32_r3; ++ gregs[4] = kregs->NDS32_r4; ++ gregs[5] = kregs->NDS32_r5; ++ gregs[6] = kregs->NDS32_r6; ++ gregs[7] = kregs->NDS32_r7; ++ gregs[8] = kregs->NDS32_r8; ++ gregs[9] = kregs->NDS32_r9; ++ gregs[10] = kregs->NDS32_r10; ++ gregs[11] = kregs->NDS32_r11; ++ gregs[12] = kregs->NDS32_r12; ++ gregs[13] = kregs->NDS32_r13; ++ gregs[14] = kregs->NDS32_r14; ++ gregs[15] = kregs->NDS32_r15; ++ gregs[16] = kregs->NDS32_r16; ++ gregs[17] = kregs->NDS32_r17; ++ gregs[18] = kregs->NDS32_r18; ++ gregs[19] = kregs->NDS32_r19; ++ gregs[20] = kregs->NDS32_r20; ++ gregs[21] = kregs->NDS32_r21; ++ gregs[22] = kregs->NDS32_r22; ++ gregs[23] = kregs->NDS32_r23; ++ gregs[24] = kregs->NDS32_r24; ++ gregs[25] = kregs->NDS32_r25; ++ gregs[26] = kregs->NDS32_pp0; ++ gregs[27] = kregs->NDS32_pp1; ++ gregs[28] = kregs->NDS32_fp; ++ gregs[29] = kregs->NDS32_gp; ++ gregs[30] = kregs->NDS32_lp; ++ gregs[31] = kregs->NDS32_sp; ++ gregs[32] = kregs->NDS32_ipc; ++ gregs[33] = kregs->NDS32_d0lo; ++ gregs[34] = kregs->NDS32_d0hi; ++ gregs[35] = kregs->NDS32_d1lo; ++ gregs[36] = kregs->NDS32_d1hi; ++ gregs[NDS32_IR0_REGNUM] = kregs->NDS32_ipsw; ++} ++ ++// ============================================================================ ++// gdb_regs_to_regs() ++// ++// Copy local gdb registers back to kgdb regs, for later copy to kernel. ++// ============================================================================ ++void gdb_regs_to_pt_regs(unsigned long *gregs, struct pt_regs *kregs) ++{ ++ kregs->NDS32_r0 = gregs[0]; ++ kregs->NDS32_r1 = gregs[1]; ++ kregs->NDS32_r2 = gregs[2]; ++ kregs->NDS32_r3 = gregs[3]; ++ kregs->NDS32_r4 = gregs[4]; ++ kregs->NDS32_r5 = gregs[5]; ++ kregs->NDS32_r6 = gregs[6]; ++ kregs->NDS32_r7 = gregs[7]; ++ kregs->NDS32_r8 = gregs[8]; ++ kregs->NDS32_r9 = gregs[9]; ++ kregs->NDS32_r10 = gregs[10]; ++ kregs->NDS32_r11 = gregs[11]; ++ kregs->NDS32_r12 = gregs[12]; ++ kregs->NDS32_r13 = gregs[13]; ++ kregs->NDS32_r14 = gregs[14]; ++ kregs->NDS32_r15 = gregs[15]; ++ kregs->NDS32_r16 = gregs[16]; ++ kregs->NDS32_r17 = gregs[17]; ++ kregs->NDS32_r18 = gregs[18]; ++ kregs->NDS32_r19 = gregs[19]; ++ kregs->NDS32_r20 = gregs[20]; ++ kregs->NDS32_r21 = gregs[21]; ++ kregs->NDS32_r22 = gregs[22]; ++ kregs->NDS32_r23 = gregs[23]; ++ kregs->NDS32_r24 = gregs[24]; ++ kregs->NDS32_r25 = gregs[25]; ++ kregs->NDS32_pp0 = gregs[26]; ++ kregs->NDS32_pp1 = gregs[27]; ++ kregs->NDS32_fp = gregs[28]; ++ kregs->NDS32_gp = gregs[29]; ++ kregs->NDS32_lp = gregs[30]; ++ kregs->NDS32_sp = gregs[31]; ++ kregs->NDS32_ipc = gregs[32]; ++ kregs->NDS32_d0lo = gregs[33]; ++ kregs->NDS32_d0hi = gregs[34]; ++ kregs->NDS32_d1lo = gregs[35]; ++ kregs->NDS32_d1hi = gregs[36]; ++ kregs->NDS32_ipsw = gregs[NDS32_IR0_REGNUM]; ++} ++ ++// ---------------------------------------------------------------------------- ++// kgdb_get_user_regs() ++// ++// Get user process registers. ++// ---------------------------------------------------------------------------- ++static inline struct pt_regs *kgdb_get_user_regs(struct task_struct *task) ++{ ++ return (struct pt_regs *) ++ ((unsigned long)task_thread_info(task) + THREAD_SIZE - ++ 8 - sizeof(struct pt_regs)); ++} ++ ++// ============================================================================ ++// sleeping_thread_to_gdb_regs() ++// ++// ============================================================================ ++void sleeping_thread_to_gdb_regs(unsigned long *gregs, struct task_struct *task) ++{ ++ int regno; ++ struct pt_regs *tregs; ++ ++ /* Just making sure... */ ++ if (task == NULL) ++ return; ++ ++ /* Initialize to zero */ ++ for (regno = 0; regno < NDS32_NUM_REGS; regno++) ++ gregs[regno] = 0; ++ ++ /* Otherwise, we have only some registers from switch_to() */ ++ tregs = kgdb_get_user_regs(task); ++ ++ gregs[0] = tregs->NDS32_r0; ++ gregs[1] = tregs->NDS32_r1; ++ gregs[2] = tregs->NDS32_r2; ++ gregs[3] = tregs->NDS32_r3; ++ gregs[4] = tregs->NDS32_r4; ++ gregs[5] = tregs->NDS32_r5; ++ gregs[6] = tregs->NDS32_r6; ++ gregs[7] = tregs->NDS32_r7; ++ gregs[8] = tregs->NDS32_r8; ++ gregs[9] = tregs->NDS32_r9; ++ gregs[10] = tregs->NDS32_r10; ++ gregs[11] = tregs->NDS32_r11; ++ gregs[12] = tregs->NDS32_r12; ++ gregs[13] = tregs->NDS32_r13; ++ gregs[14] = tregs->NDS32_r14; ++ gregs[15] = tregs->NDS32_r15; ++ gregs[16] = tregs->NDS32_r16; ++ gregs[17] = tregs->NDS32_r17; ++ gregs[18] = tregs->NDS32_r18; ++ gregs[19] = tregs->NDS32_r19; ++ gregs[20] = tregs->NDS32_r20; ++ gregs[21] = tregs->NDS32_r21; ++ gregs[22] = tregs->NDS32_r22; ++ gregs[23] = tregs->NDS32_r23; ++ gregs[24] = tregs->NDS32_r24; ++ gregs[25] = tregs->NDS32_r25; ++ gregs[26] = tregs->NDS32_pp0; ++ gregs[27] = tregs->NDS32_pp1; ++ gregs[28] = tregs->NDS32_fp; ++ gregs[29] = tregs->NDS32_gp; ++ gregs[30] = tregs->NDS32_lp; ++ gregs[31] = tregs->NDS32_sp; ++ gregs[32] = tregs->NDS32_ipc; ++ gregs[33] = tregs->NDS32_d0lo; ++ gregs[34] = tregs->NDS32_d0hi; ++ gregs[35] = tregs->NDS32_d1lo; ++ gregs[36] = tregs->NDS32_d1hi; ++ gregs[NDS32_IR0_REGNUM] = tregs->NDS32_ipsw; ++} ++ ++int kgdb_arch_handle_exception(int exception_vector, int signo, ++ int err_code, char *remcom_in_buffer, ++ char *remcom_out_buffer, ++ struct pt_regs *linux_regs) ++{ ++ long addr; ++ char *ptr; ++ ++ if (0 == atomic_dec_if_positive(&kgdb_setting_breakpoint)) ++ linux_regs->NDS32_ipc += 2; ++ ++ switch (remcom_in_buffer[0]) { ++ case 'k': ++ case 'D': ++ case 'c': ++ case 's': ++ kgdb_contthread = NULL; ++ ++ /* ++ * Try to read optional parameter, pc unchanged if no parm. ++ * If this was a compiled breakpoint, we need to move ++ * to the next instruction or we will just breakpoint ++ * over and over again. ++ */ ++ ptr = &remcom_in_buffer[1]; ++ if (kgdb_hex2long(&ptr, &addr)) { ++ linux_regs->NDS32_ipc = addr; ++ } ++ linux_regs->NDS32_ipsw &= ~0x800; ++ if (remcom_in_buffer[0] == 's') { ++ linux_regs->NDS32_ipsw |= 0x800; ++ } ++ ++ return 0; ++ } ++ ++ return -1; ++} ++ ++static int kgdb_notify(struct notifier_block *self, ++ unsigned long cmd, void *ptr) ++{ ++ struct die_args *args = ptr; ++ unsigned long addr = args->err; ++ if (addr > TASK_SIZE) { ++ kgdb_handle_exception(args->trapnr, args->signr, ++ args->err, args->regs); ++ return NOTIFY_STOP; ++ } ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block kgdb_notifier = { ++ .notifier_call = kgdb_notify, ++}; ++ ++int kgdb_arch_init(void) ++{ ++ register_die_notifier(&kgdb_notifier); ++} ++ ++void kgdb_arch_exit(void) ++{ ++ unregister_die_notifier(&kgdb_notifier); ++} ++ ++struct kgdb_arch arch_kgdb_ops = { ++#ifdef __NDS32_EL__ ++ .gdb_bpt_instr = {0xeb, 0xff} ++#else ++ .gdb_bpt_instr = {0xff, 0xeb} ++#endif ++}; +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/kprobes.c linux-3.4.110/arch/nds32/kernel/kprobes.c +--- linux-3.4.110.orig/arch/nds32/kernel/kprobes.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/kprobes.c 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,869 @@ ++/* ++ * Kernel Probes (KProbes) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Copyright (C) IBM Corporation, 2002, 2004 ++ * ++ * 2002-Oct Created by Vamsi Krishna S <vamsi_krishna@in.ibm.com> Kernel ++ * Probes initial implementation ( includes contributions from ++ * Rusty Russell). ++ * 2004-July Suparna Bhattacharya <suparna@in.ibm.com> added jumper probes ++ * interface to access function arguments. ++ * 2004-Oct Jim Keniston <jkenisto@us.ibm.com> and Prasanna S Panchamukhi ++ * <prasanna@in.ibm.com> adapted for x86_64 from i386. ++ * 2005-Mar Roland McGrath <roland@redhat.com> ++ * Fixed to handle %rip-relative addressing mode correctly. ++ * 2005-May Hien Nguyen <hien@us.ibm.com>, Jim Keniston ++ * <jkenisto@us.ibm.com> and Prasanna S Panchamukhi ++ * <prasanna@in.ibm.com> added function-return probes. ++ * 2005-May Rusty Lynch <rusty.lynch@intel.com> ++ * Added function return probes functionality ++ * 2006-Feb Masami Hiramatsu <hiramatu@sdl.hitachi.co.jp> added ++ * kprobe-booster and kretprobe-booster for i386. ++ * 2007-Dec Masami Hiramatsu <mhiramat@redhat.com> added kprobe-booster ++ * and kretprobe-booster for x86-64 ++ * 2007-Dec Masami Hiramatsu <mhiramat@redhat.com>, Arjan van de Ven ++ * <arjan@infradead.org> and Jim Keniston <jkenisto@us.ibm.com> ++ * unified x86 kprobes code. ++ */ ++ ++#include <linux/kprobes.h> ++#include <linux/ptrace.h> ++#include <linux/string.h> ++#include <linux/slab.h> ++#include <linux/hardirq.h> ++#include <linux/preempt.h> ++#include <linux/module.h> ++#include <linux/kdebug.h> ++ ++#include <asm/cacheflush.h> ++#include <asm/uaccess.h> ++ ++#ifdef __NDS32_EL__ ++#define SZINSN(insn) (((insn & 0x00000080) == 0) ? 4 : 2) ++#define BREAK16_1FE 0xFEEB ++#else ++#define SZINSN(insn) (((insn & 0x80000000) == 0) ? 4 : 2) ++#define BREAK16_1FE 0xEBFE ++#endif ++ ++void jprobe_return_point(void); ++ ++DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; ++DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); ++ ++#if 0 ++/* Insert a jump instruction at address 'from', which jumps to address 'to'.*/ ++static void __kprobes set_jmp_op(void *from, void *to) ++{ ++ struct __arch_jmp_op { ++ char op; ++ s32 raddr; ++ } __attribute__ ((packed)) * jop; ++ jop = (struct __arch_jmp_op *)from; ++ jop->raddr = (s32) ((long)(to) - ((long)(from) + 5)); ++ jop->op = RELATIVEJUMP_INSTRUCTION; ++} ++ ++/* ++ * Check for the REX prefix which can only exist on X86_64 ++ * X86_32 always returns 0 ++ */ ++static int __kprobes is_REX_prefix(kprobe_opcode_t * insn) ++{ ++#ifdef CONFIG_X86_64 ++ if ((*insn & 0xf0) == 0x40) ++ return 1; ++#endif ++ return 0; ++} ++ ++/* ++ * Returns non-zero if opcode is boostable. ++ * RIP relative instructions are adjusted at copying time in 64 bits mode ++ */ ++static int __kprobes can_boost(kprobe_opcode_t * opcodes) ++{ ++ kprobe_opcode_t opcode; ++ kprobe_opcode_t *orig_opcodes = opcodes; ++ ++ if (search_exception_tables(opcodes)) ++ return 0; /* Page fault may occur on this address. */ ++ ++retry: ++ if (opcodes - orig_opcodes > MAX_INSN_SIZE - 1) ++ return 0; ++ opcode = *(opcodes++); ++ ++ /* 2nd-byte opcode */ ++ if (opcode == 0x0f) { ++ if (opcodes - orig_opcodes > MAX_INSN_SIZE - 1) ++ return 0; ++ return test_bit(*opcodes, ++ (unsigned long *)twobyte_is_boostable); ++ } ++ ++ switch (opcode & 0xf0) { ++#ifdef CONFIG_X86_64 ++ case 0x40: ++ goto retry; /* REX prefix is boostable */ ++#endif ++ case 0x60: ++ if (0x63 < opcode && opcode < 0x67) ++ goto retry; /* prefixes */ ++ /* can't boost Address-size override and bound */ ++ return (opcode != 0x62 && opcode != 0x67); ++ case 0x70: ++ return 0; /* can't boost conditional jump */ ++ case 0xc0: ++ /* can't boost software-interruptions */ ++ return (0xc1 < opcode && opcode < 0xcc) || opcode == 0xcf; ++ case 0xd0: ++ /* can boost AA* and XLAT */ ++ return (opcode == 0xd4 || opcode == 0xd5 || opcode == 0xd7); ++ case 0xe0: ++ /* can boost in/out and absolute jmps */ ++ return ((opcode & 0x04) || opcode == 0xea); ++ case 0xf0: ++ if ((opcode & 0x0c) == 0 && opcode != 0xf1) ++ goto retry; /* lock/rep(ne) prefix */ ++ /* clear and set flags are boostable */ ++ return (opcode == 0xf5 || (0xf7 < opcode && opcode < 0xfe)); ++ default: ++ /* segment override prefixes are boostable */ ++ if (opcode == 0x26 || opcode == 0x36 || opcode == 0x3e) ++ goto retry; /* prefixes */ ++ /* CS override prefix and call are not boostable */ ++ return (opcode != 0x2e && opcode != 0x9a); ++ } ++} ++ ++/* ++ * Returns non-zero if opcode modifies the interrupt flag. ++ */ ++static int __kprobes is_IF_modifier(kprobe_opcode_t * insn) ++{ ++ switch (*insn) { ++ case 0xfa: /* cli */ ++ case 0xfb: /* sti */ ++ case 0xcf: /* iret/iretd */ ++ case 0x9d: /* popf/popfd */ ++ return 1; ++ } ++ ++ /* ++ * on X86_64, 0x40-0x4f are REX prefixes so we need to look ++ * at the next byte instead.. but of course not recurse infinitely ++ */ ++ if (is_REX_prefix(insn)) ++ return is_IF_modifier(++insn); ++ ++ return 0; ++} ++ ++/* ++ * Adjust the displacement if the instruction uses the %rip-relative ++ * addressing mode. ++ * If it does, Return the address of the 32-bit displacement word. ++ * If not, return null. ++ * Only applicable to 64-bit x86. ++ */ ++static void __kprobes fix_riprel(struct kprobe *p) ++{ ++#ifdef CONFIG_X86_64 ++ u8 *insn = p->ainsn.insn; ++ s64 disp; ++ int need_modrm; ++ ++ /* Skip legacy instruction prefixes. */ ++ while (1) { ++ switch (*insn) { ++ case 0x66: ++ case 0x67: ++ case 0x2e: ++ case 0x3e: ++ case 0x26: ++ case 0x64: ++ case 0x65: ++ case 0x36: ++ case 0xf0: ++ case 0xf3: ++ case 0xf2: ++ ++insn; ++ continue; ++ } ++ break; ++ } ++ ++ /* Skip REX instruction prefix. */ ++ if (is_REX_prefix(insn)) ++ ++insn; ++ ++ if (*insn == 0x0f) { ++ /* Two-byte opcode. */ ++ ++insn; ++ need_modrm = test_bit(*insn, ++ (unsigned long *)twobyte_has_modrm); ++ } else ++ /* One-byte opcode. */ ++ need_modrm = test_bit(*insn, ++ (unsigned long *)onebyte_has_modrm); ++ ++ if (need_modrm) { ++ u8 modrm = *++insn; ++ if ((modrm & 0xc7) == 0x05) { ++ /* %rip+disp32 addressing mode */ ++ /* Displacement follows ModRM byte. */ ++ ++insn; ++ /* ++ * The copied instruction uses the %rip-relative ++ * addressing mode. Adjust the displacement for the ++ * difference between the original location of this ++ * instruction and the location of the copy that will ++ * actually be run. The tricky bit here is making sure ++ * that the sign extension happens correctly in this ++ * calculation, since we need a signed 32-bit result to ++ * be sign-extended to 64 bits when it's added to the ++ * %rip value and yield the same 64-bit result that the ++ * sign-extension of the original signed 32-bit ++ * displacement would have given. ++ */ ++ disp = (u8 *) p->addr + *((s32 *) insn) - ++ (u8 *) p->ainsn.insn; ++ BUG_ON((s64) (s32) disp != disp); /* Sanity check. */ ++ *(s32 *) insn = (s32) disp; ++ } ++ } ++#endif ++} ++#endif ++ ++static void __kprobes arch_copy_kprobe(struct kprobe *p) ++{ ++ memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); ++ flush_icache_range((unsigned long)p->ainsn.insn, ++ (unsigned long)p->ainsn.insn + ++ MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); ++ ++// fix_riprel(p); ++ ++// if (can_boost(p->addr)) ++// p->ainsn.boostable = 0; ++// else ++ p->ainsn.boostable = -1; ++ ++ p->opcode = *p->addr; ++} ++ ++int __kprobes arch_prepare_kprobe(struct kprobe *p) ++{ ++ /* insn: must be on special executable page on x86. */ ++ p->ainsn.insn = get_insn_slot(); ++ if (!p->ainsn.insn) ++ return -ENOMEM; ++ arch_copy_kprobe(p); ++ return 0; ++} ++ ++void __kprobes arch_arm_kprobe(struct kprobe *p) ++{ ++ *p->addr = BREAK16_1FE; ++ flush_icache_range((unsigned long)p->addr, ++ (unsigned long)p->addr + sizeof(kprobe_opcode_t)); ++} ++ ++void __kprobes arch_disarm_kprobe(struct kprobe *p) ++{ ++ *p->addr = p->opcode; ++ flush_icache_range((unsigned long)p->addr, ++ (unsigned long)p->addr + sizeof(kprobe_opcode_t)); ++} ++ ++void __kprobes arch_remove_kprobe(struct kprobe *p) ++{ ++ if (p->ainsn.insn) { ++ free_insn_slot(p->ainsn.insn, (p->ainsn.boostable == 1)); ++ p->ainsn.insn = NULL; ++ } ++} ++ ++static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) ++{ ++ kcb->prev_kprobe.kp = kprobe_running(); ++ kcb->prev_kprobe.status = kcb->kprobe_status; ++ kcb->prev_kprobe.old_flags = kcb->kprobe_old_flags; ++ kcb->prev_kprobe.saved_flags = kcb->kprobe_saved_flags; ++} ++ ++static void __kprobes 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_flags = kcb->prev_kprobe.old_flags; ++ kcb->kprobe_saved_flags = kcb->prev_kprobe.saved_flags; ++} ++ ++static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, ++ struct kprobe_ctlblk *kcb) ++{ ++ __get_cpu_var(current_kprobe) = p; ++// kcb->kprobe_saved_flags = kcb->kprobe_old_flags ++// = regs->NDS32_ipsw & PSW_mskHSS; ++} ++ ++static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) ++{ ++ regs->NDS32_ipsw |= PSW_mskHSS; ++ /* single step inline if the instruction is an int3 */ ++// if (p->opcode == BREAK16_1FE) ++// regs->NDS32_ipc = (unsigned long)p->addr; ++// else ++ regs->NDS32_ipc = (unsigned long)p->ainsn.insn; ++} ++ ++void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, ++ struct pt_regs *regs) ++{ ++ ri->ret_addr = (kprobe_opcode_t *) regs->NDS32_lp; ++ regs->NDS32_lp = (unsigned long)&kretprobe_trampoline; ++} ++ ++static void __kprobes setup_singlestep(struct kprobe *p, struct pt_regs *regs, ++ struct kprobe_ctlblk *kcb) ++{ ++#if !defined(CONFIG_PREEMPT) || defined(CONFIG_FREEZER) ++ if (p->ainsn.boostable == 1 && !p->post_handler) { ++ /* Boost up -- we can execute copied instructions directly */ ++ reset_current_kprobe(); ++ regs->NDS32_ipc = (unsigned long)p->ainsn.insn; ++ preempt_enable_no_resched(); ++ return; ++ } ++#endif ++ prepare_singlestep(p, regs); ++ kcb->kprobe_status = KPROBE_HIT_SS; ++} ++ ++/* ++ * We have reentered the kprobe_handler(), since another probe was hit while ++ * within the handler. We save the original kprobes variables and just single ++ * step on the instruction of the new probe without calling any user handlers. ++ */ ++static int __kprobes reenter_kprobe(struct kprobe *p, struct pt_regs *regs, ++ struct kprobe_ctlblk *kcb) ++{ ++ switch (kcb->kprobe_status) { ++#if 0 ++ case KPROBE_HIT_SSDONE: ++#ifdef CONFIG_X86_64 ++ /* TODO: Provide re-entrancy from post_kprobes_handler() and ++ * avoid exception stack corruption while single-stepping on ++ * the instruction of the new probe. ++ */ ++ arch_disarm_kprobe(p); ++ regs->ip = (unsigned long)p->addr; ++ reset_current_kprobe(); ++ preempt_enable_no_resched(); ++ break; ++#endif ++#endif ++ case KPROBE_HIT_ACTIVE: ++ save_previous_kprobe(kcb); ++ set_current_kprobe(p, regs, kcb); ++ kprobes_inc_nmissed_count(p); ++ prepare_singlestep(p, regs); ++ kcb->kprobe_status = KPROBE_REENTER; ++ break; ++ case KPROBE_HIT_SS: ++ if (p == kprobe_running()) { ++ regs->NDS32_ipc &= ~PSW_mskHSS; ++// regs->NDS32_ipc |= kcb->kprobe_saved_flags; ++ return 0; ++ } else { ++ /* A probe has been hit in the codepath leading up ++ * to, or just after, single-stepping of a probed ++ * instruction. This entire codepath should strictly ++ * reside in .kprobes.text section. Raise a warning ++ * to highlight this peculiar case. ++ */ ++ } ++ default: ++ /* impossible cases */ ++ WARN_ON(1); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* ++ * Interrupts are disabled on entry as trap3 is an interrupt gate and they ++ * remain disabled thorough out this function. ++ */ ++static int __kprobes kprobe_handler(struct pt_regs *regs) ++{ ++ kprobe_opcode_t *addr; ++ struct kprobe *p; ++ struct kprobe_ctlblk *kcb; ++ ++ addr = (kprobe_opcode_t *) regs->NDS32_ipc; ++ if (*addr != BREAK16_1FE) { ++ /* ++ * 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. ++ * Back up over the (now missing) int3 and run ++ * the original instruction. ++ */ ++ return 1; ++ } ++ ++ /* ++ * We don't want to be preempted for the entire ++ * duration of kprobe processing. We conditionally ++ * re-enable preemption at the end of this function, ++ * and also in reenter_kprobe() and setup_singlestep(). ++ */ ++ preempt_disable(); ++ ++ kcb = get_kprobe_ctlblk(); ++ p = get_kprobe(addr); ++ ++ if (p) { ++ if (kprobe_running()) { ++ if (reenter_kprobe(p, regs, kcb)) ++ return 1; ++ } else { ++ set_current_kprobe(p, regs, kcb); ++ kcb->kprobe_status = KPROBE_HIT_ACTIVE; ++ ++ /* ++ * If we have no pre-handler or it returned 0, we ++ * continue with normal processing. If we have a ++ * pre-handler and it returned non-zero, it prepped ++ * for calling the break_handler below on re-entry ++ * for jprobe processing, so get out doing nothing ++ * more here. ++ */ ++ if (!p->pre_handler || !p->pre_handler(p, regs)) ++ setup_singlestep(p, regs, kcb); ++ return 1; ++ } ++ } else if (kprobe_running()) { ++ p = __get_cpu_var(current_kprobe); ++ if (p->break_handler && p->break_handler(p, regs)) { ++ setup_singlestep(p, regs, kcb); ++ return 1; ++ } ++ } ++ /* else: not a kprobe fault; let the kernel handle it */ ++ preempt_enable_no_resched(); ++ return 0; ++} ++ ++/* ++ * When a retprobed function returns, this code saves registers and ++ * calls trampoline_handler() runs, which calls the kretprobe's handler. ++ */ ++static void __used __kprobes kretprobe_trampoline_holder(void) ++{ ++ asm volatile (".global kretprobe_trampoline \n" ++ "kretprobe_trampoline: \n" ++ "smw.adm $r15, [$sp], $r15, #0x0\n" ++ "smw.adm $r0, [$sp], $r5, #0x1 \n" ++ "addi $r0, $sp, #-76 \n" ++ "bal trampoline_handler \n" ++ "move $lp, $r0 \n" ++ "lmw.bim $r0, [$sp], $r5, #0x1 \n" ++ "lmw.bim $r15, [$sp], $r15, #0x0\n" ++ "ret \n"); ++} ++ ++/* ++ * Called from kretprobe_trampoline ++ */ ++static __used __kprobes void *trampoline_handler(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 multiple functions in the call path have ++ * return probes installed on them, and/or more than one ++ * return probe was registered for a target function. ++ * ++ * We can handle this because: ++ * - instances are always pushed into the head of the list ++ * - when multiple return probes are registered for the same ++ * function, the (chronologically) first instance's ret_addr ++ * will be 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) { ++ __get_cpu_var(current_kprobe) = &ri->rp->kp; ++ get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE; ++ ri->rp->handler(ri, regs); ++ __get_cpu_var(current_kprobe) = NULL; ++ } ++ ++ 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); ++ ++ kretprobe_hash_unlock(current, &flags); ++ ++ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { ++ hlist_del(&ri->hlist); ++ kfree(ri); ++ } ++ return (void *)orig_ret_address; ++} ++ ++/* ++ * Called after single-stepping. p->addr is the address of the ++ * instruction whose first byte has been replaced by the "int 3" ++ * 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 ++ * interrupt. We have to fix up the stack as follows: ++ * ++ * 0) Except in the case of absolute or indirect jump or call instructions, ++ * the new ip is relative to the copied instruction. We need to make ++ * it relative to the original instruction. ++ * ++ * 1) If the single-stepped instruction was pushfl, then the TF and IF ++ * flags are set in the just-pushed flags, and may need to be cleared. ++ * ++ * 2) If the single-stepped instruction was a call, the return address ++ * that is atop the stack is the address following the copied instruction. ++ * We need to make it the address following the original instruction. ++ * ++ * If this is the first time we've single-stepped the instruction at ++ * this probepoint, and the instruction is boostable, boost it: add a ++ * jump instruction after the copied instruction, that jumps to the next ++ * instruction after the probepoint. ++ */ ++static void __kprobes resume_execution(struct kprobe *p, ++ struct pt_regs *regs, ++ struct kprobe_ctlblk *kcb) ++{ ++// unsigned long *tos = stack_addr(regs); ++// unsigned long copy_ip = (unsigned long)p->ainsn.insn; ++// unsigned long orig_ip = (unsigned long)p->addr; ++ kprobe_opcode_t *insn = p->ainsn.insn; ++ unsigned long rawinsn = *(unsigned long *)insn; ++ int size = SZINSN(rawinsn); ++ regs->NDS32_ipc = (unsigned long)p->addr + size; ++ regs->NDS32_ipsw &= ~PSW_mskHSS; ++#if 0 ++ ++ /*skip the REX prefix */ ++ if (is_REX_prefix(insn)) ++ insn++; ++ ++ regs->flags &= ~X86_EFLAGS_TF; ++ switch (*insn) { ++ case 0x9c: /* pushfl */ ++ *tos &= ~(X86_EFLAGS_TF | X86_EFLAGS_IF); ++ *tos |= kcb->kprobe_old_flags; ++ break; ++ case 0xc2: /* iret/ret/lret */ ++ case 0xc3: ++ case 0xca: ++ case 0xcb: ++ case 0xcf: ++ case 0xea: /* jmp absolute -- ip is correct */ ++ /* ip is already adjusted, no more changes required */ ++ p->ainsn.boostable = 1; ++ goto no_change; ++ case 0xe8: /* call relative - Fix return addr */ ++ *tos = orig_ip + (*tos - copy_ip); ++ break; ++#ifdef CONFIG_X86_32 ++ case 0x9a: /* call absolute -- same as call absolute, indirect */ ++ *tos = orig_ip + (*tos - copy_ip); ++ goto no_change; ++#endif ++ case 0xff: ++ if ((insn[1] & 0x30) == 0x10) { ++ /* ++ * call absolute, indirect ++ * Fix return addr; ip is correct. ++ * But this is not boostable ++ */ ++ *tos = orig_ip + (*tos - copy_ip); ++ goto no_change; ++ } else if (((insn[1] & 0x31) == 0x20) || ++ ((insn[1] & 0x31) == 0x21)) { ++ /* ++ * jmp near and far, absolute indirect ++ * ip is correct. And this is boostable ++ */ ++ p->ainsn.boostable = 1; ++ goto no_change; ++ } ++ default: ++ break; ++ } ++ ++ if (p->ainsn.boostable == 0) { ++ if ((regs->ip > copy_ip) && ++ (regs->ip - copy_ip) + 5 < MAX_INSN_SIZE) { ++ /* ++ * These instructions can be executed directly if it ++ * jumps back to correct address. ++ */ ++ set_jmp_op((void *)regs->ip, ++ (void *)orig_ip + (regs->ip - copy_ip)); ++ p->ainsn.boostable = 1; ++ } else { ++ p->ainsn.boostable = -1; ++ } ++ } ++ ++ regs->ip += orig_ip - copy_ip; ++ ++no_change: ++ restore_btf(); ++#endif ++} ++ ++/* ++ * Interrupts are disabled on entry as trap1 is an interrupt gate and they ++ * remain disabled thoroughout this function. ++ */ ++static int __kprobes post_kprobe_handler(struct pt_regs *regs) ++{ ++ struct kprobe *cur = kprobe_running(); ++ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); ++ ++ if (!cur) ++ return 0; ++ ++ resume_execution(cur, regs, kcb); ++ regs->NDS32_ipsw |= kcb->kprobe_saved_flags; ++ ++ if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { ++ kcb->kprobe_status = KPROBE_HIT_SSDONE; ++ cur->post_handler(cur, regs, 0); ++ } ++ ++ /* 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(); ++ ++ /* ++ * if somebody else is singlestepping across a probe point, flags ++ * will have TF set, in which case, continue the remaining processing ++ * of do_debug, as if this is not a probe hit. ++ */ ++ if (regs->NDS32_ipsw & PSW_mskHSS) ++ return 0; ++ ++ return 1; ++} ++ ++int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) ++{ ++ struct kprobe *cur = kprobe_running(); ++ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); ++ ++ switch (kcb->kprobe_status) { ++ case KPROBE_HIT_SS: ++ case KPROBE_REENTER: ++ /* ++ * We are here because the instruction being single ++ * stepped caused a page fault. We reset the current ++ * kprobe and the ip points back to the probe address ++ * and allow the page fault handler to continue as a ++ * normal page fault. ++ */ ++ regs->NDS32_ipc = (unsigned long)cur->addr; ++ regs->NDS32_ipsw |= kcb->kprobe_old_flags; ++ if (kcb->kprobe_status == KPROBE_REENTER) ++ restore_previous_kprobe(kcb); ++ else ++ reset_current_kprobe(); ++ preempt_enable_no_resched(); ++ break; ++ case KPROBE_HIT_ACTIVE: ++ case KPROBE_HIT_SSDONE: ++ /* ++ * We increment the nmissed count for accounting, ++ * we can also use npre/npostfault count for accounting ++ * these specific fault cases. ++ */ ++ kprobes_inc_nmissed_count(cur); ++ ++ /* ++ * We come here because instructions in the pre/post ++ * handler caused the page_fault, this could happen ++ * if handler tries to access user space by ++ * copy_from_user(), get_user() etc. Let the ++ * user-specified handler try to fix it first. ++ */ ++ if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) ++ return 1; ++ ++ /* ++ * In case the user-specified fault handler returned ++ * zero, try to fix up. ++ */ ++ if (fixup_exception(regs)) ++ return 1; ++ ++ /* ++ * fixup routine could not handle it, ++ * Let do_page_fault() fix it. ++ */ ++ break; ++ default: ++ break; ++ } ++ 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 = data; ++ int ret = NOTIFY_DONE; ++ int why = args->trapnr & 0xf; ++ ++ if (args->regs && user_mode(args->regs)) ++ return ret; ++ ++ switch (why) { ++ case 1: ++ if (kprobe_handler(args->regs)) ++ ret = NOTIFY_STOP; ++ break; ++ case 7: ++ if (post_kprobe_handler(args->regs)) ++ ret = NOTIFY_STOP; ++ 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); ++ unsigned long addr; ++ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); ++ ++ kcb->jprobe_saved_regs = *regs; ++ kcb->jprobe_saved_sp = regs->NDS32_sp; ++ addr = (unsigned long)(kcb->jprobe_saved_sp); ++ ++ /* ++ * As Linus pointed out, gcc assumes that the callee ++ * owns the argument space and could overwrite it, e.g. ++ * tailcall optimization. So, to be absolutely safe ++ * we also save and restore enough stack bytes to cover ++ * the argument area. ++ */ ++ memcpy(kcb->jprobes_stack, (kprobe_opcode_t *) addr, ++ MIN_STACK_SIZE(addr)); ++ regs->NDS32_ipsw &= ~PSW_mskGIE; ++ trace_hardirqs_off(); ++ regs->NDS32_ipc = (unsigned long)(jp->entry); ++ return 1; ++} ++ ++void __kprobes jprobe_return(void) ++{ ++ struct kprobe_ctlblk *kcd = get_kprobe_ctlblk(); ++ asm volatile (" move $sp, %0\n" ++ " .globl jprobe_return_point\n" ++ " jprobe_return_point: \n" ++ " break #0x1fe \n"::"r" (kcd-> ++ jprobe_saved_sp)); ++} ++ ++int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) ++{ ++ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); ++ struct jprobe *jp = container_of(p, struct jprobe, kp); ++ ++ if (regs->NDS32_ipc == jprobe_return_point) { ++ if (regs->NDS32_sp != kcb->jprobe_saved_sp) { ++ struct pt_regs *saved_regs = &kcb->jprobe_saved_regs; ++ printk(KERN_ERR ++ "current sp %p does not match saved sp %p\n", ++ regs->NDS32_sp, kcb->jprobe_saved_sp); ++ printk(KERN_ERR "Saved registers for jprobe %p\n", jp); ++ show_regs(saved_regs); ++ printk(KERN_ERR "Current registers\n"); ++ show_regs(regs); ++ BUG(); ++ } ++ *regs = kcb->jprobe_saved_regs; ++ memcpy((kprobe_opcode_t *) (kcb->jprobe_saved_sp), ++ kcb->jprobes_stack, ++ MIN_STACK_SIZE(kcb->jprobe_saved_sp)); ++ preempt_enable_no_resched(); ++ return 1; ++ } ++ return 0; ++} ++ ++int __init arch_init_kprobes(void) ++{ ++ return 0; ++} ++ ++int __kprobes arch_trampoline_kprobe(struct kprobe *p) ++{ ++ return 0; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/machine_kexec.c linux-3.4.110/arch/nds32/kernel/machine_kexec.c +--- linux-3.4.110.orig/arch/nds32/kernel/machine_kexec.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/machine_kexec.c 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,80 @@ ++/* ++ * machine_kexec.c - handle transition of Linux booting another kernel ++ */ ++ ++#include <linux/mm.h> ++#include <linux/kexec.h> ++#include <linux/delay.h> ++#include <linux/reboot.h> ++#include <linux/io.h> ++#include <asm/pgtable.h> ++#include <asm/pgalloc.h> ++#include <asm/mmu_context.h> ++#include <asm/cacheflush.h> ++#include <asm/mach-types.h> ++ ++extern const unsigned char relocate_new_kernel[]; ++extern const unsigned int relocate_new_kernel_size; ++ ++extern void setup_mm_for_reboot(char mode); ++ ++extern unsigned long kexec_start_address; ++extern unsigned long kexec_indirection_page; ++extern unsigned long kexec_mach_type; ++extern unsigned long kexec_boot_atags; ++ ++/* ++ * Provide a dummy crash_notes definition while crash dump arrives to nds32. ++ * This prevents breakage of crash_notes attribute in kernel/ksysfs.c. ++ */ ++ ++int machine_kexec_prepare(struct kimage *image) ++{ ++ return 0; ++} ++ ++void machine_kexec_cleanup(struct kimage *image) ++{ ++} ++ ++void machine_shutdown(void) ++{ ++} ++ ++void machine_crash_shutdown(struct pt_regs *regs) ++{ ++} ++ ++void machine_kexec(struct kimage *image) ++{ ++ unsigned long page_list; ++ unsigned long reboot_code_buffer_phys; ++ void *reboot_code_buffer; ++ ++ page_list = image->head & PAGE_MASK; ++ ++ /* we need both effective and real address here */ ++ reboot_code_buffer_phys = ++ page_to_pfn(image->control_code_page) << PAGE_SHIFT; ++ reboot_code_buffer = page_address(image->control_code_page); ++ ++ /* Prepare parameters for reboot_code_buffer */ ++ kexec_start_address = image->start; ++ kexec_indirection_page = page_list; ++ kexec_mach_type = machine_arch_type; ++ kexec_boot_atags = ++ image->start - KEXEC_NDS32_ZIMAGE_OFFSET + KEXEC_NDS32_ATAGS_OFFSET; ++ ++ /* copy our kernel relocation code to the control code page */ ++ memcpy(reboot_code_buffer, ++ relocate_new_kernel, relocate_new_kernel_size); ++ ++ flush_icache_range((unsigned long)reboot_code_buffer, ++ (unsigned long)reboot_code_buffer + ++ KEXEC_CONTROL_PAGE_SIZE); ++ printk(KERN_INFO "Bye!\n"); ++ ++ cpu_proc_fin(); ++ setup_mm_for_reboot(0); /* mode is not used, so just pass 0 */ ++ cpu_reset(reboot_code_buffer_phys); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/Makefile linux-3.4.110/arch/nds32/kernel/Makefile +--- linux-3.4.110.orig/arch/nds32/kernel/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/Makefile 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,45 @@ ++# ++# Makefile for the linux kernel. ++# ++ ++CPPFLAGS_vmlinux.lds +=-DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) ++AFLAGS_head.o := -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) ++ ++# Object file lists. ++ ++obj-y := ex-entry.o ex-exit.o ex-scall.o irq.o \ ++ process.o ptrace.o setup.o signal.o \ ++ sys_nds32.o time.o traps.o io.o proc.o \ ++ elfchk.o ++ifdef CONFIG_FUNCTION_TRACER ++CFLAGS_REMOVE_ftrace.o = -pg ++CFLAGS_REMOVE_ex-entry.o = -pg ++CFLAGS_REMOVE_ex-exit.o = -pg ++CFLAGS_REMOVE_ex-scall.o = -pg ++CFLAGS_REMOVE_stacktrace.o = -pg ++CFLAGS_REMOVE_traps.o = -pg ++endif ++ ++obj-$(CONFIG_MODULES) += nds32_ksyms.o module.o ++obj-$(CONFIG_ISA_DMA) += dma-isa.o ++obj-$(CONFIG_PCI) += bios32.o ++obj-$(CONFIG_SMP) += smp.o ++obj-$(CONFIG_KGDB) += kgdb.o ++obj-$(CONFIG_STACKTRACE) += stacktrace.o ++obj-$(CONFIG_KPROBES) += kprobes.o ++obj-$(CONFIG_FPU) += fpu.o ++obj-$(CONFIG_AUDIO) += audio.o ++obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o ++obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o ++obj-$(CONFIG_EARLY_PRINTK) += early_printk.o ++ ++extra-y := head.o init_task.o vmlinux.lds ++ ++CFLAGS_fpu.o += \ ++ $(shell $(CC) -E -dM -xc /dev/null | grep -o -m1 NDS32_EXT_FPU_SP | sed -e 's/NDS32_EXT_FPU_SP/-mext-fpu-sp/') \ ++ $(shell $(CC) -E -dM -xc /dev/null | grep -o -m1 NDS32_EXT_FPU_DP | sed -e 's/NDS32_EXT_FPU_DP/-mext-fpu-dp/') ++ifdef CONFIG_FPU ++CFLAGS_elfchk.o += \ ++ $(shell $(CC) -E -dM -xc /dev/null | grep -o -m1 NDS32_EXT_FPU_SP | sed -e 's/NDS32_EXT_FPU_SP/-mext-fpu-sp/') \ ++ $(shell $(CC) -E -dM -xc /dev/null | grep -o -m1 NDS32_EXT_FPU_DP | sed -e 's/NDS32_EXT_FPU_DP/-mext-fpu-dp/') ++endif +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/module.c linux-3.4.110/arch/nds32/kernel/module.c +--- linux-3.4.110.orig/arch/nds32/kernel/module.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/module.c 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,314 @@ ++/* ++ * linux/arch/nds32/kernel/module.c ++ * ++ * Copyright (C) 2002 Russell King. ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Module allocation method suggested by Andi Kleen. ++ */ ++#include <linux/module.h> ++#include <linux/elf.h> ++#include <linux/vmalloc.h> ++#include <linux/slab.h> ++#include <linux/mm.h> ++ ++#include <asm/pgtable.h> ++ ++#define DEBUG 0 ++#if DEBUG ++#define PRINTK printk ++#else ++#define PRINTK(x...) ++#endif ++ ++void *module_alloc(unsigned long size) ++{ ++#ifdef CONFIG_KPROBES ++ if (size == 0) ++ return NULL; ++ return vmalloc_exec(size); ++#else ++ return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, ++ GFP_KERNEL, PAGE_KERNEL, -1, ++ __builtin_return_address(0)); ++#endif ++} ++ ++void module_free(struct module *module, void *region) ++{ ++ vfree(region); ++} ++ ++int module_frob_arch_sections(Elf_Ehdr * hdr, ++ Elf_Shdr * sechdrs, ++ char *secstrings, struct module *mod) ++{ ++ return 0; ++} ++ ++void do_reloc16(unsigned int val, unsigned int *loc, unsigned int val_mask, ++ unsigned int val_shift, unsigned int loc_mask, ++ unsigned int partial_in_place, unsigned int swap) ++{ ++ unsigned int tmp = 0, tmp2 = 0; ++ ++ __asm__ __volatile__("\tlhi.bi\t%0, [%2], 0\n" ++ "\tbeqz\t%3, 1f\n" ++ "\twsbh\t%0, %1\n" ++ "1:\n":"=r"(tmp):"0"(tmp), "r"(loc), "r"(swap) ++ ); ++ ++ tmp2 = tmp & loc_mask; ++ if (partial_in_place) { ++ tmp &= (!loc_mask); ++ tmp = ++ tmp2 | ((tmp + ((val & val_mask) >> val_shift)) & val_mask); ++ } else { ++ tmp = tmp2 | ((val & val_mask) >> val_shift); ++ } ++ ++ __asm__ __volatile__("\tbeqz\t%3, 2f\n" ++ "\twsbh\t%0, %1\n" ++ "2:\n" ++ "\tshi.bi\t%0, [%2], 0\n":"=r"(tmp):"0"(tmp), ++ "r"(loc), "r"(swap) ++ ); ++} ++ ++void do_reloc32(unsigned int val, unsigned int *loc, unsigned int val_mask, ++ unsigned int val_shift, unsigned int loc_mask, ++ unsigned int partial_in_place, unsigned int swap) ++{ ++ unsigned int tmp = 0, tmp2 = 0; ++ ++ __asm__ __volatile__("\tlmw.bi\t%0, [%2], %0, 0\n" ++ "\tbeqz\t%3, 1f\n" ++ "\twsbh\t%0, %1\n" ++ "\trotri\t%0, %1, 16\n" ++ "1:\n":"=r"(tmp):"0"(tmp), "r"(loc), "r"(swap) ++ ); ++ ++ tmp2 = tmp & loc_mask; ++ if (partial_in_place) { ++ tmp &= (!loc_mask); ++ tmp = ++ tmp2 | ((tmp + ((val & val_mask) >> val_shift)) & val_mask); ++ } else { ++ tmp = tmp2 | ((val & val_mask) >> val_shift); ++ } ++ ++ __asm__ __volatile__("\tbeqz\t%3, 2f\n" ++ "\twsbh\t%0, %1\n" ++ "\trotri\t%0, %1, 16\n" ++ "2:\n" ++ "\tsmw.bi\t%0, [%2], %0, 0\n":"=r"(tmp):"0"(tmp), ++ "r"(loc), "r"(swap) ++ ); ++} ++ ++static inline int exceed_limit(int offset, unsigned int val_mask, ++ struct module *module, Elf32_Rela * rel, ++ unsigned int relindex, unsigned int reloc_order) ++{ ++ int abs_off = offset < 0 ? ~offset : offset; ++ ++ if (abs_off & (~val_mask)) { ++ printk(KERN_ERR "\n%s: relocation type %d out of range.\n" ++ "please rebuild the kernel module with gcc option \"-Wa,-mno-small-text\".\n", ++ module->name, ELF32_R_TYPE(rel->r_info)); ++ PRINTK("section %d reloc %d offset 0x%x relative 0x%x.\n" ++ relindex, reloc_order, rel->r_offset, offset); ++ return true; ++ } ++ return false; ++} ++ ++#ifdef __NDS32_EL__ ++#define NEED_SWAP 1 ++#else ++#define NEED_SWAP 0 ++#endif ++ ++int ++apply_relocate_add(Elf32_Shdr * sechdrs, const char *strtab, ++ unsigned int symindex, unsigned int relindex, ++ struct module *module) ++{ ++ Elf32_Shdr *symsec = sechdrs + symindex; ++ Elf32_Shdr *relsec = sechdrs + relindex; ++ Elf32_Shdr *dstsec = sechdrs + relsec->sh_info; ++ Elf32_Rela *rel = (void *)relsec->sh_addr; ++ unsigned int i; ++ ++ for (i = 0; i < relsec->sh_size / sizeof(Elf32_Rela); i++, rel++) { ++ Elf32_Addr *loc; ++ Elf32_Sym *sym; ++ Elf32_Addr v; ++ s32 offset; ++ ++ offset = ELF32_R_SYM(rel->r_info); ++ if (offset < 0 ++ || offset > (symsec->sh_size / sizeof(Elf32_Sym))) { ++ printk(KERN_ERR "%s: bad relocation\n", module->name); ++ PRINTK("section %d reloc %d\n", module->name, relindex, ++ i); ++ return -ENOEXEC; ++ } ++ ++ sym = ((Elf32_Sym *) symsec->sh_addr) + offset; ++ ++ if (rel->r_offset < 0 ++ || rel->r_offset > dstsec->sh_size - sizeof(u16)) { ++ printk(KERN_ERR "%s: out of bounds relocation\n", ++ module->name); ++ PRINTK("section %d reloc %d offset 0x%0x size %d\n", ++ relindex, i, rel->r_offset, dstsec->sh_size); ++ return -ENOEXEC; ++ } ++ ++ loc = (Elf32_Addr *) (dstsec->sh_addr + rel->r_offset); ++ v = sym->st_value + rel->r_addend; ++ ++ switch (ELF32_R_TYPE(rel->r_info)) { ++ case R_NDS32_NONE: ++ case R_NDS32_INSN16: ++ case R_NDS32_LABEL: ++ case R_NDS32_LONGCALL1: ++ case R_NDS32_LONGCALL2: ++ case R_NDS32_LONGCALL3: ++ case R_NDS32_LONGCALL4: ++ case R_NDS32_LONGJUMP1: ++ case R_NDS32_LONGJUMP2: ++ case R_NDS32_LONGJUMP3: ++ case R_NDS32_9_FIXED_RELA: ++ case R_NDS32_15_FIXED_RELA: ++ case R_NDS32_17_FIXED_RELA: ++ case R_NDS32_25_FIXED_RELA: ++ case R_NDS32_LOADSTORE: ++ case R_NDS32_DWARF2_OP1_RELA: ++ case R_NDS32_DWARF2_OP2_RELA: ++ case R_NDS32_DWARF2_LEB_RELA: ++ case R_NDS32_RELA_NOP_MIX...R_NDS32_RELA_NOP_MAX: ++ break; ++ ++ case R_NDS32_32_RELA: ++ do_reloc32(v, loc, 0xffffffff, 0, 0, 0, 0); ++ break; ++ ++ case R_NDS32_HI20_RELA: ++ do_reloc32(v, loc, 0xfffff000, 12, 0xfff00000, 0, ++ NEED_SWAP); ++ break; ++ ++ case R_NDS32_LO12S3_RELA: ++ do_reloc32(v, loc, 0x00000fff, 3, 0xfffff000, 0, ++ NEED_SWAP); ++ break; ++ ++ case R_NDS32_LO12S2_RELA: ++ do_reloc32(v, loc, 0x00000fff, 2, 0xfffff000, 0, ++ NEED_SWAP); ++ break; ++ ++ case R_NDS32_LO12S1_RELA: ++ do_reloc32(v, loc, 0x00000fff, 1, 0xfffff000, 0, ++ NEED_SWAP); ++ break; ++ ++ case R_NDS32_LO12S0_RELA: ++ case R_NDS32_LO12S0_ORI_RELA: ++ do_reloc32(v, loc, 0x00000fff, 0, 0xfffff000, 0, ++ NEED_SWAP); ++ break; ++ ++ case R_NDS32_9_PCREL_RELA: ++ if (exceed_limit ++ ((v - (Elf32_Addr) loc), 0x000000ff, module, rel, ++ relindex, i)) ++ return -ENOEXEC; ++ do_reloc16(v - (Elf32_Addr) loc, loc, 0x000001ff, 1, ++ 0xffffff00, 0, NEED_SWAP); ++ break; ++ ++ case R_NDS32_15_PCREL_RELA: ++ if (exceed_limit ++ ((v - (Elf32_Addr) loc), 0x00003fff, module, rel, ++ relindex, i)) ++ return -ENOEXEC; ++ do_reloc32(v - (Elf32_Addr) loc, loc, 0x00007fff, 1, ++ 0xffffc000, 0, NEED_SWAP); ++ break; ++ ++ case R_NDS32_17_PCREL_RELA: ++ if (exceed_limit ++ ((v - (Elf32_Addr) loc), 0x0000ffff, module, rel, ++ relindex, i)) ++ return -ENOEXEC; ++ do_reloc32(v - (Elf32_Addr) loc, loc, 0x0001ffff, 1, ++ 0xffff0000, 0, NEED_SWAP); ++ break; ++ ++ case R_NDS32_25_PCREL_RELA: ++ if (exceed_limit ++ ((v - (Elf32_Addr) loc), 0x00ffffff, module, rel, ++ relindex, i)) ++ return -ENOEXEC; ++ do_reloc32(v - (Elf32_Addr) loc, loc, 0x01ffffff, 1, ++ 0xff000000, 0, NEED_SWAP); ++ break; ++ case R_NDS32_WORD_9_PCREL_RELA: ++ if (exceed_limit ++ ((v - (Elf32_Addr) loc), 0x000000ff, module, rel, ++ relindex, i)) ++ return -ENOEXEC; ++ do_reloc32(v - (Elf32_Addr) loc, loc, 0x000001ff, 1, ++ 0xffffff00, 0, NEED_SWAP); ++ break; ++ ++ case R_NDS32_SDA15S3_RELA: ++ case R_NDS32_SDA15S2_RELA: ++ case R_NDS32_SDA15S1_RELA: ++ case R_NDS32_SDA15S0_RELA: ++ printk(KERN_ERR "%s: unsupported relocation type %d.\n", ++ module->name, ELF32_R_TYPE(rel->r_info)); ++ printk(KERN_ERR ++ "Small data section access doesn't work in the kernel space; " ++ "please rebuild the kernel module with gcc option -G0.\n"); ++ PRINTK("section %d reloc %d offset 0x%x size %d\n", ++ relindex, i, rel->r_offset, dstsec->sh_size); ++ break; ++ ++ default: ++ printk(KERN_ERR "%s: unsupported relocation type %d.\n", ++ module->name, ELF32_R_TYPE(rel->r_info)); ++ PRINTK("section %d reloc %d offset 0x%x size %d\n", ++ relindex, i, rel->r_offset, dstsec->sh_size); ++ } ++ } ++ return 0; ++} ++ ++int ++apply_relocate(Elf32_Shdr * sechdrs, const char *strtab, ++ unsigned int symindex, unsigned int relsec, ++ struct module *module) ++{ ++// printk(KERN_ERR "module %s: non-ADD RELOCATION unsupported\n", module->name); ++// return -ENOEXEC; ++ return 0; ++} ++ ++int ++module_finalize(const Elf32_Ehdr * hdr, const Elf_Shdr * sechdrs, ++ struct module *module) ++{ ++ return 0; ++} ++ ++void module_arch_cleanup(struct module *mod) ++{ ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/nds32-elf.h linux-3.4.110/arch/nds32/kernel/nds32-elf.h +--- linux-3.4.110.orig/arch/nds32/kernel/nds32-elf.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/nds32-elf.h 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,855 @@ ++#ifndef _NDS32_ELF_CHECK ++#define _NDS32_ELF_CHECK ++ ++//#define TEST_ELF_CHECK_FUNC ++#ifdef TEST_ELF_CHECK_FUNC ++#include <stdio.h> ++#include <stdlib.h> ++#endif ++ ++//#include <stdio.h> ++//#include <stdarg.h> ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#else ++#include <stdbool.h> ++#endif //#ifdef __cplusplus ++ ++ ++ enum ELF_HEADER_FLAG_FIELD ++ { ++ EHFF_ARCH_VER = 0xF0000000, EHFF_ARCH_VER_SHIFT = 28, ++ //EHFF_RESERVED = 0x08000000, ++ EHFF_HAS_ZOL = 0x04000000, ++ EHFF_ISA_DSP = 0x02000000, ++ EHFF_ISA_FPU_MAC = 0x01000000, ++ EHFF_FPU_REG = 0x00C00000, EHFF_FPU_REG_SHIFT = 22, ++ EHFF_ISA_L2C = 0x00200000, ++ EHFF_ISA_NO_MAC = 0x00100000, ++ EHFF_ISA_MAC_DX = 0x00100000, ++ EHFF_ISA_FPU_DP = 0x00080000, ++ //EHFF_RESERVED = 0x00040000, ++ EHFF_ISA_SATURATION = 0x00020000, ++ EHFF_REDUCED_REGS = 0x00010000, ++ EHFF_ISA_STRING = 0x00008000, ++ EHFF_ISA_16BIT = 0x00004000, ++ EHFF_ISA_IFC = 0x00004000, ++ EHFF_ISA_DIV = 0x00002000, ++ EHFF_ISA_DIV_DX = 0x00002000, ++ EHFF_ISA_AUDIO = 0x00001000, ++ EHFF_ISA_FPU_SP = 0x00000800, ++ EHFF_ISA_EXT2 = 0x00000400, ++ EHFF_ISA_EXT = 0x00000200, ++ EHFF_ISA_EIT = 0x00000100, ++ EHFF_ISA_MFUSR_PC = 0x00000100, ++ EHFF_ABI_VER = 0x000000F0, ++ EHFF_ELF_VER = 0x0000000F, EHFF_ELF_VER_SHIFT = 0, ++ }; ++ ++ ++ enum ELF_HEADER_FLAG_FIELD_ARCH_VER ++ { ++ EHFF_ARCH_VER_RESERVED = 0x0, ++ EHFF_ARCH_VER_V1 = 0x1, ++ EHFF_ARCH_VER_V2 = 0x2, ++ EHFF_ARCH_VER_V3 = 0x3, ++ EHFF_ARCH_VER_V3M = 0x4, ++ }; ++ ++ static const char *EHFF_ARCH_VER_MSG[] = ++ { ++ "RESERVED", ++ "BASE V1", ++ "BASE V2", ++ "BASE V3", ++ "BASE V3M", ++ }; ++ ++ ++ ++ ++ /* ----------------------------------------------------------- */ ++ /* 4-bit for ABI signature, allow up to 16 ABIs */ ++ /* 0 : for OLD ABI V0, phase out ++ * 1 : for V1 , starting with V0 toolchain ++ * 2 : for V2 ++ * 3 : for V2FP (fs0, fs1 as function parameter) ++ * 4 : for AABI */ ++ /* only old N1213HC use V0 */ ++ /* New ABI is used due to return register is changed to r0 from r5 */ ++ /* ----------------------------------------------------------- */ ++#define E_NDS_ABI_V0 0x00000000 ++#define E_NDS_ABI_V1 0x00000010 ++#define E_NDS_ABI_V2 0x00000020 ++#define E_NDS_ABI_V2FP 0x00000030 ++#define E_NDS_ABI_AABI 0x00000040 ++#define E_NDS_ABI_V2FP_PLUS 0x00000050 ++ ++ /* ---------------------------------------------------------------------------- */ ++ /* This flag signifies the version of Andes ELF */ ++ /* note : */ ++ /* 1. v1.3.1 and beyond is accompanying with Baseline ISA 1.0b/2.0/... in ELF. */ ++ /* 2. v1.3.1 is accompanying with Baseline ISA 1.0b in ELF. */ ++ /* ... | MAC | ... | DIV | ... */ ++ /* 3. v1.3.1 is accompanying with Baseline ISA 2.0 and beyond in ELF. */ ++ /* ... | MAC_DX | ... | DIV_DX | ... */ ++ /* ---------------------------------------------------------------------------- */ ++ ++ enum ELF_HEADER_FLAG_FIELD_ELF_VER ++ { ++ EHFF_ELF_VER_1_3_0 = 0x0, ++ EHFF_ELF_VER_1_3_1 = 0x1, ++ EHFF_ELF_VER_1_4_0 = 0x2, ++ }; ++ ++ static const char *EHFF_ELF_VER_MSG[] = ++ { ++ "1.3.0", ++ "1.3.1", ++ "1.4.0", ++ }; ++ /* */ ++ /* sr layout : */ ++ /* sr[14..10] : hardware components */ ++ /* cpu / fpu / audio / ... */ ++ /* sr[9..0] : sr index number dedicated for sr[14..10] */ ++ /* */ ++ ++ // ++ // sr[14..10] definition: ++ // 0 : cpu ++ // 1 : fpu ++ // 2 : audio ++#define INDEX_HW_MASK 0x00007c00 ++#define INDEX_HW_CPU 0x00000000 ++#define INDEX_HW_FPU 0x00000400 ++#define INDEX_HW_AUDIO 0x00000800 ++#define HW_IS_CPU(sr) ((sr & INDEX_HW_MASK) == INDEX_HW_CPU) ++#define HW_IS_FPU(sr) ((sr & INDEX_HW_MASK) == INDEX_HW_FPU) ++#define HW_IS_AUDIO(sr) ((sr & INDEX_HW_MASK) == INDEX_HW_AUDIO) ++ ++ // ++ // sr[9..0] definition: ++ // if (HW_IS_CPU(sr)) // cpu score ++ // sr[9..0] defined in chap 9 of Andes-Privilege-Architecture spec. ++ // else if (HW_IS_FPU(sr)) // fpu score ++ // sr[9..0] == SR_FPU_FPCFG, FPCFG defined in FPU_ISA_EXT spec. ++ // else if (HW_IS_AUDIO(sr)) // audio score ++ // //none register is used in loader checking mechanism ++ // ++#define SR_INDEX_MASK 0x000003ff ++#define SR_INDEX(sr) (sr & SR_INDEX_MASK) ++#define CPU_SR_INDEX(x,y,z) ((x << 7) + (y << 3) + z) ++#define FPU_SR_FPCFG() (INDEX_HW_FPU) ++ ++ //FPU-belonged system registers ++#define SR_FPU_FPCFG 0x00 ++ ++#define SR_NOT_EXIST 0xffffffff ++ ++ typedef unsigned int (* CALLBACK_FUNC) (unsigned int index); ++ ++ ++ static const char *NEC_MSG_FPU_reg[5] = ++ { ++ "N/A", ++ " 8SP/ 4DP", ++ "16SP/ 8DP", ++ "32SP/16DP", ++ "32SP/32DP" ++ }; ++ static const char *NEC_MSG_endian[2] = ++ { ++ "little", ++ "big" ++ }; ++ ++#define EM_NDS32 167 ++#if defined elf_check_swap_2 || defined elf_check_swap_4 ++#error "ERROR : elf_check_swap_2 and elf_check_swap_4 are multiple defined" ++#endif ++#define elf_check_swap_2(data) (((data&0x0000ff00)>>8) | ((data&0x000000ff)<<8)) ++#define elf_check_swap_4(data) (((data&0xff000000)>>24) | \ ++ ((data&0x00ff0000)>>8) | \ ++ ((data&0x0000ff00)<<8) | \ ++ ((data&0x000000ff)<<24)) ++ ++#define MSC_CFG_BASEV 0x0000e000 ++ ++#define CPU_VER_EXT 0x00000001 ++#define CPU_VER_A16 0x00000002 ++#define CPU_VER_EXT2 0x00000004 ++#define CPU_VER_FPU 0x00000008 ++#define CPU_VER_STRING 0x00000010 ++#define CPU_VER_SATURATION 0x00000020 ++ ++#define MSC_CFG_DIV 0x00000020 ++#define MSC_CFG_MAC 0x00000040 ++#define MSC_CFG_L2C 0x00000200 ++#define MSC_CFG_REDUCED_REG 0x00000400 ++#define MSC_CFG_NOD 0x00010000 ++#define MSC_CFG_AUDIO 0x00000180 ++#define MSC_CFG_AUDIO_NONE 0x00000000 ++#define MSC_CFG_IFC 0x00080000 ++#define MSC_CFG_MCU 0x00100000 ++#define MSC_CFG_EX9IT 0x01000000 ++#define MSC_CFG_MSC_EXT 0xc0000000 ++ ++#define MSC_CFG2_DSPPF 0x00000018 ++#define MSC_CFG2_ZOL 0x00000020 ++ ++#define MMU_CFG_DE 0x04000000 ++ ++ typedef struct nds32_elfinfo_s ++ { ++ unsigned int endian; // 1.local-used constant definition ++ // 0 : little , 1 : big ++ // 2.system-used constant definition ++ // little / big depends on system definition ++ unsigned int machine; //magic number (167 for nds32 machine) ++ unsigned int mfusr_pc; //reclaim in baseline v2 ++ unsigned int abi; // abi version ++ unsigned int base16; // 0 : not support , 1 : support ++ unsigned int pex1; ++ unsigned int div; //reclaim in baseline v2 ++ unsigned int pex2; ++ unsigned int fpu; //fpu single precision ++ unsigned int audio; ++ unsigned int string; ++ unsigned int reduced_regs; ++ unsigned int saturation; ++ unsigned int ifc; ++ unsigned int elf_ver; //elf version number, 0 for v1.3.0, 1 for v1.3.1 ++ unsigned int l2c; ++ unsigned int mac; //reclaim in baseline v2 ++ //unsigned int isa_ver;//0x0, baseline = baseline V1 - 16 bit ISA ++ //0x1, baseline = baseline V1 ++ //0x2, baseline = baseline V1 + V2 extension ISA ++ //unsigned int fpu_sp; //fpu double precision ++ //unsigned int fpu_reg; //fpu registers capacity ++ } nds32_elfinfo_t; ++ ++ typedef enum nds32_elfchk_e ++ { ++ endian_chk = 0, ++ machine_chk, ++ isa_chk, ++ abi_chk ++ } nds32_elfchk_t; ++ ++ typedef enum ELF_Fail_Type ++ { ++ EFT_NONE, ++ EFT_WARNING, ++ EFT_ERROR ++ }ELF_Fail_Type; ++ ++ static inline void NEC_itoa(unsigned int value, char *buf, const unsigned int base) ++ { ++ char temp[10] = "\0", ch; ++ int len = 1, index; ++ ++ while(value > 0) ++ { ++ ch = value%base; ++ value = value/base; ++ if(ch >= 10) ++ ch = ch+'a'-10; ++ else ++ ch = ch+'0'; ++ temp[len++] = ch; ++ } ++ len--; ++ ++ index = len; ++ while(index >= 0) ++ { ++ buf[index] = temp[len-index]; ++ index--; ++ } ++ } ++ ++ static inline void NEC_format(char *buf, unsigned int width) ++ { ++ unsigned int len = strlen(buf); ++ memmove(buf+(width-len), buf, len+1); ++ memset(buf, ' ', (width-len)); ++ } ++ ++ static void NEC_sprintf(char *buf, const char *str, ...) ++ { ++ int width, len = 0; ++ va_list ap; ++ char token, temp[100]; ++ buf[0] = '\0'; ++ ++ ++ va_start(ap, str); ++ while(*str != '\0') ++ { ++ if(*str != '%') ++ buf[len++] = *str; ++ else //*str == '%' ++ { ++ token = *(++str); ++ ++ width = 0; ++ while(token >= '0' && token <= '9') ++ { ++ width *= 10; ++ width += token-'0'; ++ token = *(++str); ++ } ++ ++ switch(token) ++ { ++ case 'd': ++ NEC_itoa(va_arg(ap, unsigned int), temp, 10); ++ break; ++ case 'x': ++ NEC_itoa(va_arg(ap, unsigned int), temp, 16); ++ break; ++ case 's': ++ strcpy(temp, va_arg(ap, char *)); ++ break; ++ } ++ ++ if(width != 0) ++ NEC_format(temp, width); ++ ++ buf[len++] = '\0'; ++ strcat(buf, temp); ++ len = strlen(buf); ++ } ++ ++ str++; ++ } ++ buf[len] = '\0'; ++ } ++ ++ //NDS32 strcat for avoiding buf overflow ++ static inline void NEC_strcat_safety(char *destination, unsigned int destination_size, char *source) ++ { ++ strncat(destination, source, destination_size - strlen(destination) - 1); ++ } ++ ++ //NDS32 Elf Check print ++ static inline void NEC_print(char *buf, unsigned int len, ELF_Fail_Type type, const char *name, const char *cpu, const char *elf, const char *error_message) ++ { ++ char temp[100]; ++ switch(type) ++ { ++ case EFT_NONE: ++ NEC_sprintf(temp, "\t | %9s | %9s | %14s\n", cpu, elf, name); ++ break; ++ case EFT_WARNING: ++ NEC_sprintf(temp, "\t?| %9s | %9s | %14s Warning: %s\n", cpu, elf, name, error_message); ++ break; ++ case EFT_ERROR: ++ NEC_sprintf(temp, "\t!| %9s | %9s | %14s Error: %s\n", cpu, elf, name, error_message); ++ break; ++ } ++ NEC_strcat_safety(buf, len, temp); ++ } ++ ++ static inline bool NEC_check_bool(char *buf, unsigned int len, ELF_Fail_Type type, const char *isa, bool cpu, bool elf) ++ { ++ bool code; ++ const char *NEC_MSG_ISA[2] = { "OFF", "ON" }; ++ if(!cpu && elf) ++ code = 1; ++ else ++ { ++ code = 0; ++ type = EFT_NONE; ++ } ++ NEC_print(buf, len, type, isa, NEC_MSG_ISA[cpu], NEC_MSG_ISA[elf], "Not supported by CPU"); ++ return code; ++ } ++ ++ static inline ELF_Fail_Type elf_ver_and_arch_ver_compatibility_check(unsigned int elf_ver, unsigned int arch_ver) ++ { ++ switch(elf_ver) ++ { ++ case EHFF_ELF_VER_1_3_0: ++ switch(arch_ver) ++ { ++ case EHFF_ARCH_VER_V1: ++ return EFT_NONE; ++ default: ++ return EFT_ERROR; ++ } ++ case EHFF_ELF_VER_1_3_1: ++ switch(arch_ver) ++ { ++ case EHFF_ARCH_VER_V1: ++ case EHFF_ARCH_VER_V2: ++ case EHFF_ARCH_VER_V3M: ++ return EFT_NONE; ++ default: ++ return EFT_ERROR; ++ } ++ case EHFF_ELF_VER_1_4_0: ++ switch(arch_ver) ++ { ++ case EHFF_ARCH_VER_V1: ++ case EHFF_ARCH_VER_V2: ++ case EHFF_ARCH_VER_V3: ++ case EHFF_ARCH_VER_V3M: ++ return EFT_NONE; ++ default: ++ return EFT_ERROR; ++ } ++ } ++ return EFT_ERROR; ++ } ++ ++ ++ static inline ELF_Fail_Type arch_ver_check(unsigned int CPU, unsigned int ELF) ++ { ++ switch(CPU) ++ { ++ case EHFF_ARCH_VER_V1: ++ switch(ELF) ++ { ++ case EHFF_ARCH_VER_V1: ++ return EFT_NONE; ++ default: ++ return EFT_ERROR; ++ } ++ case EHFF_ARCH_VER_V2: ++ switch(ELF) ++ { ++ case EHFF_ARCH_VER_V1: ++ case EHFF_ARCH_VER_V2: ++ return EFT_NONE; ++ default: ++ return EFT_ERROR; ++ } ++ case EHFF_ARCH_VER_V3: ++ switch(ELF) ++ { ++ case EHFF_ARCH_VER_V1: ++ case EHFF_ARCH_VER_V2: ++ case EHFF_ARCH_VER_V3: ++ case EHFF_ARCH_VER_V3M: ++ return EFT_NONE; ++ default: ++ return EFT_ERROR; ++ } ++ case EHFF_ARCH_VER_V3M: ++ switch(ELF) ++ { ++ case EHFF_ARCH_VER_V3M: ++ return EFT_NONE; ++ default: ++ return EFT_ERROR; ++ } ++ } ++ return EFT_ERROR; ++ } ++ ++ // buf : buffer of char*, put Target Isa Info into *buf ++ // len : length of buffer (at least 300 chars in length) ++ // buf_status : status of buffer ++ // 0 : ok ++ // 1 : overflow ++#define TARGET_ISA_INFO_LEN 2000 ++ static inline unsigned int elf_check (unsigned char *ehdr, CALLBACK_FUNC reg_read_callback, char *buf, unsigned int len, unsigned int *buf_status) ++ { ++ unsigned int SR_msc_cfg, SR_msc_cfg2 = 0, SR_cpu_ver, SR_mmu_cfg, fpcfg, fucop_exist, fpu_mount; ++ unsigned int CPU_DIV_DX_ISA, CPU_MAC_DX_ISA; ++ unsigned int eflag, ELF_arch_ver, ELF_elf_ver, CPU_arch_ver; ++ unsigned short machine; ++ unsigned char big_endian_elf = 0, big_endian_cpu; ++ ++ char temp[100]; ++ char temp_cpu[10]; ++ char temp_elf[10]; ++ int n_error, n_warning; ++ int CPU_support; ++ unsigned char FPU_reg_elf, FPU_reg_cpu; ++ ELF_Fail_Type error_type; ++ ++ ++ ++ n_error = 0; ++ n_warning = 0; ++ ++ buf[0] = '\0'; ++ *buf_status = 0; ++ ++ SR_cpu_ver = reg_read_callback(CPU_SR_INDEX(0,0,0)); ++ SR_msc_cfg = reg_read_callback(CPU_SR_INDEX(0,4,0)); ++ SR_mmu_cfg = reg_read_callback(CPU_SR_INDEX(0,3,0)); ++ ++ if (SR_msc_cfg & MSC_CFG_MSC_EXT) ++ SR_msc_cfg2 = reg_read_callback(CPU_SR_INDEX(0,4,1)); ++ ++ switch(*((char*)(ehdr+5))) ++ { ++ case 1: ++ big_endian_elf = 0; ++ break; ++ case 2: ++ big_endian_elf = 1; ++ break; ++ } ++ ++ if(SR_mmu_cfg & MMU_CFG_DE) ++ big_endian_cpu = 1; ++ else ++ big_endian_cpu = 0; ++ ++ ++ /* 20091106 note : ++ * 1. In term of OS, elf_check() would be used in OS kernel and ld.so ++ * 2. Since OS is running on SID, eflag/machine did not need endian conversion for big endian format. ++ * 3. Later, elf_check interface is going to cover "OS" case by adding a new parameter. ++ * ++ */ ++#ifdef ELF_CHECKING_OS ++ eflag = *((unsigned int *)(ehdr+36)); ++ machine = *((unsigned short*)(ehdr+18)); ++#else // GDB loader / SID loader ++ eflag = (big_endian_elf == 0)? *((unsigned int *)(ehdr+36)) : elf_check_swap_4(*((unsigned int *)(ehdr+36))); ++ machine = (big_endian_elf == 0)? *((unsigned short*)(ehdr+18)) : elf_check_swap_2(*((unsigned short*)(ehdr+18))); ++#endif ++ ++ ELF_arch_ver = (eflag & EHFF_ARCH_VER) >> EHFF_ARCH_VER_SHIFT; ++ ELF_elf_ver = (eflag & EHFF_ELF_VER) >> EHFF_ELF_VER_SHIFT; ++ ++ CPU_arch_ver = ((SR_msc_cfg & MSC_CFG_BASEV) >> 13) + 1; ++ if(CPU_arch_ver == 3) ++ if(SR_msc_cfg & MSC_CFG_MCU) ++ CPU_arch_ver = 4; ++ ++ /*Basic version check ++ ++ 1.ELF version check ++ 2.Architecture version check ++ 3.Machine check ++ */ ++ if(ELF_elf_ver > EHFF_ELF_VER_1_4_0) ++ { ++ NEC_sprintf(temp, "Error: unsupport ELF version: 0x%x\n", ELF_elf_ver); ++ NEC_strcat_safety(buf, len, temp); ++ return 1; ++ } ++ NEC_sprintf(temp, "ELF version: %s\n", EHFF_ELF_VER_MSG[ELF_elf_ver]); ++ NEC_strcat_safety(buf, len, temp); ++ ++ ++ if(elf_ver_and_arch_ver_compatibility_check(ELF_elf_ver, ELF_arch_ver) == EFT_ERROR) ++ { ++ NEC_sprintf(temp, "Error: architecture version is not supported in this ELF version: %s\n", EHFF_ARCH_VER_MSG[ELF_arch_ver]); ++ NEC_strcat_safety(buf, len, temp); ++ return 1; ++ } ++ ++ NEC_sprintf(temp, "\t %9s %9s \n", "CPU", "ELF"); ++ NEC_strcat_safety(buf, len, temp); ++ if(big_endian_cpu != big_endian_elf) ++ { ++ error_type = EFT_ERROR; ++ n_error++; ++ } ++ else ++ error_type = EFT_NONE; ++ NEC_print(buf, len, error_type, "endianess", NEC_MSG_endian[big_endian_cpu], NEC_MSG_endian[big_endian_elf], "endianess mismatch"); ++ ++ ++ ++ ++ if (EM_NDS32 != machine) ++ { ++ error_type = EFT_ERROR; ++ n_error++; ++ } ++ else ++ error_type = EFT_NONE; ++ NEC_sprintf(temp_cpu, "%d", EM_NDS32); ++ NEC_sprintf(temp_elf, "%d", machine); ++ NEC_print(buf, len, error_type, "machine", temp_cpu, temp_elf, "wrong machine"); ++ ++ ++ error_type = arch_ver_check(CPU_arch_ver, ELF_arch_ver); ++ if(error_type == EFT_ERROR) ++ n_error++; ++ NEC_print(buf, len, error_type, "BASELINE ISA", EHFF_ARCH_VER_MSG[CPU_arch_ver], EHFF_ARCH_VER_MSG[ELF_arch_ver], "BASELINE ISA mismatch"); ++ ++ /*Prepare reference variables ++ ++ 1.DIV, MAC, DX ++ 2.FPU ++ */ ++ ++ CPU_MAC_DX_ISA = 0; ++ CPU_DIV_DX_ISA = 0; ++ switch(CPU_arch_ver) ++ { ++ case EHFF_ARCH_VER_V1: ++ if (SR_msc_cfg & MSC_CFG_MAC) ++ CPU_MAC_DX_ISA = 1; ++ if (SR_msc_cfg & MSC_CFG_DIV) ++ CPU_DIV_DX_ISA = 1; ++ break; ++ case EHFF_ARCH_VER_V2: ++ case EHFF_ARCH_VER_V3: ++ case EHFF_ARCH_VER_V3M: ++ if (!(SR_msc_cfg & MSC_CFG_NOD)) ++ { ++ CPU_MAC_DX_ISA = 1; ++ CPU_DIV_DX_ISA = 1; ++ } ++ break; ++ } ++ fpu_mount = 0; ++ if (SR_cpu_ver & CPU_VER_FPU) ++ { ++ fucop_exist = reg_read_callback(CPU_SR_INDEX(0,5,0)); ++ if (fucop_exist & 0x80000000) ++ { ++ fpu_mount = 1; ++ fpcfg = reg_read_callback(FPU_SR_FPCFG()); ++ } ++ else ++ fpu_mount = 0; ++ } ++ ++ //Parse Configuration field (bit 27~8) ++ ++ //bit 27 Reserved ++ //bit 26 ZOL ++ CPU_support = 0; ++ if ((SR_msc_cfg & MSC_CFG_MSC_EXT) && (SR_msc_cfg2 & MSC_CFG2_ZOL)) ++ CPU_support = 1; ++ if (ELF_elf_ver == EHFF_ELF_VER_1_4_0) ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "ZOL", CPU_support, eflag & EHFF_HAS_ZOL); ++ ++ //bit 25 DSP ++ CPU_support = 0; ++ if ((SR_msc_cfg & MSC_CFG_MSC_EXT) && (SR_msc_cfg2 & MSC_CFG2_DSPPF)) ++ CPU_support = 1; ++ if (ELF_elf_ver == EHFF_ELF_VER_1_4_0) ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "DSP ISA", CPU_support, eflag & EHFF_ISA_DSP); ++ ++ //bit 24 ++ CPU_support = 0; ++ if(fpu_mount) ++ if(fpcfg & 0x00000010) ++ CPU_support = 1; ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "FPU MAC ISA", CPU_support, eflag & EHFF_ISA_FPU_MAC); ++ ++ //bit 23~22 ++ if(fpu_mount) ++ FPU_reg_cpu = ((fpcfg >> 2) & 0x3) + 1; ++ else ++ FPU_reg_cpu = 0; ++ ++ if(eflag & (EHFF_ISA_FPU_SP | EHFF_ISA_FPU_DP | EHFF_ISA_FPU_MAC)) ++ FPU_reg_elf = ((eflag & EHFF_FPU_REG) >> EHFF_FPU_REG_SHIFT) + 1; ++ else ++ FPU_reg_elf = 0; ++ if(FPU_reg_elf > FPU_reg_cpu) ++ { ++ error_type = EFT_ERROR; ++ n_error++; ++ } ++ else ++ error_type = EFT_NONE; ++ NEC_print(buf, len, error_type, "FPU REGISTER", NEC_MSG_FPU_reg[FPU_reg_cpu], NEC_MSG_FPU_reg[FPU_reg_elf], ++ "FPU REGISTERS not supported by CPU"); ++ //bit 21 ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "L2C ISA", SR_msc_cfg & MSC_CFG_L2C, eflag & EHFF_ISA_L2C); ++ ++ //bit 20 ++ //MAC_DX check ++ // Target Machine certainly has MAC_DX under the following conditions: ++ // 1. Baseline V1 ISA && MSC_CFG.MAC (softcore version) ++ // 2. Baseline V2 ISA && D0/D1 support ++ // 3. Baseline V3 ISA && D0/D1 support ++ ++ switch(ELF_arch_ver) ++ { ++ case EHFF_ARCH_VER_V1: ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "MAC/MAC DX ISA", CPU_MAC_DX_ISA, !(eflag & EHFF_ISA_NO_MAC)); ++ break; ++ case EHFF_ARCH_VER_V2: ++ case EHFF_ARCH_VER_V3: ++ case EHFF_ARCH_VER_V3M: ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "MAC DX ISA", CPU_MAC_DX_ISA, eflag & EHFF_ISA_MAC_DX); ++ break; ++ } ++ //bit 19 ++ CPU_support = 0; ++ if(fpu_mount) ++ if(fpcfg & 0x00000002) ++ CPU_support = 1; ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "FPU DP ISA", CPU_support, eflag & EHFF_ISA_FPU_DP); ++ ++ ++ //bit 18 Reserved ++ //bit 17 ++ switch(ELF_elf_ver) ++ { ++ case EHFF_ELF_VER_1_3_0: ++ case EHFF_ELF_VER_1_3_1: ++ break; ++ case EHFF_ELF_VER_1_4_0: ++ switch(ELF_arch_ver) ++ { ++ case EHFF_ARCH_VER_V3: ++ case EHFF_ARCH_VER_V3M: ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "SATURATION ISA", SR_cpu_ver & CPU_VER_SATURATION, eflag & EHFF_ISA_SATURATION); ++ break; ++ } ++ break; ++ } ++ //bit 16 ++ if(SR_msc_cfg & MSC_CFG_REDUCED_REG) ++ CPU_support = 0; ++ else ++ CPU_support = 1; ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "32 GPR", CPU_support, (eflag & EHFF_REDUCED_REGS) == 0); ++ ++ //bit 15 ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "STRING ISA", SR_cpu_ver & CPU_VER_STRING, eflag & EHFF_ISA_STRING); ++ ++ //bit 14 ++ switch(ELF_elf_ver) ++ { ++ case EHFF_ELF_VER_1_3_0: ++ case EHFF_ELF_VER_1_3_1: ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "16-BIT ISA", SR_cpu_ver & CPU_VER_A16, eflag & EHFF_ISA_16BIT); ++ break; ++ case EHFF_ELF_VER_1_4_0: ++ switch(ELF_arch_ver) ++ { ++ case EHFF_ARCH_VER_V1: ++ case EHFF_ARCH_VER_V2: ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "16-BIT ISA", SR_cpu_ver & CPU_VER_A16, eflag & EHFF_ISA_16BIT); ++ break; ++ case EHFF_ARCH_VER_V3: ++ case EHFF_ARCH_VER_V3M: ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "IFC ISA", SR_msc_cfg & MSC_CFG_IFC, eflag & EHFF_ISA_IFC); ++ break; ++ } ++ break; ++ } ++ ++ //bit 13 ++ switch(ELF_arch_ver) ++ { ++ case EHFF_ARCH_VER_V1: ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "DIV DX ISA", CPU_DIV_DX_ISA, eflag & EHFF_ISA_DIV); ++ break; ++ case EHFF_ARCH_VER_V2: ++ case EHFF_ARCH_VER_V3: ++ case EHFF_ARCH_VER_V3M: ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "DIV DX ISA", CPU_DIV_DX_ISA, eflag & EHFF_ISA_DIV_DX); ++ break; ++ } ++ //bit 12 ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "AUDIO/DSP ISA", SR_msc_cfg & MSC_CFG_AUDIO, eflag & EHFF_ISA_AUDIO); ++ //bit 11 ++ CPU_support = 0; ++ if(fpu_mount) ++ if(fpcfg & 0x00000001) ++ CPU_support = 1; ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "FPU SP ISA", CPU_support, eflag & EHFF_ISA_FPU_SP); ++ ++ //bit 10 ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "PEX2 ISA", SR_cpu_ver & CPU_VER_EXT2, eflag & EHFF_ISA_EXT2); ++ ++ //bit 9 ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "PEX1 ISA", SR_cpu_ver & CPU_VER_EXT, eflag & EHFF_ISA_EXT); ++ ++ //bit 8 ++ CPU_support = 0; ++ if(CPU_arch_ver == EHFF_ARCH_VER_V3M) ++ CPU_support = 1; ++ switch(ELF_elf_ver) ++ { ++ case EHFF_ELF_VER_1_3_0: ++ case EHFF_ELF_VER_1_3_1: ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "MFUSR_PC ISA", CPU_support, eflag & EHFF_ISA_MFUSR_PC); ++ break; ++ case EHFF_ELF_VER_1_4_0: ++ switch(ELF_arch_ver) ++ { ++ case EHFF_ARCH_VER_V1: ++ case EHFF_ARCH_VER_V2: ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "MFUSR_PC ISA", CPU_support, eflag & EHFF_ISA_MFUSR_PC); ++ break; ++ case EHFF_ARCH_VER_V3: ++ case EHFF_ARCH_VER_V3M: ++ n_error += NEC_check_bool(buf, len, EFT_ERROR, "EIT ISA", SR_msc_cfg & MSC_CFG_EX9IT, eflag & EHFF_ISA_EIT); ++ break; ++ } ++ break; ++ } ++ ++ if(n_error) ++ { ++ NEC_strcat_safety(buf, len, (char*)"Error: ELF and CPU mismatch\n"); ++ NEC_sprintf(temp, "Total Error: %d\n", n_error); ++ NEC_strcat_safety(buf, len, temp); ++ ++ NEC_strcat_safety(buf, len, (char*)"Usage error, Consult Andes Toolchains and their compatible Andes cores for the Toolchain-CPU compatibility.\n"); ++ NEC_strcat_safety(buf, len, (char*)"The Loader Checking can be disabled under Debug Configuration.\n"); ++ } ++ else ++ NEC_strcat_safety(buf, len, (char*)"NDS32 ELF checking pass\n"); ++ ++ if(n_warning) ++ { ++ NEC_sprintf(temp, "Total Warning: %d\n", n_warning); ++ NEC_strcat_safety(buf, len, temp); ++ } ++ ++ ++ // checking buf overflow ++ if(strlen(buf) >= len) ++ *buf_status = 1; ++ ++ return n_error; ++ } //end of elf_check ++ ++#undef elf_check_swap_2 ++#undef elf_check_swap_4 ++ ++#undef MSC_CFG_BASEV ++ ++#undef CPU_VER_STRING ++#undef CPU_VER_EXT ++#undef CPU_VER_A16 ++#undef CPU_VER_EXT2 ++#undef CPU_VER_FPU ++#undef CPU_VER_SATURATION ++ ++#undef MSC_CFG_DIV ++#undef MSC_CFG_MAC ++#undef MSC_CFG_L2C ++#undef MSC_CFG_REDUCED_REG ++#undef MSC_CFG_NOD ++#undef MSC_CFG_AUDIO ++#undef MSC_CFG_AUDIO_NONE ++#undef MSC_CFG_IFC ++#undef MSC_CFG_MCU ++#undef MSC_CFG_EX9IT ++#undef MSC_CFG_MSC_EXT ++ ++#undef MSC_CFG2_DSPPF ++#undef MSC_CFG2_ZOL ++ ++#undef MMU_CFG_DE ++ ++#ifdef __cplusplus ++} ++#endif //#ifdef __cplusplus ++ ++#endif //end of _NDS32_ELF_CHECK ++ +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/nds32_ksyms.c linux-3.4.110/arch/nds32/kernel/nds32_ksyms.c +--- linux-3.4.110.orig/arch/nds32/kernel/nds32_ksyms.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/nds32_ksyms.c 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,103 @@ ++/* ++ * arch/nds32/kernel/nds32_ksyms.c ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++ ++#include <linux/module.h> ++#include <linux/string.h> ++#include <linux/delay.h> ++#include <linux/in6.h> ++#include <linux/syscalls.h> ++ ++#include <asm/checksum.h> ++#include <asm/io.h> ++#include <asm/system.h> ++#include <asm/uaccess.h> ++ ++/* ++ * libgcc functions - functions that are used internally by the ++ * compiler... (prototypes are not correct though, but that ++ * doesn't really matter since they're not versioned). ++ */ ++extern void __ashldi3(void); ++extern void __ashrdi3(void); ++extern void __divsi3(void); ++extern void __lshrdi3(void); ++extern void __modsi3(void); ++extern void __muldi3(void); ++extern void __ucmpdi2(void); ++extern void __udivdi3(void); ++extern void __umoddi3(void); ++extern void __udivmoddi4(void); ++extern void __udivsi3(void); ++extern void __umodsi3(void); ++ ++/* ++ * This has a special calling convention; it doesn't ++ * modify any of the usual registers, except for LR. ++ */ ++#define EXPORT_SYMBOL_ALIAS(sym,orig) \ ++ const struct kernel_symbol __ksymtab_##sym \ ++ __attribute__((section("__ksymtab"))) = \ ++ { (unsigned long)&orig, #sym }; ++ ++/* ++ * floating point math emulator support. ++ * These symbols will never change their calling convention... ++ */ ++ ++/* networking */ ++EXPORT_SYMBOL(csum_partial); ++EXPORT_SYMBOL(csum_partial_copy_nocheck); ++ ++/* string / mem functions */ ++EXPORT_SYMBOL(strchr); ++EXPORT_SYMBOL(strrchr); ++EXPORT_SYMBOL(memset); ++EXPORT_SYMBOL(memcpy); ++EXPORT_SYMBOL(memmove); ++EXPORT_SYMBOL(__memzero); ++ ++/* user mem (segment) */ ++EXPORT_SYMBOL(__arch_copy_from_user); ++EXPORT_SYMBOL(__arch_copy_to_user); ++EXPORT_SYMBOL(__arch_clear_user); ++EXPORT_SYMBOL(__arch_strnlen_user); ++EXPORT_SYMBOL(__arch_strncpy_from_user); ++ ++EXPORT_SYMBOL(__get_user_1); ++EXPORT_SYMBOL(__get_user_2); ++EXPORT_SYMBOL(__get_user_4); ++EXPORT_SYMBOL(__get_user_8); ++ ++EXPORT_SYMBOL(__put_user_1); ++EXPORT_SYMBOL(__put_user_2); ++EXPORT_SYMBOL(__put_user_4); ++EXPORT_SYMBOL(__put_user_8); ++ ++/* gcc lib functions */ ++EXPORT_SYMBOL(__ashldi3); ++EXPORT_SYMBOL(__ashrdi3); ++EXPORT_SYMBOL(__divsi3); ++EXPORT_SYMBOL(__lshrdi3); ++EXPORT_SYMBOL(__modsi3); ++EXPORT_SYMBOL(__muldi3); ++EXPORT_SYMBOL(__ucmpdi2); ++EXPORT_SYMBOL(__udivdi3); ++EXPORT_SYMBOL(__umoddi3); ++EXPORT_SYMBOL(__udivmoddi4); ++EXPORT_SYMBOL(__udivsi3); ++EXPORT_SYMBOL(__umodsi3); ++ ++/* syscalls */ ++EXPORT_SYMBOL(sys_write); ++EXPORT_SYMBOL(sys_lseek); ++EXPORT_SYMBOL(sys_exit); ++EXPORT_SYMBOL(sys_wait4); ++ ++/* cache handling */ ++ ++EXPORT_SYMBOL(cpu_icache_inval_all); ++EXPORT_SYMBOL(cpu_dcache_wbinval_all); ++EXPORT_SYMBOL(cpu_dma_inval_range); ++EXPORT_SYMBOL(cpu_dma_wb_range); +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/proc.c linux-3.4.110/arch/nds32/kernel/proc.c +--- linux-3.4.110.orig/arch/nds32/kernel/proc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/proc.c 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,81 @@ ++/* ++ * linux/arch/nds32/kernel/setup.c ++ * ++ * Copyright (C) 1995-2001 Russell King ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++/* ============================================================================ ++ * Copyright (C) 2007 Andes Technology Corporation ++ * This file is part of Linux and should be licensed under the GPL. ++ * See the file COPYING for conditions for redistribution. ++ * ++ * Abstract: ++ * ++ * This program is for Andes NDS32 architecture. ++ * ++ * Revision History: ++ * ++ * Jul.05.2007 Initial ported by Tom, revised and patched for KGDB ++ * by Harry. ++ * ++ * Note: ++ * ++ * ============================================================================ ++ */ ++ ++#include <asm/procinfo.h> ++ ++struct proc_info_item info_item = { ++ "AndesCore", ++#ifndef CONFIG_CPU_ICACHE_DISABLE ++ "I" ++#endif ++#ifndef CONFIG_CPU_DCACHE_DISABLE ++ "D" ++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH ++ "(wt)" ++#else ++ "(wb)" ++#endif ++#endif ++}; ++ ++struct proc_info_list n10_proc_info ++ __attribute__ ((section(".proc.info.init"))) = { ++.cpu_val = 0x0a000000,.cpu_mask = 0xff000000,.arch_name = ++ "NDS32 N10",.elf_name = "NDS32 ELF",.elf_hwcap = 0,.info = ++ &info_item,}; ++ ++struct proc_info_list n12_proc_info ++ __attribute__ ((section(".proc.info.init"))) = { ++.cpu_val = 0x0c000000,.cpu_mask = 0xff000000,.arch_name = ++ "NDS32 N12",.elf_name = "NDS32 ELF",.elf_hwcap = 0,.info = ++ &info_item,}; ++ ++struct proc_info_list n13_proc_info ++ __attribute__ ((section(".proc.info.init"))) = { ++.cpu_val = 0x0d000000,.cpu_mask = 0xff000000,.arch_name = ++ "NDS32 N13",.elf_name = "NDS32 ELF",.elf_hwcap = 0,.info = ++ &info_item,}; ++ ++struct proc_info_list n968_proc_info ++ __attribute__ ((section(".proc.info.init"))) = { ++.cpu_val = 0x19000000,.cpu_mask = 0xff000000,.arch_name = ++ "NDS32 N968",.elf_name = "NDS32 ELF",.elf_hwcap = 0,.info = ++ &info_item,}; ++ ++struct proc_info_list n1068_proc_info ++ __attribute__ ((section(".proc.info.init"))) = { ++.cpu_val = 0x1a000000,.cpu_mask = 0xff000000,.arch_name = ++ "NDS32 N1068",.elf_name = "NDS32 ELF",.elf_hwcap = 0,.info = ++ &info_item,}; ++ ++// the last one (a roust way to do so) ++struct proc_info_list nXX_proc_info ++ __attribute__ ((section(".proc.info.init"))) = { ++.cpu_val = 0x00000000,.cpu_mask = 0x00000000,.arch_name = ++ "NDS32 N??",.elf_name = "NDS32 ELF",.elf_hwcap = 0,.info = ++ &info_item,}; +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/process.c linux-3.4.110/arch/nds32/kernel/process.c +--- linux-3.4.110.orig/arch/nds32/kernel/process.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/process.c 2016-04-07 10:20:50.942081024 +0200 +@@ -0,0 +1,630 @@ ++/* ++ * linux/arch/nds32/kernel/process.c ++ */ ++/* Copyright (C) 1996-2000 Russell King - Converted to ARM. ++ * Original Copyright (C) 1995 Linus Torvalds ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++/* ============================================================================ ++ * Copyright (C) 2007 Andes Technology Corporation ++ * This file is part of Linux and should be licensed under the GPL. ++ * See the file COPYING for conditions for redistribution. ++ * ++ * Abstract: ++ * ++ * This program is process implementation for NDS32 architecture, and it ++ * is original referred from ARM. ++ * ++ * Revision History: ++ * ++ * Oct.02.2007 Initial ported by Tom, Shawn, Steven, and Harry. ++ * Oct.03.2007 Updated get_wchan() for info under /proc. ++ * ++ * Note: ++ * ++ * ============================================================================ ++ */ ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++#include <linux/kallsyms.h> ++#include <asm/hardware.h> ++#include <asm/leds.h> ++#include <asm/uaccess.h> ++#include <asm/elf.h> ++#include <asm/fpu.h> ++#include <asm/audio.h> ++#include <linux/elf.h> ++#include <linux/tick.h> ++#include <linux/proc_fs.h> ++ ++extern const char *processor_modes[]; ++extern void setup_mm_for_reboot(char mode); ++extern struct task_struct *_switch(struct task_struct *last, ++ struct thread_info *prev, ++ struct thread_info *next); ++ ++#ifndef CONFIG_UNLAZY_FPU ++struct task_struct *last_task_used_math = NULL; ++#endif ++#ifndef CONFIG_UNLAZY_AUDIO ++struct task_struct *last_task_used_audio = NULL; ++#endif ++static volatile int hlt_counter; ++ ++#ifdef CONFIG_PROC_FS ++struct proc_dir_entry *proc_dir_cpu; ++EXPORT_SYMBOL(proc_dir_cpu); ++#endif ++ ++extern inline void arch_reset(char mode) ++{ ++ if (mode == 's') { ++ /* Use cpu handler, jump to 0 */ ++ cpu_reset(0); ++ } else { ++ /* ++ * Suppose there should be HW function. ++ * Here we used one tick watchdog as a trick. ++ * It is not very good idea in the view of SoC ++ * design, but smart in firmware functionality. ++ * Harry@Jan,08.2008 ++ */ ++ REG32(WDT_FTWDT010_0_VA_BASE + 0x0C) = 0; // WdCR ++ REG32(WDT_FTWDT010_0_VA_BASE + 0x04) = 1; // WdLoad ++ REG32(WDT_FTWDT010_0_VA_BASE + 0x08) = 0x5AB9; // WdRestart ++ REG32(WDT_FTWDT010_0_VA_BASE + 0x0C) = 0x13; // Go... ++ } ++} ++ ++#ifndef arch_idle ++static inline void arch_idle(void) ++{ ++ cpu_do_idle(); ++} ++#endif ++ ++void disable_hlt(void) ++{ ++ hlt_counter++; ++} ++ ++EXPORT_SYMBOL(disable_hlt); ++ ++void enable_hlt(void) ++{ ++ hlt_counter--; ++} ++ ++EXPORT_SYMBOL(enable_hlt); ++ ++static int __init nohlt_setup(char *__unused) ++{ ++ hlt_counter = 1; ++ return 1; ++} ++ ++static int __init hlt_setup(char *__unused) ++{ ++ hlt_counter = 0; ++ return 1; ++} ++ ++__setup("nohlt", nohlt_setup); ++__setup("hlt", hlt_setup); ++ ++/* ++ * The following aren't currently used. ++ */ ++ ++void (*pm_idle) (void) = NULL; ++EXPORT_SYMBOL(pm_idle); ++ ++void (*pm_power_off) (void); ++EXPORT_SYMBOL(pm_power_off); ++ ++/* ++ * This is our default idle handler. We need to disable ++ * interrupts here to ensure we don't miss a wakeup call. ++ */ ++void default_idle(void) ++{ ++ local_irq_disable(); ++ if (!need_resched() && !hlt_counter) ++ arch_idle(); ++ local_irq_enable(); ++} ++ ++/* ++ * The idle thread. We try to conserve power, while trying to keep ++ * overall latency low. The architecture specific idle is passed ++ * a value to indicate the level of "idleness" of the system. ++ */ ++void cpu_idle(void) ++{ ++ ++ /* endless idle loop with no priority at all */ ++ while (1) { ++ void (*idle) (void) = pm_idle; ++ ++ if (!idle) ++ idle = default_idle; ++ tick_nohz_idle_enter(); ++ leds_event(led_idle_start); ++ while (!need_resched()) ++ idle(); ++ leds_event(led_idle_end); ++ tick_nohz_idle_exit(); ++ preempt_enable_no_resched(); ++ schedule(); ++ preempt_disable(); ++ } ++} ++ ++static char reboot_mode = 'h'; ++ ++int __init reboot_setup(char *str) ++{ ++ reboot_mode = str[0]; ++ return 1; ++} ++ ++#ifdef CONFIG_PLAT_AG102 ++static int cpub_pwroff(void) ++{ ++ //PCU_SET_REG(PCS9_PARA, ++ // PCU_PREPARE(PCS9_PARA, IE, 0x0) | ++ // PCU_PREPARE(PCS9_PARA, CMD, PCS_CMD_SCALING) | ++ // PCU_PREPARE(PCS9_PARA, SYNC, PCS_SYNC_SRC) | ++ // PCU_PREPARE(PCS9_PARA, NXTPAR, 0x1b) // turn off cpub power ++ //); ++ //printk("cpub Power off: ok!!!OKOKOK\n"); ++ //REG32(PCU_VA_BASE + 0x1A4) = (0x0000001B & 0x00FFFFFF)| ((0x2 << 24) & 0x0F000000) | ((0x1 << 28) & 0x70000000) | 0x00000000; ++ //__asm__ volatile ("standby wait_done\n"); ++ //PCU_SET_REG(PCS9_ST1, 0x0); // clear status ++ //REG32(PCU_VA_BASE + 0x1A8) = 0x0; ++ ++ //par = PCS_POWER_CPUB; ++ //PCU_SET_REG(PCS9_PARA, ++ //PCU_PREPARE(PCS9_PARA, IE, 0x1) | ++ //PCU_PREPARE(PCS9_PARA, CMD, PCS_CMD_PW_DOWN) | ++ //PCU_PREPARE(PCS9_PARA, SYNC, PCS_SYNC_SRC) | ++ //PCU_PREPARE(PCS9_PARA, NXTPAR, 0x6) // turn off all power ++ ++ //printk("cpua Power off: ok!!!YAYAYA\n"); ++ //printk("The value = 0x%08x\n", (0x00000006 & 0x00FFFFFF)| ((0x1 << 24) & 0x0F000000) | ((0x2 << 28) & 0x70000000) | 0x80000000); ++ REG32(PCU_VA_BASE + 0x1A4) = ++ (0x00000006 & 0x00FFFFFF) | ((0x1 << 24) & 0x0F000000) | ++ ((0x2 << 28) & 0x70000000) | 0x80000000; ++ __asm__ volatile ("standby wake_grant\n"); ++ return (0); ++} ++#else ++static int cpub_pwroff(void) ++{ ++ return 0; ++} ++ ++#endif ++ ++__setup("reboot=", reboot_setup); ++ ++void machine_halt(void) ++{ ++ //ADD by river 2011.04.14 ++ cpub_pwroff(); ++} ++ ++EXPORT_SYMBOL(machine_halt); ++ ++void machine_power_off(void) ++{ ++ if (pm_power_off) ++ pm_power_off(); ++} ++ ++EXPORT_SYMBOL(machine_power_off); ++ ++void machine_restart(char *__unused) ++{ ++ /* ++ * Clean and disable cache, and turn off interrupts ++ */ ++ cpu_proc_fin(); ++ ++ /* ++ * Tell the mm system that we are going to reboot - ++ * we may need it to insert some 1:1 mappings so that ++ * soft boot works. ++ */ ++ setup_mm_for_reboot(reboot_mode); ++ ++ /* ++ * Now call the architecture specific reboot code. ++ */ ++ arch_reset(reboot_mode); ++ ++ /* ++ * Whoops - the architecture was unable to reboot. ++ * Tell the user! ++ */ ++ mdelay(1000); ++ printk("Reboot failed -- System halted\n"); ++ while (1) ; ++} ++ ++EXPORT_SYMBOL(machine_restart); ++ ++void show_regs(struct pt_regs *regs) ++{ ++ print_symbol("PC is at %s\n", instruction_pointer(regs)); ++ print_symbol("LR is at %s\n", regs->NDS32_lp); ++ printk("pc : [<%08lx>] lp : [<%08lx>] %s\n" ++ "sp : %08lx fp : %08lx gp : %08lx\n", ++ instruction_pointer(regs), ++ regs->NDS32_lp, print_tainted(), regs->NDS32_sp, ++ regs->NDS32_fp, regs->NDS32_gp); ++ printk("r25: %08lx r24 : %08lx\n", regs->NDS32_r25, regs->NDS32_r24); ++ ++ printk("r23: %08lx r22: %08lx r21: %08lx r20: %08lx\n", ++ regs->NDS32_r23, regs->NDS32_r22, ++ regs->NDS32_r21, regs->NDS32_r20); ++ printk("r19: %08lx r18: %08lx r17: %08lx r16: %08lx\n", ++ regs->NDS32_r19, regs->NDS32_r18, ++ regs->NDS32_r17, regs->NDS32_r16); ++ printk("r15: %08lx r14: %08lx r13: %08lx r12: %08lx\n", ++ regs->NDS32_r15, regs->NDS32_r14, ++ regs->NDS32_r13, regs->NDS32_r12); ++ printk("r11: %08lx r10: %08lx r9 : %08lx r8 : %08lx\n", ++ regs->NDS32_r11, regs->NDS32_r10, ++ regs->NDS32_r9, regs->NDS32_r8); ++ printk("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", ++ regs->NDS32_r7, regs->NDS32_r6, regs->NDS32_r5, regs->NDS32_r4); ++ printk("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", ++ regs->NDS32_r3, regs->NDS32_r2, regs->NDS32_r1, regs->NDS32_r0); ++ printk(" IRQs o%s Segment %s\n", ++ interrupts_enabled(regs) ? "n" : "ff", ++ segment_eq(get_fs(), get_ds())? "kernel" : "user"); ++} ++ ++void show_fpregs(struct user_fp *regs) ++{ ++ int i; ++ ++ for (i = 0; i < 8; i++) { ++ unsigned long *p; ++ char type; ++ ++ p = (unsigned long *)(regs->fpregs + i); ++ ++ switch (regs->ftype[i]) { ++ case 1: ++ type = 'f'; ++ break; ++ case 2: ++ type = 'd'; ++ break; ++ case 3: ++ type = 'e'; ++ break; ++ default: ++ type = '?'; ++ break; ++ } ++ if (regs->init_flag) ++ type = '?'; ++ ++ printk(" f%d(%c): %08lx %08lx %08lx%c", ++ i, type, p[0], p[1], p[2], i & 1 ? '\n' : ' '); ++ } ++ ++ printk("FPSR: %08lx FPCR: %08lx\n", ++ (unsigned long)regs->fpsr, (unsigned long)regs->fpcr); ++} ++ ++/* ++ * Task structure and kernel stack allocation. ++ */ ++static unsigned long *thread_info_head; ++static unsigned int nr_thread_info; ++ ++#define EXTRA_TASK_STRUCT 4 ++#define ll_alloc_task_struct() ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) ++#define ll_free_task_struct(p) free_pages((unsigned long)(p),1) ++ ++struct thread_info *alloc_thread_info(struct task_struct *task) ++{ ++ struct thread_info *thread = NULL; ++ ++ if (EXTRA_TASK_STRUCT) { ++ unsigned long *p = thread_info_head; ++ ++ if (p) { ++ thread_info_head = (unsigned long *)p[0]; ++ nr_thread_info -= 1; ++ } ++ thread = (struct thread_info *)p; ++ } ++ ++ if (!thread) ++ thread = ll_alloc_task_struct(); ++ ++#ifdef CONFIG_MAGIC_SYSRQ ++ /* ++ * The stack must be cleared if you want SYSRQ-T to ++ * give sensible stack usage information ++ */ ++ if (thread) { ++ char *p = (char *)thread; ++ memzero(p + KERNEL_STACK_SIZE, KERNEL_STACK_SIZE); ++ } ++#endif ++ return thread; ++} ++ ++void free_thread_info(struct thread_info *thread) ++{ ++ if (EXTRA_TASK_STRUCT && nr_thread_info < EXTRA_TASK_STRUCT) { ++ unsigned long *p = (unsigned long *)thread; ++ p[0] = (unsigned long)thread_info_head; ++ thread_info_head = p; ++ nr_thread_info += 1; ++ } else ++ ll_free_task_struct(thread); ++} ++ ++/* ++ * Free current thread data structures etc.. ++ */ ++void exit_thread(void) ++{ ++#if defined(CONFIG_FPU) ++# ifndef CONFIG_UNLAZY_FPU ++ if (last_task_used_math == current) { ++ last_task_used_math = NULL; ++ } ++# endif ++#endif ++#if defined(CONFIG_AUDIO) ++# ifndef CONFIG_UNLAZY_AUDIO ++ if (last_task_used_audio == current) { ++ last_task_used_audio = NULL; ++ } ++# endif ++#endif ++} ++ ++void flush_thread(void) ++{ ++ struct task_struct *tsk = current; ++ ++ memset(&tsk->thread.debug, 0, sizeof(struct debug_info)); ++#if defined(CONFIG_FPU) ++ clear_fpu(task_pt_regs(tsk)); ++ clear_used_math(); ++# ifndef CONFIG_UNLAZY_FPU ++ if (last_task_used_math == current) { ++ last_task_used_math = NULL; ++ } ++# endif ++#endif ++ ++#if defined(CONFIG_AUDIO) ++ clear_audio(task_pt_regs(tsk)); ++ clear_tsk_thread_flag(tsk, TIF_USEDAUDIO); ++# ifndef CONFIG_UNLAZY_AUDIO ++ if (last_task_used_audio == current) { ++ last_task_used_audio = NULL; ++ } ++# endif ++#endif ++ ++} ++ ++void release_thread(struct task_struct *dead_task) ++{ ++} ++ ++asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); ++ ++/* ++ * Shuffle the argument into the correct register before calling the ++ * thread function. $r1 is the thread argument, $r2 is the pointer to ++ * the thread function, and $r3 points to the exit function. ++ */ ++extern void kernel_thread_helper(void); ++asm(".section .text\n" ++ " .align\n" ++ " .type kernel_thread_helper, #function\n" ++ "kernel_thread_helper:\n" ++ " move $r2, $lp\n" ++ " move $r0, $r1\n" ++ " move $lp, $r3\n" ++ " jr $r2 \n" ++ " .size kernel_thread_helper, . - kernel_thread_helper\n" ++ " .previous"); ++ ++pid_t kernel_thread(int (*fn) (void *), void *arg, unsigned long flags) ++{ ++ struct pt_regs regs; ++ ++ memset(®s, 0, sizeof(regs)); ++ ++ regs.NDS32_r1 = (unsigned long)arg; ++ regs.NDS32_r2 = (unsigned long)fn; ++ /* to apply right path */ ++ regs.NDS32_lp = regs.NDS32_r2; ++ regs.NDS32_r3 = (unsigned long)do_exit; ++ regs.NDS32_ipc = (unsigned long)kernel_thread_helper; ++ ++#ifdef __NDS32_EB__ ++#define PSW_DE PSW_mskBE ++#else ++#define PSW_DE 0x0 ++#endif ++ ++#ifdef CONFIG_WBNA ++#define PSW_valWBNA PSW_mskWBNA ++#else ++#define PSW_valWBNA 0x0 ++#endif ++ ++ regs.NDS32_ipsw = ++ (PSW_CPL_ANY | PSW_valWBNA | PSW_mskDT | PSW_mskIT | PSW_DE | ++ PSW_SYSTEM | PSW_INTL_1 | PSW_mskGIE); ++ regs.NDS32_ir0 = ++ (PSW_CPL_ANY | PSW_valWBNA | PSW_mskDT | PSW_mskIT | PSW_DE | ++ PSW_SYSTEM | PSW_INTL_1); ++ ++ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, ++ NULL); ++} ++ ++EXPORT_SYMBOL(kernel_thread); ++ ++int ++copy_thread(unsigned long clone_flags, unsigned long stack_start, ++ unsigned long stk_sz, struct task_struct *p, struct pt_regs *regs) ++{ ++ struct thread_info *thread = task_thread_info(p); ++ struct pt_regs *childregs; ++ ++ childregs = ++ ((struct pt_regs *)((unsigned long)thread + THREAD_SIZE - 8)) - 1; ++ ++ *childregs = *regs; ++ childregs->NDS32_r0 = 0; /* child get zero as ret. */ ++ childregs->NDS32_sp = stack_start; ++ childregs->NDS32_osp = 0; ++ ++ thread->sp_save = ((struct cpu_context_save *)(childregs)) - 1; ++ /* cpu context switching */ ++ thread->sp_save->pc = (unsigned long)ret_from_fork; ++ if (clone_flags & CLONE_SETTLS) ++ childregs->NDS32_r25 = regs->NDS32_r3; ++ ++#ifdef CONFIG_FPU ++ if (used_math()) { ++# ifdef CONFIG_UNLAZY_FPU ++ unlazy_fpu(current); ++# else ++ preempt_disable(); ++ if (last_task_used_math == current) ++ save_fpu(current); ++ preempt_enable(); ++# endif ++ p->thread.fpu = current->thread.fpu; ++ clear_fpu(task_pt_regs(p)); ++ set_stopped_child_used_math(p); ++ } ++#endif ++ ++#ifdef CONFIG_AUDIO ++ if (test_tsk_thread_flag(current, TIF_USEDAUDIO)) { ++# ifdef CONFIG_UNLAZY_AUDIO ++ unlazy_audio(current); ++# else ++ preempt_disable(); ++ if (last_task_used_audio == current) ++ save_audio(current); ++ preempt_enable(); ++# endif ++ p->thread.audio = current->thread.audio; ++ clear_audio(childregs); ++ set_tsk_thread_flag(p, TIF_USEDAUDIO); ++ } ++#endif ++ ++#ifdef CONFIG_HWZOL ++ childregs->NDS32_lb = 0; ++ childregs->NDS32_le = 0; ++ childregs->NDS32_lc = 0; ++#endif ++ ++ return 0; ++} ++ ++struct task_struct *__switch_to(struct task_struct *last, ++ struct thread_info *prev, ++ struct thread_info *next) ++{ ++#if defined(CONFIG_FPU) || defined(CONFIG_AUDIO) ++# ifdef CONFIG_UNLAZY_FPU ++ unlazy_fpu(prev->task); ++# endif ++# ifdef CONFIG_UNLAZY_AUDIO ++ unlazy_audio(prev->task); ++# endif ++ if (!(next->task->flags & PF_KTHREAD)) { ++#ifdef CONFIG_FPU ++ clear_fpu(task_pt_regs(next->task)); ++#endif ++#ifdef CONFIG_AUDIO ++ clear_audio(task_pt_regs(next->task)); ++#endif ++ } ++#endif ++ return _switch(last, prev, next); ++} ++ ++/* ++ * fill in the fpe structure for a core dump... ++ */ ++int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpu) ++{ ++ int fpvalid = 0; ++ ++#if 0 // XXX defined(CONFIG_FPU) ++ struct task_struct *tsk = current; ++ ++ fpvalid = !!tsk_used_math(tsk); ++ if (fpvalid) { ++ unlazy_fpu(tsk, regs); ++ memcpy(fpu, &tsk->thread.fpu, sizeof(*fpu)); ++ } ++#endif ++ ++ return fpvalid; ++} ++ ++EXPORT_SYMBOL(dump_fpu); ++ ++unsigned long get_wchan(struct task_struct *p) ++{ ++ unsigned long fp, lr; ++ unsigned long stack_start, stack_end; ++ int count = 0; ++ ++ if (!p || p == current || p->state == TASK_RUNNING) ++ return 0; ++ ++#ifdef CONFIG_FRAME_POINTER ++ stack_start = (unsigned long)end_of_stack(p); ++ stack_end = (unsigned long)task_stack_page(p) + THREAD_SIZE; ++ ++ fp = thread_saved_fp(p); ++ do { ++ if (fp < stack_start || fp > stack_end) ++ return 0; ++ lr = ((unsigned long *)fp)[0]; ++ if (!in_sched_functions(lr)) ++ return lr; ++ fp = *(unsigned long *)(fp + 4); ++ } while (count++ < 16); ++ return 0; ++#else ++ return 0; ++#endif ++} ++ ++EXPORT_SYMBOL(get_wchan); ++ ++extern int do_elf_check_arch(const struct elf32_hdr *hdr); ++ ++int elf_check_arch(const struct elf32_hdr *hdr) ++{ ++ return do_elf_check_arch(hdr); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/ptrace.c linux-3.4.110/arch/nds32/kernel/ptrace.c +--- linux-3.4.110.orig/arch/nds32/kernel/ptrace.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/ptrace.c 2016-04-07 10:22:02.056831821 +0200 +@@ -0,0 +1,919 @@ ++/* ++ * linux/arch/nds32/kernel/ptrace.c ++ */ ++/* By Ross Biro 1/23/92 ++ * edited by Linus Torvalds ++ * ARM modifications Copyright (C) 2000 Russell King ++ * NDS32 modifications Copyright (C) 2007 Harry Pan ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++/* ============================================================================ ++ * Copyright (C) 2007 Andes Technology Corporation ++ * This file is part of Linux and should be licensed under the GPL. ++ * See the file COPYING for conditions for redistribution. ++ * ++ * Abstract: ++ * ++ * This program is for Andes NDS32 architecture. ++ * ++ * Revision History: ++ * ++ * Jul.31.2007 Initial ported by Tom, Shawn, and Steven, ++ * revised by Harry. ++ * Current implmentation is based on Andes Instruction ++ * Set Architecture Specification (AS-0001-0001) ++ * version:3.7 date:7-20-2007. ++ * It is original taken from ARM, then fit to NDS32. ++ * Aug.15.2007 Mainly updated breakpoint handling base on NDS32 ISA. ++ * I also did code revise. ++ * Nov.14.2007 Fixed up ptrace_set_bpt() while handling 16-bit insn. ++ * Nov.27.2007 Added checking duplicate breakpoints in ++ * add_breakpoint(), based on Shawn's idea. ++ * Dec.06.2007 Added get_user_gpr(). ++ * Apr.17.2009 Added support for FPU and Audio regs. ++ * Added support for PTRACE_GETFPREGS, PTRACE_SETFPREGS, ++ * PTRACE_GETAUREGS, PTRACE_SETAUREGS ++ * ++ * Note: ++ * ++ * Current layout: 0-31 GR, 32-34 SPR, 35-... SR, index start from zero. ++ * ++ * +----------+-----+--------------+---+--------+ ++ * | GR | SPR | SR |...| Audio | ++ * +----------+-----+--------------+---+--------+ ++ * 0 32 35 ...500 531 ++ * ++ * ============================================================================ ++ */ ++#include <linux/kernel.h> ++#include <linux/sched.h> ++#include <linux/mm.h> ++#include <linux/smp.h> ++#include <linux/ptrace.h> ++#include <linux/user.h> ++#include <linux/security.h> ++#include <linux/init.h> ++ ++#include <asm/uaccess.h> ++#include <asm/pgtable.h> ++#include <asm/system.h> ++#include <asm/traps.h> ++#include <asm/fpu.h> ++#include <asm/audio.h> ++ ++#include "ptrace.h" ++ ++#ifdef __NDS32_EL__ ++#define BREAKINST 0x01EA ++#else ++#define BREAKINST 0xEA01 ++#endif ++ ++/* get_user_reg() ++ * ++ * This routine will get a word off of the processes privileged stack. ++ * the offset is how far from the base addr as stored in the THREAD. ++ * this routine assumes that all the privileged stacks are in our ++ * data space. ++ */ ++static inline unsigned int get_user_reg(struct task_struct *task, int offset) ++{ ++ return task_pt_regs(task)->uregs[offset]; ++} ++ ++#if !defined(CONFIG_HSS) ++/* get_user_gpr() ++ * ++ */ ++static unsigned int get_user_gpr(struct task_struct *task, int idx) ++{ ++ unsigned int ret; ++ ++ if (idx < 26) // r0 to r25 ++ ret = get_user_reg(task, idx + 13); ++ else if (idx == 26 || idx == 27) // p0, p1 ++ ret = get_user_reg(task, idx - 26 + 7); ++ else if (idx > 27 && idx < 31) // fp, gp, lp ++ ret = get_user_reg(task, idx + 11); ++ else if (idx == 31) // sp ++ ret = get_user_reg(task, 3); ++ else ++ ret = 0; ++ ++ return ret; ++} ++#endif ++ ++/* put_user_reg() ++ * ++ * this routine will put a word on the processes privileged stack. ++ * the offset is how far from the base addr as stored in the THREAD. ++ * this routine assumes that all the privileged stacks are in our ++ * data space. ++ */ ++static inline int put_user_reg(struct task_struct *task, int offset, long data) ++{ ++ struct pt_regs newregs, *regs = task_pt_regs(task); ++ int ret = -EINVAL; ++ ++ newregs = *regs; ++ newregs.uregs[offset] = data; ++ ++ if (valid_user_regs(&newregs)) { ++ regs->uregs[offset] = data; ++ ret = 0; ++ } ++ ++ return ret; ++} ++ ++#if !defined(CONFIG_HSS) ++/* ++ * Read instruction. ++ */ ++static inline int ++read_insn(struct task_struct *task, unsigned long addr, u32 * res) ++{ ++ int ret; ++ *res = 0; ++ ret = access_process_vm(task, addr, res, 2, 0); ++ if (ret != 2) ++ return 0; ++#ifdef __NDS32_EL__ ++ *res = swab16(*res); ++#endif ++ if ((*res) & 0x8000) ++ return 2; ++ ++ ret = access_process_vm(task, addr, res, 4, 0); ++ if (ret != 4) ++ return 0; ++#ifdef __NDS32_EL__ ++ *res = swab32(*res); ++#endif ++ return 4; ++} ++ ++/* get_branch_address() ++ * ++ * Decode branch instructions and destination. ++ */ ++static unsigned long ++get_branch_address(struct task_struct *child, ++ unsigned long pc, unsigned long insn, unsigned int size) ++{ ++ unsigned int tpc = 0; ++ ++ /* ++ * TODO: COLE ++ * would it be simpler if we use two BREAKs, ++ * one for take, one for not ++ */ ++ ++ if (size == 4) { ++ /* 32-bit instruction */ ++ if ((insn & 0x7e000000) == 0x4c000000) // BR1 ++ { ++ int cond, imm14s; ++ unsigned int rt, ra; ++ ++ rt = (insn >> 20) & 0x1f; ++ ra = (insn >> 15) & 0x1f; ++ cond = (insn >> 14) & 0x01; ++ imm14s = insn & 0x00003fff; ++ ++ if (imm14s & 0x00002000) // sign extend ++ imm14s -= (0x00002000 << 1); ++ ++ rt = get_user_gpr(child, rt); ++ ra = get_user_gpr(child, ra); ++ ++ if (((cond == 1) && (rt != ra)) || // bne ++ ((cond == 0) && (rt == ra))) // beq ++ tpc = pc + (imm14s << 1); ++ } else if ((insn & 0x7e000000) == 0x4e000000) // BR2 ++ { ++ int cond, imm16s, taken = 0; ++ int rt; ++ ++ rt = (insn >> 20) & 0x1f; ++ cond = (insn >> 16) & 0x0f; ++ imm16s = insn & 0x0000ffff; ++ ++ if (imm16s & 0x00008000) // sign extend ++ imm16s -= (0x00008000 << 1); ++ ++ rt = get_user_gpr(child, rt); ++ ++ switch (cond) { ++ case 0x02: // beqz ++ if (rt == 0) ++ taken = 1; ++ break; ++ case 0x03: // bnez ++ if (rt != 0) ++ taken = 1; ++ break; ++ case 0x06: // bgtz ++ if (rt > 0) ++ taken = 1; ++ break; ++ case 0x07: // blez ++ if (rt <= 0) ++ taken = 1; ++ break; ++ case 0x04: // bgez ++ case 0x0c: // bgezal ++ if (rt >= 0) ++ taken = 1; ++ break; ++ case 0x05: // bltz ++ case 0x0d: // bltzal ++ if (rt < 0) ++ taken = 1; ++ break; ++ default: ++ printk(KERN_WARNING ++ "ptrace: unknown conditional branch.\n"); ++ break; ++ } ++ ++ if (taken) ++ tpc = pc + (imm16s << 1); ++ } else if ((insn & 0x7e000000) == 0x48000000) // JI ++ { ++ int imm24s; ++ ++ imm24s = insn & 0x00ffffff; ++ ++ if (imm24s & 0x00800000) // sign extend ++ imm24s -= (0x00800000 << 1); ++ ++ tpc = pc + (imm24s << 1); ++ } else if ((insn & 0x7e000000) == 0x4a000000) // JREG ++ { ++ unsigned int rb = (insn >> 10) & 0x1f; ++ ++ tpc = get_user_gpr(child, rb); ++ } ++ ++ } else { ++ /* 16-bit instruction */ ++ ++ if ((insn & 0xf800) == 0xc000) // beqz38 ++ { ++ unsigned int rt3; ++ ++ rt3 = (insn >> 8) & 0x07; ++ ++ rt3 = get_user_gpr(child, rt3); ++ ++ if (rt3 == 0) { ++ int imm8s; ++ ++ imm8s = insn & 0x00ff; ++ ++ if (imm8s & 0x0080) // sign extend ++ imm8s -= (0x0080 << 1); ++ ++ tpc = pc + (imm8s << 1); ++ } ++ } ++ ++ if ((insn & 0xf800) == 0xc800) // bnez38 ++ { ++ unsigned int rt3; ++ ++ rt3 = (insn >> 8) & 0x07; ++ ++ rt3 = get_user_gpr(child, rt3); ++ ++ if (rt3 != 0) { ++ int imm8s; ++ ++ imm8s = insn & 0x00ff; ++ ++ if (imm8s & 0x0080) // sign extend ++ imm8s -= (0x0080 << 1); ++ ++ tpc = pc + (imm8s << 1); ++ } ++ } ++ ++ if ((insn & 0xf800) == 0xd000) // beqs38, j8 ++ { ++ unsigned int rt3, r5; ++ ++ rt3 = (insn >> 8) & 0x07; ++ ++ rt3 = get_user_gpr(child, rt3); ++ r5 = get_user_gpr(child, 5); ++ ++ if (r5 == rt3) { ++ int imm8s; ++ imm8s = insn & 0x00ff; ++ ++ if (imm8s & 0x0080) // sign extend ++ imm8s -= (0x0080 << 1); ++ ++ tpc = pc + (imm8s << 1); ++ } ++ } ++ ++ if ((insn & 0xf800) == 0xd800) // bnes38 ++ { ++ unsigned int rt3, r5; ++ ++ rt3 = (insn >> 8) & 0x07; ++ ++ r5 = get_user_gpr(child, 5); ++ rt3 = get_user_gpr(child, rt3); ++ ++ if (r5 != rt3) { ++ int imm8s; ++ ++ imm8s = insn & 0x00ff; ++ ++ if (imm8s & 0x0080) // sign extend ++ imm8s -= (0x0080 << 1); ++ ++ tpc = pc + (imm8s << 1); ++ } ++ } ++ ++ if ((insn & 0xffe0) == 0xdd00 || // jr5 ++ (insn & 0xffe0) == 0xdd80 || // ret5 ++ (insn & 0xffe0) == 0xdd20) // jral5 ++ { ++ unsigned int rb5; ++ ++ rb5 = insn & 0x1f; ++ ++ tpc = get_user_gpr(child, rb5); ++ } ++ ++ if ((insn & 0xfe00) == 0xe800) { ++ int taken = 0; ++ unsigned int r15; ++ ++ r15 = get_user_gpr(child, 15); ++ ++ if (insn & 0x0100) // bnezs8 ++ { ++ if (r15 != 0) ++ taken = 1; ++ } else // beqzs8 ++ { ++ if (r15 == 0) ++ taken = 1; ++ } ++ ++ if (taken) { ++ int imm8s; ++ ++ imm8s = insn & 0x00ff; ++ ++ if (imm8s & 0x0080) // sign extend ++ imm8s -= (0x0080 << 1); ++ ++ tpc = pc + (imm8s << 1); ++ } ++ } ++ } ++ ++ return tpc; ++} ++ ++/* ++ * Swap instructions in the user program. ++ * swap in new_insn. save orignal value in old_insn ++ * assume new_insn is 2-bytes long ++ */ ++static int ++swap_insn(struct task_struct *task, unsigned long addr, ++ u16 * old_insn, u16 * new_insn) ++{ ++ int ret; ++ ++ ret = access_process_vm(task, addr, old_insn, 2, 0); ++ if (ret == 2) ++ ret = access_process_vm(task, addr, new_insn, 2, 1); ++ ++ return ret; ++} ++ ++/* ++ * Add one breakpoint in the user program. ++ */ ++static void ++add_breakpoint(struct task_struct *task, struct debug_info *dbg, ++ unsigned long addr) ++{ ++ u16 new_insn = BREAKINST; ++ int res; ++ ++ if (dbg->valid) { ++ printk(KERN_ERR "ptrace: too many breakpoints\n"); ++ return; ++ } ++ ++ dbg->address = addr; ++ res = swap_insn(task, addr, &dbg->insn, &new_insn); ++ if (res == 2) ++ dbg->valid = 1; ++ if (!dbg->valid) ++ printk(KERN_ERR "ptrace: fail to add breakpoint\n"); ++} ++ ++/* ++ * Clear one software breakpoint in the user program. ++ */ ++static void clear_breakpoint(struct task_struct *task, struct debug_info *dbg) ++{ ++ int ret; ++ unsigned int addr = dbg->address; ++ u16 old_insn; ++ ++ if (!dbg->valid) { ++ return; ++ } ++ dbg->valid = 0; ++ ++ ret = swap_insn(task, addr, &old_insn, &dbg->insn); ++ ++ if (ret != 2 || old_insn != BREAKINST) { ++ printk(KERN_ERR "ptrace: %s:%d: corrupted NDS16 breakpoint at " ++ "0x%08x (0x%04x)\n", task->comm, task->pid, ++ addr, old_insn); ++ } ++} ++ ++/* ++ * ptrace_set_swbk ++ * Set breakpoint in user program. ++ */ ++void ptrace_set_swbk(struct task_struct *child) ++{ ++ struct pt_regs *regs; ++ unsigned long pc; ++ unsigned int size; ++ u32 insn; ++ ++ /* ++ * always clear before set, ++ * since in some sepcial case, it may fail to hit ++ */ ++ ptrace_cancel_swbk(child); ++ regs = task_pt_regs(child); ++ pc = instruction_pointer(regs); ++ size = read_insn(child, pc, &insn); ++ ++ printk(KERN_DEBUG " STEP.size=%d\n", size); ++ ++ if (size > 0) { ++ struct debug_info *dbg = &child->thread.debug; ++ unsigned int tpc; ++ ++ /* Predict next PC. */ ++ tpc = get_branch_address(child, pc, insn, size); ++ ++ if (tpc) { ++ printk(KERN_DEBUG " STEP.addr=0x%x\n", tpc); ++ add_breakpoint(child, dbg, tpc); ++ } else { ++ if (size == 4) { ++ printk(KERN_DEBUG " STEP.addr=0x%x\n", ++ (unsigned int)(pc + 4)); ++ add_breakpoint(child, dbg, pc + 4); ++ } else if (size == 2) { ++ printk(KERN_DEBUG " STEP.addr=0x%x\n", ++ (unsigned int)(pc + 2)); ++ add_breakpoint(child, dbg, pc + 2); ++ } else { ++ printk(KERN_ERR ++ "ptrace: bad step address, pc + %d\n", ++ size); ++ } ++ } ++ } ++} ++ ++/* ++ * Ensure no single-step breakpoint is pending. Returns non-zero ++ * value if child was being single-stepped. ++ */ ++void ptrace_cancel_swbk(struct task_struct *child) ++{ ++ if (!child->thread.debug.valid) { ++ return; ++ } ++ ++ clear_breakpoint(child, &child->thread.debug); ++} ++#endif /* end of !defined (CONFIG_HSS) */ ++ ++/* ++ * Called by kernel/ptrace.c when detaching.. ++ * ++ * Make sure the single step bit is not set. ++ */ ++void ptrace_disable(struct task_struct *child) ++{ ++ user_disable_single_step(child); ++} ++ ++/* ++ * Handle hitting a breakpoint. ++ */ ++void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, ++ int error_code, int si_code) ++{ ++ struct siginfo info; ++ ++#if !defined (CONFIG_HSS) ++ /* clear the swbk; otherwise the user will see it */ ++ ptrace_cancel_swbk(tsk); ++#endif ++ ++ tsk->thread.trap_no = 1; ++ tsk->thread.error_code = error_code; ++ ++ memset(&info, 0, sizeof(info)); ++ info.si_signo = SIGTRAP; ++ info.si_code = si_code; ++ ++ info.si_addr = (void __user *)instruction_pointer(regs); ++ ++ /* Send us the fake SIGTRAP */ ++ force_sig_info(SIGTRAP, &info, tsk); ++} ++ ++/* ptrace_read_user() ++ * ++ * Read the word at offset "off" into the "struct user". We ++ * actually access the pt_regs stored on the kernel stack. ++ */ ++static int ++ptrace_read_user(struct task_struct *tsk, unsigned long off, ++ unsigned long __user * ret) ++{ ++ unsigned long tmp = 0; ++ ++ if (off < 500) { ++ if (off & 3 || off >= sizeof(struct user)) ++ return -EIO; ++ ++ if (off < sizeof(struct pt_regs)) ++ tmp = get_user_reg(tsk, off >> 2); ++ ++ return put_user(tmp, ret); ++ } else if (off < 532) { ++#ifdef CONFIG_AUDIO ++ off -= 500; ++ if (test_tsk_thread_flag(tsk, TIF_USEDAUDIO)) { ++#ifdef CONFIG_UNLAZY_AUDIO ++ unlazy_audio(tsk); ++#else ++ preempt_disable(); ++ if (last_task_used_audio == tsk) ++ save_audio(tsk); ++ preempt_enable(); ++#endif ++ tmp = tsk->thread.audio.auregs[off]; ++ } ++#endif ++ return put_user(tmp, ret); ++ } else ++ return -EIO; ++} ++ ++/* ptrace_write_user() ++ * ++ * Write the word at offset "off" into "struct user". We ++ * actually access the pt_regs stored on the kernel stack. ++ */ ++static int ++ptrace_write_user(struct task_struct *tsk, unsigned long off, unsigned long val) ++{ ++ if (off < 500) { ++ if (off & 3 || off >= sizeof(struct user)) ++ return -EIO; ++ ++ if (off >= sizeof(struct pt_regs)) ++ return 0; ++ ++ return put_user_reg(tsk, off >> 2, val); ++ } else if (off < 532) { ++#ifdef CONFIG_AUDIO ++ off -= 500; ++ if (!test_tsk_thread_flag(tsk, TIF_USEDAUDIO)) { ++ /* First time Audio user. */ ++ memset(&tsk->thread.audio, 0, ++ sizeof(struct audio_struct)); ++ set_tsk_thread_flag(tsk, TIF_USEDAUDIO); ++ } else { ++#ifdef CONFIG_UNLAZY_AUDIO ++ unlazy_audio(tsk); ++#else ++ if (last_task_used_audio == tsk) { ++ preempt_disable(); ++ save_audio(tsk); ++ preempt_enable(); ++ } ++#endif ++ /* Let the lazy mechanism do the restore. */ ++ clear_audio(task_pt_regs(tsk)); ++ } ++ tsk->thread.audio.auregs[off] = val; ++#endif ++ return 0; ++ } else ++ return -EIO; ++} ++ ++/* ptrace_getregs() ++ * ++ * Get all user integer registers. ++ */ ++static int ptrace_getregs(struct task_struct *tsk, void __user * uregs) ++{ ++ struct pt_regs *regs = task_pt_regs(tsk); ++ ++ return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; ++} ++ ++/* ptrace_setregs() ++ * ++ * Set all user integer registers. ++ */ ++static int ptrace_setregs(struct task_struct *tsk, void __user * uregs) ++{ ++ struct pt_regs newregs; ++ int ret; ++ ++ ret = -EFAULT; ++ if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { ++ struct pt_regs *regs = task_pt_regs(tsk); ++ ++ ret = -EINVAL; ++ if (valid_user_regs(&newregs)) { ++ *regs = newregs; ++ ret = 0; ++ } ++ } ++ ++ return ret; ++} ++ ++/* ptrace_getfpregs() ++ * ++ * Get the child FPU state. ++ */ ++static int ptrace_getfpregs(struct task_struct *tsk, void __user * ufpregs) ++{ ++#ifdef CONFIG_FPU ++ if (used_math()) { ++# ifdef CONFIG_UNLAZY_FPU ++ unlazy_fpu(tsk); ++# else ++ preempt_disable(); ++ if (last_task_used_math == tsk) ++ save_fpu(tsk); ++ preempt_enable(); ++# endif ++ return copy_to_user(ufpregs, &tsk->thread.fpu, ++ sizeof(struct fpu_struct)) ? -EFAULT : 0; ++ } else { ++ /* First time FPU user. */ ++ memset(ufpregs, -1, sizeof(struct fpu_struct)); ++ return 0; ++ } ++ ++#else ++ return -EFAULT; ++#endif ++} ++ ++/* ++ * Set the child FPU state. ++ */ ++static int ptrace_setfpregs(struct task_struct *tsk, void __user * ufpregs) ++{ ++#ifdef CONFIG_FPU ++ int ret; ++ ++# ifndef CONFIG_UNLAZY_FPU ++ if (last_task_used_math == tsk) ++# endif ++ clear_fpu(task_pt_regs(tsk)); ++ ++ ret = ++ copy_from_user(&tsk->thread.fpu, ufpregs, ++ sizeof(struct fpu_struct)) ? -EFAULT : 0; ++ ++ if (!ret && !used_math()) { ++ /* First time Audio user. */ ++ set_used_math(); ++ } ++ ++ return ret; ++#else ++ return -EFAULT; ++#endif ++} ++ ++/* ptrace_getauregs() ++ * ++ * Get the child Audio state. ++ */ ++static int ptrace_getauregs(struct task_struct *tsk, void __user * uauregs) ++{ ++#ifdef CONFIG_AUDIO ++ if (test_tsk_thread_flag(tsk, TIF_USEDAUDIO)) { ++#ifdef CONFIG_UNLAZY_AUDIO ++ unlazy_audio(tsk); ++#else ++ preempt_disable(); ++ if (last_task_used_audio == tsk) ++ save_audio(tsk); ++ preempt_enable(); ++#endif ++ return copy_to_user(uauregs, &tsk->thread.audio, ++ sizeof(struct audio_struct)) ? -EFAULT : 0; ++ } else { ++ /* First time Audio user. */ ++ memset(uauregs, 0, sizeof(struct audio_struct)); ++ return 0; ++ } ++ ++#else ++ return -EFAULT; ++#endif ++} ++ ++/* ++ * Set the child Audio state. ++ */ ++static int ptrace_setauregs(struct task_struct *tsk, void __user * uauregs) ++{ ++#ifdef CONFIG_AUDIO ++ int ret; ++ ++#ifdef CONFIG_UNLAZY_AUDIO ++ clear_audio(task_pt_regs(tsk)); ++#else ++ if (last_task_used_audio == tsk) ++ clear_audio(task_pt_regs(tsk)); ++#endif ++ ret = ++ copy_from_user(&tsk->thread.audio, uauregs, ++ sizeof(struct audio_struct)) ? -EFAULT : 0; ++ ++ if (!ret && !test_tsk_thread_flag(tsk, TIF_USEDAUDIO)) { ++ /* First time Audio user. */ ++ set_tsk_thread_flag(tsk, TIF_USEDAUDIO); ++ } ++ ++ return ret; ++#else ++ return -EFAULT; ++#endif ++} ++ ++/* do_ptrace() ++ * ++ * Provide ptrace defined service. ++ */ ++long arch_ptrace(struct task_struct *child, long request, unsigned long addr, ++ unsigned long data) ++{ ++ int ret; ++ ++ switch (request) { ++ case PTRACE_PEEKUSR: ++ ret = ++ ptrace_read_user(child, addr, (unsigned long __user *)data); ++ break; ++ ++ case PTRACE_POKEUSR: ++ ret = ptrace_write_user(child, addr, data); ++ break; ++ ++ case PTRACE_GETREGS: ++ ret = ptrace_getregs(child, (void __user *)data); ++ break; ++ ++ case PTRACE_SETREGS: ++ ret = ptrace_setregs(child, (void __user *)data); ++ break; ++ ++ case PTRACE_GETFPREGS: ++ ret = ptrace_getfpregs(child, (void __user *)data); ++ break; ++ ++ case PTRACE_SETAUREGS: ++ ret = ptrace_setauregs(child, (void __user *)data); ++ break; ++ ++ case PTRACE_GETAUREGS: ++ ret = ptrace_getauregs(child, (void __user *)data); ++ break; ++ ++ case PTRACE_SETFPREGS: ++ ret = ptrace_setfpregs(child, (void __user *)data); ++ break; ++/* ++ case PTRACE_GET_THREAD_AREA: ++ ret = put_user(task_thread_info(child)->tp_value, ++ (unsigned long __user *) data); ++ break; ++*/ ++ ++ default: ++ ret = ptrace_request(child, request, addr, data); ++ break; ++ } ++ ++ return ret; ++} ++ ++void user_enable_single_step(struct task_struct *child) ++{ ++ struct pt_regs *regs; ++ regs = task_pt_regs(child); ++#ifdef CONFIG_HSS ++ regs->NDS32_ipsw |= PSW_mskHSS; ++#else ++ ptrace_set_swbk(child); ++#endif ++ set_tsk_thread_flag(child, TIF_SINGLESTEP); ++} ++ ++void user_disable_single_step(struct task_struct *child) ++{ ++ struct pt_regs *regs; ++ regs = task_pt_regs(child); ++#ifdef CONFIG_HSS ++ regs->NDS32_ipsw &= ~PSW_mskHSS; ++#else ++ ptrace_cancel_swbk(child); ++#endif ++ clear_tsk_thread_flag(child, TIF_SINGLESTEP); ++} ++ ++/* sys_trace() ++ * ++ * syscall trace handler. ++ */ ++static inline void do_syscall_trace(void) ++{ ++ if (!test_thread_flag(TIF_SYSCALL_TRACE)) ++ return; ++ if (!(current->ptrace & PT_PTRACED)) ++ return; ++ ++ /* the 0x80 provides a way for the tracing parent to distinguish ++ between a syscall stop and SIGTRAP delivery */ ++ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ++ ? 0x80 : 0)); ++ /* ++ * this isn't the same as continuing with a signal, but it will do ++ * for normal use. strace only continues with a signal if the ++ * stopping signal is not SIGTRAP. -brl ++ */ ++ if (current->exit_code) { ++ send_sig(current->exit_code, current, 1); ++ current->exit_code = 0; ++ } ++} ++ ++asmlinkage int syscall_trace_enter(int syscall, struct pt_regs *regs) ++{ ++ int orig_r0; ++ ++ orig_r0 = regs->NDS32_ORIG_r0; ++ regs->NDS32_ORIG_r0 = syscall; ++ do_syscall_trace(); ++ syscall = regs->NDS32_ORIG_r0; ++ regs->NDS32_ORIG_r0 = orig_r0; ++ return syscall & 0xfff; ++} ++ ++asmlinkage void syscall_trace_leave(struct pt_regs *regs) ++{ ++ do_syscall_trace(); ++ ++ /* synthsize a single-step */ ++#if !defined(CONFIG_HSS) ++ /* for SWBK, break should be remove */ ++ ptrace_cancel_swbk(current); ++#endif ++ if (test_thread_flag(TIF_SINGLESTEP)) { ++ printk(KERN_INFO "synthsize trap (tf=0x%0x\n", ++ (unsigned int)current_thread_info()->flags); ++ send_sigtrap(current, regs, 0, TRAP_BRKPT); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/ptrace.h linux-3.4.110/arch/nds32/kernel/ptrace.h +--- linux-3.4.110.orig/arch/nds32/kernel/ptrace.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/ptrace.h 2016-04-07 10:20:50.946081179 +0200 +@@ -0,0 +1,48 @@ ++/* ++ * linux/arch/nds32/kernel/ptrace.h ++ */ ++/* Copyright (C) 2000-2003 Russell King ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++/* ============================================================================ ++ * Copyright (C) 2007 Andes Technology Corporation ++ * This file is part of Linux and should be licensed under the GPL. ++ * See the file COPYING for conditions for redistribution. ++ * ++ * Abstract: ++ * ++ * This program is for Andes NDS32 architecture. ++ * ++ * Revision History: ++ * ++ * Jul.31.2007 Initial ported by Tom, Shawn, and Steven, ++ * revised by Harry. ++ * Current implmentation is based on Andes Instruction ++ * Set Architecture Specification (AS-0001-0001) ++ * version:3.7 date:7-20-2007. ++ * It is original taken from ARM, then fit to NDS32. ++ * ++ * Note: ++ * ++ * Current layout: 0-31 GR, 32-34 SPR, 35-... SR, index start from zero. ++ * ++ * +----------+-----+--------------+ ++ * | GR | SPR | SR | ++ * +-------------------------------+ ++ * 0 32 35 ... ++ * ++ * ============================================================================ ++ */ ++#ifndef __KERNEL_PTRACE_H__ ++#define __KERNEL_PTRACE_H__ ++ ++extern void ptrace_cancel_swbk(struct task_struct *); ++extern void ptrace_set_swbk(struct task_struct *); ++extern void ptrace_break(struct task_struct *, struct pt_regs *); ++extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, ++ int error_code, int si_code); ++ ++#endif // __KERNEL_PTRACE_H__ +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/relocate_kernel.S linux-3.4.110/arch/nds32/kernel/relocate_kernel.S +--- linux-3.4.110.orig/arch/nds32/kernel/relocate_kernel.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/relocate_kernel.S 2016-04-07 10:20:50.946081179 +0200 +@@ -0,0 +1,89 @@ ++/* ++ * relocate_kernel.S - put the kernel image in place to boot ++ */ ++ ++#include <asm/kexec.h> ++ ++ .globl relocate_new_kernel ++relocate_new_kernel: ++ la $r0, kexec_indirection_page ++ slli $r0, $r0, 2 ++ srli $r0, $r0, 2 ++ lwi $r0, [$r0] ++ la $r1, kexec_start_address ++ slli $r1, $r1, 2 ++ srli $r1, $r1, 2 ++ lwi $r1, [$r1] ++ ++0: /* top, read another word for the indirection page */ ++ lwi.bi $r3, [$r0], #4 ++ ++ /* Is it a destination page. Put destination address to r4 */ ++ andi $p0, $r3, #1 ++ beqz $p0, 1f ++ li $p0, ~#1 ++ and $r4, $r3, $p0 ++ b 0b ++1: ++ /* Is it an indirection page */ ++ andi $p0, $r3, #2 ++ beqz $p0, 1f ++ li $p0, ~#2 ++ and $r0, $r3, $p0 ++ b 0b ++1: ++ /* are we done ? */ ++ andi $p0, $r3, #4 ++ beqz $p0, 1f ++ b 2f ++1: ++ /* is it source ? */ ++ andi $p0, $r3, #8 ++ beqz $p0, 0b ++ li $p0, ~#8 ++ and $r3, $r3, $p0 ++ li $r6, #(1024/16) /* 16 words per loop */ ++9: ++ lmw.bim $r7, [$r3], $r22 ++ smw.bim $r7, [$r4], $r22 ++ addi $r6, $r6, -1 ++ bnez $r6, 9b ++ b 0b ++2: ++ /* Jump to relocated kernel */ ++ move $lp, $r1 ++ li $r0, 0 ++ la $r1, kexec_mach_type ++ slli $r1, $r1, 2 ++ srli $r1, $r1, 2 ++ lwi $r1, [$r1] ++ la $r2, kexec_boot_atags ++ slli $r2, $r2, 2 ++ srli $r2, $r2, 2 ++ lwi $r2, [$r2] ++ ret ++ ++ .globl kexec_start_address ++kexec_start_address: ++ .long 0x0 ++ ++ .globl kexec_indirection_page ++kexec_indirection_page: ++ .long 0x0 ++ ++ .globl kexec_mach_type ++kexec_mach_type: ++ .long 0x0 ++ ++ /* phy addr of the atags for the new kernel */ ++ .globl kexec_boot_atags ++kexec_boot_atags: ++ .long 0x0 ++ ++relocate_new_kernel_end: ++ ++ .globl relocate_new_kernel_size ++relocate_new_kernel_size: ++ .long relocate_new_kernel_end - relocate_new_kernel ++ ++ +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/setup.c linux-3.4.110/arch/nds32/kernel/setup.c +--- linux-3.4.110.orig/arch/nds32/kernel/setup.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/setup.c 2016-04-07 10:20:50.946081179 +0200 +@@ -0,0 +1,1049 @@ ++/* ++ * linux/arch/nds32/kernel/setup.c ++ * ++ * Copyright (C) 1995-2001 Russell King ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++/* ============================================================================ ++ * Copyright (C) 2007 Andes Technology Corporation ++ * This file is part of Linux and should be licensed under the GPL. ++ * See the file COPYING for conditions for redistribution. ++ * ++ * Abstract: ++ * ++ * This program is for Andes NDS32 architecture. ++ * ++ * Revision History: ++ * ++ * Jul.05.2007 Initial ported by Tom, revised and patched for KGDB ++ * by Harry. ++ * Aug.26.2008 Some reworks on CPU info output for SMP. ++ * ++ * Note: ++ * ++ * ============================================================================ ++ */ ++#include <linux/module.h> ++#include <linux/ioport.h> ++#include <linux/delay.h> ++#include <linux/utsname.h> ++#include <linux/initrd.h> ++#include <linux/console.h> ++#include <linux/bootmem.h> ++#include <linux/seq_file.h> ++#include <linux/screen_info.h> ++#include <linux/root_dev.h> ++#include <linux/cpu.h> ++#include <linux/fs.h> ++#include <linux/memblock.h> ++#include <asm/cpu.h> ++#include <asm/setup.h> ++#include <asm/mach-types.h> ++#include <asm/cacheflush.h> ++#include <asm/mach/arch.h> ++#include <asm/mach/time.h> ++#include <asm/cpuver.h> ++#include <asm/procinfo.h> ++#include <asm/traps.h> ++#include <asm/fpu.h> ++#include <asm/cache_info.h> ++#include <nds32_intrinsic.h> ++ ++#ifndef MEM_SIZE ++#define MEM_SIZE CONFIG_SDRAM_SIZE ++#endif ++ ++#ifndef RAMDISK_SIZE ++#define RAMDISK_SIZE CONFIG_BLK_DEV_RAM_SIZE ++#endif ++ ++extern void (*init_arch_irq) (void); ++ ++extern void paging_init(struct machine_desc *desc); ++extern void reboot_setup(char *str); ++extern int root_mountflags; ++extern unsigned long _stext, _text, _etext, _sdata, _edata, _end; ++extern unsigned int ag101_cpufreq_get(unsigned int dummy); ++ ++unsigned long cpu_id, cpu_rev, cpu_cfgid; ++char *endianness = NULL; ++ ++unsigned int __machine_arch_type; ++EXPORT_SYMBOL(__machine_arch_type); ++ ++unsigned int elf_hwcap; ++EXPORT_SYMBOL(elf_hwcap); ++ ++unsigned char aux_device_present; ++ ++char elf_platform[ELF_PLATFORM_SIZE]; ++EXPORT_SYMBOL(elf_platform); ++ ++unsigned long phys_initrd_start __initdata = 0; ++unsigned long phys_initrd_size __initdata = 0; ++ ++static struct meminfo meminfo __initdata = { 0, }; ++ ++static const char *machine_name; ++static struct proc_info_item proc_info; ++static char command_line[COMMAND_LINE_SIZE]; ++ ++struct machine_desc *machine_desc __initdata; ++ ++static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; ++ ++DEFINE_PER_CPU(struct cpuinfo_nds32, cpu_data); ++ ++/* ++ * Standard memory resources ++ */ ++static struct resource mem_res[] = { ++ { ++ .name = "Video RAM", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_MEM}, ++ { ++ .name = "Kernel text", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_MEM}, ++ { ++ .name = "Kernel data", ++ .start = 0, ++ .end = 0, ++ .flags = IORESOURCE_MEM} ++}; ++ ++#define video_ram mem_res[0] ++#define kernel_code mem_res[1] ++#define kernel_data mem_res[2] ++ ++static struct resource io_res[] = { ++ { ++ .name = "reserved", ++ .start = 0x3bc, ++ .end = 0x3be, ++ .flags = IORESOURCE_IO | IORESOURCE_BUSY}, ++ { ++ .name = "reserved", ++ .start = 0x378, ++ .end = 0x37f, ++ .flags = IORESOURCE_IO | IORESOURCE_BUSY}, ++ { ++ .name = "reserved", ++ .start = 0x278, ++ .end = 0x27f, ++ .flags = IORESOURCE_IO | IORESOURCE_BUSY} ++}; ++ ++#define lp0 io_res[0] ++#define lp1 io_res[1] ++#define lp2 io_res[2] ++ ++/* ++ * The following string table, must sync with HWCAP_xx bitmask, ++ * which is defined in <asm/procinfo.h> ++ */ ++static const char *hwcap_str[] = { ++ "mfusr_pc", ++ "perf1", ++ "perf2", ++ "fpu", ++ "audio", ++ "16b", ++ "string", ++ "reduced_regs", ++ "video", ++ "encrypt", ++ "edm", ++ "lmdma", ++ "pfm", ++ "hsmp", ++ "trace", ++ "div", ++ "mac", ++ "l2c", ++ "dx_regs", ++ "v2", ++ NULL, ++}; ++ ++static void __init squash_mem_tags(struct tag *tag) ++{ ++ for (; tag->hdr.size; tag = tag_next(tag)) ++ if (tag->hdr.tag == ATAG_MEM) ++ tag->hdr.tag = ATAG_NONE; ++} ++ ++struct cache_info L1_cache_info[2]; ++ ++static void __init dump_cpu_info(int cpu) ++{ ++ int i = 0, aliasing_num; ++#ifdef CONFIG_CACHE_L2 ++ unsigned long l2set, l2way, l2clsz; ++#endif ++ printk("CPU%d Features: ", cpu); ++ ++ for (i = 0; hwcap_str[i]; i++) { ++ if (elf_hwcap & (1 << i)) ++ printk("%s ", hwcap_str[i]); ++ } ++ ++ printk("\n"); ++ ++ L1_cache_info[ICACHE].cache_type = ICACHE; ++ L1_cache_info[ICACHE].ways = CACHE_WAY(ICACHE); ++ L1_cache_info[ICACHE].way_bits = ilog2(CACHE_WAY(ICACHE)); ++ L1_cache_info[ICACHE].line_size = CACHE_LINE_SIZE(ICACHE); ++ L1_cache_info[ICACHE].line_bits = ilog2(CACHE_LINE_SIZE(ICACHE)); ++ L1_cache_info[ICACHE].sets = CACHE_SET(ICACHE); ++ L1_cache_info[ICACHE].set_bits = ilog2(CACHE_SET(ICACHE)); ++ L1_cache_info[ICACHE].size = ++ CACHE_SET(ICACHE) * CACHE_WAY(ICACHE) * CACHE_LINE_SIZE(ICACHE) / ++ 1024; ++ printk("L1I:%dKB/%dS/%dW/%dB\n", L1_cache_info[ICACHE].size, ++ L1_cache_info[ICACHE].sets, L1_cache_info[ICACHE].ways, ++ L1_cache_info[ICACHE].line_size); ++ aliasing_num = ++ L1_cache_info[ICACHE].size * 1024 / PAGE_SIZE / ++ L1_cache_info[ICACHE].ways; ++ if (aliasing_num & 1 && aliasing_num != 1) ++ printk ++ ("%s: not alising:%d, it should be multiple of 2 if it ia aliasing cache.\n", ++ __func__, aliasing_num); ++ L1_cache_info[ICACHE].aliasing_num = aliasing_num; ++ L1_cache_info[ICACHE].aliasing_mask = (aliasing_num - 1) << PAGE_SHIFT; ++ L1_cache_info[ICACHE].not_aliasing_mask = ++ ~L1_cache_info[ICACHE].aliasing_mask; ++ L1_cache_info[DCACHE].cache_type = DCACHE; ++ L1_cache_info[DCACHE].ways = CACHE_WAY(DCACHE); ++ L1_cache_info[DCACHE].way_bits = ilog2(CACHE_WAY(DCACHE)); ++ L1_cache_info[DCACHE].line_size = CACHE_LINE_SIZE(DCACHE); ++ L1_cache_info[DCACHE].line_bits = ilog2(CACHE_LINE_SIZE(DCACHE)); ++ L1_cache_info[DCACHE].sets = CACHE_SET(DCACHE); ++ L1_cache_info[DCACHE].set_bits = ilog2(CACHE_SET(DCACHE)); ++ L1_cache_info[DCACHE].size = ++ CACHE_SET(DCACHE) * CACHE_WAY(DCACHE) * CACHE_LINE_SIZE(DCACHE) / ++ 1024; ++ printk("L1D:%dKB/%dS/%dW/%dB\n", L1_cache_info[DCACHE].size, ++ L1_cache_info[DCACHE].sets, L1_cache_info[DCACHE].ways, ++ L1_cache_info[DCACHE].line_size); ++ aliasing_num = ++ L1_cache_info[DCACHE].size * 1024 / PAGE_SIZE / ++ L1_cache_info[DCACHE].ways; ++#ifdef CONFIG_HIGHMEM ++ if (aliasing_num > 1 && CONFIG_HIGHMEM) ++ WARN(1, ++ "%s: HIGHMEM is not supported for alising VIPT cache. aliasing_num:%d\n", ++ __func__, aliasing_num); ++#else ++ if (aliasing_num & 1 && aliasing_num != 1) ++ printk ++ ("%s: not alising:%d, it should be multiple of 2 if it ia aliasing cache.\n", ++ __func__, aliasing_num); ++#endif ++ L1_cache_info[DCACHE].aliasing_num = aliasing_num; ++ L1_cache_info[DCACHE].aliasing_mask = (aliasing_num - 1) << PAGE_SHIFT; ++ L1_cache_info[DCACHE].not_aliasing_mask = ++ ~L1_cache_info[DCACHE].aliasing_mask; ++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH ++ printk("L1 D-Cache is WRITE-THROUGH\n"); ++#else ++ printk("L1 D-Cache is WRITE-BACK\n"); ++#endif ++ ++ ++#ifdef CONFIG_CACHE_L2 ++ /* Here translation is on but I/O address is not mapped yet. */ ++ SET_PSW(GET_PSW() & ~PSW_mskDT); ++ DSB(); ++ l2set = ++ 64 << ((inl(L2CC_PA_BASE + L2_CA_CONF_OFF) & L2_CA_CONF_mskL2SET) >> ++ L2_CA_CONF_offL2SET); ++ l2way = ++ 1 + ++ ((inl(L2CC_PA_BASE + L2_CA_CONF_OFF) & L2_CA_CONF_mskL2WAY) >> ++ L2_CA_CONF_offL2WAY); ++ l2clsz = ++ 4 << ((inl(L2CC_PA_BASE + L2_CA_CONF_OFF) & L2_CA_CONF_mskL2CLSZ) >> ++ L2_CA_CONF_offL2CLSZ); ++ SET_PSW(GET_PSW() | PSW_mskDT); ++ DSB(); ++ ++ printk("L2:%luKB/%luS/%luW/%luB\n", ++ l2set * l2way * l2clsz / 1024, l2set, l2way, l2clsz); ++#endif ++#ifdef CONFIG_FPU ++ /* Disable fpu and enable when it is used. */ ++ disable_fpu(); ++ printk("FPU is able to use.\n"); ++#endif ++} ++ ++static void __init setup_processor(void) ++{ ++ unsigned long tmp = 0; ++ struct proc_info_list *list; ++ extern struct proc_info_list __proc_info_begin, __proc_info_end; ++ ++ register unsigned coreid = GET_CPU_VER(); ++ for (list = &__proc_info_begin; list < &__proc_info_end; list++) ++// if (list->cpu_val == (GET_CPU_VER() & CPU_VER_mskCPUID)) ++ if (list->cpu_val == (coreid & list->cpu_mask)) ++ break; ++ /* ++ * If the architecture type is not recognised, then we ++ * can co nothing... ++ */ ++ if (list >= &__proc_info_end) { ++ printk ++ ("Processor configuration botched (CPU_VER 0x%lx), unable to continue.\n", ++ GET_CPU_VER()); ++ while (1) ; ++ } ++ ++ proc_info = *list->info; ++ ++ cpu_dcache_inval_all(); // XXX head.S turn $$ on, need change. ++ cpu_icache_inval_all(); ++ DSB(); ++ ISB(); ++ ++ cpu_id = GET_CPU_ID(); ++ cpu_rev = GET_CPU_REV(); ++ cpu_cfgid = GET_CPU_CFGID(); ++ ++ printk("CPU: %s, %s %s, CPU_VER 0x%08lx(id %lu, rev %lu, cfg %lu)\n", ++ list->arch_name, ++ proc_info.manufacturer, proc_info.cpu_name, ++ GET_CPU_VER(), cpu_id, cpu_rev, cpu_cfgid); ++ ++ elf_hwcap |= HWCAP_MFUSR_PC; ++ ++ if (((GET_MSC_CFG() & MSC_CFG_mskBASEV) >> MSC_CFG_offBASEV) == 0) { ++ if (CPU_IS_N1213_43U1HA0() || CPU_IS_N1213_43U1HB0()) ++ elf_hwcap &= ~HWCAP_MFUSR_PC; ++ ++ if (GET_MSC_CFG() & MSC_CFG_mskDIV) ++ elf_hwcap |= HWCAP_DIV; ++ ++ if ((GET_MSC_CFG() & MSC_CFG_mskMAC) ++ || (cpu_id == 12 && cpu_rev < 4)) ++ elf_hwcap |= HWCAP_MAC; ++ } else { ++ elf_hwcap |= HWCAP_V2; ++ elf_hwcap |= HWCAP_DIV; ++ elf_hwcap |= HWCAP_MAC; ++ } ++ ++ if (cpu_cfgid & 0x0001) ++ elf_hwcap |= HWCAP_EXT; ++ ++ if (cpu_cfgid & 0x0002) ++ elf_hwcap |= HWCAP_BASE16; ++ ++ if (cpu_cfgid & 0x0004) ++ elf_hwcap |= HWCAP_EXT2; ++ ++ if (cpu_cfgid & 0x0008) ++ elf_hwcap |= HWCAP_FPU; ++ ++ if (cpu_cfgid & 0x0010) ++ elf_hwcap |= HWCAP_STRING; ++ ++ if (GET_MMU_CFG() & MMU_CFG_mskDE) ++ endianness = "MSB"; ++ else ++ endianness = "LSB"; ++ ++ if (GET_MSC_CFG() & MSC_CFG_mskEDM) ++ elf_hwcap |= HWCAP_EDM; ++ ++ if (GET_MSC_CFG() & MSC_CFG_mskLMDMA) ++ elf_hwcap |= HWCAP_LMDMA; ++ ++ if (GET_MSC_CFG() & MSC_CFG_mskPFM) ++ elf_hwcap |= HWCAP_PFM; ++ ++ if (GET_MSC_CFG() & MSC_CFG_mskHSMP) ++ elf_hwcap |= HWCAP_HSMP; ++ ++ if (GET_MSC_CFG() & MSC_CFG_mskTRACE) ++ elf_hwcap |= HWCAP_TRACE; ++ ++ if (GET_MSC_CFG() & MSC_CFG_mskAUDIO) ++ elf_hwcap |= HWCAP_AUDIO; ++ ++ if (GET_MSC_CFG() & MSC_CFG_mskL2C) ++ elf_hwcap |= HWCAP_L2C; ++ ++#ifdef CONFIG_ANDES_PAGE_SIZE_4KB ++ if (CPU_IS_N1213_43U1HA0()) { ++ /* ++ * Downsize dcache to bypass N1213-43u1h inconsistent ++ * use of PA and VA in fill-buffer logic issue. ++ */ ++ ++ if ((CACHE_SET(DCACHE) * CACHE_LINE_SIZE(DCACHE)) > 4096) ++ tmp |= 0x02 << SDZ_CTL_offDCDZ; ++ ++ if ((CACHE_SET(ICACHE) * CACHE_LINE_SIZE(ICACHE)) > 4096) ++ tmp |= 0x02 << SDZ_CTL_offICDZ; ++ ++ SET_SDZ_CTL(tmp); ++ ISB(); ++ printk("CPU%i enabled dcache downsizing to half set/4-way.\n", ++ smp_processor_id()); ++ } ++#endif /* CONFIG_ANDES_PAGE_SIZE_4KB */ ++ ++#ifdef CONFIG_CACHE_L2 ++#ifdef CONFIG_PLAT_AG102 ++ SET_HSMP_SADDR((CPU_MEM_PA_BASE & HSMP_SADDR_mskSADDR) | ++ (0xC00 << HSMP_SADDR_offRANGE) | HSMP_SADDR_mskEN); ++#endif ++ ++ /* Here translation is on but I/O address is not mapped yet. */ ++ SET_PSW(GET_PSW() & ~PSW_mskDT); ++ DSB(); ++ ++ /* This is the time when we enable L2$. */ ++ /* All masters can't write another master register */ ++ tmp = inl(L2CC_PA_BASE + L2CC_PROT_OFF); ++ tmp &= ~L2CC_PROT_mskMRWEN; ++ outl(tmp, L2CC_PA_BASE + L2CC_PROT_OFF); ++ ++ /* All masters share the whole cache memory space */ ++ tmp = inl(L2CC_PA_BASE + L2CC_SETUP_OFF); ++ tmp &= ~L2CC_SETUP_mskPART; ++ outl(tmp, L2CC_PA_BASE + L2CC_SETUP_OFF); ++ ++ /* each master access self master, does not add master base */ ++ tmp = inl(L2CC_PA_BASE + L2CC_CTRL_OFF); ++ tmp |= L2CC_CTRL_mskEN; ++ outl(tmp, L2CC_PA_BASE + L2CC_CTRL_OFF); ++ ++ SET_PSW(GET_PSW() | PSW_mskDT); ++ ISB(); ++#endif ++ tmp = GET_CACHE_CTL(); ++#ifndef CONFIG_CPU_DCACHE_DISABLE ++ tmp |= CACHE_CTL_mskDC_EN; ++#endif ++ ++#ifndef CONFIG_CPU_ICACHE_DISABLE ++ tmp |= CACHE_CTL_mskIC_EN; ++#endif ++ SET_CACHE_CTL(tmp); ++ DSB(); ++ ISB(); ++ ++ sprintf(elf_platform, "%s %s", list->elf_name, endianness); ++ ++ dump_cpu_info(smp_processor_id()); ++} ++ ++static struct machine_desc *__init setup_machine(unsigned int nr) ++{ ++ struct machine_desc *list; ++ ++ extern struct machine_desc __arch_info_begin, __arch_info_end; ++ /* ++ * locate machine in the list of supported machines. ++ */ ++ for (list = &__arch_info_begin; list < &__arch_info_end; list++) ++ if (list->nr == nr) ++ break; ++ /* ++ * If the architecture type is not recognised, then we ++ * can co nothing... ++ */ ++ if (list >= &__arch_info_end) { ++ printk("Architecture configuration botched (nr 0x%x), unable " ++ "to continue.\n", nr); ++ while (1) ; ++ } ++ ++ printk(KERN_INFO "Machine: %s\n", list->name); ++ ++ return list; ++} ++ ++static void __init early_initrd(char **p) ++{ ++ unsigned long start, size; ++ ++ start = memparse(*p, p); ++ if (**p == ',') { ++ size = memparse((*p) + 1, p); ++ ++ phys_initrd_start = start; //pa ++ phys_initrd_size = size; ++ } ++ printk(KERN_INFO ++ "phys_initrd_start at 0x%08lx, phys_initrd_size:0x%08lx\n", ++ phys_initrd_start, phys_initrd_size); ++ //memblock_reserve(phys_initrd_start, phys_initrd_size); ++} ++ ++__early_param("initrd=", early_initrd); ++ ++/* ++ * Pick out the memory size. We look for mem=size@start, ++ * where start and size are "size[KkMm]" ++ */ ++static void __init early_mem(char **p) ++{ ++ static int usermem __initdata = 0; ++ unsigned long size, start; ++ ++ /* ++ * If the user specifies memory size, we ++ * blow away any automatically generated ++ * size. ++ */ ++ if (usermem == 0) { ++ usermem = 1; ++ meminfo.nr_banks = 0; ++ } ++ ++ start = PHYS_OFFSET; //Tom 0x0 ++ size = memparse(*p, p); ++ if (**p == '@') ++ start = memparse(*p + 1, p); ++ ++ meminfo.bank[meminfo.nr_banks].start = start; ++ meminfo.bank[meminfo.nr_banks].size = size; ++ meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(start); ++ memblock_add_node(meminfo.bank[meminfo.nr_banks].start, ++ meminfo.bank[meminfo.nr_banks].size, 0); ++ meminfo.nr_banks += 1; ++ ++} ++ ++__early_param("mem=", early_mem); ++ ++/* ++ * Initial parsing of the command line. ++ */ ++void __init parse_cmdline(char **cmdline_p, char *from) ++{ ++ char c = ' ', *to = command_line; ++ int len = 0; ++ ++ for (;;) { ++ if (c == ' ') { ++ extern struct early_params __early_begin, __early_end; ++ struct early_params *p; ++ ++ for (p = &__early_begin; p < &__early_end; p++) { ++ int len = strlen(p->arg); ++ ++ if (memcmp(from, p->arg, len) == 0) { ++ if (to != command_line) ++ to -= 1; ++ from += len; ++ p->fn(&from); ++ ++ while (*from != ' ' && *from != '\0') ++ from++; ++ break; ++ } ++ } ++ } ++ c = *from++; ++ if (!c) ++ break; ++ if (COMMAND_LINE_SIZE <= ++len) ++ break; ++ *to++ = c; ++ } ++ *to = '\0'; ++ *cmdline_p = command_line; ++} ++ ++static void __init ++setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) ++{ ++#ifdef CONFIG_BLK_DEV_RAM ++ extern int rd_size, rd_image_start, rd_prompt, rd_doload; ++ ++ rd_image_start = image_start; ++ rd_prompt = prompt; ++ rd_doload = doload; ++ ++ if (rd_sz) ++ rd_size = rd_sz; ++#endif ++} ++ ++static void __init ++request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc) ++{ ++ struct resource *res; ++ int i; ++ ++ kernel_code.start = virt_to_phys(&_text); ++ kernel_code.end = virt_to_phys(&_etext - 1); ++ kernel_data.start = virt_to_phys(&_sdata); ++ kernel_data.end = virt_to_phys(&_end - 1); ++ ++ for (i = 0; i < mi->nr_banks; i++) { ++ unsigned long virt_start, virt_end; ++ ++ if (mi->bank[i].size == 0) ++ continue; ++ ++ virt_start = __phys_to_virt(mi->bank[i].start); ++ virt_end = virt_start + mi->bank[i].size - 1; ++ ++ res = alloc_bootmem_low(sizeof(*res)); ++ res->name = "System RAM"; ++ res->start = __virt_to_phys(virt_start); ++ res->end = __virt_to_phys(virt_end); ++ res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; ++ ++ request_resource(&iomem_resource, res); ++ ++ if (kernel_code.start >= res->start && ++ kernel_code.end <= res->end) ++ request_resource(res, &kernel_code); ++ if (kernel_data.start >= res->start && ++ kernel_data.end <= res->end) ++ request_resource(res, &kernel_data); ++ } ++ ++ if (mdesc->video_start) { ++ video_ram.start = mdesc->video_start; ++ video_ram.end = mdesc->video_end; ++ request_resource(&iomem_resource, &video_ram); ++ } ++ ++ /* ++ * Some machines don't have the possibility of ever ++ * possessing lp0, lp1 or lp2 ++ */ ++ if (mdesc->reserve_lp0) ++ request_resource(&ioport_resource, &lp0); ++ if (mdesc->reserve_lp1) ++ request_resource(&ioport_resource, &lp1); ++ if (mdesc->reserve_lp2) ++ request_resource(&ioport_resource, &lp2); ++} ++ ++/* ++ * Tag parsing. ++ * ++ * This is the new way of passing data to the kernel at boot time. Rather ++ * than passing a fixed inflexible structure to the kernel, we pass a list ++ * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE ++ * tag for the list to be recognised (to distinguish the tagged list from ++ * a param_struct). The list is terminated with a zero-length tag (this tag ++ * is not parsed in any way). ++ */ ++//flag bit 0 = read-only ++static int __init parse_tag_core(const struct tag *tag) ++{ ++ if (tag->hdr.size > 2) { ++ if ((tag->u.core.flags & 1) == 0) ++ root_mountflags &= ~MS_RDONLY; ++ ROOT_DEV = old_decode_dev(tag->u.core.rootdev); ++ } ++ return 0; ++} ++ ++__tagtable(ATAG_CORE, parse_tag_core); ++ ++static int __init parse_tag_mem32(const struct tag *tag) ++{ ++ if (meminfo.nr_banks >= NR_BANKS) { ++ printk(KERN_WARNING ++ "Ignoring memory bank 0x%08x size %dKB\n", ++ tag->u.mem.start, tag->u.mem.size / 1024); ++ return -EINVAL; ++ } ++ meminfo.bank[meminfo.nr_banks].start = tag->u.mem.start; ++ meminfo.bank[meminfo.nr_banks].size = tag->u.mem.size; ++ memblock_add_node(meminfo.bank[meminfo.nr_banks].start, ++ meminfo.bank[meminfo.nr_banks].size, 0); ++ meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(tag->u.mem.start); ++ meminfo.nr_banks += 1; ++ ++ return 0; ++} ++ ++__tagtable(ATAG_MEM, parse_tag_mem32); ++ ++#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE) ++struct screen_info screen_info = { ++ .orig_video_lines = 30, ++ .orig_video_cols = 80, ++ .orig_video_mode = 0, ++ .orig_video_ega_bx = 0, ++ .orig_video_isVGA = 1, ++ .orig_video_points = 8 ++}; ++ ++static int __init parse_tag_videotext(const struct tag *tag) ++{ ++ screen_info.orig_x = tag->u.videotext.x; ++ screen_info.orig_y = tag->u.videotext.y; ++ screen_info.orig_video_page = tag->u.videotext.video_page; ++ screen_info.orig_video_mode = tag->u.videotext.video_mode; ++ screen_info.orig_video_cols = tag->u.videotext.video_cols; ++ screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx; ++ screen_info.orig_video_lines = tag->u.videotext.video_lines; ++ screen_info.orig_video_isVGA = tag->u.videotext.video_isvga; ++ screen_info.orig_video_points = tag->u.videotext.video_points; ++ return 0; ++} ++ ++__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext); ++#endif ++ ++static int __init parse_tag_ramdisk(const struct tag *tag) ++{ ++ setup_ramdisk((tag->u.ramdisk.flags & 1) == 0, ++ (tag->u.ramdisk.flags & 2) == 0, ++ tag->u.ramdisk.start, tag->u.ramdisk.size); ++ return 0; ++} ++ ++__tagtable(ATAG_RAMDISK, parse_tag_ramdisk); ++ ++static int __init parse_tag_initrd(const struct tag *tag) ++{ ++ printk(KERN_WARNING "ATAG_INITRD is deprecated; " ++ "please update your bootloader.\n"); ++ phys_initrd_start = __virt_to_phys(tag->u.initrd.start); ++ phys_initrd_size = tag->u.initrd.size; ++ return 0; ++} ++ ++__tagtable(ATAG_INITRD, parse_tag_initrd); ++ ++static int __init parse_tag_initrd2(const struct tag *tag) ++{ ++ phys_initrd_start = tag->u.initrd.start; ++ phys_initrd_size = tag->u.initrd.size; ++ return 0; ++} ++ ++__tagtable(ATAG_INITRD2, parse_tag_initrd2); ++ ++static int __init parse_tag_revision(const struct tag *tag) ++{ ++ return 0; ++} ++ ++__tagtable(ATAG_REVISION, parse_tag_revision); ++ ++static int __init parse_tag_cmdline(const struct tag *tag) ++{ ++ strlcpy(default_command_line, tag->u.cmdline.cmdline, ++ COMMAND_LINE_SIZE); ++ return 0; ++} ++ ++__tagtable(ATAG_CMDLINE, parse_tag_cmdline); ++ ++/* ++ * Scan the tag table for this tag, and call its parse function. ++ * The tag table is built by the linker from all the __tagtable ++ * declarations. ++ */ ++static int __init parse_tag(const struct tag *tag) ++{ ++ extern struct tagtable __tagtable_begin, __tagtable_end; ++ struct tagtable *t; ++ ++ for (t = &__tagtable_begin; t < &__tagtable_end; t++) ++ if (tag->hdr.tag == t->tag) { ++ t->parse(tag); ++ break; ++ } ++ ++ return t < &__tagtable_end; ++} ++ ++/* ++ * Parse all tags in the list, checking both the global and architecture ++ * specific tag tables. ++ */ ++static void __init parse_tags(const struct tag *t) ++{ ++ for (; t->hdr.size; t = tag_next(t)) ++ if (!parse_tag(t)) ++ printk(KERN_WARNING ++ "Ignoring unrecognised tag 0x%08x\n", ++ t->hdr.tag); ++} ++ ++/* ++ * This holds our defaults. ++ */ ++static struct init_tags { ++ struct tag_header hdr1; ++ struct tag_core core; ++ struct tag_header hdr2; ++ struct tag_mem32 mem; ++ struct tag_header hdr3; ++} init_tags __initdata = { ++ {tag_size(tag_core), ATAG_CORE}, //hdr1 ++ {0, PAGE_SIZE, 0xff}, ++ {tag_size(tag_mem32), ATAG_MEM}, //hdr2 ++ {MEM_SIZE, PHYS_OFFSET}, ++ {0, ATAG_NONE} ++}; ++ ++static unsigned long __init setup_memory(void) ++{ ++ unsigned long bootmap_size; ++ unsigned long ram_start_pfn; ++ unsigned long free_ram_start_pfn; ++ phys_addr_t memory_start, memory_end; ++ struct memblock_region *region; ++ ++ memory_end = memory_start = 0; ++ ++ /* Find main memory where is the kernel */ ++ for_each_memblock(memory, region) { ++ memory_start = region->base; ++ memory_end = region->base + region->size; ++ printk(KERN_INFO "%s: Memory: 0x%x-0x%x\n", __func__, ++ memory_start, memory_end); ++ } ++ ++ if (!memory_end) { ++ panic("No memory!"); ++ } ++ ++ ram_start_pfn = PFN_UP(memblock_start_of_DRAM()); ++ /* free_ram_start_pfn is first page after kernel */ ++ free_ram_start_pfn = PFN_UP(__pa(&_end)); ++ max_pfn = PFN_DOWN(memblock_end_of_DRAM()); ++ ++ /* it could update max_pfn */ ++ if (max_pfn - ram_start_pfn <= MAXMEM_PFN) ++ max_low_pfn = max_pfn; ++ else { ++ max_low_pfn = MAXMEM_PFN + ram_start_pfn; ++#ifndef CONFIG_HIGHMEM ++ max_pfn = MAXMEM_PFN + ram_start_pfn; ++#endif ++ } ++ /* high_memory is related with VMALLOC */ ++ high_memory = (void *)__va(max_low_pfn * PAGE_SIZE); ++ min_low_pfn = free_ram_start_pfn; ++ ++ /* ++ * initialize the boot-time allocator (with low memory only). ++ * ++ * This makes the memory from the end of the kernel to the end of ++ * RAM usable. ++ * init_bootmem sets the global values min_low_pfn, max_low_pfn. ++ */ ++ bootmap_size = init_bootmem_node(NODE_DATA(0), free_ram_start_pfn, ++ ram_start_pfn, max_low_pfn); ++ free_bootmem(PFN_PHYS(free_ram_start_pfn), ++ (max_low_pfn - free_ram_start_pfn) << PAGE_SHIFT); ++ reserve_bootmem(PFN_PHYS(free_ram_start_pfn), bootmap_size, ++ BOOTMEM_DEFAULT); ++ ++ for_each_memblock(reserved, region) { ++ if (region->size != 0) { ++ printk(KERN_INFO "Reserved - 0x%08x-0x%08x\n", ++ (u32) region->base, (u32) region->size); ++ reserve_bootmem(region->base, region->size, ++ BOOTMEM_DEFAULT); ++ } ++ } ++ return max_low_pfn; ++} ++ ++void __init setup_arch(char **cmdline_p) ++{ ++ struct tag *tags = (struct tag *)&init_tags; ++ struct machine_desc *mdesc; ++ char *from = default_command_line; ++ ++ setup_processor(); ++ mdesc = setup_machine(machine_arch_type); ++ machine_desc = mdesc; ++ machine_name = mdesc->name; ++ ++ if (mdesc->soft_reboot) ++ reboot_setup("s"); ++ ++ if (mdesc->param_offset) ++ tags = phys_to_virt(mdesc->param_offset); ++ ++ if (tags->hdr.tag != ATAG_CORE) ++ tags = (struct tag *)&init_tags; ++ ++ if (tags->hdr.tag == ATAG_CORE) { ++ if (meminfo.nr_banks != 0) ++ squash_mem_tags(tags); ++ parse_tags(tags); ++ } ++ ++ init_mm.start_code = (unsigned long)&_text; ++ init_mm.end_code = (unsigned long)&_etext; ++ init_mm.end_data = (unsigned long)&_edata; ++ init_mm.brk = (unsigned long)&_end; ++ ++ memcpy(boot_command_line, from, COMMAND_LINE_SIZE); ++ boot_command_line[COMMAND_LINE_SIZE - 1] = '\0'; ++ parse_cmdline(cmdline_p, from); ++ ++ /* use generic way to parse */ ++ parse_early_param(); ++ ++ /* setup bootmem allocator */ ++ setup_memory(); ++ ++ strlcpy(command_line, from, COMMAND_LINE_SIZE); ++ *cmdline_p = command_line; ++ ++ paging_init(mdesc); ++ request_standard_resources(&meminfo, mdesc); //- for test only ++ ++#ifdef CONFIG_SMP ++ smp_init_cpus(); ++#endif ++ ++ /* ++ * Set up various architecture-specific pointers ++ */ ++ init_arch_irq = mdesc->init_irq; ++ system_timer = mdesc->timer; ++ if (mdesc->init_machine) ++ mdesc->init_machine(); ++ ++#if defined(CONFIG_VT) ++#if defined(CONFIG_VGA_CONSOLE) ++ conswitchp = &vga_con; ++#elif defined(CONFIG_DUMMY_CONSOLE) ++ conswitchp = &dummy_con; //+ Tom: we will reach here ++#endif ++#endif ++ ++ early_trap_init(); ++} ++ ++/* ++ * cpu_init - initialise one CPU. ++ * ++ * cpu_init dumps the cache information, initialises SMP specific ++ * information. ++ */ ++ ++void __init cpu_init(void) ++{ ++ unsigned int cpu = smp_processor_id(), tmp = 0; ++ ++ if (cpu >= NR_CPUS) { ++ printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu); ++ BUG(); ++ } ++ ++ if (system_state == SYSTEM_BOOTING) ++ dump_cpu_info(cpu); ++ ++ tmp = 1 << IVB_offESZ; ++#ifdef CONFIG_EVIC ++ tmp |= 1 << IVB_offEVIC; ++#endif ++ SET_IVB(tmp | IVB_BASE); ++ tmp = 0x10003; ++ SET_INT_MASK(tmp); ++ ISB(); ++} ++ ++static int __init topology_init(void) ++{ ++ int cpu; ++ ++ for_each_possible_cpu(cpu) ++ register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu); ++ ++ return 0; ++} ++ ++subsys_initcall(topology_init); ++ ++static int c_show(struct seq_file *m, void *v) ++{ ++ int i; ++ ++ seq_printf(m, "Processor\t: %s %s (id %lu, rev %lu, cfg %lu)\n", ++ proc_info.manufacturer, proc_info.cpu_name, ++ cpu_id, cpu_rev, cpu_cfgid); ++#if defined(CONFIG_AG101_CPU_FREQ_SCALING_MODE) || defined(CONFIG_AG101_CPU_FREQ_FCS) ++ seq_printf(m, "MHz\t\t: %u\n", ag101_cpufreq_get(1) / 1000); ++#endif ++ ++ seq_printf(m, "L1I\t\t: %luKB/%luS/%luW/%luB\n", ++ CACHE_SET(ICACHE) * CACHE_WAY(ICACHE) * ++ CACHE_LINE_SIZE(ICACHE) / 1024, CACHE_SET(ICACHE), ++ CACHE_WAY(ICACHE), CACHE_LINE_SIZE(ICACHE)); ++ ++ seq_printf(m, "L1D\t\t: %luKB/%luS/%luW/%luB\n", ++ CACHE_SET(DCACHE) * CACHE_WAY(DCACHE) * ++ CACHE_LINE_SIZE(DCACHE) / 1024, CACHE_SET(DCACHE), ++ CACHE_WAY(DCACHE), CACHE_LINE_SIZE(DCACHE)); ++ ++#if defined(CONFIG_SMP) ++ for_each_online_cpu(i) { ++ seq_printf(m, "Processor\t: %d\n", i); ++ seq_printf(m, "BogoMIPS\t: %lu.%02lu\n\n", ++ per_cpu(cpu_data, ++ i).loops_per_jiffy / (500000UL / HZ), ++ (per_cpu(cpu_data, i).loops_per_jiffy / ++ (5000UL / HZ)) % 100); ++ } ++#else /* CONFIG_SMP */ ++ seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", ++ loops_per_jiffy / (500000 / HZ), ++ (loops_per_jiffy / (5000 / HZ)) % 100); ++#endif ++ ++ /* dump out the processor features */ ++ seq_puts(m, "Features\t: "); ++ ++ for (i = 0; hwcap_str[i]; i++) ++ if (elf_hwcap & (1 << i)) ++ seq_printf(m, "%s ", hwcap_str[i]); ++ ++ seq_puts(m, "\n\n"); ++ seq_printf(m, "Hardware\t: %s\n", elf_platform); ++ ++ return 0; ++} ++ ++static void *c_start(struct seq_file *m, loff_t * pos) ++{ ++ return *pos < 1 ? (void *)1 : NULL; ++} ++ ++static void *c_next(struct seq_file *m, void *v, loff_t * pos) ++{ ++ ++*pos; ++ return NULL; ++} ++ ++static void c_stop(struct seq_file *m, void *v) ++{ ++} ++ ++struct seq_operations cpuinfo_op = { ++ .start = c_start, ++ .next = c_next, ++ .stop = c_stop, ++ .show = c_show ++}; +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/signal.c linux-3.4.110/arch/nds32/kernel/signal.c +--- linux-3.4.110.orig/arch/nds32/kernel/signal.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/signal.c 2016-04-07 10:20:50.946081179 +0200 +@@ -0,0 +1,850 @@ ++/* ++ * linux/arch/nds32/kernel/signal.c ++ * ++ * Copyright (C) 1995-2002 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/errno.h> ++#include <linux/signal.h> ++#include <linux/ptrace.h> ++#include <linux/personality.h> ++#include <linux/freezer.h> ++#include <linux/tracehook.h> ++ ++#include <asm/cacheflush.h> ++#include <asm/ucontext.h> ++#include <asm/uaccess.h> ++#include <asm/unistd.h> ++#include <asm/fpu.h> ++#include <asm/audio.h> ++ ++#include "ptrace.h" ++#include "signal.h" ++#include "fpu.h" ++#include "audio.h" ++ ++#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) ++ ++/* ++ * For NDS32 syscalls, we encode the syscall number into the instruction. ++ */ ++#if defined( __NDS32_EL__) ++#define SWI_SYS_SIGRETURN (0xeb0e0a64) ++#define SWI_SYS_RT_SIGRETURN (0xab150a64) ++#define SWI_SYS_RESTART (0x0b000a64) /* syscall __NR_restart_syscall */ ++#define SWI_SYS_RESTART_LWIBI (0x0180af0d) /* lwi.bi $p0, [$sp], 4 */ ++#define SWI_SYS_RESTART_JRP0 (0x0068004a) /* jr $p0 */ ++#elif defined(__NDS32_EB__) ++#define SWI_SYS_SIGRETURN (0x6400000b|(__NR_sigreturn<<5)) ++#define SWI_SYS_RT_SIGRETURN (0x6400000b|(__NR_rt_sigreturn<<5)) ++#define SWI_SYS_RESTART (0x640a000b) /* syscall __NR_restart_syscall */ ++#define SWI_SYS_RESTART_LWIBI (0x0daf8001) /* lwi.bi $p0, [$sp], 4 */ ++#define SWI_SYS_RESTART_JRP0 (0x4a006800) /* jr $p0 */ ++#else ++#error "NDS32, but neither __NDS32_EB__, nor __NDS32_EL__???" ++#endif ++ ++#ifdef CONFIG_FPU ++static struct fpu_struct init_fpuregs = { ++ .fs_regs = {[0 ... 31] = sNAN32}, ++ .fd_regs = {[0 ... 15] = sNAN64}, ++ .fpcsr = FPCSR_INIT ++}; ++#endif ++#ifdef CONFIG_AUDIO ++static struct audio_struct init_audioregs = { ++ .auregs = {[0...31] = NAN32} ++}; ++#endif ++const unsigned long retcodes[2] = { ++ SWI_SYS_SIGRETURN, ++ SWI_SYS_RT_SIGRETURN ++}; ++ ++const unsigned long syscall_restart_code[3] = { ++ SWI_SYS_RESTART, /* syscall __NR_restart_syscall */ ++ SWI_SYS_RESTART_LWIBI, /* lwi.bi $p0, [$sp], 4 */ ++ SWI_SYS_RESTART_JRP0 /* jr $p0 */ ++}; ++ ++static int do_signal(sigset_t * oldset, struct pt_regs *regs, int syscall); ++ ++/* ++ * atomically swap in the new signal mask, and wait for a signal. ++ */ ++asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, ++ old_sigset_t mask, struct pt_regs *regs) ++{ ++ sigset_t blocked; ++ ++ mask &= _BLOCKABLE; ++ current->saved_sigmask = current->blocked; ++ siginitset(&blocked, mask); ++ set_current_blocked(&blocked); ++ ++ current->state = TASK_INTERRUPTIBLE; ++ schedule(); ++ set_thread_flag(TIF_RESTORE_SIGMASK); ++ return -ERESTARTNOHAND; ++} ++ ++asmlinkage int sys_rt_sigsuspend(sigset_t __user * unewset, size_t sigsetsize, ++ struct pt_regs *regs) ++{ ++ sigset_t newset; ++ ++ /* XXX: Don't preclude handling different sized sigset_t's. */ ++ if (sigsetsize != sizeof(sigset_t)) ++ return -EINVAL; ++ ++ if (copy_from_user(&newset, unewset, sizeof(newset))) ++ return -EFAULT; ++ sigdelsetmask(&newset, ~_BLOCKABLE); ++ current->saved_sigmask = current->blocked; ++ set_current_blocked(&newset); ++ current->state = TASK_INTERRUPTIBLE; ++ schedule(); ++ set_thread_flag(TIF_RESTORE_SIGMASK); ++ return -ERESTARTNOHAND; ++} ++ ++asmlinkage int sys_sigaction(int sig, const struct old_sigaction __user * act, ++ struct old_sigaction __user * oact) ++{ ++ struct k_sigaction new_ka, old_ka; ++ int ret; ++ ++ if (act) { ++ old_sigset_t mask; ++ if (!access_ok(VERIFY_READ, act, sizeof(*act)) || ++ __get_user(new_ka.sa.sa_handler, &act->sa_handler) || ++ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) { ++ ++ return -EFAULT; ++ } ++ __get_user(new_ka.sa.sa_flags, &act->sa_flags); ++ __get_user(mask, &act->sa_mask); ++ ++ siginitset(&new_ka.sa.sa_mask, mask); ++ } ++ ++ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); ++ ++ if (!ret && oact) { ++ ++ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || ++ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || ++ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) { ++ ++ return -EFAULT; ++ } ++ __put_user(old_ka.sa.sa_flags, &oact->sa_flags); ++ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); ++ } ++ ++ return ret; ++} ++ ++/* ++ * Auxiliary signal frame. This saves stuff like FP state. ++ * The layout of this structure is not part of the user ABI. ++ */ ++struct aux_sigframe { ++}; ++ ++/* ++ * Do a signal return; undo the signal stack. These are aligned to 64-bit. ++ */ ++struct sigframe { ++ struct sigcontext sc; ++ unsigned long extramask[_NSIG_WORDS - 1]; ++ unsigned long retcode; ++ struct aux_sigframe aux __attribute__ ((aligned(8))); ++}; ++ ++struct rt_sigframe { ++ struct siginfo __user *pinfo; ++ void __user *puc; ++ struct siginfo info; ++ struct ucontext uc; ++ unsigned long retcode; ++ struct aux_sigframe aux __attribute__ ((aligned(8))); ++}; ++ ++#ifdef CONFIG_FPU ++static inline int restore_sigcontext_fpu(struct pt_regs *regs, ++ struct sigcontext __user * sc) ++{ ++ struct task_struct *tsk = current; ++ unsigned long used_math_flag; ++ int ret = 0; ++ ++ if (!(GET_FUCOP_EXIST() & FUCOP_EXIST_mskCP0ISFPU)) ++ return 0; ++ ++ __get_user_error(used_math_flag, &sc->used_math_flag, ret); ++ ++ if (!used_math_flag) ++ return 0; ++ ++ set_used_math(); ++ ++#ifdef CONFIG_UNLAZY_FPU ++ clear_fpu(regs); ++#else ++ preempt_disable(); ++ if (current == last_task_used_math) { ++ last_task_used_math = NULL; ++ release_fpu(regs); ++ } ++ preempt_enable(); ++#endif ++ ++ return __copy_from_user(&tsk->thread.fpu, &sc->fpu, ++ sizeof(struct fpu_struct)); ++} ++ ++static inline int setup_sigcontext_fpu(struct pt_regs *regs, ++ struct sigcontext __user * sc) ++{ ++ struct task_struct *tsk = current; ++ int ret = 0; ++ ++ if (!(GET_FUCOP_EXIST() & FUCOP_EXIST_mskCP0ISFPU)) ++ return 0; ++ ++ __put_user_error(used_math(), &sc->used_math_flag, ret); ++ ++ if (!used_math()) ++ return ret; ++ ++ preempt_disable(); ++#ifdef CONFIG_UNLAZY_FPU ++ unlazy_fpu(tsk); ++#else ++ if (last_task_used_math != NULL) ++ save_fpu(last_task_used_math); ++#endif ++ ret = __copy_to_user(&sc->fpu, &tsk->thread.fpu, ++ sizeof(struct fpu_struct)); ++ ++ grab_fpu(task_pt_regs(tsk)); ++ fpload(&init_fpuregs); ++#ifndef CONFIG_UNLAZY_FPU //Lazy FPU ++ last_task_used_math = current; ++#endif ++ preempt_enable(); ++ return ret; ++} ++#else ++static inline int ++restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user * sc) ++{ ++ return 0; ++} ++ ++static inline int ++setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user * sc) ++{ ++ return 0; ++} ++#endif /* CONFIG_FPU */ ++ ++#ifdef CONFIG_AUDIO ++static inline int restore_sigcontext_audio(struct pt_regs *regs, ++ struct sigcontext __user * sc) ++{ ++ struct task_struct *tsk = current; ++ unsigned long used_audio_flag; ++ int ret = 0; ++ ++ if (!(GET_MSC_CFG() & MSC_CFG_mskAUDIO)) ++ return 0; ++ ++ __get_user_error(used_audio_flag, &sc->used_audio_flag, ret); ++ ++ if (!used_audio_flag) ++ return 0; ++ ++ set_tsk_thread_flag(tsk, TIF_USEDAUDIO); ++#ifdef CONFIG_UNLAZY_AUDIO ++ clear_audio(regs); ++#else ++ preempt_disable(); ++ if (current == last_task_used_audio) { ++ last_task_used_audio = NULL; ++ clear_audio(regs); ++ } ++ preempt_enable(); ++#endif ++ ++ return __copy_from_user(&tsk->thread.audio, &sc->audio, ++ sizeof(struct audio_struct)); ++} ++ ++static inline int setup_sigcontext_audio(struct pt_regs *regs, ++ struct sigcontext __user * sc) ++{ ++ struct task_struct *tsk = current; ++ int ret = 0; ++ ++ if (!(GET_MSC_CFG() & MSC_CFG_mskAUDIO)) ++ return 0; ++ ++ __put_user_error(test_tsk_thread_flag(tsk, TIF_USEDAUDIO), ++ &sc->used_audio_flag, ret); ++ ++ if (!test_tsk_thread_flag(tsk, TIF_USEDAUDIO)) ++ return ret; ++ ++ preempt_disable(); ++#ifdef CONFIG_UNLAZY_AUDIO ++ unlazy_audio(tsk); ++#else ++ if (NULL != last_task_used_audio) { ++ save_audio(tsk); ++ } ++#endif ++ ret = __copy_to_user(&sc->audio, &tsk->thread.audio, ++ sizeof(struct audio_struct)); ++ ++ grab_audio(task_pt_regs(tsk)); ++ audioload(&init_audioregs); ++#ifndef CONFIG_UNLAZY_AUDIO //Lazy audio ++ last_task_used_audio = current; ++#endif ++ preempt_enable(); ++ return ret; ++} ++#else /*CONFIG_AUDIO */ ++static inline int ++restore_sigcontext_audio(struct pt_regs *regs, struct sigcontext __user * sc) ++{ ++ return 0; ++} ++ ++static inline int ++setup_sigcontext_audio(struct pt_regs *regs, struct sigcontext __user * sc) ++{ ++ return 0; ++} ++#endif ++ ++static int restore_sigcontext(struct pt_regs *regs, ++ struct sigcontext __user * sc, ++ struct aux_sigframe __user * aux) ++{ ++ int err = 0; ++ ++ __get_user_error(regs->NDS32_r0, &sc->nds32_r0, err); ++ __get_user_error(regs->NDS32_r1, &sc->nds32_r1, err); ++ __get_user_error(regs->NDS32_r2, &sc->nds32_r2, err); ++ __get_user_error(regs->NDS32_r3, &sc->nds32_r3, err); ++ __get_user_error(regs->NDS32_r4, &sc->nds32_r4, err); ++ __get_user_error(regs->NDS32_r5, &sc->nds32_r5, err); ++ __get_user_error(regs->NDS32_r6, &sc->nds32_r6, err); ++ __get_user_error(regs->NDS32_r7, &sc->nds32_r7, err); ++ __get_user_error(regs->NDS32_r8, &sc->nds32_r8, err); ++ __get_user_error(regs->NDS32_r9, &sc->nds32_r9, err); ++ __get_user_error(regs->NDS32_r10, &sc->nds32_r10, err); ++ __get_user_error(regs->NDS32_r11, &sc->nds32_r11, err); ++ __get_user_error(regs->NDS32_r12, &sc->nds32_r12, err); ++ __get_user_error(regs->NDS32_r13, &sc->nds32_r13, err); ++ __get_user_error(regs->NDS32_r14, &sc->nds32_r14, err); ++ __get_user_error(regs->NDS32_r15, &sc->nds32_r15, err); ++ __get_user_error(regs->NDS32_r16, &sc->nds32_r16, err); ++ __get_user_error(regs->NDS32_r17, &sc->nds32_r17, err); ++ __get_user_error(regs->NDS32_r18, &sc->nds32_r18, err); ++ __get_user_error(regs->NDS32_r19, &sc->nds32_r19, err); ++ __get_user_error(regs->NDS32_r20, &sc->nds32_r20, err); ++ ++ __get_user_error(regs->NDS32_r21, &sc->nds32_r21, err); ++ __get_user_error(regs->NDS32_r22, &sc->nds32_r22, err); ++ __get_user_error(regs->NDS32_r23, &sc->nds32_r23, err); ++ __get_user_error(regs->NDS32_r24, &sc->nds32_r24, err); ++ __get_user_error(regs->NDS32_r25, &sc->nds32_r25, err); ++ __get_user_error(regs->NDS32_fp, &sc->nds32_fp, err); ++ __get_user_error(regs->NDS32_gp, &sc->nds32_gp, err); ++ __get_user_error(regs->NDS32_lp, &sc->nds32_lr, err); ++ __get_user_error(regs->NDS32_sp, &sc->nds32_sp, err); ++ ++ __get_user_error(regs->NDS32_ipc, &sc->nds32_ipc, err); ++#if defined(CONFIG_HWZOL) ++ __get_user_error(regs->NDS32_lc, &sc->zol.nds32_lc, err); ++ __get_user_error(regs->NDS32_le, &sc->zol.nds32_le, err); ++ __get_user_error(regs->NDS32_lb, &sc->zol.nds32_lb, err); ++#endif ++ ++ err |= !valid_user_regs(regs); ++ err |= restore_sigcontext_audio(regs, sc); ++ err |= restore_sigcontext_fpu(regs, sc); ++ ++ return err; ++} ++ ++asmlinkage int sys_sigreturn(struct pt_regs *regs) ++{ ++ struct sigframe __user *frame; ++ sigset_t set; ++ ++ /* Always make any pending restarted system calls return -EINTR */ ++ current_thread_info()->restart_block.fn = do_no_restart_syscall; ++ ++ /* ++ * Since we stacked the signal on a 64-bit boundary, ++ * then 'sp' should be word aligned here. If it's ++ * not, then the user is trying to mess with us. ++ */ ++ if (regs->NDS32_sp & 7) ++ goto badframe; ++ ++ frame = (struct sigframe __user *)regs->NDS32_sp; ++ ++ if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) ++ goto badframe; ++ ++ if (__get_user(set.sig[0], &frame->sc.oldmask) ++ || (_NSIG_WORDS > 1 ++ && __copy_from_user(&set.sig[1], &frame->extramask, ++ sizeof(frame->extramask)))) ++ goto badframe; ++ ++ sigdelsetmask(&set, ~_BLOCKABLE); ++ spin_lock_irq(¤t->sighand->siglock); ++ current->blocked = set; ++ recalc_sigpending(); ++ spin_unlock_irq(¤t->sighand->siglock); ++ ++ if (restore_sigcontext(regs, &frame->sc, &frame->aux)) ++ goto badframe; ++ ++ return regs->NDS32_r0; ++ ++badframe: ++ force_sig(SIGSEGV, current); ++ return 0; ++} ++ ++asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) ++{ ++ struct rt_sigframe __user *frame; ++ sigset_t set; ++ ++ /* Always make any pending restarted system calls return -EINTR */ ++ current_thread_info()->restart_block.fn = do_no_restart_syscall; ++ ++ /* ++ * Since we stacked the signal on a 64-bit boundary, ++ * then 'sp' should be word aligned here. If it's ++ * not, then the user is trying to mess with us. ++ */ ++ if (regs->NDS32_sp & 7) ++ goto badframe; ++ ++ frame = (struct rt_sigframe __user *)regs->NDS32_sp; ++ ++ if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) ++ goto badframe; ++ ++ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) ++ goto badframe; ++ ++ sigdelsetmask(&set, ~_BLOCKABLE); ++ spin_lock_irq(¤t->sighand->siglock); ++ current->blocked = set; ++ recalc_sigpending(); ++ spin_unlock_irq(¤t->sighand->siglock); ++ ++ if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &frame->aux)) ++ goto badframe; ++ ++ if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->NDS32_sp) == ++ -EFAULT) ++ goto badframe; ++ ++ return regs->NDS32_r0; ++ ++badframe: ++ force_sig(SIGSEGV, current); ++ return 0; ++} ++ ++static int setup_sigcontext(struct sigcontext __user * sc, ++ struct aux_sigframe __user * aux, ++ struct pt_regs *regs, unsigned long mask) ++{ ++ int err = 0; ++ ++ err |= setup_sigcontext_fpu(regs, sc); ++ err |= setup_sigcontext_audio(regs, sc); ++ ++ __put_user_error(regs->NDS32_r0, &sc->nds32_r0, err); ++ __put_user_error(regs->NDS32_r1, &sc->nds32_r1, err); ++ __put_user_error(regs->NDS32_r2, &sc->nds32_r2, err); ++ __put_user_error(regs->NDS32_r3, &sc->nds32_r3, err); ++ __put_user_error(regs->NDS32_r4, &sc->nds32_r4, err); ++ __put_user_error(regs->NDS32_r5, &sc->nds32_r5, err); ++ __put_user_error(regs->NDS32_r6, &sc->nds32_r6, err); ++ __put_user_error(regs->NDS32_r7, &sc->nds32_r7, err); ++ __put_user_error(regs->NDS32_r8, &sc->nds32_r8, err); ++ __put_user_error(regs->NDS32_r9, &sc->nds32_r9, err); ++ __put_user_error(regs->NDS32_r10, &sc->nds32_r10, err); ++ __put_user_error(regs->NDS32_r11, &sc->nds32_r11, err); ++ __put_user_error(regs->NDS32_r12, &sc->nds32_r12, err); ++ __put_user_error(regs->NDS32_r13, &sc->nds32_r13, err); ++ __put_user_error(regs->NDS32_r14, &sc->nds32_r14, err); ++ __put_user_error(regs->NDS32_r15, &sc->nds32_r15, err); ++ __put_user_error(regs->NDS32_r16, &sc->nds32_r16, err); ++ __put_user_error(regs->NDS32_r17, &sc->nds32_r17, err); ++ __put_user_error(regs->NDS32_r18, &sc->nds32_r18, err); ++ __put_user_error(regs->NDS32_r19, &sc->nds32_r19, err); ++ __put_user_error(regs->NDS32_r20, &sc->nds32_r20, err); ++ ++ __put_user_error(regs->NDS32_r21, &sc->nds32_r21, err); ++ __put_user_error(regs->NDS32_r22, &sc->nds32_r22, err); ++ __put_user_error(regs->NDS32_r23, &sc->nds32_r23, err); ++ __put_user_error(regs->NDS32_r24, &sc->nds32_r24, err); ++ __put_user_error(regs->NDS32_r25, &sc->nds32_r25, err); ++ __put_user_error(regs->NDS32_fp, &sc->nds32_fp, err); ++ __put_user_error(regs->NDS32_gp, &sc->nds32_gp, err); ++ __put_user_error(regs->NDS32_lp, &sc->nds32_lr, err); ++ __put_user_error(regs->NDS32_sp, &sc->nds32_sp, err); ++ __put_user_error(regs->NDS32_ipc, &sc->nds32_ipc, err); ++#if defined(CONFIG_HWZOL) ++ __get_user_error(regs->NDS32_lc, &sc->zol.nds32_lc, err); ++ __get_user_error(regs->NDS32_le, &sc->zol.nds32_le, err); ++ __get_user_error(regs->NDS32_lb, &sc->zol.nds32_lb, err); ++#endif ++ ++ __put_user_error(current->thread.trap_no, &sc->trap_no, err); ++ __put_user_error(current->thread.error_code, &sc->error_code, err); ++ __put_user_error(current->thread.address, &sc->fault_address, err); ++ __put_user_error(mask, &sc->oldmask, err); ++ ++ return err; ++} ++ ++static inline void __user *get_sigframe(struct k_sigaction *ka, ++ struct pt_regs *regs, int framesize) ++{ ++ unsigned long sp = regs->NDS32_sp; ++ void __user *frame; ++ ++ /* ++ * This is the X/Open sanctioned signal stack switching. ++ */ ++ if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) ++ sp = current->sas_ss_sp + current->sas_ss_size; ++ ++ /* ++ * ATPCS B01 mandates 8-byte alignment ++ */ ++ frame = (void __user *)((sp - framesize) & ~7); ++ ++ /* ++ * Check that we can actually write to the signal frame. ++ */ ++ if (!access_ok(VERIFY_WRITE, frame, framesize)) ++ frame = NULL; ++ ++ return frame; ++} ++ ++static int setup_return(struct pt_regs *regs, struct k_sigaction *ka, ++ unsigned long __user * rc, void __user * frame, ++ int usig) ++{ ++ unsigned long handler = (unsigned long)ka->sa.sa_handler; ++ unsigned long retcode; ++ struct sigframe *sf = (struct sigframe *)frame; ++ ++ /* ++ * Maybe we need to deliver a 32-bit signal to a 26-bit task. ++ */ ++ if (ka->sa.sa_flags & SA_RESTORER) { ++ retcode = (unsigned long)ka->sa.sa_restorer; ++ } else { ++ ++ unsigned int idx = 0; //thumb; ++ unsigned long line_size = CACHE_LINE_SIZE(ICACHE); ++ unsigned long start, end; ++ ++ if (ka->sa.sa_flags & SA_SIGINFO) ++ idx++; ++ ++ if (__put_user(retcodes[idx], rc)) ++ return 1; ++ ++ /* ++ * Ensure that the instruction cache sees ++ * the return code written onto the stack. ++ */ ++ start = (unsigned long)rc & ~(line_size - 1); ++ end = start + line_size; ++ flush_icache_range(start, end); ++ ++ retcode = KERN_SIGRETURN_CODE + (idx << 2); ++ } ++ ++ regs->NDS32_r0 = usig; ++ regs->NDS32_r1 = 0; ++ regs->NDS32_r2 = (unsigned long)&sf->sc; ++ regs->NDS32_sp = (unsigned long)frame; ++ regs->NDS32_lp = retcode; ++ regs->NDS32_ipc = handler; ++ /* Also store handler address in r15 for updating GP in the handler. */ ++ regs->NDS32_r15 = handler; ++ ++ return 0; ++} ++ ++static int setup_frame(int usig, struct k_sigaction *ka, sigset_t * set, ++ struct pt_regs *regs) ++{ ++ struct sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame)); ++ int err = 0; ++ ++ if (!frame) ++ return 1; ++ ++ err |= setup_sigcontext(&frame->sc, &frame->aux, regs, set->sig[0]); ++ ++ if (_NSIG_WORDS > 1) { ++ err |= __copy_to_user(frame->extramask, &set->sig[1], ++ sizeof(frame->extramask)); ++ } ++ ++ if (err == 0) ++ err = setup_return(regs, ka, &frame->retcode, frame, usig); ++ ++ return err; ++} ++ ++static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t * info, ++ sigset_t * set, struct pt_regs *regs) ++{ ++ struct rt_sigframe __user *frame = ++ get_sigframe(ka, regs, sizeof(*frame)); ++ stack_t stack; ++ int err = 0; ++ ++ if (!frame) ++ return 1; ++ ++ __put_user_error(&frame->info, &frame->pinfo, err); ++ __put_user_error(&frame->uc, &frame->puc, err); ++ err |= copy_siginfo_to_user(&frame->info, info); ++ ++ __put_user_error(0, &frame->uc.uc_flags, err); ++ __put_user_error(NULL, &frame->uc.uc_link, err); ++ ++ memset(&stack, 0, sizeof(stack)); ++ stack.ss_sp = (void __user *)current->sas_ss_sp; ++ stack.ss_flags = sas_ss_flags(regs->NDS32_sp); //NDS32_sp ++ stack.ss_size = current->sas_ss_size; ++ err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack)); ++ ++ err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->aux, ++ regs, set->sig[0]); ++ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); ++ ++ if (err == 0) ++ err = setup_return(regs, ka, &frame->retcode, frame, usig); ++ ++ if (err == 0) { ++ /* ++ * For realtime signals we must also set the second and third ++ * arguments for the signal handler. ++ * -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06 ++ */ ++ regs->NDS32_r1 = (unsigned long)&frame->info; ++ regs->NDS32_r2 = (unsigned long)&frame->uc; ++ } ++ ++ return err; ++} ++ ++static inline void setup_restart_syscall(struct pt_regs *regs) ++{ ++ regs->NDS32_r0 = regs->NDS32_ORIG_r0; ++ regs->NDS32_ipc -= 4; ++} ++ ++/* ++ * OK, we're invoking a handler ++ */ ++static void handle_signal(unsigned long sig, struct k_sigaction *ka, ++ siginfo_t * info, sigset_t * oldset, ++ struct pt_regs *regs, int syscall) ++{ ++ struct thread_info *thread = current_thread_info(); ++ struct task_struct *tsk = current; ++ int usig = sig; ++ int ret; ++ ++ /* ++ * If we were from a system call, check for system call restarting... ++ */ ++ if (syscall) { ++ switch (regs->NDS32_r0) { ++ case -ERESTART_RESTARTBLOCK: ++ case -ERESTARTNOHAND: ++ regs->NDS32_r0 = -EINTR; ++ break; ++ case -ERESTARTSYS: ++ if (!(ka->sa.sa_flags & SA_RESTART)) { ++ regs->NDS32_r0 = -EINTR; ++ break; ++ } ++ /* fallthrough */ ++ case -ERESTARTNOINTR: ++ setup_restart_syscall(regs); ++ } ++ } ++ ++ /* ++ * translate the signal ++ */ ++ if (usig < 32 && thread->exec_domain ++ && thread->exec_domain->signal_invmap) ++ usig = thread->exec_domain->signal_invmap[usig]; ++ ++ /* ++ * Set up the stack frame ++ */ ++ if (ka->sa.sa_flags & SA_SIGINFO) ++ ret = setup_rt_frame(usig, ka, info, oldset, regs); ++ else ++ ret = setup_frame(usig, ka, oldset, regs); ++ ++ /* ++ * Check that the resulting registers are actually sane. ++ */ ++ ret |= !valid_user_regs(regs); ++ ++ /* ++ * Block the signal if we were unsuccessful. ++ */ ++ if (ret == 0) { ++ spin_lock_irq(&tsk->sighand->siglock); ++ sigorsets(&tsk->blocked, &tsk->blocked, &ka->sa.sa_mask); ++ if (!(ka->sa.sa_flags & SA_NODEFER)) ++ sigaddset(&tsk->blocked, sig); ++ recalc_sigpending(); ++ spin_unlock_irq(&tsk->sighand->siglock); ++#if 0 & defined(CONFIG_HSS) ++ /* COLE: i marked this tempory. ++ It doesn't behave the same as x86 */ ++ /* Clear HSS when entering the signal handler, ++ User should be step into signal handler */ ++ if (regs->NDS32_ipsw & PSW_mskHSS) { ++ regs->NDS32_ipsw &= ~PSW_mskHSS; ++ printk(KERN_INFO "clear for sig %d. pc=0x%08x\n", sig, ++ regs->NDS32_ipc); ++ } ++#endif ++ return; ++ } ++ ++ force_sigsegv(sig, tsk); ++} ++ ++/* ++ * Note that 'init' is a special process: it doesn't get signals it doesn't ++ * want to handle. Thus you cannot kill init even with a SIGKILL even by ++ * mistake. ++ * ++ * Note that we go through the signals twice: once to check the signals that ++ * the kernel can handle, and then we build all the user-level signal handling ++ * stack-frames in one go after that. ++ */ ++asmlinkage int do_signal(sigset_t * oldset, struct pt_regs *regs, int syscall) ++{ ++ struct k_sigaction ka; ++ siginfo_t info; ++ int signr; ++ ++ /* ++ * We want the common case to go fast, which ++ * is why we may in certain cases get here from ++ * kernel mode. Just return without doing anything ++ * if so. ++ */ ++ ++ if (!user_mode(regs)) ++ return 0; ++ ++ if (try_to_freeze()) ++ goto no_signal; ++ ++ if (test_thread_flag(TIF_RESTORE_SIGMASK)) ++ oldset = ¤t->saved_sigmask; ++ ++ signr = get_signal_to_deliver(&info, &ka, regs, NULL); ++ ++ if (signr > 0) { ++ handle_signal(signr, &ka, &info, oldset, regs, syscall); ++ /* ++ * A signal was successfully delivered; the saved ++ * sigmask will have been stored in the signal frame, ++ * and will be restored by sigreturn, so we can simply ++ * clear the TIF_RESTORE_SIGMASK flag. ++ */ ++ if (test_thread_flag(TIF_RESTORE_SIGMASK)) ++ clear_thread_flag(TIF_RESTORE_SIGMASK); ++ return 1; ++ } ++ ++no_signal: ++ /* ++ * No signal to deliver to the process - restart the syscall. ++ */ ++ if (syscall) { ++ switch (regs->NDS32_r0) { ++ u32 __user *usp; ++ ++ case -ERESTART_RESTARTBLOCK: ++ regs->NDS32_sp -= 4; ++ usp = (u32 __user *) regs->NDS32_sp; ++ ++ if (put_user(regs->NDS32_ipc, usp) == 0) ++ regs->NDS32_ipc = KERN_RESTART_CODE; ++ else { ++ regs->NDS32_sp += 4; ++ force_sigsegv(0, current); ++ } ++ regs->NDS32_r0 = regs->NDS32_ORIG_r0; ++ break; ++ ++ case -ERESTARTNOHAND: ++ case -ERESTARTSYS: ++ case -ERESTARTNOINTR: ++ ++ setup_restart_syscall(regs); ++ break; ++ } ++ if (test_thread_flag(TIF_RESTORE_SIGMASK)) { ++ clear_thread_flag(TIF_RESTORE_SIGMASK); ++ sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); ++ } ++ } ++ ++ return 0; ++} ++ ++asmlinkage void do_notify_resume(struct pt_regs *regs, ++ unsigned int thread_flags, int syscall) ++{ ++ if (thread_flags & _TIF_SIGPENDING) ++ do_signal(¤t->blocked, regs, syscall); ++ if (thread_flags & _TIF_NOTIFY_RESUME) { ++ clear_thread_flag(TIF_NOTIFY_RESUME); ++ tracehook_notify_resume(regs); ++ if (current->replacement_session_keyring) ++ key_replace_session_keyring(); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/signal.h linux-3.4.110/arch/nds32/kernel/signal.h +--- linux-3.4.110.orig/arch/nds32/kernel/signal.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/signal.h 2016-04-07 10:20:50.946081179 +0200 +@@ -0,0 +1,20 @@ ++/* ++ * linux/arch/arm/kernel/signal.h ++ * ++ * Copyright (C) 2005-2009 Russell King. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <asm/fixmap.h> ++ ++#define RETURN_SYSCALL_BASE (0x2000) ++#define RETURN_SYSCALL_PA_BASE (PHYS_OFFSET | RETURN_SYSCALL_BASE) ++ ++#define KERN_SIGRETURN_CODE (fix_to_virt(FIX_RETURN_SYSCALL)) ++#define KERN_RESTART_CODE (KERN_SIGRETURN_CODE + sizeof(retcodes)) ++ ++extern const unsigned long retcodes[2]; ++extern const unsigned long syscall_restart_code[3]; +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/smp.c linux-3.4.110/arch/nds32/kernel/smp.c +--- linux-3.4.110.orig/arch/nds32/kernel/smp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/smp.c 2016-04-07 10:20:50.946081179 +0200 +@@ -0,0 +1,335 @@ ++/* ++ * linux/arch/nds32/kernel/smp.c ++ * ++ * Copyright (C) 2002 ARM Limited, All Rights Reserved. ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/spinlock.h> ++#include <linux/sched.h> ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/cache.h> ++#include <linux/profile.h> ++#include <linux/errno.h> ++#include <linux/mm.h> ++#include <linux/cpu.h> ++#include <linux/smp.h> ++#include <linux/seq_file.h> ++#include <asm/atomic.h> ++#include <asm/cacheflush.h> ++#include <asm/cpu.h> ++#include <asm/processor.h> ++#include <asm/tlbflush.h> ++#include <asm/ptrace.h> ++#include <linux/err.h> ++#include <asm/irq_regs.h> ++#include <asm/mmu_context.h> ++#include <asm/mmu.h> ++ ++void smp_init_cpus(void) ++{ ++ int i; ++ for (i = 0; i < NR_CPUS; i++) ++ cpu_set(i, cpu_possible_map); ++} ++ ++int setup_profiling_timer(unsigned int multiplier) ++{ ++ return 0; ++} ++ ++struct tlb_data { ++ struct vm_area_struct *vma; ++ unsigned long start; ++ unsigned long end; ++}; ++ ++static void ipi_flush_tlb_all(void *data) ++{ ++ local_flush_tlb_all(); ++} ++ ++void flush_tlb_all(void) ++{ ++ on_each_cpu(ipi_flush_tlb_all, NULL, 1); ++} ++ ++static void ipi_flush_tlb_mm(void *data) ++{ ++ struct mm_struct *mm = (struct mm_struct *)data; ++ local_flush_tlb_mm(mm); ++} ++ ++void flush_tlb_mm(struct mm_struct *mm) ++{ ++ on_each_cpu(ipi_flush_tlb_mm, mm, 1); ++} ++ ++static void ipi_flush_tlb_page(void *data) ++{ ++ struct tlb_data *t = (struct tlb_data *)data; ++ local_flush_tlb_page(t->vma, t->start); ++} ++ ++void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) ++{ ++ struct tlb_data data; ++ ++ data.vma = vma; ++ data.start = addr; ++ on_each_cpu(ipi_flush_tlb_page, &data, 1); ++} ++ ++static void ipi_flush_tlb_range(void *data) ++{ ++ struct tlb_data *t = (struct tlb_data *)data; ++ local_flush_tlb_range(t->vma, t->start, t->end); ++} ++ ++void flush_tlb_range(struct vm_area_struct *vma, ++ unsigned long start, unsigned long end) ++{ ++ struct tlb_data data; ++ ++ data.vma = vma; ++ data.start = start; ++ data.end = end; ++ on_each_cpu(ipi_flush_tlb_range, &data, 1); ++} ++ ++static void ipi_flush_tlb_kernel_range(void *data) ++{ ++ struct tlb_data *t = (struct tlb_data *)data; ++ local_flush_tlb_kernel_range(t->start, t->end); ++} ++ ++void flush_tlb_kernel_range(unsigned long start, unsigned long end) ++{ ++ struct tlb_data data; ++ ++ data.start = start; ++ data.end = end; ++ on_each_cpu(ipi_flush_tlb_kernel_range, &data, 1); ++} ++ ++/* IPI implementation */ ++static inline unsigned long read_ipi_trigger(void) ++{ ++ /* AMIC IPI trigger register */ ++ return *(volatile unsigned long *)(AMIC_VA_BASE + 0x40); ++} ++ ++static inline void write_ipi_trigger(const struct cpumask *mask) ++{ ++ unsigned long data = *cpus_addr(*mask); ++ *(volatile unsigned long *)(AMIC_VA_BASE + 0x40) = data; ++} ++ ++static inline void clear_ipi_status(void) ++{ ++ *(volatile unsigned long *)(AMIC_VA_BASE + 0x44) = 0xf; ++ asm("msync store\nisb"); ++} ++ ++static void __init send_IPI_boot(int cpu, struct task_struct *tsk) ++{ ++ extern void secondary_startup(void); ++ unsigned long *ptr = (unsigned long *)(0xc0006000 + (cpu << 9)); ++ ptr[5] = virt_to_phys(secondary_startup); ++ ptr[6] = (unsigned long)task_stack_page(tsk) + THREAD_SIZE - 8; ++ asm("cctl %0, L1D_VA_WB, alevel\n"::"r"(ptr)); ++ asm("cctl %0, L1D_VA_INVAL, alevel\nmsync\ndsb\n"::"r"(ptr)); ++ write_ipi_trigger(get_cpu_mask(cpu)); ++} ++ ++static int __init wait_cpu_boot_done(int cpu) ++{ ++ int i, state; ++ for (i = 0; i < 10000; i++) { ++ state = read_ipi_trigger(); ++ if ((state & (1 << cpu)) == 0) ++ break; ++ udelay(100); ++ } ++ return (i == 10000) ? -1 : 0; ++} ++ ++void __init secondary_start_kernel(void) ++{ ++ unsigned long tmp; ++ unsigned int cpu = smp_processor_id(); ++ ++ atomic_inc(&init_mm.mm_count); ++ current->active_mm = &init_mm; ++ ++ /* ++ * enable cache. ++ */ ++ ++#ifdef CONFIG_ANDES_PAGE_SIZE_4KB ++ if (CPU_IS_N1213_43U1HA0()) { ++ /* Downsize cache to bypass cache aliasing issue */ ++ ++ if ((CACHE_SET(ICACHE) * CACHE_LINE_SIZE(ICACHE)) > 4096) ++ tmp = 0x02 << SDZ_CTL_offICDZ; ++ ++ if ((CACHE_SET(DCACHE) * CACHE_LINE_SIZE(DCACHE)) > 4096) ++ tmp |= 0x02 << SDZ_CTL_offDCDZ; ++ ++ SET_SDZ_CTL(tmp); ++ ISB(); ++// printk("CPU%d enabled cache downsizing.\n", cpu); ++ } ++#endif /* CONFIG_ANDES_PAGE_SIZE_4KB */ ++ ++ tmp = GET_CACHE_CTL(); ++#ifndef CONFIG_CPU_DCACHE_DISABLE ++ tmp |= CACHE_CTL_mskDC_EN; ++#endif ++ ++#ifndef CONFIG_CPU_ICACHE_DISABLE ++ tmp |= CACHE_CTL_mskIC_EN; ++#endif ++ SET_CACHE_CTL(tmp); ++ DSB(); ++ ISB(); ++ ++ preempt_disable(); ++ local_irq_enable(); ++ ++ //assume all of cores runs the same speed ++ //calibrate_delay(); ++ /* store cpu info ot the second cpu */ ++ smp_store_cpu_info(cpu); ++ ++ clear_ipi_status(); ++ cpu_idle(); ++} ++ ++/* ++ * Called by both boot and secondaries to move global data into ++ * per-processor storage. ++ */ ++void __init smp_store_cpu_info(unsigned int cpuid) ++{ ++ struct cpuinfo_nds32 *cpu_info = &per_cpu(cpu_data, cpuid); ++ ++ cpu_info->loops_per_jiffy = loops_per_jiffy; ++} ++ ++/* functions be used by generic layer */ ++void arch_send_call_function_single_ipi(int cpu) ++{ ++ write_ipi_trigger(get_cpu_mask(cpu)); ++} ++ ++void arch_send_call_function_ipi_mask(const struct cpumask *mask) ++{ ++ write_ipi_trigger(mask); ++} ++ ++static void __init smp_boot_one_cpu(int cpu) ++{ ++ struct task_struct *idle; ++ int ret; ++ ++ idle = fork_idle(cpu); ++ if (IS_ERR(idle)) ++ panic(KERN_ERR "Fork failed for CPU %d", cpu); ++ ++ send_IPI_boot(cpu, idle); ++ ret = wait_cpu_boot_done(cpu); ++ if (ret == 0) ++ cpu_set(cpu, cpu_online_map); ++ else ++ put_task_struct(idle); ++} ++ ++static void ipi_timer(void *data) ++{ ++ profile_tick(CPU_PROFILING); ++ update_process_times(user_mode(get_irq_regs())); ++} ++ ++void smp_send_timer(void) ++{ ++ smp_call_function(ipi_timer, NULL, 0); ++} ++ ++static void ipi_stop(void *data) ++{ ++ cpu_clear(smp_processor_id(), cpu_online_map); ++ local_irq_enable(); ++ for (;;) ; ++} ++ ++void smp_send_stop(void) ++{ ++ smp_call_function(ipi_stop, NULL, 0); ++} ++ ++void smp_send_reschedule(int cpu) ++{ ++ write_ipi_trigger(get_cpu_mask(cpu)); ++} ++ ++static void ipi_handler(unsigned int irq, struct irq_desc *desc) ++{ ++ clear_ipi_status(); ++ generic_smp_call_function_single_interrupt(); ++ generic_smp_call_function_interrupt(); ++} ++ ++void __init smp_prepare_cpus(unsigned int max_cpus) ++{ ++ /* ++ * XXX detect how many cores exist ++ */ ++ int i; ++ unsigned int cpu = smp_processor_id(); ++ ++ /* store master core cpu info */ ++ smp_store_cpu_info(cpu); ++ for (i = 0; i < max_cpus; i++) ++ cpu_set(i, cpu_present_map); ++ ++ /* setup IPI handler */ ++ set_irq_chip(32, &dummy_irq_chip); ++ set_irq_chained_handler(32, ipi_handler); ++} ++ ++int __cpuinit __cpu_up(unsigned int cpu) ++{ ++ smp_boot_one_cpu(cpu); ++ return cpu_online(cpu) ? 0 : -ENOSYS; ++} ++ ++void __init smp_cpus_done(unsigned int max_cpus) ++{ ++ int cpu; ++ unsigned long bogosum = 0; ++ ++ for_each_online_cpu(cpu) ++ bogosum += per_cpu(cpu_data, cpu).loops_per_jiffy; ++ ++ printk(KERN_INFO "SMP: Total of %d processors activated " ++ "(%lu.%02lu BogoMIPS).\n", ++ num_online_cpus(), ++ bogosum / (500000 / HZ), (bogosum / (5000 / HZ)) % 100); ++ ++ /* now we can set all interruption don't cared */ ++ *(volatile unsigned long *)(AMIC_VA_BASE + 0x4) = 0xffffffff; ++} ++ ++void __init smp_prepare_boot_cpu(void) ++{ ++ unsigned int cpu = smp_processor_id(); ++ unsigned long *ptr = (unsigned long *)(0xc0006000 + (cpu << 9)); ++ ptr[4] = 1; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/stacktrace.c linux-3.4.110/arch/nds32/kernel/stacktrace.c +--- linux-3.4.110.orig/arch/nds32/kernel/stacktrace.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/stacktrace.c 2016-04-07 10:20:50.946081179 +0200 +@@ -0,0 +1,41 @@ ++#include <linux/sched.h> ++#include <linux/stacktrace.h> ++void save_stack_trace(struct stack_trace *trace) ++{ ++ save_stack_trace_tsk(current, trace); ++} ++ ++void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) ++{ ++ unsigned long *fpn; ++ int skip = trace->skip; ++ int savesched; ++ ++ if (tsk == current) { ++ __asm__ __volatile__("\tori\t%0, $fp, #0\n":"=r"(fpn)); ++ savesched = 1; ++ } else { ++ fpn = (unsigned long *)thread_saved_fp(tsk); ++ savesched = 0; ++ } ++ ++ while (!kstack_end(fpn) && !((unsigned long)fpn & 0x3) ++ && (fpn >= (unsigned long *)TASK_SIZE)) { ++ unsigned long lpp, fpp; ++ lpp = fpn[0]; ++ fpp = fpn[-1]; ++ if (!__kernel_text_address(lpp)) ++ break; ++ ++ if (savesched || !in_sched_functions(lpp)) { ++ if (skip) { ++ skip--; ++ } else { ++ trace->entries[trace->nr_entries++] = lpp; ++ if (trace->nr_entries >= trace->max_entries) ++ break; ++ } ++ } ++ fpn = (unsigned long *)fpp; ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/sys_nds32.c linux-3.4.110/arch/nds32/kernel/sys_nds32.c +--- linux-3.4.110.orig/arch/nds32/kernel/sys_nds32.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/sys_nds32.c 2016-04-07 10:20:50.946081179 +0200 +@@ -0,0 +1,331 @@ ++/* ++ * linux/arch/nds32/kernel/sys_nds32.c ++ * ++ * Copyright (C) People who wrote linux/arch/i386/kernel/sys_i386.c ++ * Copyright (C) 2007 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This file contains various random system calls that ++ * have a non-standard calling sequence on the Linux/nds32 ++ * platform. ++ */ ++#include <linux/module.h> ++#include <linux/errno.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/mm.h> ++#include <linux/sem.h> ++#include <linux/msg.h> ++#include <linux/shm.h> ++#include <linux/stat.h> ++#include <linux/syscalls.h> ++#include <linux/mman.h> ++#include <linux/fs.h> ++#include <linux/file.h> ++#include <linux/utsname.h> ++#include <linux/ipc.h> ++ ++#include <asm/uaccess.h> ++#include <asm/unistd.h> ++#include <asm/pfm.h> ++ ++extern unsigned long do_mremap(unsigned long addr, unsigned long old_len, ++ unsigned long new_len, unsigned long flags, ++ unsigned long new_addr); ++ ++struct mmap_arg_struct { ++ unsigned long addr; ++ unsigned long len; ++ unsigned long prot; ++ unsigned long flags; ++ unsigned long fd; ++ unsigned long offset; ++}; ++ ++asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flags, ++ unsigned long fd, unsigned long pgoff) ++{ ++ if (pgoff & (~PAGE_MASK >> 12)) ++ return -EINVAL; ++ ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, ++ pgoff >> (PAGE_SHIFT - 12)); ++} ++ ++asmlinkage unsigned long ++sys_nds32_mremap(unsigned long addr, unsigned long old_len, ++ unsigned long new_len, unsigned long flags, ++ unsigned long new_addr) ++{ ++ unsigned long ret = -EINVAL; ++ ++ if (flags & MREMAP_FIXED && new_addr < FIRST_USER_ADDRESS) ++ goto out; ++ ++ down_write(¤t->mm->mmap_sem); ++ ret = do_mremap(addr, old_len, new_len, flags, new_addr); ++ up_write(¤t->mm->mmap_sem); ++ ++out: ++ return ret; ++} ++ ++/* ++ * Perform the select(nd, in, out, ex, tv) and mmap() system ++ * calls. ++ */ ++ ++struct sel_arg_struct { ++ unsigned long n; ++ fd_set __user *inp, *outp, *exp; ++ struct timeval __user *tvp; ++}; ++ ++asmlinkage int old_select(struct sel_arg_struct __user * arg) ++{ ++ struct sel_arg_struct a; ++ ++ if (copy_from_user(&a, arg, sizeof(a))) ++ return -EFAULT; ++ /* sys_select() does the appropriate kernel locking */ ++ return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); ++} ++ ++/* ++ * sys_ipc() is the de-multiplexer for the SysV IPC calls.. ++ * ++ * This is really horribly ugly. ++ */ ++asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second, ++ unsigned long third, void __user * ptr, long fifth) ++{ ++ int version, ret; ++ ++ version = call >> 16; /* hack for backward compatibility */ ++ call &= 0xffff; ++ ++ switch (call) { ++ case SEMOP: ++ return sys_semtimedop(first, (struct sembuf __user *)ptr, ++ second, NULL); ++ case SEMTIMEDOP: ++ return sys_semtimedop(first, (struct sembuf __user *)ptr, ++ second, ++ (const struct timespec __user *)fifth); ++ ++ case SEMGET: ++ return sys_semget(first, second, third); ++ case SEMCTL:{ ++ union semun fourth; ++ if (!ptr) ++ return -EINVAL; ++ if (get_user(fourth.__pad, (void __user * __user *)ptr)) ++ return -EFAULT; ++ return sys_semctl(first, second, third, fourth); ++ } ++ ++ case MSGSND: ++ return sys_msgsnd(first, (struct msgbuf __user *)ptr, ++ second, third); ++ case MSGRCV: ++ switch (version) { ++ case 0:{ ++ struct ipc_kludge tmp; ++ if (!ptr) ++ return -EINVAL; ++ if (copy_from_user ++ (&tmp, (struct ipc_kludge __user *)ptr, ++ sizeof(tmp))) ++ return -EFAULT; ++ return sys_msgrcv(first, tmp.msgp, second, ++ tmp.msgtyp, third); ++ } ++ default: ++ return sys_msgrcv(first, ++ (struct msgbuf __user *)ptr, ++ second, fifth, third); ++ } ++ case MSGGET: ++ return sys_msgget((key_t) first, second); ++ case MSGCTL: ++ return sys_msgctl(first, second, (struct msqid_ds __user *)ptr); ++ ++ case SHMAT: ++ switch (version) { ++ default:{ ++ ulong raddr; ++ ret = ++ do_shmat(first, (char __user *)ptr, second, ++ &raddr); ++ if (ret) ++ return ret; ++ return put_user(raddr, (ulong __user *) third); ++ } ++ case 1: /* Of course, we don't support iBCS2! */ ++ return -EINVAL; ++ } ++ case SHMDT: ++ return sys_shmdt((char __user *)ptr); ++ case SHMGET: ++ return sys_shmget(first, second, third); ++ case SHMCTL: ++ return sys_shmctl(first, second, (struct shmid_ds __user *)ptr); ++ default: ++ return -ENOSYS; ++ } ++} ++ ++/* Fork a new task - this creates a new program thread. ++ * This is called indirectly via a small wrapper ++ */ ++asmlinkage int sys_fork(struct pt_regs *regs) ++{ ++ return do_fork(SIGCHLD, regs->NDS32_sp, regs, 0, NULL, NULL); ++} ++ ++/* Clone a task - this clones the calling program thread. ++ * This is called indirectly via a small wrapper ++ */ ++asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, ++ int __user * parent_tidptr, int tls_val, ++ int __user * child_tidptr, struct pt_regs *regs) ++{ ++ if (!newsp) ++ newsp = regs->NDS32_sp; ++ ++ return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, ++ child_tidptr); ++} ++ ++asmlinkage int sys_vfork(struct pt_regs *regs) ++{ ++ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->NDS32_sp, regs, ++ 0, NULL, NULL); ++} ++ ++/* sys_execve() executes a new program. ++ * This is called indirectly via a small wrapper ++ */ ++asmlinkage int sys_execve(const char __user * filenamei, ++ const char __user * const __user * argv, ++ const char __user * const __user * envp, ++ struct pt_regs *regs) ++{ ++ int error; ++ char *filename; ++ ++ filename = getname(filenamei); ++ error = PTR_ERR(filename); ++ if (IS_ERR(filename)) ++ goto out; ++ ++ error = do_execve(filename, argv, envp, regs); ++ putname(filename); ++ ++out: ++ return error; ++} ++ ++asmlinkage unsigned long sys_getpagesize(void) ++{ ++ return PAGE_SIZE; /* Possibly older binaries want 8192 on sun4's? */ ++} ++ ++int kernel_execve(const char *filename, const char *const argv[], ++ const char *const envp[]) ++{ ++ struct pt_regs regs; ++ int ret; ++ ++ memset(®s, 0, sizeof(struct pt_regs)); ++ ret = do_execve(filename, argv, envp, ®s); ++ ++ if (ret < 0) { ++ goto out; ++ } ++ /* ++ * Save argc to the register structure for userspace. ++ */ ++ regs.NDS32_r0 = ret; ++ ++ /* ++ * We were successful. We won't be returning to our caller, but ++ * instead to user space by manipulating the kernel stack. ++ */ ++ asm("addi $r0, %0, %1\n\t" ++ "move $r1, %2\n\t" ++ "move $r2, %3\n\t" ++ "bal memmove\n\t" /* copy regs to top of stack */ ++ "move $r8, #0\n\t" /* not a syscall */ ++ "move $r9, %0\n\t" /* thread structure */ ++ "move $sp, $r0\n\t" /* reposition stack pointer */ ++"b resume_userspace": ++: "r"(current_thread_info()), ++ "ir"(THREAD_SIZE - 8 - sizeof(regs)), ++ "r"(®s), "ir"(sizeof(regs)) ++#ifdef _GCC444 ++: "$r0", "$r1", "$r2", "$r4", "$r5", "$r8", "$r9", "$p0", "$p1", ++ "memory"); ++#else ++: "$r0", "$r1", "$r2", "$r4", "$r5", "$r8", "$r9", "$r26", "$r27", ++ "memory"); ++#endif ++out: ++ return ret; ++} ++ ++EXPORT_SYMBOL(kernel_execve); ++ ++int sys_cacheflush(unsigned int start, unsigned int end) ++{ ++ struct vm_area_struct *vma; ++ ++ vma = find_vma(current->mm, start); ++ if (!vma) ++ return 0; ++ cpu_cache_wbinval_range_check(vma, start, end); ++ return 0; ++} ++ ++asmlinkage long sys_fadvise64_64_wrapper(int fd, int advice, loff_t offset, ++ loff_t len) ++{ ++ return sys_fadvise64_64(fd, offset, len, advice); ++} ++ ++asmlinkage int nds32_syscall(int number, struct pt_regs *regs) ++{ ++ switch (number) { ++ case 0x7000: /* cacheflush */ ++ return sys_cacheflush(regs->NDS32_r1, regs->NDS32_r2); ++ ++#ifdef CONFIG_OPROFILE ++ case __NR_pfmctl: ++ sys_pfmctl(regs->NDS32_r1, regs->NDS32_r2, regs->NDS32_r3, ++ regs->NDS32_r4); ++ return 0; ++ ++ case __NR_getpfm: ++ return sys_getpfm((struct pcounter __user *)regs->NDS32_r1); ++ ++ case __NR_setpfm: ++ return sys_setpfm(regs->NDS32_r1, regs->NDS32_r2, ++ regs->NDS32_r3, ++ (struct pcounter __user *)regs->NDS32_r4); ++#endif ++ case __NR_wbna: ++ if (regs->NDS32_r1) ++ regs->NDS32_ipsw |= PSW_mskWBNA; ++ else ++ regs->NDS32_ipsw &= ~PSW_mskWBNA; ++ return 0; ++ ++ default: ++ return -ENOSYS; ++ } ++ return -ENOSYS; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/time.c linux-3.4.110/arch/nds32/kernel/time.c +--- linux-3.4.110.orig/arch/nds32/kernel/time.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/time.c 2016-04-07 10:20:50.950081334 +0200 +@@ -0,0 +1,94 @@ ++/* ++ * linux/arch/nds32/kernel/time.c ++ * ++ * Copyright (C) 1991, 1992, 1995 Linus Torvalds ++ * Modifications for ARM (C) 1994-2001 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * This file contains the ARM-specific time handling details: ++ * reading the RTC at bootup, etc... ++ * ++ * 1994-07-02 Alan Modra ++ * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime ++ * 1998-12-20 Updated NTP code according to technical memorandum Jan '96 ++ * "A Kernel Model for Precision Timekeeping" by Dave Mills ++ */ ++#include <linux/sched.h> ++#include <linux/profile.h> ++#include <linux/timer.h> ++#include <asm/irq_regs.h> ++#include <linux/syscore_ops.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/time.h> ++ ++/* ++ * Our system timer. ++ */ ++struct sys_timer *system_timer; ++ ++#ifdef CONFIG_SMP ++unsigned long profile_pc(struct pt_regs *regs) ++{ ++ unsigned long fp, pc = instruction_pointer(regs); ++ ++ if (in_lock_functions(pc)) { ++ fp = regs->NDS32_fp; ++ pc = ((unsigned long *)fp)[-1]; ++ } ++ ++ return pc; ++} ++ ++EXPORT_SYMBOL(profile_pc); ++#endif ++#if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS) ++static int timer_suspend(void) ++{ ++ if (system_timer->suspend) ++ system_timer->suspend(); ++ ++ return 0; ++} ++ ++static void timer_resume(void) ++{ ++ if (system_timer->resume) ++ system_timer->resume(); ++} ++#else ++#define timer_suspend NULL ++#define timer_resume NULL ++#endif ++#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET ++u32 arch_gettimeoffset(void) ++{ ++ if (system_timer->offset != NULL) ++ return system_timer->offset() * 1000; ++ ++ return 0; ++} ++#endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */ ++static struct syscore_ops timer_syscore_ops = { ++ .suspend = timer_suspend, ++ .resume = timer_resume, ++}; ++ ++static int __init timer_init_syscore_ops(void) ++{ ++ register_syscore_ops(&timer_syscore_ops); ++ ++ return 0; ++} ++ ++device_initcall(timer_init_syscore_ops); ++ ++void __init time_init(void) ++{ ++ system_timer = machine_desc->timer; ++ system_timer->init(); // link to cpe_timer_init ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/traps.c linux-3.4.110/arch/nds32/kernel/traps.c +--- linux-3.4.110.orig/arch/nds32/kernel/traps.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/traps.c 2016-04-07 10:20:50.950081334 +0200 +@@ -0,0 +1,733 @@ ++/* ++ * linux/arch/nds32/kernel/traps.c ++ * ++ * Copyright (C) 1995-2002 Russell King ++ * Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * 'traps.c' handles hardware exceptions after we have saved some state in ++ * 'linux/arch/nds32/lib/traps.S'. Mostly a debugging aid, but will probably ++ * kill the offending process. ++ */ ++/* ============================================================================ ++ * ++ * linux/arch/nds32/kernel/traps.c ++ * ++ * Copyright (C) 2007 Andes Technology Corporation ++ * This file is part of Linux and should be licensed under the GPL. ++ * See the file COPYING for conditions for redistribution. ++ * ++ * Abstract: ++ * ++ * This program is trap handling for NDS32 core, initial refer from ARM. ++ * ++ * Revision History: ++ * ++ * Jul.16.2007 Initial ported by Tom, revised for KGDB by Harry. ++ * ++ * Note: ++ * ++ * ============================================================================ ++ */ ++#include <linux/module.h> ++#include <linux/personality.h> ++#include <linux/kallsyms.h> ++#include <linux/hardirq.h> ++#include <linux/kdebug.h> ++ ++#include <asm/cacheflush.h> ++#include <asm/uaccess.h> ++#include <asm/unistd.h> ++#include <asm/traps.h> ++#include <asm/fpu.h> ++#include <asm/audio.h> ++ ++#include <linux/ptrace.h> ++#include <nds32_intrinsic.h> ++#include "ptrace.h" ++#include "signal.h" ++ ++extern void show_pte(struct mm_struct *mm, unsigned long addr); ++ ++#ifdef CONFIG_DEBUG_USER ++unsigned int user_debug; ++ ++static int __init user_debug_setup(char *str) ++{ ++ get_option(&str, &user_debug); ++ return 1; ++} ++ ++__setup("user_debug=", user_debug_setup); ++#endif ++ ++/* ++ * Dump out the contents of some memory nicely... ++ */ ++void dump_mem(const char *str, unsigned long bottom, unsigned long top) ++{ ++ unsigned long p = bottom & ~31; ++ mm_segment_t fs; ++ int i; ++ ++ /* ++ * We need to switch to kernel mode so that we can use __get_user ++ * to safely read from kernel space. Note that we now dump the ++ * code first, just in case the backtrace kills us. ++ */ ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); ++ ++ for (p = bottom & ~31; p < top;) { ++ printk("%04lx: ", p & 0xffff); ++ ++ for (i = 0; i < 8; i++, p += 4) { ++ unsigned int val; ++ ++ if (p < bottom || p >= top) ++ printk(" "); ++ else { ++ __get_user(val, (unsigned long *)p); ++ printk("%08x ", val); ++ } ++ } ++ printk("\n"); ++ } ++ ++ set_fs(fs); ++} ++ ++EXPORT_SYMBOL(dump_mem); ++ ++/* These intrinsic functions are not supported in V2 toolchains of BSP321. */ ++#ifndef __NDS32_BASELINE_V2__ ++#define DEBUG_TLB_CACHE ++#endif ++#ifdef DEBUG_TLB_CACHE ++/* This is the number of TLB entries. User should change it if necessary. */ ++#define TLB_NUM 128 ++unsigned int tlb_misc_new[TLB_NUM], tlb_vpn_new[TLB_NUM], tlb_data_new[TLB_NUM]; ++/* To get the whole TLB contents once it uses va=0x0 */ ++void dump_tlb(unsigned long va) ++{ ++ unsigned int rd_num, tlb_vpn, tlb_misc, tlb_data, mmu_cfg, tlb_num; ++ ++ /* save tlb system registers */ ++ tlb_vpn = __nds32__mfsr(NDS32_SR_TLB_VPN); ++ tlb_misc = __nds32__mfsr(NDS32_SR_TLB_MISC); ++ tlb_data = __nds32__mfsr(NDS32_SR_TLB_DATA); ++ mmu_cfg = __nds32__mfsr(NDS32_SR_MMU_CFG); ++ tlb_num = ++ (((mmu_cfg & MMU_CFG_mskTBW) >> MMU_CFG_offTBW) + ++ 1) * (1 << (((mmu_cfg & MMU_CFG_mskTBS) >> MMU_CFG_offTBS) + 2)); ++ ++ for (rd_num = 0; rd_num < tlb_num; rd_num++) { ++ /* read tlb entry with index */ ++ __nds32__tlbop_trd(rd_num); ++ __nds32__dsb(); ++ tlb_vpn_new[rd_num] = __nds32__mfsr(NDS32_SR_TLB_VPN); ++ tlb_misc_new[rd_num] = __nds32__mfsr(NDS32_SR_TLB_MISC); ++ tlb_data_new[rd_num] = __nds32__mfsr(NDS32_SR_TLB_DATA); ++ } ++ ++ /* restore tlb system registers */ ++ __nds32__mtsr(tlb_vpn, NDS32_SR_TLB_VPN); ++ __nds32__mtsr(tlb_misc, NDS32_SR_TLB_MISC); ++ __nds32__dsb(); ++ ++ printk("cur VPN:%08x, MISC:%08x, DATA:%08x\n", tlb_vpn, tlb_misc, ++ tlb_data); ++ /* to read out all the data */ ++ for (rd_num = 0; rd_num < tlb_num; rd_num++) { ++ /*unsigned int vpn = tlb_vpn_new[rd_num] & PAGE_MASK; */ ++ if (tlb_data_new[rd_num] & 0x1) ++ if (va == 0x0 ++ || (va != 0x0 ++ && (tlb_vpn_new[rd_num] == (va & PAGE_MASK)))) ++ printk ++ ("idx:0x%08x, VPN:%08x, MISC:%08x, DATA:%08x\n", ++ rd_num, tlb_vpn_new[rd_num], ++ tlb_misc_new[rd_num], ++ tlb_data_new[rd_num]); ++ } ++} ++ ++EXPORT_SYMBOL(dump_tlb); ++ ++struct cache_element { ++ unsigned int pa; ++ unsigned int wd; ++ unsigned int cacheline[8]; ++ unsigned char dirty; ++ unsigned char valid; ++ unsigned char lock; ++}; ++ ++/* This is the number of cache entries. User should change it if necessary. */ ++#define CACHE_SET_NUM 0x100 ++#define CACHE_WAY_NUM 0x4 ++volatile struct cache_element ce[CACHE_SET_NUM][CACHE_WAY_NUM]; ++#define CCTL_mskDIRTY 0x400000 ++#define CCTL_offDIRTY 22 ++#define CCTL_mskVALID 0x2 ++#define CCTL_offVALID 1 ++#define CCTL_mskLOCK 0x1 ++#define CCTL_offLOCK 0 ++#define CCTL_mskTAG 0x3ffffc ++#define CCTL_offTAG 0x2 ++extern unsigned long va2idx(unsigned long va, unsigned int cache_type, ++ unsigned long *way_offset); ++#include <asm/cache_info.h> ++extern struct cache_info L1_cache_info[2]; ++void dump_cache(unsigned int cache_type) ++{ ++ volatile unsigned long idx, way, ra, tag, i; ++ unsigned long sets, ways, line_size, set_bits, way_bits, line_bits, ++ way_offset; ++ ++ ways = L1_cache_info[DCACHE].ways; ++ sets = L1_cache_info[DCACHE].sets; ++ set_bits = L1_cache_info[cache_type].set_bits; ++ way_bits = L1_cache_info[cache_type].way_bits; ++ line_bits = L1_cache_info[cache_type].line_bits; ++ line_size = L1_cache_info[cache_type].line_size; ++ way_offset = set_bits + line_bits; ++ ++ if (cache_type != ICACHE && cache_type != DCACHE) { ++ printk("%s not supported cache_type:%x\n", __func__, ++ cache_type); ++ return; ++ } ++ ++ /* NDS32_CCTL_L1I_IX_RTAG Read tag L1I cache */ ++ /* NDS32_CCTL_L1I_IX_RWD Read word data L1I cache */ ++ ++ for (idx = 0; idx < sets; idx++) { ++ for (way = 0; way < ways; way++) { ++ ra = (way << way_offset) | (idx << line_bits); ++ if (cache_type == ICACHE) ++ tag = ++ __nds32__cctlidx_read ++ (NDS32_CCTL_L1I_IX_RTAG, ra); ++ else ++ tag = ++ __nds32__cctlidx_read ++ (NDS32_CCTL_L1D_IX_RTAG, ra); ++ ce[idx][way].dirty = ++ (unsigned char)(tag & CCTL_mskDIRTY) >> ++ CCTL_offDIRTY; ++ ce[idx][way].valid = ++ (unsigned char)(tag & CCTL_mskVALID) >> ++ CCTL_offVALID; ++ ce[idx][way].lock = ++ (unsigned char)(tag & CCTL_mskLOCK) >> CCTL_offLOCK; ++ ce[idx][way].pa = ++ (tag & CCTL_mskTAG) >> CCTL_offTAG << PAGE_SHIFT; ++ for (i = 0; i < line_size / 4; i++) { ++ if (cache_type == ICACHE) ++ ce[idx][way].cacheline[i] = ++ __nds32__cctlidx_read ++ (NDS32_CCTL_L1I_IX_RWD, ++ (ra | i << 2)); ++ else ++ ce[idx][way].cacheline[i] = ++ __nds32__cctlidx_read ++ (NDS32_CCTL_L1D_IX_RWD, ++ (ra | i << 2)); ++ } ++ } ++ } ++ printk("dump %s\n", cache_type ? "DCACHE" : "ICACHE"); ++ printk("%8s %4s %4s %1s %1s %1s %8s %8s %8s %8s %8s %8s %8s %8s\n", ++ "ADDRESS", "SET", "WAY", "V", "D", "L", "00", "04", "08", "0C", ++ "10", "14", "18", "1C"); ++ for (idx = 0; idx < sets; idx++) { ++ for (way = 0; way < ways; way++) { ++ printk("%08lx %04lx %04lx %1u %1u %1u ", ++ ce[idx][way].pa + ++ ((idx * line_size) % PAGE_SIZE), idx, way, ++ ce[idx][way].valid, ce[idx][way].dirty, ++ ce[idx][way].lock); ++ for (i = 0; i < line_size / 4; i++) { ++ printk("%08x ", ce[idx][way].cacheline[i]); ++ } ++ printk("\n"); ++ } ++ } ++} ++ ++EXPORT_SYMBOL(dump_cache); ++ ++void dump_cache_va(unsigned int cache_type, unsigned int va) ++{ ++ volatile struct cache_element cache_entry[4]; ++ volatile unsigned long idx, way, tag, ra, i; ++ unsigned long ways, line_size, set_bits, line_bits, way_offset; ++ ++ ways = L1_cache_info[cache_type].ways; ++ line_size = CACHE_LINE_SIZE(cache_type); ++ set_bits = L1_cache_info[cache_type].set_bits; ++ line_bits = L1_cache_info[cache_type].line_bits; ++ ++ if (cache_type != ICACHE && cache_type != DCACHE) { ++ printk("%s not supported cache_type:%x\n", __func__, ++ cache_type); ++ return; ++ } ++ idx = va2idx(va, cache_type, &way_offset); ++ //idx = (va & (((1 << set_bits) - 1) << line_bits)) >> line_bits; ++ for (way = 0; way < ways; way++) { ++ ra = (way << way_offset) | idx; ++ if (cache_type == ICACHE) ++ tag = __nds32__cctlidx_read(NDS32_CCTL_L1I_IX_RTAG, ra); ++ else ++ tag = __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RTAG, ra); ++ cache_entry[way].dirty = ++ (unsigned char)(tag & CCTL_mskDIRTY) >> CCTL_offDIRTY; ++ cache_entry[way].valid = ++ (unsigned char)(tag & CCTL_mskVALID) >> CCTL_offVALID; ++ cache_entry[way].lock = ++ (unsigned char)(tag & CCTL_mskLOCK) >> CCTL_offLOCK; ++ cache_entry[way].pa = ++ (tag & CCTL_mskTAG) >> CCTL_offTAG << PAGE_SHIFT; ++ for (i = 0; i < line_size / 4; i++) { ++ if (cache_type == ICACHE) ++ cache_entry[way].cacheline[i] = ++ __nds32__cctlidx_read(NDS32_CCTL_L1I_IX_RWD, ++ (ra | i << 2)); ++ else ++ cache_entry[way].cacheline[i] = ++ __nds32__cctlidx_read(NDS32_CCTL_L1D_IX_RWD, ++ (ra | i << 2)); ++ } ++ } ++ printk("dump %s va:%x\n", cache_type ? "DCACHE" : "ICACHE", va); ++ ++ printk("%8s %4s %4s %1s %1s %1s %8s %8s %8s %8s %8s %8s %8s %8s\n", ++ "ADDRESS", "SET", "WAY", "V", "D", "L", "00", "04", "08", "0C", ++ "10", "14", "18", "1C"); ++ for (way = 0; way < ways; way++) { ++ printk("%08lx %04lx %04lx %1u %1u %1u ", ++ cache_entry[way].pa + ++ (((idx >> line_bits) * line_size) % PAGE_SIZE), ++ (idx >> line_bits), way, cache_entry[way].valid, ++ cache_entry[way].dirty, cache_entry[way].lock); ++ for (i = 0; i < 8; i++) { ++ printk("%08x ", cache_entry[way].cacheline[i]); ++ } ++ printk("\n"); ++ } ++} ++ ++EXPORT_SYMBOL(dump_cache_va); ++#endif ++ ++static void dump_instr(struct pt_regs *regs) ++{ ++ unsigned long addr = instruction_pointer(regs); ++ const int width = 8; ++ mm_segment_t fs; ++ int i; ++ ++ return; ++ /* ++ * We need to switch to kernel mode so that we can use __get_user ++ * to safely read from kernel space. Note that we now dump the ++ * code first, just in case the backtrace kills us. ++ */ ++ fs = get_fs(); ++ set_fs(KERNEL_DS); ++ ++ printk("Code: "); ++ for (i = -4; i < 1; i++) { ++ unsigned int val, bad; ++ ++ bad = __get_user(val, &((u32 *) addr)[i]); ++ ++ if (!bad) ++ printk(i == 0 ? "(%0*x) " : "%0*x ", width, val); ++ else { ++ printk("bad PC value."); ++ break; ++ } ++ } ++ printk("\n"); ++ ++ set_fs(fs); ++} ++ ++#define LOOP_TIMES (100) ++void dump_stack(void) ++{ ++ int cnt = LOOP_TIMES; ++#ifndef CONFIG_FRAME_POINTER ++ unsigned long *stack; ++ unsigned long addr; ++ ++ __asm__ __volatile__("\tori\t%0, $sp, #0\n":"=r"(stack)); ++ printk("Call Trace:\n"); ++ while (!kstack_end(stack)) { ++ addr = *stack++; ++ if (__kernel_text_address(addr)) { ++ printk("[<%08lx>] ", addr); ++ print_symbol("%s\n", addr); ++ } ++ cnt--; ++ if (cnt < 0) ++ break; ++ } ++ printk("\n"); ++#else ++ unsigned long *fpn; ++ __asm__ __volatile__("\tori\t%0, $fp, #0\n":"=r"(fpn)); ++ printk("Call Trace:\n"); ++ while (!kstack_end((void *)fpn) && !((unsigned long)fpn & 0x3) ++ && ((unsigned long)fpn >= TASK_SIZE)) { ++ unsigned long lpp, fpp; ++#if !defined(NDS32_ABI_2) ++ lpp = fpn[0]; ++ fpp = fpn[1]; ++#else ++ lpp = fpn[0]; ++ fpp = fpn[-1]; ++#endif ++ if (__kernel_text_address(lpp)) { ++ printk("[<%08lx>] ", lpp); ++ print_symbol("%s\n", lpp); ++ fpn = (unsigned long *)fpp; ++ } ++ cnt--; ++ if (cnt < 0) ++ break; ++ } ++ printk("\n"); ++#endif ++} ++ ++EXPORT_SYMBOL(dump_stack); ++ ++void show_stack(struct task_struct *tsk, unsigned long *sp) ++{ ++ unsigned long fp; ++ ++ if (!tsk) ++ tsk = current; ++ ++ if (tsk != current) ++ fp = thread_saved_fp(tsk); ++ else ++ asm("move %0, $fp":"=r"(fp)); ++ ++ dump_stack(); ++ barrier(); ++} ++ ++DEFINE_SPINLOCK(die_lock); ++ ++/* ++ * This function is protected against re-entrancy. ++ */ ++void die(const char *str, struct pt_regs *regs, int err) ++{ ++ struct task_struct *tsk = current; ++ static int die_counter; ++ ++ console_verbose(); ++ spin_lock_irq(&die_lock); ++ bust_spinlocks(1); ++ ++ printk("Internal error: %s: %x [#%d]\n", str, err, ++die_counter); ++ print_modules(); ++ printk("CPU: %i\n", smp_processor_id()); ++ show_regs(regs); ++ printk("Process %s (pid: %d, stack limit = 0x%p)\n", ++ tsk->comm, tsk->pid, task_thread_info(tsk) + 1); ++ ++ if (!user_mode(regs) || in_interrupt()) { ++ dump_mem("Stack: ", regs->NDS32_sp, ++ 8192 + (unsigned long)task_thread_info(tsk)); ++ dump_instr(regs); ++ dump_stack(); ++ } ++ ++ bust_spinlocks(0); ++ spin_unlock_irq(&die_lock); ++ do_exit(SIGSEGV); ++} ++ ++void die_if_kernel(const char *str, struct pt_regs *regs, int err) ++{ ++ if (user_mode(regs)) ++ return; ++ ++ die(str, regs, err); ++} ++ ++int bad_syscall(int n, struct pt_regs *regs) ++{ ++ struct thread_info *thread = current_thread_info(); ++ siginfo_t info; ++ ++ if (current->personality != PER_LINUX && thread->exec_domain->handler) { ++ thread->exec_domain->handler(n, regs); ++ return regs->NDS32_r0; ++ } ++#ifdef CONFIG_DEBUG_USER ++ if (user_debug & UDBG_SYSCALL) { ++ printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n", ++ current->pid, current->comm, n); ++ dump_instr(regs); ++ } ++#endif ++ ++ info.si_signo = SIGILL; ++ info.si_errno = 0; ++ info.si_code = ILL_ILLTRP; ++ info.si_addr = (void __user *)instruction_pointer(regs) - 4; ++ ++ force_sig_info(SIGILL, &info, current); ++ die_if_kernel("Oops - bad syscall", regs, n); ++ return regs->NDS32_r0; ++} ++ ++void __pte_error(const char *file, int line, unsigned long val) ++{ ++ printk("%s:%d: bad pte %08lx.\n", file, line, val); ++} ++ ++void __pmd_error(const char *file, int line, unsigned long val) ++{ ++ printk("%s:%d: bad pmd %08lx.\n", file, line, val); ++} ++ ++void __pgd_error(const char *file, int line, unsigned long val) ++{ ++ printk("%s:%d: bad pgd %08lx.\n", file, line, val); ++} ++ ++extern char exception_vector[73][64]; ++void __init trap_init(void) ++{ ++ return; ++} ++ ++void __init early_trap_init(void) ++{ ++ unsigned long ivb = 0; ++ unsigned long base = 0xc0000000; ++ ++ memcpy((unsigned long *)base, (unsigned long *)exception_vector, ++ sizeof(exception_vector)); ++ ivb = __nds32__mfsr(NDS32_SR_IVB); ++#ifdef CONFIG_EVIC ++ __nds32__mtsr((ivb & ~IVB_mskESZ) | (2 << IVB_offESZ) | ++ (1 << IVB_offEVIC) | IVB_BASE, NDS32_SR_IVB); ++#else ++ /* Check platform support. */ ++# if defined (CONFIG_IVIC_INTC) ++ if (((ivb & IVB_mskNIVIC) >> IVB_offNIVIC) >= 2) ++ panic ++ ("IVIC mode is not allowed on the platform with interrupt controller\n"); ++# elif defined(CONFIG_IVIC) ++ if (((ivb & IVB_mskNIVIC) >> IVB_offNIVIC) < 2) ++ panic ++ ("IVIC mode is not allowed on the platform without interrupt controller\n"); ++# endif ++ __nds32__mtsr((ivb & ~IVB_mskESZ) | (2 << IVB_offESZ) | IVB_BASE, ++ NDS32_SR_IVB); ++#endif ++ __nds32__mtsr(0x10003, NDS32_SR_INT_MASK); ++ /* ++ * Copy signal return handlers into the vector page, and ++ * set sigreturn to be a pointer to these. ++ */ ++ memcpy((void *)KERN_SIGRETURN_CODE, retcodes, sizeof(retcodes)); ++ memcpy((void *)KERN_RESTART_CODE, syscall_restart_code, ++ sizeof(syscall_restart_code)); ++ ++ /* ++ * 0x2000 is 8K-aligned of 0x1240 = 73 vectors * 64byte ++ * 0x1000 is page saving sigreturn & restart code ++ */ ++ flush_icache_range(base, base + 0x3000); ++} ++ ++#if 0 ++COLE:use send_sigtrap instread ++ static __inline__ void do_trap(int trapnr, int signr, const char *str, ++ struct pt_regs *regs, ++ unsigned long error_code, siginfo_t * info) ++{ ++ if (user_mode(regs)) { ++ /* trap_signal */ ++ struct task_struct *tsk = current; ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = trapnr; ++ if (info) ++ force_sig_info(signr, info, tsk); ++ else ++ force_sig(signr, tsk); ++ return; ++ } else { ++ /* kernel_trap */ ++ if (!fixup_exception(regs)) ++ die(str, regs, error_code); ++ return; ++ } ++} ++#endif ++ ++/* ++ * I modified original debug_trap to apply KGDB stuff, ++ * Harry@Jul.18.2007 ++ */ ++void do_debug_trap(unsigned long entry, unsigned long addr, ++ unsigned long type, struct pt_regs *regs) ++{ ++ if (notify_die(DIE_DEBUG, "debug", regs, addr, type, SIGTRAP) ++ == NOTIFY_STOP) ++ return; ++ ++#if !defined(CONFIG_HSS) ++ /* clear the swbk; otherwise the user will see it */ ++ if (test_tsk_thread_flag(current, TIF_SINGLESTEP)) ++ ptrace_cancel_swbk(current); ++#endif ++ ++ /* do_trap(1, SIGTRAP, 0, regs, 0, NULL); */ ++ if (user_mode(regs)) { ++ /* trap_signal */ ++ send_sigtrap(current, regs, 0, TRAP_BRKPT); ++ } else { ++ /* kernel_trap */ ++ if (!fixup_exception(regs)) ++ die("unexpected kernel_trap", regs, 0); ++ } ++} ++ ++void unhandled_interruption(struct pt_regs *regs) ++{ ++ siginfo_t si; ++ printk("unhandled_interruption\n"); ++ show_regs(regs); ++ if (!user_mode(regs)) ++ do_exit(SIGKILL); ++ si.si_signo = SIGKILL; ++ si.si_errno = 0; ++ force_sig_info(SIGKILL, &si, current); ++} ++ ++void unhandled_exceptions(unsigned long entry, unsigned long addr, ++ unsigned long type, struct pt_regs *regs) ++{ ++ siginfo_t si; ++ printk("Unhandled Exception: entry: %lx addr:%lx itype:%lx\n", entry, ++ addr, type); ++ show_regs(regs); ++ if (!user_mode(regs)) ++ do_exit(SIGKILL); ++ si.si_signo = SIGKILL; ++ si.si_errno = 0; ++ si.si_addr = (void *)addr; ++ force_sig_info(SIGKILL, &si, current); ++} ++ ++extern int do_page_fault(unsigned long entry, unsigned long addr, ++ unsigned int error_code, struct pt_regs *regs); ++ ++/* ++ * 2:DEF dispatch for TLB MISC exception handler ++*/ ++ ++void do_dispatch_tlb_misc(unsigned long entry, unsigned long addr, ++ unsigned long type, struct pt_regs *regs) ++{ ++ type = type & (ITYPE_mskINST | ITYPE_mskETYPE); ++ if ((type & 0xf) < 5) ++ do_page_fault(entry, addr, type, regs); ++ else ++ unhandled_exceptions(entry, addr, type, regs); ++} ++ ++int (*do_unaligned_access) (unsigned long entry, unsigned long addr, ++ unsigned long type, struct pt_regs * regs) = NULL; ++ ++EXPORT_SYMBOL(do_unaligned_access); ++ ++void do_revinsn(struct pt_regs *regs) ++{ ++ siginfo_t si; ++ printk("Reserved Instruction\n"); ++ show_regs(regs); ++ if (!user_mode(regs)) ++ do_exit(SIGILL); ++ si.si_signo = SIGILL; ++ si.si_errno = 0; ++ force_sig_info(SIGILL, &si, current); ++} ++ ++/* ++ * 7:DEF dispatch for General exception handler ++ */ ++void do_dispatch_general(unsigned long entry, unsigned long addr, ++ unsigned long itype, struct pt_regs *regs, ++ unsigned long oipc) ++{ ++ unsigned int swid = itype >> ITYPE_offSWID; ++ unsigned long type = itype & (ITYPE_mskINST | ITYPE_mskETYPE); ++ if (type == 0) { /* Alignment check */ ++ ++ if (do_unaligned_access) { ++ ++ int ret = do_unaligned_access(entry, addr, type, regs); ++ ++ if (ret == 0) ++ return; ++ ++ if (ret == -EFAULT) ++ printk ++ ("Unhandled unaligned access exception\n"); ++ } ++ do_page_fault(entry, addr, type, regs); ++ } else if (type == 1) /* Reserved instruction */ ++ do_revinsn(regs); ++ else if (type == 6) { /* Coprocessor */ ++ if (((GET_ITYPE() & ITYPE_mskSTYPE) >> ITYPE_offSTYPE) == 3) { ++#ifdef CONFIG_AUDIO ++ preempt_disable(); ++ do_audio_context_switch(type, regs); ++ preempt_enable(); ++#else ++ unhandled_exceptions(entry, addr, type, regs); ++#endif ++ } else { ++#ifdef CONFIG_FPU ++ do_fpu_exception(type, regs); ++#else ++ unhandled_exceptions(entry, addr, type, regs); ++#endif ++ } ++ } else if (type == 2 && swid == 0x1a) { ++ /* trap, used on v3 EDM target debugging workaround */ ++ /* ++ * DIPC(OIPC) is passed as parameter before ++ * interrupt is enabled, so the DIPC will not be corrupted ++ * even though interrupts are coming in ++ */ ++ /* ++ * 1. update ipc ++ * 2. update pt_regs ipc with oipc ++ * 3. update pt_regs ipsw (clear DEX) ++ */ ++ __asm__ volatile ("mtsr %0, $IPC\n\t"::"r" (oipc)); ++ regs->NDS32_ipc = oipc; ++ regs->NDS32_ipsw &= ~0x400; ++ do_debug_trap(entry, addr, itype, regs); ++ } else ++ unhandled_exceptions(entry, addr, type, regs); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/kernel/vmlinux.lds.S linux-3.4.110/arch/nds32/kernel/vmlinux.lds.S +--- linux-3.4.110.orig/arch/nds32/kernel/vmlinux.lds.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/kernel/vmlinux.lds.S 2016-04-07 10:20:50.950081334 +0200 +@@ -0,0 +1,74 @@ ++#include <asm/page.h> ++#include <asm/thread_info.h> ++#include <asm/cache.h> ++#include <asm/memory.h> ++ ++#define LOAD_OFFSET (PAGE_OFFSET - PHYS_OFFSET) ++#include <asm-generic/vmlinux.lds.h> ++ ++OUTPUT_ARCH(nds32) ++ENTRY(_stext_lma) ++jiffies = jiffies_64; ++ ++SECTIONS ++{ ++ _stext_lma = TEXTADDR - LOAD_OFFSET; ++ . = TEXTADDR; ++ __init_begin = .; ++ HEAD_TEXT_SECTION ++ INIT_TEXT_SECTION(PAGE_SIZE) ++ /* These sections are arch specific. */ ++ .arch_info : AT(ADDR(.arch_info) - LOAD_OFFSET) { ++ . = ALIGN(4); ++ VMLINUX_SYMBOL(__proc_info_begin) = .; ++ *(.proc.info.init) ++ VMLINUX_SYMBOL(__proc_info_end) = .; ++ __arch_info_begin = .; ++ *(.arch.info) ++ __arch_info_end = .; ++ __tagtable_begin = .; ++ *(.taglist) ++ __tagtable_end = .; ++ . = ALIGN(16); ++ __pv_table_begin = .; ++ *(.pv_table) ++ __pv_table_end = .; ++ __early_begin = .; ++ *(__early_param) ++ __early_end = .; ++ } ++ ++ INIT_DATA_SECTION(16) ++ PERCPU_SECTION(L1_CACHE_BYTES) ++ __init_end = .; ++ ++ . = ALIGN(PAGE_SIZE); ++ _stext = .; ++ /* Real text segment */ ++ .text : AT(ADDR(.text) - LOAD_OFFSET) { ++ _text = .; /* Text and read-only data */ ++ TEXT_TEXT ++ SCHED_TEXT ++ LOCK_TEXT ++ KPROBES_TEXT ++ IRQENTRY_TEXT ++ *(.fixup) ++ } ++ ++ _etext = .; /* End of text and rodata section */ ++ ++ _sdata = .; ++ RO_DATA_SECTION(PAGE_SIZE) ++ RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) ++ _edata = .; ++ ++ EXCEPTION_TABLE(16) ++ NOTES ++ BSS_SECTION(4, 4, 4) ++ _end = .; ++ ++ STABS_DEBUG ++ DWARF_DEBUG ++ ++ DISCARDS ++} +diff -Nur linux-3.4.110.orig/arch/nds32/lib/copy_page.S linux-3.4.110/arch/nds32/lib/copy_page.S +--- linux-3.4.110.orig/arch/nds32/lib/copy_page.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/copy_page.S 2016-04-07 10:20:50.950081334 +0200 +@@ -0,0 +1,36 @@ ++/* ++ * linux/arch/nds32/lib/copypage.S ++ * Copyright (C) 2009 Andes Technology Corporation ++ */ ++#include <linux/linkage.h> ++#include <asm/page.h> ++ ++ .text ++ENTRY(copy_page) ++ pushm $r2, $r10 ++ movi $r2, PAGE_SIZE >> 5 ++.Lcopy_loop: ++ lmw.bim $r3, [$r1], $r10 ++ smw.bim $r3, [$r0], $r10 ++ subi45 $r2, #1 ++ bnez38 $r2, .Lcopy_loop ++ popm $r2, $r10 ++ ret ++ ++ENTRY(clear_page) ++ pushm $r1, $r9 ++ movi $r1, PAGE_SIZE >> 5 ++ movi55 $r2, #0 ++ movi55 $r3, #0 ++ movi55 $r4, #0 ++ movi55 $r5, #0 ++ movi55 $r6, #0 ++ movi55 $r7, #0 ++ movi55 $r8, #0 ++ movi55 $r9, #0 ++.Lclear_loop: ++ smw.bim $r2, [$r0], $r9 ++ subi45 $r1, #1 ++ bnez38 $r1, .Lclear_loop ++ popm $r1, $r9 ++ ret +diff -Nur linux-3.4.110.orig/arch/nds32/lib/csum_partial.c linux-3.4.110/arch/nds32/lib/csum_partial.c +--- linux-3.4.110.orig/arch/nds32/lib/csum_partial.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/csum_partial.c 2016-04-07 10:20:50.950081334 +0200 +@@ -0,0 +1,135 @@ ++/* ++ * INET An implementation of the TCP/IP protocol suite for the LINUX ++ * operating system. INET is implemented using the BSD Socket ++ * interface as the means of communication with the user level. ++ * ++ * MIPS specific IP/TCP/UDP checksumming routines ++ * ++ * Authors: Ralf Baechle, <ralf@waldorf-gmbh.de> ++ * Lots of code moved from tcp.c and ip.c; see those files ++ * for more names. ++ * ++ * 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. ++ */ ++#include <linux/module.h> ++#include <linux/types.h> ++ ++#include <net/checksum.h> ++#include <asm/byteorder.h> ++#include <asm/string.h> ++#include <asm/uaccess.h> ++ ++#define addc(_t,_r) \ ++ __asm__ __volatile__ ( \ ++ "add\t%0, %0, %1\n\t" \ ++ "slt\t$p1, %0, %1\n\t" \ ++ "add\r%0, %0, $p1\n\t" \ ++ : "=r"(_t) \ ++ : "r"(_r), "0"(_t)); ++ ++static inline unsigned short from32to16(unsigned int x) ++{ ++ /* 32 bits --> 16 bits + carry */ ++ x = (x & 0xffff) + (x >> 16); ++ /* 16 bits + carry --> 16 bits including carry */ ++ x = (x & 0xffff) + (x >> 16); ++ return (unsigned short)x; ++} ++ ++static inline unsigned int do_csum(const unsigned char *buff, int len) ++{ ++ int odd; ++ register unsigned int result = 0; ++ register unsigned int count; ++ if (len <= 0) ++ goto out; ++ odd = 1 & (unsigned long)buff; ++ if (odd) { ++ result = be16_to_cpu(*buff); ++ len--; ++ buff++; ++ } ++ count = len >> 1; /* nr of 16-bit words.. */ ++ if (count) { ++ if (2 & (unsigned long)buff) { ++ result += *(unsigned short *)buff; ++ count--; ++ len -= 2; ++ buff += 2; ++ } ++ count >>= 1; /* nr of 32-bit words.. */ ++ if (count) { ++ while (count >= 8) { ++ __asm__ ++ __volatile__("lmw.bi $r17, [%1], $r24\n\t" ++ "add\t%0, %0, $r17\n\t" ++ "slt\t$p1, %0, $r17\n\t" ++ "add\r%0, %0, $p1\n\t" ++ "add\t%0, %0, $r18\n\t" ++ "slt\t$p1, %0, $r18\n\t" ++ "add\r%0, %0, $p1\n\t" ++ "add\t%0, %0, $r19\n\t" ++ "slt\t$p1, %0, $r19\n\t" ++ "add\r%0, %0, $p1\n\t" ++ "add\t%0, %0, $r20\n\t" ++ "slt\t$p1, %0, $r20\n\t" ++ "add\r%0, %0, $p1\n\t" ++ "add\t%0, %0, $r21\n\t" ++ "slt\t$p1, %0, $r21\n\t" ++ "add\r%0, %0, $p1\n\t" ++ "add\t%0, %0, $r22\n\t" ++ "slt\t$p1, %0, $r22\n\t" ++ "add\r%0, %0, $p1\n\t" ++ "add\t%0, %0, $r23\n\t" ++ "slt\t$p1, %0, $r23\n\t" ++ "add\r%0, %0, $p1\n\t" ++ "add\t%0, %0, $r24\n\t" ++ "slt\t$p1, %0, $r24\n\t" ++ "add\r%0, %0, $p1\n\t":"=r" ++ (result) ++ :"r"(buff), "0"(result) ++ :"$r17", "$r18", "$r19", ++ "$r20", "$r21", "$r22", "$r23", ++ "$r24"); ++ count -= 8; ++ buff += 32; ++ } ++ while (count) { ++ unsigned int w = *(unsigned int *)buff; ++ count--; ++ buff += 4; ++ addc(result, w); ++ } ++ result = (result & 0xffff) + (result >> 16); ++ } ++ if (len & 2) { ++ result += *(unsigned short *)buff; ++ buff += 2; ++ } ++ } ++ if (len & 1) ++ result += le16_to_cpu(*buff); ++ result = from32to16(result); ++ if (odd) ++ result = swab16(result); ++out: ++ return result; ++} ++ ++/* ++ * computes a partial checksum, e.g. for TCP/UDP fragments ++ */ ++/* ++ * why bother folding? ++ */ ++unsigned int csum_partial(const void *buff, int len, unsigned int sum) ++{ ++ unsigned int result = 0; ++// printk("csum_partial %x %x %x\n", buff, len, sum); ++ result = do_csum(buff, len); ++ addc(result, sum); ++ return (unsigned short)from32to16(result); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/lib/csum_partial_copy.c linux-3.4.110/arch/nds32/lib/csum_partial_copy.c +--- linux-3.4.110.orig/arch/nds32/lib/csum_partial_copy.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/csum_partial_copy.c 2016-04-07 10:20:50.950081334 +0200 +@@ -0,0 +1,58 @@ ++/* ++ * INET An implementation of the TCP/IP protocol suite for the LINUX ++ * operating system. INET is implemented using the BSD Socket ++ * interface as the means of communication with the user level. ++ * ++ * MIPS specific IP/TCP/UDP checksumming routines ++ * ++ * Authors: Ralf Baechle, <ralf@waldorf-gmbh.de> ++ * Lots of code moved from tcp.c and ip.c; see those files ++ * for more names. ++ * ++ * 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. ++ */ ++#include <linux/kernel.h> ++#include <net/checksum.h> ++#include <linux/types.h> ++#include <asm/byteorder.h> ++#include <asm/string.h> ++#include <asm/uaccess.h> ++ ++/* ++ * copy while checksumming, otherwise like csum_partial ++ */ ++unsigned int csum_partial_copy_nocheck(const unsigned char *src, ++ unsigned char *dst, int len, ++ unsigned int sum) ++{ ++ /* ++ * It's 2:30 am and I don't feel like doing it real ... ++ * This is lots slower than the real thing (tm) ++ */ ++ sum = csum_partial(src, len, sum); ++ memcpy(dst, src, len); ++ ++ return sum; ++} ++ ++/* ++ * Copy from userspace and compute checksum. If we catch an exception ++ * then zero the rest of the buffer. ++ */ ++unsigned int csum_partial_copy_from_user(const unsigned char *src, ++ unsigned char *dst, int len, ++ unsigned int sum, int *err_ptr) ++{ ++ int missing; ++ ++ missing = copy_from_user(dst, src, len); ++ if (missing) { ++ memset(dst + len - missing, 0, missing); ++ *err_ptr = -EFAULT; ++ } ++ ++ return csum_partial(dst, len, sum); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/lib/divmod.c linux-3.4.110/arch/nds32/lib/divmod.c +--- linux-3.4.110.orig/arch/nds32/lib/divmod.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/divmod.c 2016-04-07 10:20:50.950081334 +0200 +@@ -0,0 +1,46 @@ ++extern unsigned long udivmodsi4(unsigned long num, unsigned long den, ++ int modwanted); ++ ++long __divsi3(long a, long b) ++{ ++ int neg = 0; ++ long res; ++ ++ if (a < 0) { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodsi4(a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++long __modsi3(long a, long b) ++{ ++ int neg = 0; ++ long res; ++ ++ if (a < 0) { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodsi4(a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/lib/findbit.S linux-3.4.110/arch/nds32/lib/findbit.S +--- linux-3.4.110.orig/arch/nds32/lib/findbit.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/findbit.S 2016-04-07 10:20:50.950081334 +0200 +@@ -0,0 +1,108 @@ ++/* ++ * linux/arch/nds32/lib/findbit.S ++ * ++ * Copyright (C) 1995-2000 Russell King ++ * Copyright (C) 2006 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/linkage.h> ++ ++ .text ++ ++/* ++ * Purpose : Find a 'zero' bit ++ * Prototype: int find_first_zero_bit(void *addr, int maxbit); ++ */ ++ENTRY(_find_first_zero_bit) ++ move $r2, #0 ++ move $p0, #0 ! Reset bit count ++next_word: ++ move $r4, #4 ++ lmw.bim $p1, [$r0], $p1 ++ li $r3, #0xffffffff ! Inversion mask ++ xor $p1, $p1, $r3 ! Inverted the word ++ addi $p0, $p0, #32 ++ beqz $p1, next_word ++ addi $p0, $p0, #-32 ++next_byte: ++ beqz $r4, next_word ++ andi $r3, $p1, #0xff ! Get the next byte ++ bnez $r3, found ! Found zero bit in this byte ++ addi $p0, $p0, #8 ! Update bit count ++ addi $r4, $r4, #-1 ++ srli $p1, $p1, #8 ++ bgt $r1, $p0, next_byte ++ addi $r0, $r1, #1 ! Return not found ++ ret ++ ++/* ++ * Purpose : Find next 'zero' bit ++ * Prototype: int find_next_zero_bit(void *addr, int maxbit, int offset) ++ */ ++ENTRY(_find_next_zero_bit) ++ beqz $r2, _find_first_zero_bit ! If offset=0, goto find_first_zero_bit ++ srli $p0, $r2, #5 ! Get offset byte count ++ slli $p0, $p0, #2 ++ add $r0, $r0, $p0 ! $r0 is the first word to load ++ lmw.bim $p1, [$r0], $p1 ++ li $p0, #0xffffffff ! Inversion mask ++ xor $p1, $p1, $p0 ! Inverted the word ++ andi $r4, $r2, #31 ! Left bits in offset ++ srl $p1, $p1, $r4 ! Shift out the left bits ++ xor $p0, $p0, $p0 ++ subri $r4, $r4, #31 ++loop: ++ andi $r3, $p1, #0xff ! The first byte to check ++ bnez $r3, found ! Found zero bit in this byte ++ addi $p0, $p0, #8 ++ addi $r4, $r4, #-8 ++ srli $p1, $p1, #8 ! Move on to the next byte ++ bgtz $r4, loop ++ b next_word ++ ++/* ++ * One or more bits in the LSB of $p1 are assumed to be set. ++ */ ++ ++found: ++ move $p1, $r3 ++ xor $r4, $r4, $r4 ++ andi $r5, $p1, #0x0f ! Get bits 0-3 ++ move $r3, #4 ! For 0 case (no set bit found) ++ cmovn $r3, $r4, $r5 ! Not 0 case (There's set bit in these 4 bits) ++ add $p0, $p0, $r3 ! Update bit count ++ slli $r3, $p1, #4 ! Not 0 case (Find set bit in these 4 bits) ++ cmovn $p1, $r3, $r5 ! For 0 case (Find set bit in the rest 4 bits) ++ andi $r5, $p1, #0x30 ! Get 4-5 ++ move $r3, #2 ! For 0 case (no set bit found) ++ cmovn $r3, $r4, $r5 ! Not 0 case (There's set bit in these 2 bits) ++ add $p0, $p0, $r3 ! Update bit count ++ slli $r3, $p1, #2 ! Not 0 case (Find set bit in these 2 bits) ++ cmovn $p1, $r3, $r5 ! For 0 case (Find set bit in the rest 2 bits) ++ andi $r5, $p1, #0x40 ! Get bit 6 ++ move $r3, #1 ! For 0 case (bit 6 is not set) ++ cmovn $r3, $r4, $r5 ! Not 0 case (bit 6 is set bit) ++ add $r5, $p0, $r3 ++ add $r0, $r5, $r2 ++ ret ++ ++ENTRY(_ext2_find_first_zero_bit) ++ pushm $r2, $r4 ++ move $r2, #0 ++ move $p0, #0 ! Reset bit count ++1: ++ lbi.bi $r3, [$r0], #1 ++ xori $r3, $r3, #0xff ++ addi $p0, $p0, #8 ++ beqz $r3, 1b ++ addi $p0, $p0, #-8 ++ ++2: ++ b found ! No return ++ popm $r2, $r4 ++ ret ++ +diff -Nur linux-3.4.110.orig/arch/nds32/lib/getuser.S linux-3.4.110/arch/nds32/lib/getuser.S +--- linux-3.4.110.orig/arch/nds32/lib/getuser.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/getuser.S 2016-04-07 10:20:50.950081334 +0200 +@@ -0,0 +1,79 @@ ++/* ++ * linux/arch/nds32/lib/getuser.S ++ * ++ * Copyright (C) 2001 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Idea from x86 version, (C) Copyright 1998 Linus Torvalds ++ * ++ * These functions have a non-standard call interface to make them more ++ * efficient, especially as they return an error value in addition to ++ * the "real" return value. ++ * ++ * __get_user_X ++ * ++ * Inputs: $r0 contains the address ++ * Outputs: $r0 is the error code ++ * $r2, $r3 contains the zero-extended value ++ * lr corrupted ++ * ++ * No other registers must be altered. (see include/asm-nds32/uaccess.h ++ * for specific ASM register usage). ++ * ++ * Note that ADDR_LIMIT is either 0 or 0xc0000000. ++ * Note also that it is intended that __get_user_bad is not global. ++ */ ++#include <asm/asm-offsets.h> ++#include <asm/thread_info.h> ++#include <asm/errno.h> ++#include <linux/linkage.h> ++ ++ ++ENTRY(__get_user_1) ++1: lbi $r2, [$r0] ++ move $r0, #0 ++ ret ++ ++ENTRY(__get_user_2) ++2: lbi.bi $r2, [$r0], #1 ++3: lbi $r3, [$r0] ++#ifndef __NDS32_EB__ ++ slli $p1, $r3, #8 ++ or $r2, $r2, $p1 ++#else ++ slli $p1, $r2, #8 ++ or $r2, $r3, $p1 ++#endif ++ move $r0, #0 ++ ret ++ ++ENTRY(__get_user_4) ++4: lwi $r2, [$r0] ++ move $r0, #0 ++ ret ++ ++ENTRY(__get_user_8) ++5: lwi.bi $r2, [$r0], #4 ++6: lwi $r3, [$r0] ++ move $r0, #0 ++ ret ++ ++__get_user_bad_8: ++ move $r3, #0 ++__get_user_bad: ++ move $r2, #0 ++ move $r0, #-EFAULT ++ ret ++ ++.section __ex_table, "a" ++ .long 1b, __get_user_bad ++ .long 2b, __get_user_bad ++ .long 3b, __get_user_bad ++ .long 4b, __get_user_bad ++ .long 5b, __get_user_bad_8 ++ .long 6b, __get_user_bad_8 ++.previous +diff -Nur linux-3.4.110.orig/arch/nds32/lib/libgcc2.c linux-3.4.110/arch/nds32/lib/libgcc2.c +--- linux-3.4.110.orig/arch/nds32/lib/libgcc2.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/libgcc2.c 2016-04-07 10:20:50.950081334 +0200 +@@ -0,0 +1,351 @@ ++#define BITS_PER_UNIT 8 ++#include "longlong.h" ++typedef unsigned int UQItype __attribute__ ((mode(QI))); ++typedef int SItype __attribute__ ((mode(SI))); ++typedef unsigned int USItype __attribute__ ((mode(SI))); ++typedef int DItype __attribute__ ((mode(DI))); ++typedef unsigned int UDItype __attribute__ ((mode(DI))); ++ ++typedef int word_type __attribute__ ((mode(__word__))); ++ ++#define Wtype SItype ++#define UWtype USItype ++#define DWtype DItype ++#define UDWtype UDItype ++ ++#ifdef __NDS32_EB__ ++struct DWstruct { ++ Wtype high, low; ++}; ++#else ++struct DWstruct { ++ Wtype low, high; ++}; ++#endif ++ ++typedef union { ++ struct DWstruct s; ++ DWtype ll; ++} DWunion; ++DWtype __negdi2(DWtype u) ++{ ++ const DWunion uu = {.ll = u }; ++ const DWunion w = { {.low = -uu.s.low, ++ .high = -uu.s.high - ((UWtype) - uu.s.low > 0)} ++ }; ++ ++ return w.ll; ++} ++ ++DWtype __lshrdi3(DWtype u, word_type b) ++{ ++ const DWunion uu = {.ll = u }; ++ const word_type bm = (sizeof(Wtype) * BITS_PER_UNIT) - b; ++ DWunion w; ++ ++ if (b == 0) ++ return u; ++ ++ if (bm <= 0) { ++ w.s.high = 0; ++ w.s.low = (UWtype) uu.s.high >> -bm; ++ } else { ++ const UWtype carries = (UWtype) uu.s.high << bm; ++ ++ w.s.high = (UWtype) uu.s.high >> b; ++ w.s.low = ((UWtype) uu.s.low >> b) | carries; ++ } ++ ++ return w.ll; ++} ++ ++DWtype __ashldi3(DWtype u, word_type b) ++{ ++ const DWunion uu = {.ll = u }; ++ const word_type bm = (sizeof(Wtype) * BITS_PER_UNIT) - b; ++ DWunion w; ++ ++ if (b == 0) ++ return u; ++ ++ if (bm <= 0) { ++ w.s.low = 0; ++ w.s.high = (UWtype) uu.s.low << -bm; ++ } else { ++ const UWtype carries = (UWtype) uu.s.low >> bm; ++ ++ w.s.low = (UWtype) uu.s.low << b; ++ w.s.high = ((UWtype) uu.s.high << b) | carries; ++ } ++ ++ return w.ll; ++} ++ ++DWtype __ashrdi3(DWtype u, word_type b) ++{ ++ const DWunion uu = {.ll = u }; ++ const word_type bm = (sizeof(Wtype) * BITS_PER_UNIT) - b; ++ DWunion w; ++ ++ if (b == 0) ++ return u; ++ ++ if (bm <= 0) { ++ /* w.s.high = 1..1 or 0..0 */ ++ w.s.high = uu.s.high >> (sizeof(Wtype) * BITS_PER_UNIT - 1); ++ w.s.low = uu.s.high >> -bm; ++ } else { ++ const UWtype carries = (UWtype) uu.s.high << bm; ++ ++ w.s.high = uu.s.high >> b; ++ w.s.low = ((UWtype) uu.s.low >> b) | carries; ++ } ++ ++ return w.ll; ++} ++ ++DWtype __muldi3(DWtype u, DWtype v) ++{ ++ const DWunion uu = {.ll = u }; ++ const DWunion vv = {.ll = v }; ++ DWunion w = {.ll = __umulsidi3(uu.s.low, vv.s.low) }; ++ ++ w.s.high += ((UWtype) uu.s.low * (UWtype) vv.s.high ++ + (UWtype) uu.s.high * (UWtype) vv.s.low); ++ ++ return w.ll; ++} ++ ++const UQItype __clz_tab[] = { ++ 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, ++ 5, 5, 5, 5, 5, 5, 5, 5, ++ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, ++ 6, 6, 6, 6, 6, 6, 6, 6, ++ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, ++ 7, 7, 7, 7, 7, 7, 7, 7, ++ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, ++ 7, 7, 7, 7, 7, 7, 7, 7, ++ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, ++ 8, 8, 8, 8, 8, 8, 8, 8, ++}; ++ ++UDWtype __udivmoddi4(UDWtype n, UDWtype d, UDWtype * rp) ++{ ++ const DWunion nn = {.ll = n }; ++ const DWunion dd = {.ll = d }; ++ DWunion rr; ++ UWtype d0, d1, n0, n1, n2; ++ UWtype q0, q1; ++ UWtype b, bm; ++ DWunion ww; ++ ++ d0 = dd.s.low; ++ d1 = dd.s.high; ++ n0 = nn.s.low; ++ n1 = nn.s.high; ++ ++#if !UDIV_NEEDS_NORMALIZATION ++ if (d1 == 0) { ++ if (d0 > n1) { ++ /* 0q = nn / 0D */ ++ ++ udiv_qrnnd(q0, n0, n1, n0, d0); ++ q1 = 0; ++ ++ /* Remainder in n0. */ ++ } else { ++ /* qq = NN / 0d */ ++ ++ if (d0 == 0) ++ d0 = 1 / d0; /* Divide intentionally by zero. */ ++ ++ udiv_qrnnd(q1, n1, 0, n1, d0); ++ udiv_qrnnd(q0, n0, n1, n0, d0); ++ ++ /* Remainder in n0. */ ++ } ++ ++ if (rp != 0) { ++ rr.s.low = n0; ++ rr.s.high = 0; ++ *rp = rr.ll; ++ } ++ } ++#else /* UDIV_NEEDS_NORMALIZATION */ ++ ++ if (d1 == 0) { ++ if (d0 > n1) { ++ /* 0q = nn / 0D */ ++ ++ count_leading_zeros(bm, d0); ++ ++ if (bm != 0) { ++ /* Normalize, i.e. make the most significant bit of the ++ denominator set. */ ++ ++ d0 = d0 << bm; ++ n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); ++ n0 = n0 << bm; ++ } ++ ++ udiv_qrnnd(q0, n0, n1, n0, d0); ++ q1 = 0; ++ ++ /* Remainder in n0 >> bm. */ ++ } else { ++ /* qq = NN / 0d */ ++ ++ if (d0 == 0) ++ d0 = 1 / d0; /* Divide intentionally by zero. */ ++ ++ count_leading_zeros(bm, d0); ++ ++ if (bm == 0) { ++ /* From (n1 >= d0) /\ (the most significant bit of d0 is set), ++ conclude (the most significant bit of n1 is set) /\ (the ++ leading quotient digit q1 = 1). ++ ++ This special case is necessary, not an optimization. ++ (Shifts counts of W_TYPE_SIZE are undefined.) */ ++ ++ n1 -= d0; ++ q1 = 1; ++ } else { ++ /* Normalize. */ ++ ++ b = W_TYPE_SIZE - bm; ++ ++ d0 = d0 << bm; ++ n2 = n1 >> b; ++ n1 = (n1 << bm) | (n0 >> b); ++ n0 = n0 << bm; ++ ++ udiv_qrnnd(q1, n1, n2, n1, d0); ++ } ++ ++ /* n1 != d0... */ ++ ++ udiv_qrnnd(q0, n0, n1, n0, d0); ++ ++ /* Remainder in n0 >> bm. */ ++ } ++ ++ if (rp != 0) { ++ rr.s.low = n0 >> bm; ++ rr.s.high = 0; ++ *rp = rr.ll; ++ } ++ } ++#endif /* UDIV_NEEDS_NORMALIZATION */ ++ ++ else { ++ if (d1 > n1) { ++ /* 00 = nn / DD */ ++ ++ q0 = 0; ++ q1 = 0; ++ ++ /* Remainder in n1n0. */ ++ if (rp != 0) { ++ rr.s.low = n0; ++ rr.s.high = n1; ++ *rp = rr.ll; ++ } ++ } else { ++ /* 0q = NN / dd */ ++ ++ count_leading_zeros(bm, d1); ++ if (bm == 0) { ++ /* From (n1 >= d1) /\ (the most significant bit of d1 is set), ++ conclude (the most significant bit of n1 is set) /\ (the ++ quotient digit q0 = 0 or 1). ++ ++ This special case is necessary, not an optimization. */ ++ ++ /* The condition on the next line takes advantage of that ++ n1 >= d1 (true due to program flow). */ ++ if (n1 > d1 || n0 >= d0) { ++ q0 = 1; ++ sub_ddmmss(n1, n0, n1, n0, d1, d0); ++ } else ++ q0 = 0; ++ ++ q1 = 0; ++ ++ if (rp != 0) { ++ rr.s.low = n0; ++ rr.s.high = n1; ++ *rp = rr.ll; ++ } ++ } else { ++ UWtype m1, m0; ++ /* Normalize. */ ++ ++ b = W_TYPE_SIZE - bm; ++ ++ d1 = (d1 << bm) | (d0 >> b); ++ d0 = d0 << bm; ++ n2 = n1 >> b; ++ n1 = (n1 << bm) | (n0 >> b); ++ n0 = n0 << bm; ++ ++ udiv_qrnnd(q0, n1, n2, n1, d1); ++ umul_ppmm(m1, m0, q0, d0); ++ ++ if (m1 > n1 || (m1 == n1 && m0 > n0)) { ++ q0--; ++ sub_ddmmss(m1, m0, m1, m0, d1, d0); ++ } ++ ++ q1 = 0; ++ ++ /* Remainder in (n1n0 - m1m0) >> bm. */ ++ if (rp != 0) { ++ sub_ddmmss(n1, n0, n1, n0, m1, m0); ++ rr.s.low = (n1 << b) | (n0 >> bm); ++ rr.s.high = n1 >> bm; ++ *rp = rr.ll; ++ } ++ } ++ } ++ } ++ ++ ww.s.low = q0, ww.s.high = q1; ++ return ww.ll; ++} ++ ++UDWtype __umoddi3(UDWtype u, UDWtype v) ++{ ++ UDWtype w; ++ ++ (void)__udivmoddi4(u, v, &w); ++ ++ return w; ++} ++ ++UDWtype __udivdi3(UDWtype n, UDWtype d) ++{ ++ return __udivmoddi4(n, d, (UDWtype *) 0); ++} ++ ++word_type __ucmpdi2(DWtype a, DWtype b) ++{ ++ const DWunion au = {.ll = a }; ++ const DWunion bu = {.ll = b }; ++ ++ if ((UWtype) au.s.high < (UWtype) bu.s.high) ++ return 0; ++ else if ((UWtype) au.s.high > (UWtype) bu.s.high) ++ return 2; ++ if ((UWtype) au.s.low < (UWtype) bu.s.low) ++ return 0; ++ else if ((UWtype) au.s.low > (UWtype) bu.s.low) ++ return 2; ++ return 1; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/lib/longlong.h linux-3.4.110/arch/nds32/lib/longlong.h +--- linux-3.4.110.orig/arch/nds32/lib/longlong.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/longlong.h 2016-04-07 10:20:50.950081334 +0200 +@@ -0,0 +1,105 @@ ++#define __BITS4 (W_TYPE_SIZE / 4) ++#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) ++#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) ++#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) ++ ++#define W_TYPE_SIZE (4 * 8) ++#define UHWtype USItype ++ ++#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ ++ do { \ ++ UWtype __x; \ ++ __x = (al) - (bl); \ ++ (sh) = (ah) - (bh) - (__x > (al)); \ ++ (sl) = __x; \ ++ } while (0) ++ ++#define umul_ppmm(w1, w0, u, v) \ ++ do { \ ++ UWtype __x0, __x1, __x2, __x3; \ ++ UHWtype __ul, __vl, __uh, __vh; \ ++ \ ++ __ul = __ll_lowpart (u); \ ++ __uh = __ll_highpart (u); \ ++ __vl = __ll_lowpart (v); \ ++ __vh = __ll_highpart (v); \ ++ \ ++ __x0 = (UWtype) __ul * __vl; \ ++ __x1 = (UWtype) __ul * __vh; \ ++ __x2 = (UWtype) __uh * __vl; \ ++ __x3 = (UWtype) __uh * __vh; \ ++ \ ++ __x1 += __ll_highpart (__x0);/* this can't give carry */ \ ++ __x1 += __x2; /* but this indeed can */ \ ++ if (__x1 < __x2) /* did we get it? */ \ ++ __x3 += __ll_B; /* yes, add it in the proper pos. */ \ ++ \ ++ (w1) = __x3 + __ll_highpart (__x1); \ ++ (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \ ++ } while (0) ++ ++#define __umulsidi3(u, v) \ ++ ({DWunion __w; \ ++ umul_ppmm (__w.s.high, __w.s.low, u, v); \ ++ __w.ll; }) ++ ++#define __udiv_qrnnd_c(q, r, n1, n0, d) \ ++ do { \ ++ UWtype __d1, __d0, __q1, __q0; \ ++ UWtype __r1, __r0, __m; \ ++ __d1 = __ll_highpart (d); \ ++ __d0 = __ll_lowpart (d); \ ++ \ ++ __r1 = (n1) % __d1; \ ++ __q1 = (n1) / __d1; \ ++ __m = (UWtype) __q1 * __d0; \ ++ __r1 = __r1 * __ll_B | __ll_highpart (n0); \ ++ if (__r1 < __m) \ ++ { \ ++ __q1--, __r1 += (d); \ ++ if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ ++ if (__r1 < __m) \ ++ __q1--, __r1 += (d); \ ++ } \ ++ __r1 -= __m; \ ++ \ ++ __r0 = __r1 % __d1; \ ++ __q0 = __r1 / __d1; \ ++ __m = (UWtype) __q0 * __d0; \ ++ __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ ++ if (__r0 < __m) \ ++ { \ ++ __q0--, __r0 += (d); \ ++ if (__r0 >= (d)) \ ++ if (__r0 < __m) \ ++ __q0--, __r0 += (d); \ ++ } \ ++ __r0 -= __m; \ ++ \ ++ (q) = (UWtype) __q1 * __ll_B | __q0; \ ++ (r) = __r0; \ ++ } while (0) ++ ++#define UDIV_NEEDS_NORMALIZATION 1 ++#define udiv_qrnnd __udiv_qrnnd_c ++ ++#define count_leading_zeros(count, x) \ ++ do { \ ++ UWtype __xr = (x); \ ++ UWtype __a; \ ++ \ ++ if (W_TYPE_SIZE <= 32) \ ++ { \ ++ __a = __xr < ((UWtype)1<<2*__BITS4) \ ++ ? (__xr < ((UWtype)1<<__BITS4) ? 0 : __BITS4) \ ++ : (__xr < ((UWtype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ ++ } \ ++ else \ ++ { \ ++ for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ ++ if (((__xr >> __a) & 0xff) != 0) \ ++ break; \ ++ } \ ++ \ ++ (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ ++ } while (0) +diff -Nur linux-3.4.110.orig/arch/nds32/lib/Makefile linux-3.4.110/arch/nds32/lib/Makefile +--- linux-3.4.110.orig/arch/nds32/lib/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/Makefile 2016-04-07 10:20:50.950081334 +0200 +@@ -0,0 +1,19 @@ ++# ++# linux/arch/nds32/lib/Makefile ++# ++# Copyright (C) 2006 Andes Technology Corporation ++# ++ ++lib-y := csum_partial_copy.o csum_partial.o \ ++ copy_page.o memcpy.o memmove.o \ ++ memset.o memzero.o strncpy_from_user.o \ ++ strnlen_user.o strchr.o strrchr.o \ ++ uaccess.o getuser.o \ ++ putuser.o libgcc2.o divmod.o udivmod.o udivmodsi4.o ++ ++ifdef CONFIG_FUNCTION_TRACER ++CFLAGS_REMOVE_libgcc2.o = -pg ++CFLAGS_REMOVE_divmod.o = -pg ++CFLAGS_REMOVE_udivmod.o = -pg ++CFLAGS_REMOVE_udivmodsi4.o = -pg ++endif +diff -Nur linux-3.4.110.orig/arch/nds32/lib/memcpy.S linux-3.4.110/arch/nds32/lib/memcpy.S +--- linux-3.4.110.orig/arch/nds32/lib/memcpy.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/memcpy.S 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,101 @@ ++/* ++ * linux/arch/nds32/lib/memcpy.S -- Memory copy function. ++ * ++ * 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) 2001 Hiroyuki Kondo, and Hirokazu Takata ++ * Copyright (C) 2004 Hirokazu Takata ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ */ ++ ++#include <linux/linkage.h> ++ ++/* ++ void *memcpy(void *dst, const void *src, int n); ++ ++ dst: $r0 ++ src: $r1 ++ n : $r2 ++ ret: $r0 - pointer to the memory area dst. ++*/ ++ ++#include <linux/linkage.h> ++ ++ .text ++ ++ENTRY(memcpy) ++ move $r5, $r0 ++ beq $r0, $r1, quit_memcpy ++ beqz $r2, quit_memcpy ++ srli $r3, $r2, #5 ! check if len < cache-line size 32 ++ beqz $r3, word_copy_entry ++ andi $r4, $r0, #0x3 ! check byte-align ++ beqz $r4, unalign_word_copy_entry ++ ++ addi $r4, $r4,#-4 ++ abs $r4, $r4 ! check how many un-align byte to copy ++ sub $r2, $r2, $r4 ! update $R2 ++ ++unalign_byte_copy: ++ lbi.bi $r3, [$r1], #1 ++ addi $r4, $r4, #-1 ++ sbi.bi $r3, [$r0], #1 ++ bnez $r4, unalign_byte_copy ++ beqz $r2, quit_memcpy ++ ++unalign_word_copy_entry: ++ andi $r3, $r0, 0x1f ! check cache-line unaligncount ++ beqz $r3, cache_copy ++ ++ addi $r3, $r3, #-32 ++ abs $r3, $r3 ++ sub $r2, $r2, $r3 ! update $R2 ++ ++unalign_word_copy: ++ lmw.bim $r4, [$r1], $r4 ++ addi $r3, $r3, #-4 ++ smw.bim $r4, [$r0], $r4 ++ bnez $r3, unalign_word_copy ++ beqz $r2, quit_memcpy ++ ++ addi $r3, $r2, #-32 ! to check $r2< cache_line , than go to word_copy ++ bltz $r3, word_copy_entry ++cache_copy: ++ srli $r3, $r2, #5 ++ beqz $r3, word_copy_entry ++ pushm $r6, $r13 ++3: ++ lmw.bim $r6, [$r1], $r13 ++ addi $r3, $r3, #-1 ++ smw.bim $r6, [$r0], $r13 ++ bnez $r3, 3b ++ popm $r6, $r13 ++ ++word_copy_entry: ++ andi $r2, $r2, #31 ++ ++ beqz $r2, quit_memcpy ++5: ++ srli $r3, $r2, #2 ++ beqz $r3, byte_copy ++word_copy: ++ lmw.bim $r4, [$r1], $r4 ++ addi $r3, $r3, #-1 ++ smw.bim $r4, [$r0], $r4 ++ bnez $r3, word_copy ++ andi $r2, $r2, #3 ++ beqz $r2, quit_memcpy ++byte_copy: ++ lbi.bi $r3, [$r1], #1 ++ addi $r2, $r2, #-1 ++ ++ sbi.bi $r3, [$r0], #1 ++ bnez $r2, byte_copy ++quit_memcpy: ++ move $r0, $r5 ++ ret ++ ++ .end +diff -Nur linux-3.4.110.orig/arch/nds32/lib/memmove.S linux-3.4.110/arch/nds32/lib/memmove.S +--- linux-3.4.110.orig/arch/nds32/lib/memmove.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/memmove.S 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,80 @@ ++/* ++ * linux/arch/nds32/lib/memmove.S -- Memory move function. ++ * ++ * 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) 2001 Hiroyuki Kondo, and Hirokazu Takata ++ * Copyright (C) 2004 Hirokazu Takata ++ * Copyright (C) 2006 Andes Technology Corporation ++ * ++ */ ++ ++#include <linux/linkage.h> ++ ++/* ++ void *memmove(void *dst, const void *src, int n); ++ ++ dst: $r0 ++ src: $r1 ++ n : $r2 ++ ret: $r0 - pointer to the memory area dst. ++*/ ++ .text ++ ++ENTRY(memmove) ++ move $r5, $r0 ! Set return value = det ++ beq $r0, $r1, exit_memcpy ! Exit when det = src ++ beqz $r2, exit_memcpy ! Exit when n = 0 ++ pushm $t0, $t1 ! Save reg ++ srli $p1, $r2, #2 ! $p1 is how many words to copy ++ ++ ! Avoid data lost when memory overlap ++ ! Copy data reversely when src < dst ++ slt $p0, $r0, $r1 ! check if $r0 < $r1 ++ beqz $p0, do_reverse ! branch if dst > src ++ ++ ! No reverse, dst < src ++ andi $r2, $r2, #3 ! How many bytes are less than a word ++ li $t0, #1 ! Determining copy direction in byte_cpy ++ beqz $p1, byte_cpy ! When n is less than a word ++ ++word_cpy: ++ lmw.bim $p0, [$r1], $p0 ! Read a word from src ++ addi $p1, $p1, #-1 ! How many words left to copy ++ smw.bim $p0, [$r0], $p0 ! Copy the word to det ++ bnez $p1, word_cpy ! If remained words > 0 ++ beqz $r2, end_memcpy ! No left bytes to copy ++ b byte_cpy ++ ++do_reverse: ++ add $r0, $r0, $r2 ! Start with the end of $r0 ++ add $r1, $r1, $r2 ! Start with the end of $r1 ++ andi $r2, $r2, #3 ! How many bytes are less than a word ++ li $t0, #-1 ! Determining copy direction in byte_cpy ++ beqz $p1, reverse_byte_cpy ! When n is less than a word ++ ++reverse_word_cpy: ++ lmw.adm $p0, [$r1], $p0 ! Read a word from src ++ addi $p1, $p1, #-1 ! How many words left to copy ++ smw.adm $p0, [$r0], $p0 ! Copy the word to det ++ bnez $p1, reverse_word_cpy ! If remained words > 0 ++ beqz $r2, end_memcpy ! No left bytes to copy ++ ++reverse_byte_cpy: ++ addi $r0, $r0, #-1 ++ addi $r1, $r1, #-1 ++byte_cpy: ! Less than 4 bytes to copy now ++ lb.bi $p0, [$r1], $t0 ! Read a byte from src ++ addi $r2, $r2, #-1 ! How many bytes left to copy ++ sb.bi $p0, [$r0], $t0 ! copy the byte to det ++ bnez $r2, byte_cpy ! If remained bytes > 0 ++ ++end_memcpy: ++ popm $t0, $t1 ++exit_memcpy: ++ move $r0, $r5 ++ ret ++ ++ .end +diff -Nur linux-3.4.110.orig/arch/nds32/lib/memset.S linux-3.4.110/arch/nds32/lib/memset.S +--- linux-3.4.110.orig/arch/nds32/lib/memset.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/memset.S 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,51 @@ ++ ++/* ++ * linux/arch/nds32/lib/memset.S -- memset function. ++ * ++ * 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) 2001,2002 Hiroyuki Kondo, and Hirokazu Takata ++ * Copyright (C) 2004 Hirokazu Takata ++ * Copyright (C) 2006 Andes Technology Corporation ++ * ++ */ ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++ ++/* ++ void *memset(void *dst, int val, int len); ++ ++ dst: $r0 ++ val: $r1 ++ len: $r2 ++ ret: $r0 - pointer to the memory area dst. ++*/ ++ .text ++ENTRY(memset) ++ move $r5, $r0 ! Return value ++ beqz $r2, end_memset ! Exit when len = 0 ++ srli $p1, $r2, 2 ! $p1 is how many words to copy ++ andi $r2, $r2, 3 ! How many bytes are less than a word ++ beqz $p1, byte_set ! When n is less than a word ++ ++ ! set $r1 from ??????ab to abababab ++ andi $r1, $r1, #0x00ff ! $r1 = 000000ab ++ slli $p0, $r1, #8 ! $p0 = 0000ab00 ++ or $r1, $r1, $p0 ! $r1 = 0000abab ++ slli $p0, $r1, #16 ! $p0 = abab0000 ++ or $r1, $r1, $p0 ! $r1 = abababab ++word_set: ++ addi $p1, $p1, #-1 ! How many words left to copy ++ smw.bim $r1, [$r0], $r1 ! Copy the word to det ++ bnez $p1, word_set ! Still words to set, continue looping ++ beqz $r2, end_memset ! No left byte to set ++byte_set: ! Less than 4 bytes left to set ++ addi $r2, $r2, #-1 ! Decrease len by 1 ++ sbi.bi $r1, [$r0], #1 ! Set data of the next byte to $r1 ++ bnez $r2, byte_set ! Still bytes left to set ++end_memset: ++ move $r0, $r5 ++ ret ++ +diff -Nur linux-3.4.110.orig/arch/nds32/lib/memzero.S linux-3.4.110/arch/nds32/lib/memzero.S +--- linux-3.4.110.orig/arch/nds32/lib/memzero.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/memzero.S 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,36 @@ ++/* ++ * linux/arch/nds32/lib/memzero.S ++ * ++ * Copyright (C) 1995-2000 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++ ++ .text ++/* ++ * void *__memzero(void *dst, int len); ++ * ++ * dst: $r0 ++ * len: $r1 ++ * ret: $r0 - pointer to the memory area dst. ++ * ++ * Call memset(dst, 0, len) to perform memzero. ++ * Currently no optimization because only being referenced in 31 files ++ * (For comparison, memset being referenced in 2527 files) ++ */ ++ENTRY(__memzero) ++ beqz $r1, 1f ++ push $lp ++ move $r2, $r1 ++ move $r1, #0 ++ push $r0 ++ bal memset ++ pop $r0 ++ pop $lp ++1: ++ ret +diff -Nur linux-3.4.110.orig/arch/nds32/lib/putuser.S linux-3.4.110/arch/nds32/lib/putuser.S +--- linux-3.4.110.orig/arch/nds32/lib/putuser.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/putuser.S 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,68 @@ ++/* ++ * linux/arch/nds32/lib/putuser.S ++ * ++ * Copyright (C) 2001 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Idea from x86 version, (C) Copyright 1998 Linus Torvalds ++ * ++ * These functions have a non-standard call interface to make ++ * them more efficient, especially as they return an error ++ * value in addition to the "real" return value. ++ * ++ * __put_user_X ++ * ++ * Inputs: $r0 contains the address ++ * $r2, $r3 contains the value ++ * Outputs: $r0 is the error code ++ * lr corrupted ++ * ++ * No other registers must be altered. (see include/asm-arm/uaccess.h ++ * for specific ASM register usage). ++ * ++ * Note that ADDR_LIMIT is either 0 or 0xc0000000 ++ * Note also that it is intended that __put_user_bad is not global. ++ */ ++#include <asm/asm-offsets.h> ++#include <asm/thread_info.h> ++#include <asm/errno.h> ++#include <linux/linkage.h> ++ ++ .text ++ ++ENTRY(__put_user_1) ++1: sb $r2, [$r0] ++ move $r0, #0 ++ ret ++ ++ENTRY(__put_user_2) ++2: shi $r2, [$r0] ! Store input halfword ++ move $r0, #0 ++ ret ++ ++ENTRY(__put_user_4) ++3: sw $r2, [$r0] ++ move $r0, #0 ++ ret ++ ++ENTRY(__put_user_8) ++5: swi.bi $r2, [$r0], #4 ++6: sw $r3, [$r0] ++ move $r0, #0 ++ ret ++ ++__put_user_bad: ++ move $r0, #-EFAULT ++ ret ++ ++.section __ex_table, "a" ++ .long 1b, __put_user_bad ++ .long 2b, __put_user_bad ++ .long 3b, __put_user_bad ++ .long 5b, __put_user_bad ++ .long 6b, __put_user_bad ++.previous +diff -Nur linux-3.4.110.orig/arch/nds32/lib/strchr.S linux-3.4.110/arch/nds32/lib/strchr.S +--- linux-3.4.110.orig/arch/nds32/lib/strchr.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/strchr.S 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,37 @@ ++/* ++ * linux/arch/nds32/lib/strchr.S ++ * ++ * Copyright (C) 1995-2000 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * ASM optimised string functions ++ */ ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++ ++/* ++ * Prototype: char *strrchr(const char *s, int c); ++ * Purpose : Returns a pointer to the first occurrence of the character c ++ * in the string s. Here "character" means "byte" - these functions ++ * do not work with wide or multi-byte characters. ++ */ ++ ++ .text ++ ++ENTRY(strchr) ++ move $r5, $r0 ! Setup return value ++ andi $r1, $r1, #0xff ! Wipe out useless bits ++loop: ++ lbi.bi $p0, [$r5], #1 ! Load the next byte ++ beqz $p0, exit ! Reach EOS (NULL), return NULL ++ bne $p0, $r1, loop ! Continue if != c ++ addi $r5, $r5, #-1 ! Found ++exit: ++ cmovz $r5, $p0, $p0 ! Return NULL if EOS (NULL) ++ move $r0, $r5 ++ ret ++ +diff -Nur linux-3.4.110.orig/arch/nds32/lib/strncpy_from_user.S linux-3.4.110/arch/nds32/lib/strncpy_from_user.S +--- linux-3.4.110.orig/arch/nds32/lib/strncpy_from_user.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/strncpy_from_user.S 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,45 @@ ++/* ++ * linux/arch/nds32/lib/strncpy_from_user.S ++ * ++ * Copyright (C) 1995-2000 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++#include <asm/errno.h> ++ ++ ++/* ++ * Copy a string from user space to kernel space. ++ * $r0 = dst, $r1 = src, $r2 = n (byte length) ++ * returns the number of characters copied (strlen of copied string), ++ * -EFAULT on exception, or "len" if we fill the whole buffer ++ */ ++ ++ .text ++ .align 4 ++ENTRY(__arch_strncpy_from_user) ++ move $p1, $r1 ! Record the start src addr ++loop: ++ addi $r2, $r2, #-1 ! Decrease n by 1 ++ bltz $r2, exit ! Exit if n < 0 ++USER( lbi.bi, $p0, [$r1], #1) ! Load the byte from src ++ sbi.bi $p0, [$r0], #1 ! Store the byte to dst ++ bnez $p0, loop ! Continue looping if terminator is not reached ++ addi $r1, $r1, #-1 ! Don't count the terminator ++exit: ++ sub $r0, $r1, $p1 ! Get copied count ++ ret ++ ++ .section .fixup,"ax" ++ .align 0 ++9001: xor $p0, $p0, $p0 ++ sb $p0, [$r0] ! Zero the buffer ++ move $r0, -EFAULT ! Return -EFAULT ++ ret ++ .previous ++ +diff -Nur linux-3.4.110.orig/arch/nds32/lib/strnlen_user.S linux-3.4.110/arch/nds32/lib/strnlen_user.S +--- linux-3.4.110.orig/arch/nds32/lib/strnlen_user.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/strnlen_user.S 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,43 @@ ++/* ++ * linux/arch/nds32/lib/strnlen_user.S ++ * ++ * Copyright (C) 1995-2000 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++#include <asm/errno.h> ++ ++ .text ++ ++/* Prototype: unsigned long ___arch_strnlen_user(const char *str, long n) ++ * Purpose : get length of a string in user memory ++ * Params : str - address of string in user memory ++ * Returns : length of string *including terminator* ++ * or zero on exception, or n + 1 if too long ++ */ ++ .align 4 ++ENTRY(__arch_strnlen_user) ++ move $p0, $r0 ! Record the start addr ++ ! beqz $r0, exit ! Exit when Null address ++ beqz $r1, exit ! Exit when n = 0 ++loop: ++USER( lbi.bi, $p1, [$r0], #1) ! Load the next byte ++ beqz $p1, exit ! Exit when terminator is reached ++ addi $r1, $r1, #-1 ! Decrease n by 1 ++ bnez $r1, loop ! Continue looping if n != 0 ++ addi $r0, $r0, #1 ! Return n+1 if too long ++exit: ++ sub $r0, $r0, $p0 ! Get the counted length ++ ret ++ ++ .section .fixup,"ax" ++ .align 0 ++9001: move $r0, #0 ! Return 0 on exception ++ ret ++ .previous ++ +diff -Nur linux-3.4.110.orig/arch/nds32/lib/strrchr.S linux-3.4.110/arch/nds32/lib/strrchr.S +--- linux-3.4.110.orig/arch/nds32/lib/strrchr.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/strrchr.S 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,37 @@ ++/* ++ * linux/arch/nds32/lib/strrchr.S ++ * ++ * Copyright (C) 1995-2000 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * ASM optimised string functions ++ */ ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++ ++ .text ++/* ++ * Prototype: char *strrchr(const char *s, int c); ++ * Purpose : Returns a pointer to the last occurrence of the character c ++ * in the string s. Here "character" means "byte" - these functions ++ * do not work with wide or multi-byte characters. ++ */ ++ .align 4 ++ENTRY(strrchr) ++ move $r5, #0 ++ beqz $r0, exit ++ andi $r1, $r1, #0xff ! Wipe out useless bits ++loop: ++ lbi $p0, [$r0] ! Load the next byte ++ xor $p1, $p0, $r1 ! Test if the byte == c ++ cmovz $r5, $r0, $p1 ! Save the current position ++ addi $r0, $r0, #1 ! Move on to the next byte ++ bnez $p0, loop ! Continue if not NULL (EOS) ++exit: ++ move $r0, $r5 ++ ret ++ +diff -Nur linux-3.4.110.orig/arch/nds32/lib/uaccess.S linux-3.4.110/arch/nds32/lib/uaccess.S +--- linux-3.4.110.orig/arch/nds32/lib/uaccess.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/uaccess.S 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,159 @@ ++/* ++ * linux/arch/nds32/lib/uaccess.S ++ * ++ * Copyright (C) 1995, 1996,1997,1998 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Routines to block copy data to/from user memory ++ * These are highly optimised both for the 4k page size ++ * and for various alignments. ++ */ ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++#include <asm/errno.h> ++ ++ .text ++ ++//#define PAGE_SHIFT 12 ++ ++/* Prototype: int __arch_copy_to_user(void *to, const char *from, size_t n) ++ * Purpose : copy a block to user memory from kernel memory ++ * Params : to - user memory ++ * : from - kernel memory ++ * : n - number of bytes to copy ++ * Returns : Number of bytes NOT copied. ++ */ ++ ++ENTRY(__arch_copy_to_user) ++ push $r0 ++ push $r2 ++ beqz $r2, ctu_exit ++ srli $p0, $r2, #2 ! $p0 = number of word to clear ++ andi $r2, $r2, #3 ! Bytes less than a word to copy ++ beqz $p0, byte_ctu ! Only less than a word to copy ++word_ctu: ++ lmw.bim $p1, [$r1], $p1 ! Load the next word ++USER( smw.bim,$p1, [$r0], $p1) ! Store the next word ++ addi $p0, $p0, #-1 ! Decrease word count ++ bnez $p0, word_ctu ! Continue looping to copy all words ++ beqz $r2, ctu_exit ! No left bytes to copy ++byte_ctu: ++ lbi.bi $p1, [$r1], #1 ! Load the next byte ++USER( sbi.bi, $p1, [$r0], #1) ! Store the next byte ++ addi $r2, $r2, #-1 ! Decrease byte count ++ bnez $r2, byte_ctu ! Continue looping to clear all left bytes ++ctu_exit: ++ move $r0, $r2 ! Set return value ++ pop $r2 ++ pop $r2 ! Pop saved $r0 to $r2 to not corrupt return value ++ ret ++ ++ .section .fixup,"ax" ++ .align 0 ++9001: ++ pop $p1 ! Original $r2, n ++ pop $p0 ! Original $r0, void *to ++ sub $r1, $r0, $p0 ! Bytes copied ++ sub $r2, $p1, $r1 ! Bytes left to copy ++ push $lp ++ move $r0, $p0 ++ bal __memzero ! Clean up the memory ++ pop $lp ++ move $r0, $r2 ++ ret ++ ++ .previous ++ ++/* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n); ++ * Purpose : copy a block from user memory to kernel memory ++ * Params : to - kernel memory ++ * : from - user memory ++ * : n - number of bytes to copy ++ * Returns : Number of bytes NOT copied. ++ */ ++ ++ ++ENTRY(__arch_copy_from_user) ++ push $r1 ++ push $r2 ++ beqz $r2, cfu_exit ++ srli $p0, $r2, #2 ! $p0 = number of word to clear ++ andi $r2, $r2, #3 ! Bytes less than a word to copy ++ beqz $p0, byte_cfu ! Only less than a word to copy ++word_cfu: ++USER( lmw.bim,$p1, [$r1], $p1) ! Load the next word ++ smw.bim $p1, [$r0], $p1 ! Store the next word ++ addi $p0, $p0, #-1 ! Decrease word count ++ bnez $p0, word_cfu ! Continue looping to copy all words ++ beqz $r2, cfu_exit ! No left bytes to copy ++byte_cfu: ++USER( lbi.bi, $p1, [$r1], #1) ! Load the next byte ++ sbi.bi $p1, [$r0], #1 ! Store the next byte ++ addi $r2, $r2, #-1 ! Decrease byte count ++ bnez $r2, byte_cfu ! Continue looping to clear all left bytes ++cfu_exit: ++ move $r0, $r2 ! Set return value ++ pop $r2 ++ pop $r1 ++ ret ++ ++ .section .fixup,"ax" ++ .align 0 ++ /* ++ * We took an exception. $r0 contains a pointer to ++ * the byte not copied. ++ */ ++9001: ++ pop $p1 ! Original $r2, n ++ pop $p0 ! Original $r0, void *to ++ sub $r1, $r1, $p0 ! Bytes copied ++ sub $r2, $p1, $r1 ! Bytes left to copy ++ push $lp ++ bal __memzero ! Clean up the memory ++ pop $lp ++ move $r0, $r2 ++ ret ++ .previous ++ ++/* Prototype: int __arch_clear_user(void *addr, size_t sz) ++ * Purpose : clear some user memory ++ * Params : addr - user memory address to clear ++ * : sz - number of bytes to clear ++ * Returns : number of bytes NOT cleared ++ */ ++ .align 5 ++ENTRY(__arch_clear_user) ++ pushm $r0, $r1 ++ beqz $r1, clear_exit ++ xor $p1, $p1, $p1 ! Use $p1=0 to clear mem ++ srli $p0, $r1, #2 ! $p0 = number of word to clear ++ andi $r1, $r1, #3 ! Bytes less than a word to copy ++ beqz $p0, byte_clear ! Only less than a word to clear ++word_clear: ++USER( smw.bim,$p1, [$r0], $p1) ! Clear the word ++ addi $p0, $p0, #-1 ! Decrease word count ++ bnez $p0, word_clear ! Continue looping to clear all words ++ beqz $r1, clear_exit ! No left bytes to copy ++byte_clear: ++USER( sbi.bi, $p1, [$r0], #1) ! Clear the byte ++ addi $r1, $r1, #-1 ! Decrease byte count ++ bnez $r1, byte_clear ! Continue looping to clear all left bytes ++clear_exit: ++ move $r0, $r1 ! Set return value ++ pop $r1 ++ pop $r1 ! Pop saved $r0 to $r1 to not corrupt return value ++ ret ++ ++ .section .fixup,"ax" ++ .align 0 ++9001: ++ popm $p0, $p1 ! $p0 = original $r0, *addr, $p1 = original $r1, n ++ sub $p0, $r0, $p0 ! Bytes copied ++ sub $r0, $p1, $p0 ! Bytes left to copy ++ ret ++ .previous ++ +diff -Nur linux-3.4.110.orig/arch/nds32/lib/udivmod.c linux-3.4.110/arch/nds32/lib/udivmod.c +--- linux-3.4.110.orig/arch/nds32/lib/udivmod.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/udivmod.c 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,12 @@ ++extern unsigned long udivmodsi4(unsigned long num, unsigned long den, ++ int modwanted); ++ ++long __udivsi3(long a, long b) ++{ ++ return udivmodsi4(a, b, 0); ++} ++ ++long __umodsi3(long a, long b) ++{ ++ return udivmodsi4(a, b, 1); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/lib/udivmodsi4.c linux-3.4.110/arch/nds32/lib/udivmodsi4.c +--- linux-3.4.110.orig/arch/nds32/lib/udivmodsi4.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/lib/udivmodsi4.c 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,21 @@ ++unsigned long udivmodsi4(unsigned long num, unsigned long den, int modwanted) ++{ ++ unsigned long bit = 1; ++ unsigned long res = 0; ++ ++ while (den < num && bit && !(den & (1L << 31))) { ++ den <<= 1; ++ bit <<= 1; ++ } ++ while (bit) { ++ if (num >= den) { ++ num -= den; ++ res |= bit; ++ } ++ bit >>= 1; ++ den >>= 1; ++ } ++ if (modwanted) ++ return num; ++ return res; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/Makefile linux-3.4.110/arch/nds32/Makefile +--- linux-3.4.110.orig/arch/nds32/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/Makefile 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,100 @@ ++# ++# arch/nds32/Makefile ++# ++# 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) 1995-2001 by Russell King ++ ++LDFLAGS_vmlinux :=-nostdlib --no-undefined -X ++OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S ++GZFLAGS :=-9 ++KBUILD_CFLAGS +=-pipe -mno-sched-prolog-epilog ++ ++# Do not use arch/nds32/defconfig - it's always outdated. ++# Select a platform tht is kept up-to-date ++KBUILD_DEFCONFIG := orca_defconfig ++ ++ifeq ($(CONFIG_FRAME_POINTER),y) ++KBUILD_CFLAGS +=-fno-omit-frame-pointer ++endif ++ ++comma = , ++ ++# This selects which instruction set is used. ++# Note that GCC does not numerically define an architecture version ++# macro, but instead defines a whole series of macros which makes ++# testing for a specific architecture or later rather impossible. ++arch-y +=-D__nds32__ ++gcc_ver :=$(shell $(CC) -E -dM -xc /dev/null | grep __VERSION__ | sed 's/\#define __VERSION__ //') ++ifeq ($(shell expr `echo $(gcc_ver)` \>= 4.9.2 ), 1) ++arch-y += \ ++ $(shell $(CC) -E -dM -xc /dev/null | \ ++ grep -o -m1 NDS32_EXT_FPU_SP | \ ++ sed -e 's/NDS32_EXT_FPU_SP/-mno-ext-fpu-sp -mfloat-abi=soft/') \ ++ $(shell $(CC) -E -dM -xc /dev/null | \ ++ grep -o -m1 NDS32_EXT_FPU_DP | \ ++ sed -e 's/NDS32_EXT_FPU_DP/-mno-ext-fpu-dp -mfloat-abi=soft/') ++tune-y =-D__OPTIMIZE__ -mcmodel=large -D__ARCH_WANT_SYS_WAITPID ++else ++$(shell echo $(__VERSION__)) ++arch-y += $(shell $(CC) -E -dM -xc /dev/null | grep -o -m1 NDS32_EXT_FPU_SP | \ ++ sed -e 's/NDS32_EXT_FPU_SP/-mno-ext-fpu-sp/') \ ++ $(shell $(CC) -E -dM -xc /dev/null | grep -o -m1 NDS32_EXT_FPU_DP | \ ++ sed -e 's/NDS32_EXT_FPU_DP/-mno-ext-fpu-dp/') \ ++ $(shell $(CC) -E -dM -xc /dev/null | grep -o -m1 NDS32_ABI | \ ++ sed -e 's/NDS32_ABI/-mabi=2/') ++tune-y =-D__OPTIMIZE__ -G0 -D__ARCH_WANT_SYS_WAITPID -D_GCC444 ++endif ++ ++# This is a workaround for FUNCTION_TRACER because v3push will push $fp, $gp and $lp. ++ifdef CONFIG_FUNCTION_TRACER ++arch-y += -mno-v3push ++endif ++# This selects how we optimise for the processor. ++# Need -Unds32 for gcc < 3.x ++CHECKFLAGS += -D__nds32__ ++ ++KBUILD_CFLAGS +=$(CFLAGS_ABI) $(arch-y) $(tune-y) -Unds32 -DSTRICT_MM_TYPECHECKS # for c-style checking for page.h ++KBUILD_AFLAGS +=$(AFLAGS_ABI) $(arch-y) $(tune-y) ++ ++#Default value ++head-y := arch/nds32/kernel/head.o arch/nds32/kernel/init_task.o ++textaddr-y := 0xC000C000 ++ ++TEXTADDR := $(textaddr-y) ++ ++export TEXTADDR DATAADDR GZFLAGS ++ ++ ++# If we have a machine-specific directory, then include it in the build. ++core-y += arch/nds32/kernel/ arch/nds32/mm/ ++core-y += arch/nds32/platforms/ ++core-$(CONFIG_FPU) += arch/nds32/math-emu/ ++ ++drivers-$(CONFIG_OPROFILE) += arch/nds32/oprofile/ ++ ++libs-y += arch/nds32/lib/ ++ ++boot := arch/nds32/boot ++ ++.PHONY: FORCE ++ ++Image: vmlinux ++ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ ++ ++CLEAN_FILES += include/asm-nds32/constants.h* ++ ++# We use MRPROPER_FILES and CLEAN_FILES now ++archclean: ++ $(Q)$(MAKE) $(clean)=$(boot) ++ ++.PHONY: arch/nds32/kernel/asm-offsets.s ++arch/nds32/kernel/asm-offsets.s: arch/nds32/kernel/asm-offsets.c ++ $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) ++ ++ ++define archhelp ++ echo ' Image - kernel image (arch/$(ARCH)/boot/Image)' ++endef +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_add.c linux-3.4.110/arch/nds32/math-emu/dp_add.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_add.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_add.c 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,179 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y) ++{ ++ COMPXDP; ++ COMPYDP; ++ ++ EXPLODEXDP; ++ EXPLODEYDP; ++ ++ CLEARCX; ++ ++ FLUSHXDP; ++ FLUSHYDP; ++ ++ switch (CLPAIR(xc, yc)) { ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_nanxcpt(ieee754dp_indef(), "add", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): ++ return x; ++ ++ /* Infinity handling ++ */ ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): ++ if (xs == ys) ++ return x; ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_xcpt(ieee754dp_indef(), "add", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): ++ return x; ++ ++ /* Zero handling ++ */ ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): ++ if (xs == ys) ++ return x; ++ else ++ return ieee754dp_zero(ieee754_csr.rm == IEEE754_RD); ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): ++ return x; ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): ++ DPDNORMX; ++ ++ /* FALL THROUGH */ ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): ++ DPDNORMY; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): ++ DPDNORMX; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): ++ break; ++ } ++ assert(xm & DP_HIDDEN_BIT); ++ assert(ym & DP_HIDDEN_BIT); ++ ++ /* provide guard,round and stick bit space */ ++ xm <<= 3; ++ ym <<= 3; ++ ++ if (xe > ye) { ++ /* have to shift y fraction right to align ++ */ ++ int s = xe - ye; ++ ym = XDPSRS(ym, s); ++ ye += s; ++ } else if (ye > xe) { ++ /* have to shift x fraction right to align ++ */ ++ int s = ye - xe; ++ xm = XDPSRS(xm, s); ++ xe += s; ++ } ++ assert(xe == ye); ++ assert(xe <= DP_EMAX); ++ ++ if (xs == ys) { ++ /* generate 28 bit result of adding two 27 bit numbers ++ * leaving result in xm,xs,xe ++ */ ++ xm = xm + ym; ++ xe = xe; ++ xs = xs; ++ ++ if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ ++ xm = XDPSRS1(xm); ++ xe++; ++ } ++ } else { ++ if (xm >= ym) { ++ xm = xm - ym; ++ xe = xe; ++ xs = xs; ++ } else { ++ xm = ym - xm; ++ xe = xe; ++ xs = ys; ++ } ++ if (xm == 0) ++ return ieee754dp_zero(ieee754_csr.rm == IEEE754_RD); ++ ++ /* normalize to rounding precision */ ++ while ((xm >> (DP_MBITS + 3)) == 0) { ++ xm <<= 1; ++ xe--; ++ } ++ ++ } ++ DPNORMRET2(xs, xe, xm, "add", x, y); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_cmp.c linux-3.4.110/arch/nds32/math-emu/dp_cmp.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_cmp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_cmp.c 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,66 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cmp, int sig) ++{ ++ COMPXDP; ++ COMPYDP; ++ ++ EXPLODEXDP; ++ EXPLODEYDP; ++ FLUSHXDP; ++ FLUSHYDP; ++ CLEARCX; /* Even clear inexact flag here */ ++ ++ if (ieee754dp_isnan(x) || ieee754dp_isnan(y)) { ++ if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN) ++ SETCX(IEEE754_INVALID_OPERATION); ++ if (cmp & IEEE754_CUN) ++ return 1; ++ if (cmp & (IEEE754_CLT | IEEE754_CGT)) { ++ if (sig && SETANDTESTCX(IEEE754_INVALID_OPERATION)) ++ return ieee754si_xcpt(0, "fcmpf", x); ++ } ++ return 0; ++ } else { ++ s64 vx = x.bits; ++ s64 vy = y.bits; ++ ++ if (vx < 0) ++ vx = -vx ^ DP_SIGN_BIT; ++ if (vy < 0) ++ vy = -vy ^ DP_SIGN_BIT; ++ ++ if (vx < vy) ++ return (cmp & IEEE754_CLT) != 0; ++ else if (vx == vy) ++ return (cmp & IEEE754_CEQ) != 0; ++ else ++ return (cmp & IEEE754_CGT) != 0; ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_div.c linux-3.4.110/arch/nds32/math-emu/dp_div.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_div.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_div.c 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,155 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y) ++{ ++ COMPXDP; ++ COMPYDP; ++ ++ EXPLODEXDP; ++ EXPLODEYDP; ++ ++ CLEARCX; ++ ++ FLUSHXDP; ++ FLUSHYDP; ++ ++ switch (CLPAIR(xc, yc)) { ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_nanxcpt(ieee754dp_indef(), "div", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): ++ return x; ++ ++ /* Infinity handling ++ */ ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): ++ return ieee754dp_zero(xs ^ ys); ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): ++ return ieee754dp_inf(xs ^ ys); ++ ++ /* Zero handling ++ */ ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_xcpt(ieee754dp_indef(), "div", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): ++ SETCX(IEEE754_ZERO_DIVIDE); ++ return ieee754dp_xcpt(ieee754dp_inf(xs ^ ys), "div", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): ++ return ieee754dp_zero(xs == ys ? 0 : 1); ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): ++ DPDNORMX; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): ++ DPDNORMY; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): ++ DPDNORMX; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): ++ break; ++ } ++ assert(xm & DP_HIDDEN_BIT); ++ assert(ym & DP_HIDDEN_BIT); ++ ++ /* provide rounding space */ ++ xm <<= 3; ++ ym <<= 3; ++ ++ { ++ /* now the dirty work */ ++ ++ u64 rm = 0; ++ int re = xe - ye; ++ u64 bm; ++ ++ for (bm = DP_MBIT(DP_MBITS + 2); bm; bm >>= 1) { ++ if (xm >= ym) { ++ xm -= ym; ++ rm |= bm; ++ if (xm == 0) ++ break; ++ } ++ xm <<= 1; ++ } ++ rm <<= 1; ++ if (xm) ++ rm |= 1; /* have remainder, set sticky */ ++ ++ assert(rm); ++ ++ /* normalise rm to rounding precision ? ++ */ ++ while ((rm >> (DP_MBITS + 3)) == 0) { ++ rm <<= 1; ++ re--; ++ } ++ ++ DPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_fint.c linux-3.4.110/arch/nds32/math-emu/dp_fint.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_fint.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_fint.c 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,79 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++ieee754dp ieee754dp_fint(int x) ++{ ++ u64 xm; ++ int xe; ++ int xs; ++ ++ CLEARCX; ++ ++ if (x == 0) ++ return ieee754dp_zero(0); ++ if (x == 1 || x == -1) ++ return ieee754dp_one(x < 0); ++ if (x == 10 || x == -10) ++ return ieee754dp_ten(x < 0); ++ ++ xs = (x < 0); ++ if (xs) { ++ if (x == (1 << 31)) ++ xm = ((unsigned)1 << 31); /* max neg can't be safely negated */ ++ else ++ xm = -x; ++ } else { ++ xm = x; ++ } ++ ++#if 1 ++ /* normalize - result can never be inexact or overflow */ ++ xe = DP_MBITS; ++ while ((xm >> DP_MBITS) == 0) { ++ xm <<= 1; ++ xe--; ++ } ++ return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); ++#else ++ /* normalize */ ++ xe = DP_MBITS + 3; ++ while ((xm >> (DP_MBITS + 3)) == 0) { ++ xm <<= 1; ++ xe--; ++ } ++ DPNORMRET1(xs, xe, xm, "fint", x); ++#endif ++} ++ ++ieee754dp ieee754dp_funs(unsigned int u) ++{ ++ if ((int)u < 0) ++ return ieee754dp_add(ieee754dp_1e31(), ++ ieee754dp_fint(u & ~(1 << 31))); ++ return ieee754dp_fint(u); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_flong.c linux-3.4.110/arch/nds32/math-emu/dp_flong.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_flong.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_flong.c 2016-04-07 10:20:50.958081643 +0200 +@@ -0,0 +1,77 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++ieee754dp ieee754dp_flong(s64 x) ++{ ++ u64 xm; ++ int xe; ++ int xs; ++ ++ CLEARCX; ++ ++ if (x == 0) ++ return ieee754dp_zero(0); ++ if (x == 1 || x == -1) ++ return ieee754dp_one(x < 0); ++ if (x == 10 || x == -10) ++ return ieee754dp_ten(x < 0); ++ ++ xs = (x < 0); ++ if (xs) { ++ if (x == (1ULL << 63)) ++ xm = (1ULL << 63); /* max neg can't be safely negated */ ++ else ++ xm = -x; ++ } else { ++ xm = x; ++ } ++ ++ /* normalize */ ++ xe = DP_MBITS + 3; ++ if (xm >> (DP_MBITS + 1 + 3)) { ++ /* shunt out overflow bits */ ++ while (xm >> (DP_MBITS + 1 + 3)) { ++ XDPSRSX1(); ++ } ++ } else { ++ /* normalize in grs extended double precision */ ++ while ((xm >> (DP_MBITS + 3)) == 0) { ++ xm <<= 1; ++ xe--; ++ } ++ } ++ DPNORMRET1(xs, xe, xm, "dp_flong", x); ++} ++ ++ieee754dp ieee754dp_fulong(u64 u) ++{ ++ if ((s64) u < 0) ++ return ieee754dp_add(ieee754dp_1e63(), ++ ieee754dp_flong(u & ~(1ULL << 63))); ++ return ieee754dp_flong(u); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_frexp.c linux-3.4.110/arch/nds32/math-emu/dp_frexp.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_frexp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_frexp.c 2016-04-07 10:20:50.974082262 +0200 +@@ -0,0 +1,52 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++/* close to ieeep754dp_logb ++*/ ++ieee754dp ieee754dp_frexp(ieee754dp x, int *eptr) ++{ ++ COMPXDP; ++ CLEARCX; ++ EXPLODEXDP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ case IEEE754_CLASS_QNAN: ++ case IEEE754_CLASS_INF: ++ case IEEE754_CLASS_ZERO: ++ *eptr = 0; ++ return x; ++ case IEEE754_CLASS_DNORM: ++ DPDNORMX; ++ break; ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ *eptr = xe + 1; ++ return builddp(xs, -1 + DP_EBIAS, xm & ~DP_HIDDEN_BIT); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_fsp.c linux-3.4.110/arch/nds32/math-emu/dp_fsp.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_fsp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_fsp.c 2016-04-07 10:20:50.974082262 +0200 +@@ -0,0 +1,71 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++ieee754dp ieee754dp_fsp(ieee754sp x) ++{ ++ COMPXSP; ++ ++ EXPLODEXSP; ++ ++ CLEARCX; ++ ++ FLUSHXSP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_nanxcpt(ieee754dp_indef(), "fsp"); ++ case IEEE754_CLASS_QNAN: ++ return ieee754dp_nanxcpt(builddp(xs, ++ DP_EMAX + 1 + DP_EBIAS, ++ ((u64) xm ++ << (DP_MBITS - ++ SP_MBITS))), "fsp", x); ++ case IEEE754_CLASS_INF: ++ return ieee754dp_inf(xs); ++ case IEEE754_CLASS_ZERO: ++ return ieee754dp_zero(xs); ++ case IEEE754_CLASS_DNORM: ++ /* normalize */ ++ while ((xm >> SP_MBITS) == 0) { ++ xm <<= 1; ++ xe--; ++ } ++ break; ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ ++ /* CANT possibly overflow,underflow, or need rounding ++ */ ++ ++ /* drop the hidden bit */ ++ xm &= ~SP_HIDDEN_BIT; ++ ++ return builddp(xs, xe + DP_EBIAS, (u64) xm << (DP_MBITS - SP_MBITS)); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_logb.c linux-3.4.110/arch/nds32/math-emu/dp_logb.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_logb.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_logb.c 2016-04-07 10:20:50.974082262 +0200 +@@ -0,0 +1,53 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++ieee754dp ieee754dp_logb(ieee754dp x) ++{ ++ COMPXDP; ++ ++ CLEARCX; ++ ++ EXPLODEXDP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ return ieee754dp_nanxcpt(x, "logb", x); ++ case IEEE754_CLASS_QNAN: ++ return x; ++ case IEEE754_CLASS_INF: ++ return ieee754dp_inf(0); ++ case IEEE754_CLASS_ZERO: ++ return ieee754dp_inf(1); ++ case IEEE754_CLASS_DNORM: ++ DPDNORMX; ++ break; ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ return ieee754dp_fint(xe); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_modf.c linux-3.4.110/arch/nds32/math-emu/dp_modf.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_modf.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_modf.c 2016-04-07 10:20:50.974082262 +0200 +@@ -0,0 +1,79 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++/* modf function is always exact for a finite number ++*/ ++ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip) ++{ ++ COMPXDP; ++ ++ CLEARCX; ++ ++ EXPLODEXDP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ case IEEE754_CLASS_QNAN: ++ case IEEE754_CLASS_INF: ++ case IEEE754_CLASS_ZERO: ++ *ip = x; ++ return x; ++ case IEEE754_CLASS_DNORM: ++ /* far to small */ ++ *ip = ieee754dp_zero(xs); ++ return x; ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ if (xe < 0) { ++ *ip = ieee754dp_zero(xs); ++ return x; ++ } ++ if (xe >= DP_MBITS) { ++ *ip = x; ++ return ieee754dp_zero(xs); ++ } ++ /* generate ipart mantissa by clearing bottom bits ++ */ ++ *ip = builddp(xs, xe + DP_EBIAS, ++ ((xm >> (DP_MBITS - xe)) << (DP_MBITS - xe)) & ++ ~DP_HIDDEN_BIT); ++ ++ /* generate fpart mantissa by clearing top bits ++ * and normalizing (must be able to normalize) ++ */ ++ xm = (xm << (64 - (DP_MBITS - xe))) >> (64 - (DP_MBITS - xe)); ++ if (xm == 0) ++ return ieee754dp_zero(xs); ++ ++ while ((xm >> DP_MBITS) == 0) { ++ xm <<= 1; ++ xe--; ++ } ++ return builddp(xs, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_mul.c linux-3.4.110/arch/nds32/math-emu/dp_mul.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_mul.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_mul.c 2016-04-07 10:20:50.974082262 +0200 +@@ -0,0 +1,170 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y) ++{ ++ COMPXDP; ++ COMPYDP; ++ ++ EXPLODEXDP; ++ EXPLODEYDP; ++ ++ CLEARCX; ++ ++ FLUSHXDP; ++ FLUSHYDP; ++ ++ switch (CLPAIR(xc, yc)) { ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_nanxcpt(ieee754dp_indef(), "mul", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): ++ return x; ++ ++ /* Infinity handling */ ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_xcpt(ieee754dp_indef(), "mul", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): ++ return ieee754dp_inf(xs ^ ys); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): ++ return ieee754dp_zero(xs ^ ys); ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): ++ DPDNORMX; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): ++ DPDNORMY; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): ++ DPDNORMX; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): ++ break; ++ } ++ /* rm = xm * ym, re = xe+ye basicly */ ++ assert(xm & DP_HIDDEN_BIT); ++ assert(ym & DP_HIDDEN_BIT); ++ { ++ int re = xe + ye; ++ int rs = xs ^ ys; ++ u64 rm; ++ ++ /* shunt to top of word */ ++ xm <<= 64 - (DP_MBITS + 1); ++ ym <<= 64 - (DP_MBITS + 1); ++ ++ /* multiply 32bits xm,ym to give high 32bits rm with stickness ++ */ ++ ++ /* 32 * 32 => 64 */ ++#define DPXMULT(x, y) ((u64)(x) * (u64)y) ++ ++ { ++ unsigned lxm = xm; ++ unsigned hxm = xm >> 32; ++ unsigned lym = ym; ++ unsigned hym = ym >> 32; ++ u64 lrm; ++ u64 hrm; ++ ++ lrm = DPXMULT(lxm, lym); ++ hrm = DPXMULT(hxm, hym); ++ ++ { ++ u64 t = DPXMULT(lxm, hym); ++ { ++ u64 at = lrm + (t << 32); ++ hrm += at < lrm; ++ lrm = at; ++ } ++ hrm = hrm + (t >> 32); ++ } ++ ++ { ++ u64 t = DPXMULT(hxm, lym); ++ { ++ u64 at = lrm + (t << 32); ++ hrm += at < lrm; ++ lrm = at; ++ } ++ hrm = hrm + (t >> 32); ++ } ++ rm = hrm | (lrm != 0); ++ } ++ ++ /* ++ * sticky shift down to normal rounding precision ++ */ ++ if ((s64) rm < 0) { ++ rm = (rm >> (64 - (DP_MBITS + 1 + 3))) | ++ ((rm << (DP_MBITS + 1 + 3)) != 0); ++ re++; ++ } else { ++ rm = (rm >> (64 - (DP_MBITS + 1 + 3 + 1))) | ++ ((rm << (DP_MBITS + 1 + 3 + 1)) != 0); ++ } ++ assert(rm & (DP_HIDDEN_BIT << 3)); ++ DPNORMRET2(rs, re, rm, "mul", x, y); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_scalb.c linux-3.4.110/arch/nds32/math-emu/dp_scalb.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_scalb.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_scalb.c 2016-04-07 10:20:50.974082262 +0200 +@@ -0,0 +1,56 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++ieee754dp ieee754dp_scalb(ieee754dp x, int n) ++{ ++ COMPXDP; ++ ++ CLEARCX; ++ ++ EXPLODEXDP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ return ieee754dp_nanxcpt(x, "scalb", x, n); ++ case IEEE754_CLASS_QNAN: ++ case IEEE754_CLASS_INF: ++ case IEEE754_CLASS_ZERO: ++ return x; ++ case IEEE754_CLASS_DNORM: ++ DPDNORMX; ++ break; ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ DPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n); ++} ++ ++ieee754dp ieee754dp_ldexp(ieee754dp x, int n) ++{ ++ return ieee754dp_scalb(x, n); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_simple.c linux-3.4.110/arch/nds32/math-emu/dp_simple.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_simple.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_simple.c 2016-04-07 10:20:50.974082262 +0200 +@@ -0,0 +1,87 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++int ieee754dp_finite(ieee754dp x) ++{ ++ return DPBEXP(x) != DP_EMAX + 1 + DP_EBIAS; ++} ++ ++ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y) ++{ ++ CLEARCX; ++ DPSIGN(x) = DPSIGN(y); ++ return x; ++} ++ ++ieee754dp ieee754dp_neg(ieee754dp x) ++{ ++ COMPXDP; ++ ++ EXPLODEXDP; ++ CLEARCX; ++ FLUSHXDP; ++ ++ /* ++ * Invert the sign ALWAYS to prevent an endless recursion on ++ * pow() in libc. ++ */ ++ /* quick fix up */ ++ DPSIGN(x) ^= 1; ++ ++ if (xc == IEEE754_CLASS_SNAN) { ++ ieee754dp y = ieee754dp_indef(); ++ SETCX(IEEE754_INVALID_OPERATION); ++ DPSIGN(y) = DPSIGN(x); ++ return ieee754dp_nanxcpt(y, "neg"); ++ } ++ ++ if (ieee754dp_isnan(x)) /* but not infinity */ ++ return ieee754dp_nanxcpt(x, "neg", x); ++ return x; ++} ++ ++ieee754dp ieee754dp_abs(ieee754dp x) ++{ ++ COMPXDP; ++ ++ EXPLODEXDP; ++ CLEARCX; ++ FLUSHXDP; ++ ++ if (xc == IEEE754_CLASS_SNAN) { ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_nanxcpt(ieee754dp_indef(), "neg"); ++ } ++ ++ if (ieee754dp_isnan(x)) /* but not infinity */ ++ return ieee754dp_nanxcpt(x, "abs", x); ++ ++ /* quick fix up */ ++ DPSIGN(x) = 0; ++ return x; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_sqrt.c linux-3.4.110/arch/nds32/math-emu/dp_sqrt.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_sqrt.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_sqrt.c 2016-04-07 10:20:50.974082262 +0200 +@@ -0,0 +1,164 @@ ++/* IEEE754 floating point arithmetic ++ * double precision square root ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++static const unsigned table[] = { ++ 0, 1204, 3062, 5746, 9193, 13348, 18162, 23592, ++ 29598, 36145, 43202, 50740, 58733, 67158, 75992, ++ 85215, 83599, 71378, 60428, 50647, 41945, 34246, ++ 27478, 21581, 16499, 12183, 8588, 5674, 3403, ++ 1742, 661, 130 ++}; ++ ++ieee754dp ieee754dp_sqrt(ieee754dp x) ++{ ++ struct _ieee754_csr oldcsr; ++ ieee754dp y, z, t; ++ unsigned scalx, yh; ++ COMPXDP; ++ ++ EXPLODEXDP; ++ CLEARCX; ++ FLUSHXDP; ++ ++ /* x == INF or NAN? */ ++ switch (xc) { ++ case IEEE754_CLASS_QNAN: ++ /* sqrt(Nan) = Nan */ ++ return ieee754dp_nanxcpt(x, "sqrt"); ++ case IEEE754_CLASS_SNAN: ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); ++ case IEEE754_CLASS_ZERO: ++ /* sqrt(0) = 0 */ ++ return x; ++ case IEEE754_CLASS_INF: ++ if (xs) { ++ /* sqrt(-Inf) = Nan */ ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); ++ } ++ /* sqrt(+Inf) = Inf */ ++ return x; ++ case IEEE754_CLASS_DNORM: ++ DPDNORMX; ++ /* fall through */ ++ case IEEE754_CLASS_NORM: ++ if (xs) { ++ /* sqrt(-x) = Nan */ ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_nanxcpt(ieee754dp_indef(), "sqrt"); ++ } ++ break; ++ } ++ ++ /* save old csr; switch off INX enable & flag; set RN rounding */ ++ oldcsr = ieee754_csr; ++ ieee754_csr.mx &= ~IEEE754_INEXACT; ++ ieee754_csr.sx &= ~IEEE754_INEXACT; ++ ieee754_csr.rm = IEEE754_RN; ++ ++ /* adjust exponent to prevent overflow */ ++ scalx = 0; ++ if (xe > 512) { /* x > 2**-512? */ ++ xe -= 512; /* x = x / 2**512 */ ++ scalx += 256; ++ } else if (xe < -512) { /* x < 2**-512? */ ++ xe += 512; /* x = x * 2**512 */ ++ scalx -= 256; ++ } ++ ++ y = x = builddp(0, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); ++ ++ /* magic initial approximation to almost 8 sig. bits */ ++ yh = y.bits >> 32; ++ yh = (yh >> 1) + 0x1ff80000; ++ yh = yh - table[(yh >> 15) & 31]; ++ y.bits = ((u64) yh << 32) | (y.bits & 0xffffffff); ++ ++ /* Heron's rule once with correction to improve to ~18 sig. bits */ ++ /* t=x/y; y=y+t; py[n0]=py[n0]-0x00100006; py[n1]=0; */ ++ t = ieee754dp_div(x, y); ++ y = ieee754dp_add(y, t); ++ y.bits -= 0x0010000600000000LL; ++ y.bits &= 0xffffffff00000000LL; ++ ++ /* triple to almost 56 sig. bits: y ~= sqrt(x) to within 1 ulp */ ++ /* t=y*y; z=t; pt[n0]+=0x00100000; t+=z; z=(x-z)*y; */ ++ z = t = ieee754dp_mul(y, y); ++ t.parts.bexp += 0x001; ++ t = ieee754dp_add(t, z); ++ z = ieee754dp_mul(ieee754dp_sub(x, z), y); ++ ++ /* t=z/(t+x) ; pt[n0]+=0x00100000; y+=t; */ ++ t = ieee754dp_div(z, ieee754dp_add(t, x)); ++ t.parts.bexp += 0x001; ++ y = ieee754dp_add(y, t); ++ ++ /* twiddle last bit to force y correctly rounded */ ++ ++ /* set RZ, clear INEX flag */ ++ ieee754_csr.rm = IEEE754_RZ; ++ ieee754_csr.sx &= ~IEEE754_INEXACT; ++ ++ /* t=x/y; ...chopped quotient, possibly inexact */ ++ t = ieee754dp_div(x, y); ++ ++ if (ieee754_csr.sx & IEEE754_INEXACT || t.bits != y.bits) { ++ ++ if (!(ieee754_csr.sx & IEEE754_INEXACT)) ++ /* t = t-ulp */ ++ t.bits -= 1; ++ ++ /* add inexact to result status */ ++ oldcsr.cx |= IEEE754_INEXACT; ++ oldcsr.sx |= IEEE754_INEXACT; ++ ++ switch (oldcsr.rm) { ++ case IEEE754_RP: ++ y.bits += 1; ++ /* drop through */ ++ case IEEE754_RN: ++ t.bits += 1; ++ break; ++ } ++ ++ /* y=y+t; ...chopped sum */ ++ y = ieee754dp_add(y, t); ++ ++ /* adjust scalx for correctly rounded sqrt(x) */ ++ scalx -= 1; ++ } ++ ++ /* py[n0]=py[n0]+scalx; ...scale back y */ ++ y.parts.bexp += scalx; ++ ++ /* restore rounding mode, possibly set inexact */ ++ ieee754_csr = oldcsr; ++ ++ return y; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_sub.c linux-3.4.110/arch/nds32/math-emu/dp_sub.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_sub.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_sub.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,187 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y) ++{ ++ COMPXDP; ++ COMPYDP; ++ ++ EXPLODEXDP; ++ EXPLODEYDP; ++ ++ CLEARCX; ++ ++ FLUSHXDP; ++ FLUSHYDP; ++ ++ switch (CLPAIR(xc, yc)) { ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_nanxcpt(ieee754dp_indef(), "sub", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): ++ return x; ++ ++ /* Infinity handling ++ */ ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): ++ if (xs != ys) ++ return x; ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754dp_xcpt(ieee754dp_indef(), "sub", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): ++ return ieee754dp_inf(ys ^ 1); ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): ++ return x; ++ ++ /* Zero handling ++ */ ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): ++ if (xs != ys) ++ return x; ++ else ++ return ieee754dp_zero(ieee754_csr.rm == IEEE754_RD); ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): ++ return x; ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): ++ /* quick fix up */ ++ DPSIGN(y) ^= 1; ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): ++ DPDNORMX; ++ /* FAAL THOROUGH */ ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): ++ /* normalize ym,ye */ ++ DPDNORMY; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): ++ /* normalize xm,xe */ ++ DPDNORMX; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): ++ break; ++ } ++ /* flip sign of y and handle as add */ ++ ys ^= 1; ++ ++ assert(xm & DP_HIDDEN_BIT); ++ assert(ym & DP_HIDDEN_BIT); ++ ++ /* provide guard,round and stick bit dpace */ ++ xm <<= 3; ++ ym <<= 3; ++ ++ if (xe > ye) { ++ /* have to shift y fraction right to align ++ */ ++ int s = xe - ye; ++ ym = XDPSRS(ym, s); ++ ye += s; ++ } else if (ye > xe) { ++ /* have to shift x fraction right to align ++ */ ++ int s = ye - xe; ++ xm = XDPSRS(xm, s); ++ xe += s; ++ } ++ assert(xe == ye); ++ assert(xe <= DP_EMAX); ++ ++ if (xs == ys) { ++ /* generate 28 bit result of adding two 27 bit numbers ++ */ ++ xm = xm + ym; ++ xe = xe; ++ xs = xs; ++ ++ if (xm >> (DP_MBITS + 1 + 3)) { /* carry out */ ++ xm = XDPSRS1(xm); /* shift preserving sticky */ ++ xe++; ++ } ++ } else { ++ if (xm >= ym) { ++ xm = xm - ym; ++ xe = xe; ++ xs = xs; ++ } else { ++ xm = ym - xm; ++ xe = xe; ++ xs = ys; ++ } ++ if (xm == 0) { ++ if (ieee754_csr.rm == IEEE754_RD) ++ return ieee754dp_zero(1); /* round negative inf. => sign = -1 */ ++ else ++ return ieee754dp_zero(0); /* other round modes => sign = 1 */ ++ } ++ ++ /* normalize to rounding precision ++ */ ++ while ((xm >> (DP_MBITS + 3)) == 0) { ++ xm <<= 1; ++ xe--; ++ } ++ } ++ DPNORMRET2(xs, xe, xm, "sub", x, y); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_tint.c linux-3.4.110/arch/nds32/math-emu/dp_tint.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_tint.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_tint.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,121 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 <linux/kernel.h> ++#include "ieee754dp.h" ++ ++int ieee754dp_tint(ieee754dp x) ++{ ++ COMPXDP; ++ ++ CLEARCX; ++ ++ EXPLODEXDP; ++ FLUSHXDP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ case IEEE754_CLASS_QNAN: ++ case IEEE754_CLASS_INF: ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); ++ case IEEE754_CLASS_ZERO: ++ return 0; ++ case IEEE754_CLASS_DNORM: ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ if (xe > 31) { ++ /* Set invalid. We will only use overflow for floating ++ point overflow */ ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); ++ } ++ /* oh gawd */ ++ if (xe > DP_MBITS) { ++ xm <<= xe - DP_MBITS; ++ } else if (xe < DP_MBITS) { ++ u64 residue; ++ int round; ++ int sticky; ++ int odd; ++ ++ if (xe < -1) { ++ residue = xm; ++ round = 0; ++ sticky = residue != 0; ++ xm = 0; ++ } else { ++ residue = xm << (64 - DP_MBITS + xe); ++ round = (residue >> 63) != 0; ++ sticky = (residue << 1) != 0; ++ xm >>= DP_MBITS - xe; ++ } ++ /* Note: At this point upper 32 bits of xm are guaranteed ++ to be zero */ ++ odd = (xm & 0x1) != 0x0; ++ switch (ieee754_csr.rm) { ++ case IEEE754_RN: ++ if (round && (sticky || odd)) ++ xm++; ++ break; ++ case IEEE754_RZ: ++ break; ++ case IEEE754_RU: /* toward +Infinity */ ++ if ((round || sticky) && !xs) ++ xm++; ++ break; ++ case IEEE754_RD: /* toward -Infinity */ ++ if ((round || sticky) && xs) ++ xm++; ++ break; ++ } ++ /* look for valid corner case 0x80000000 */ ++ if ((xm >> 31) != 0 && (xs == 0 || xm != 0x80000000)) { ++ /* This can happen after rounding */ ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754si_xcpt(ieee754si_indef(), "dp_tint", x); ++ } ++ if (round || sticky) ++ SETCX(IEEE754_INEXACT); ++ } ++ if (xs) ++ return -xm; ++ else ++ return xm; ++} ++ ++unsigned int ieee754dp_tuns(ieee754dp x) ++{ ++ ieee754dp hb = ieee754dp_1e31(); ++ ++ /* what if x < 0 ?? */ ++ if (ieee754dp_lt(x, hb)) ++ return (unsigned)ieee754dp_tint(x); ++ ++ return (unsigned)ieee754dp_tint(ieee754dp_sub(x, hb)) | ++ ((unsigned)1 << 31); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/dp_tlong.c linux-3.4.110/arch/nds32/math-emu/dp_tlong.c +--- linux-3.4.110.orig/arch/nds32/math-emu/dp_tlong.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/dp_tlong.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,123 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++s64 ieee754dp_tlong(ieee754dp x) ++{ ++ COMPXDP; ++ ++ CLEARCX; ++ ++ EXPLODEXDP; ++ FLUSHXDP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ case IEEE754_CLASS_QNAN: ++ case IEEE754_CLASS_INF: ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); ++ case IEEE754_CLASS_ZERO: ++ return 0; ++ case IEEE754_CLASS_DNORM: ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ if (xe >= 63) { ++ /* look for valid corner case */ ++ if (xe == 63 && xs && xm == DP_HIDDEN_BIT) ++ return -0x8000000000000000LL; ++ /* Set invalid. We will only use overflow for floating ++ point overflow */ ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); ++ } ++ /* oh gawd */ ++ if (xe > DP_MBITS) { ++ xm <<= xe - DP_MBITS; ++ } else if (xe < DP_MBITS) { ++ u64 residue; ++ int round; ++ int sticky; ++ int odd; ++ ++ if (xe < -1) { ++ residue = xm; ++ round = 0; ++ sticky = residue != 0; ++ xm = 0; ++ } else { ++ /* Shifting a u64 64 times does not work, ++ * so we do it in two steps. Be aware that xe ++ * may be -1 */ ++ residue = xm << (xe + 1); ++ residue <<= 63 - DP_MBITS; ++ round = (residue >> 63) != 0; ++ sticky = (residue << 1) != 0; ++ xm >>= DP_MBITS - xe; ++ } ++ odd = (xm & 0x1) != 0x0; ++ switch (ieee754_csr.rm) { ++ case IEEE754_RN: ++ if (round && (sticky || odd)) ++ xm++; ++ break; ++ case IEEE754_RZ: ++ break; ++ case IEEE754_RU: /* toward +Infinity */ ++ if ((round || sticky) && !xs) ++ xm++; ++ break; ++ case IEEE754_RD: /* toward -Infinity */ ++ if ((round || sticky) && xs) ++ xm++; ++ break; ++ } ++ if ((xm >> 63) != 0) { ++ /* This can happen after rounding */ ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754di_xcpt(ieee754di_indef(), "dp_tlong", x); ++ } ++ if (round || sticky) ++ SETCX(IEEE754_INEXACT); ++ } ++ if (xs) ++ return -xm; ++ else ++ return xm; ++} ++ ++u64 ieee754dp_tulong(ieee754dp x) ++{ ++ ieee754dp hb = ieee754dp_1e63(); ++ ++ /* what if x < 0 ?? */ ++ if (ieee754dp_lt(x, hb)) ++ return (u64) ieee754dp_tlong(x); ++ ++ return (u64) ieee754dp_tlong(ieee754dp_sub(x, hb)) | (1ULL << 63); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/fpuemu.c linux-3.4.110/arch/nds32/math-emu/fpuemu.c +--- linux-3.4.110.orig/arch/nds32/math-emu/fpuemu.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/fpuemu.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,565 @@ ++/* ++ * linux/arch/nds32/math-emu/fpuemu.c: a nds32 coprocessor (fpu) instruction emulator ++ * ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com ++ * Copyright (C) 2000 MIPS Technologies, Inc. ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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. ++ * ++ * A complete emulator for MIPS coprocessor 1 instructions. This is ++ * required for #float(switch) or #float(trap), where it catches all ++ * COP1 instructions via the "CoProcessor Unusable" exception. ++ * ++ * More surprisingly it is also required for #float(ieee), to help out ++ * the hardware fpu at the boundaries of the IEEE-754 representation ++ * (denormalised values, infinities, underflow, etc). It is made ++ * quite nasty because emulation of some non-COP1 instructions is ++ * required, e.g. in branch delay slots. ++ * ++ * Note if you know that you won't have an fpu, then you'll get much ++ * better performance by compiling with -msoft-float! ++ */ ++#include <linux/sched.h> ++#include <linux/debugfs.h> ++ ++#include <asm/processor.h> ++#include <asm/ptrace.h> ++#include <asm/bitfield.h> ++#include <asm/uaccess.h> ++ ++#include "ieee754.h" ++#include "insn.h" ++#include "fpu_emulator.h" ++ ++/* Function which emulates a floating point instruction. */ ++ ++static int fpu_emu(struct pt_regs *, struct fpu_struct *, unsigned long); ++ ++/* Further private data for which no space exists in fpu_struct */ ++ ++struct fpu_emulator_stats fpuemustats; ++ ++/* rounding mode */ ++#define FPU_FPCSR_RN 0x0 /* nearest */ ++#define FPU_FPCSR_RU 0x1 /* towards +Infinity */ ++#define FPU_FPCSR_RD 0x2 /* towards -Infinity */ ++#define FPU_FPCSR_RZ 0x3 /* towards zero */ ++ ++/* Convert Mips rounding mode (0..3) to IEEE library modes. */ ++static const unsigned char ieee_rm[4] = { ++ [FPU_FPCSR_RN] = IEEE754_RN, ++ [FPU_FPCSR_RU] = IEEE754_RU, ++ [FPU_FPCSR_RD] = IEEE754_RD, ++ [FPU_FPCSR_RZ] = IEEE754_RZ, ++}; ++ ++/* Convert IEEE library modes to NDS32 rounding mode (0..3). */ ++static const unsigned char nds32_rm[4] = { ++ [IEEE754_RN] = FPU_FPCSR_RN, ++ [IEEE754_RZ] = FPU_FPCSR_RZ, ++ [IEEE754_RD] = FPU_FPCSR_RD, ++ [IEEE754_RU] = FPU_FPCSR_RU, ++}; ++ ++/* ++ * In the Linux kernel, we support selection of FPR format on the ++ * basis of the Status.FR bit. This does imply that, if a full 32 ++ * FPRs are desired, there needs to be a flip-flop that can be written ++ * to one at that bit position. In any case, O32 MIPS ABI uses ++ * only the even FPRs (Status.FR = 0). ++ */ ++ ++#define CP0_STATUS_FR_SUPPORT ++ ++#ifdef CP0_STATUS_FR_SUPPORT ++#define FR_BIT ST0_FR ++#else ++#define FR_BIT 0 ++#endif ++ ++#define SIFROMREG(si, x) ((si) = *((unsigned long *)ctx + x)) ++#define SITOREG(si, x) (*((unsigned long *)ctx + x)= (si)) ++ ++#ifdef __NDS32_EL__ ++#define DIFROMREG(di, x) ((di) = (unsigned long long)ptr[2*x] << 32 | (unsigned long long)ptr[2*x+1]) ++#define DITOREG(di, x) ptr[2*x] = (di) >> 32; ptr[2*x+1] = (unsigned long)(di) ++#else ++#define DIFROMREG(di, x) ((di) = (unsigned long long)ptr[2*x+1] << 32 | (unsigned long long)ptr[2*x]) ++#define DITOREG(di, x) ptr[2*x+1] = (di) >> 32; ptr[2*x] = (unsigned long)(di) ++#endif ++ ++#define SPFROMREG(sp, x) SIFROMREG((sp).bits, x) ++#define SPTOREG(sp, x) SITOREG((sp).bits, x) ++#define DPFROMREG(dp, x) DIFROMREG((dp).bits, x) ++#define DPTOREG(dp, x) DITOREG((dp).bits, x) ++ ++#define DEF3OP(name, p, f1, f2, f3) \ ++static ieee754##p fpemu_##p##_##name(ieee754##p r, ieee754##p s, \ ++ ieee754##p t) \ ++{ \ ++ struct _ieee754_csr ieee754_csr_save; \ ++ s = f1(s, t); \ ++ ieee754_csr_save = ieee754_csr; \ ++ s = f2(s, r); \ ++ ieee754_csr_save.cx |= ieee754_csr.cx; \ ++ ieee754_csr_save.sx |= ieee754_csr.sx; \ ++ s = f3(s); \ ++ ieee754_csr.cx |= ieee754_csr_save.cx; \ ++ ieee754_csr.sx |= ieee754_csr_save.sx; \ ++ return s; \ ++} ++ ++DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add,); ++DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub,); ++DEF3OP(nmadd, sp, ieee754sp_mul, ieee754sp_add, ieee754sp_neg); ++DEF3OP(nmsub, sp, ieee754sp_mul, ieee754sp_sub, ieee754sp_neg); ++DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add,); ++DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub,); ++DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg); ++DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg); ++ ++/* ++ * Emulate the floating point instruction w/ denorm input pointed at by IPC. ++ * According to spec, only FPU arithmetic, data format conversion, and compare instructions. ++ */ ++ ++static int fpuEmulate(struct pt_regs *regs, struct fpu_struct *fpu) ++{ ++ unsigned long insn = 0, addr = regs->NDS32_ipc; ++ unsigned long emulpc, contpc; ++ unsigned char *pc = (void *)&insn; ++ char c; ++ int i = 0; ++ ++ for (i = 0; i < 4; i++) { ++ if (__get_user(c, (unsigned char *)addr++)) ++ return SIGBUS; ++ *pc++ = c; ++ } ++ ++ insn = be32_to_cpu(insn); ++ ++ emulpc = regs->NDS32_ipc; ++ contpc = regs->NDS32_ipc + 4; ++ ++ fpuemustats.emulated++; ++ switch (NDS32Insn_OPCODE(insn)) { ++ case cop0_op: ++ switch (NDS32Insn_OPCODE_COP0(insn)) { ++ ++ case fs1_op: ++ case fs2_op: ++ case fd1_op: ++ case fd2_op: ++ { ++ int sig; ++ ++ /* a real fpu computation instruction */ ++ if ((sig = fpu_emu(regs, fpu, insn))) ++ return sig; ++ } ++ break; ++ ++ default: ++ return SIGILL; ++ } ++ break; ++ default: ++ return SIGILL; ++ } ++ ++ /* we did it !! */ ++ regs->NDS32_ipc = contpc; ++ ++ return 0; ++} ++ ++/* ++ * Conversion table from NDS32 fcmp TYP ++ * cond = ieee754dp_cmp(x,y,IEEE754_UN,sig); ++ */ ++static const unsigned char cmptab[8] = { ++ IEEE754_CEQ, ++ IEEE754_CLT, ++ IEEE754_CLT | IEEE754_CEQ, ++ IEEE754_CUN, ++ 0, ++ 0, ++ 0, ++ 0, ++}; ++ ++/* ++ * Emulate a single FPU arithmetic instruction. ++ */ ++static int fpu_emu(struct pt_regs *xcp, struct fpu_struct *ctx, ++ unsigned long insn) ++{ ++ int rfmt; /* resulting format */ ++ unsigned rfpcsr = 0; /* resulting csr */ ++ unsigned long *ptr = (unsigned long *)ctx; ++ union { ++ ieee754dp d; ++ ieee754sp s; ++ int w; ++ } rv; /* resulting value */ ++ ++ fpuemustats.fpuops++; ++ switch (rfmt = NDS32Insn_OPCODE_COP0(insn)) { ++ case fs1_op:{ ++ union { ++ ieee754sp(*t) (ieee754sp, ieee754sp, ieee754sp); ++ ieee754sp(*b) (ieee754sp, ieee754sp); ++ ieee754sp(*u) (ieee754sp); ++ } handler; ++ ++ switch (NDS32Insn_OPCODE_BIT69(insn)) { ++ case fadds_op: ++ handler.b = ieee754sp_add; ++ goto scopbop; ++ case fsubs_op: ++ handler.b = ieee754sp_sub; ++ goto scopbop; ++ case fmadds_op: ++ handler.t = fpemu_sp_madd; ++ goto scoptop; ++ case fmsubs_op: ++ handler.t = fpemu_sp_msub; ++ goto scoptop; ++ case fnmadds_op: ++ handler.t = fpemu_sp_nmadd; ++ goto scoptop; ++ case fnmsubs_op: ++ handler.t = fpemu_sp_nmsub; ++ goto scoptop; ++ case fmuls_op: ++ handler.b = ieee754sp_mul; ++ goto scopbop; ++ case fdivs_op: ++ handler.b = ieee754sp_div; ++ goto scopbop; ++ ++ /* binary op on handler */ ++scoptop: ++ { ++ ieee754sp fd, fr, fs, ft; ++ ++ SPFROMREG(fr, ++ NDS32Insn_OPCODE_Rt(insn)); ++ SPFROMREG(fs, ++ NDS32Insn_OPCODE_Ra(insn)); ++ SPFROMREG(ft, ++ NDS32Insn_OPCODE_Rb(insn)); ++ fd = (*handler.t) (fr, fs, ft); ++ SPTOREG(fd, NDS32Insn_OPCODE_Rt(insn)); ++ } ++scopbop: ++ { ++ ieee754sp fs, ft; ++ ++ SPFROMREG(fs, ++ NDS32Insn_OPCODE_Ra(insn)); ++ SPFROMREG(ft, ++ NDS32Insn_OPCODE_Rb(insn)); ++ ++ rv.s = (*handler.b) (fs, ft); ++ goto copcsr; ++ } ++scopuop: ++ { ++ ieee754sp fs; ++ ++ SPFROMREG(fs, ++ NDS32Insn_OPCODE_Ra(insn)); ++ rv.s = (*handler.u) (fs); ++ goto copcsr; ++ } ++copcsr: ++ if (ieee754_cxtest(IEEE754_INEXACT)) ++ rfpcsr |= FPCSR_mskIEX; ++ if (ieee754_cxtest(IEEE754_UNDERFLOW)) ++ rfpcsr |= FPCSR_mskUDF; ++ if (ieee754_cxtest(IEEE754_OVERFLOW)) ++ rfpcsr |= FPCSR_mskOVF; ++ if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) ++ rfpcsr |= FPCSR_mskDBZ; ++ if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) ++ rfpcsr |= FPCSR_mskIVO; ++ break; ++ ++ case fs1_f2op_op: ++ switch (NDS32Insn_OPCODE_BIT1014(insn)) { ++ case fs2d_op:{ ++ ieee754sp fs; ++ SPFROMREG(fs, ++ NDS32Insn_OPCODE_Ra ++ (insn)); ++ rv.d = ieee754dp_fsp(fs); ++ rfmt = fd1_op; ++ goto copcsr; ++ } ++ case fsqrts_op: ++ handler.u = ieee754sp_sqrt; ++ goto scopuop; ++ case fabss_op: ++ handler.u = ieee754sp_abs; ++ goto scopuop; ++ default: ++ return SIGILL; ++ } ++ default: ++ return SIGILL; ++ } ++ break; ++ } ++ ++ case fs2_op: ++ switch (NDS32Insn_OPCODE_BIT69(insn)) { ++ case fcmpeqs_op: ++ case fcmpeqs_e_op: ++ case fcmplts_op: ++ case fcmplts_e_op: ++ case fcmples_op: ++ case fcmples_e_op: ++ case fcmpuns_op: ++ case fcmpuns_e_op: ++ { ++ unsigned int cmpop = ++ NDS32Insn_OPCODE_BIT69(insn); ++ if (cmpop < 0x8) { ++ ieee754sp fs, ft; ++ ++ SPFROMREG(fs, ++ NDS32Insn_OPCODE_Ra(insn)); ++ SPFROMREG(ft, ++ NDS32Insn_OPCODE_Rb(insn)); ++ rv.w = ++ ieee754sp_cmp(fs, ft, ++ cmptab[(cmpop >> 1) & ++ 0x7], ++ cmpop & 0x1); ++ if ((cmpop & 0x1) ++ && ++ ieee754_cxtest ++ (IEEE754_INVALID_OPERATION)) ++ rfpcsr = FPCSR_mskIVO; ++ else ++ goto copcsr; ++ } else ++ return SIGILL; ++ } ++ break; ++ ++ default: ++ return SIGILL; ++ } ++ break; ++ ++ case fd1_op: ++ { ++ union { ++ ieee754dp(*t) (ieee754dp, ieee754dp, ieee754dp); ++ ieee754dp(*b) (ieee754dp, ieee754dp); ++ ieee754dp(*u) (ieee754dp); ++ } handler; ++ ++ switch (NDS32Insn_OPCODE_BIT69(insn)) { ++ case faddd_op: ++ handler.b = ieee754dp_add; ++ goto dcopbop; ++ case fsubd_op: ++ handler.b = ieee754dp_sub; ++ goto dcopbop; ++ case fmaddd_op: ++ handler.t = fpemu_dp_madd; ++ goto tdcoptop; ++ case fmsubd_op: ++ handler.t = fpemu_dp_msub; ++ goto tdcoptop; ++ case fnmaddd_op: ++ handler.t = fpemu_dp_nmadd; ++ goto tdcoptop; ++ case fnmsubd_op: ++ handler.t = fpemu_dp_nmsub; ++ goto tdcoptop; ++ ++tdcoptop: ++ { ++ ieee754dp fd, fr, fs, ft; ++ ++ DPFROMREG(fr, ++ NDS32Insn_OPCODE_Rt(insn)); ++ DPFROMREG(fs, ++ NDS32Insn_OPCODE_Ra(insn)); ++ DPFROMREG(ft, ++ NDS32Insn_OPCODE_Rb(insn)); ++ fd = (*handler.t) (fr, fs, ft); ++ DPTOREG(fd, NDS32Insn_OPCODE_Rt(insn)); ++ goto copcsr; ++ } ++ ++ case fmuld_op: ++ handler.b = ieee754dp_mul; ++ goto dcopbop; ++ case fdivd_op: ++ handler.b = ieee754dp_div; ++ goto dcopbop; ++ ++ /* binary op on handler */ ++dcopbop: { ++ ieee754dp fs, ft; ++ ++ DPFROMREG(fs, ++ NDS32Insn_OPCODE_Ra(insn)); ++ DPFROMREG(ft, ++ NDS32Insn_OPCODE_Rb(insn)); ++ ++ rv.d = (*handler.b) (fs, ft); ++ goto copcsr; ++ } ++dcopuop: { ++ ieee754dp fs; ++ ++ DPFROMREG(fs, ++ NDS32Insn_OPCODE_Ra(insn)); ++ rv.d = (*handler.u) (fs); ++ goto copcsr; ++ } ++ ++ case fd1_f2op_op: ++ switch (NDS32Insn_OPCODE_BIT1014(insn)) { ++ case fd2s_op:{ ++ ieee754dp fs; ++ ++ DPFROMREG(fs, ++ NDS32Insn_OPCODE_Ra ++ (insn)); ++ rv.s = ieee754sp_fdp(fs); ++ rfmt = fd1_op; ++ goto copcsr; ++ } ++ case fsqrtd_op: ++ handler.u = ieee754dp_sqrt; ++ goto dcopuop; ++ case fabsd_op: ++ handler.u = ieee754dp_abs; ++ goto dcopuop; ++ default: ++ return SIGILL; ++ } ++ default: ++ return SIGILL; ++ } ++ break; ++ } ++ ++ case fd2_op: ++ switch (NDS32Insn_OPCODE_BIT69(insn)) { ++ case fcmpeqd_op: ++ case fcmpeqd_e_op: ++ case fcmpltd_op: ++ case fcmpltd_e_op: ++ case fcmpled_op: ++ case fcmpled_e_op: ++ case fcmpund_op: ++ case fcmpund_e_op: ++ { ++ unsigned cmpop = NDS32Insn_OPCODE_BIT69(insn); ++ if (cmpop < 0x8) { ++ ieee754dp fs, ft; ++ ++ DPFROMREG(fs, ++ NDS32Insn_OPCODE_Ra(insn)); ++ DPFROMREG(ft, ++ NDS32Insn_OPCODE_Rb(insn)); ++ rv.w = ++ ieee754dp_cmp(fs, ft, ++ cmptab[(cmpop >> 1) & ++ 0x7], ++ cmpop & 0x1); ++ rfmt = fs2_op; ++ if ((cmpop & 0x1) ++ && ++ ieee754_cxtest ++ (IEEE754_INVALID_OPERATION)) ++ rfpcsr = FPCSR_mskIVO; ++ else ++ goto copcsr; ++ } else ++ return SIGILL; ++ } ++ break; ++ default: ++ return SIGILL; ++ } ++ break; ++ ++ default: ++ return SIGILL; ++ } ++ ++ /* ++ * Now we can safely write the result back to the register file. ++ */ ++ switch (rfmt) { ++ case fd1_op: ++ case fd2_op: ++ DPTOREG(rv.d, NDS32Insn_OPCODE_Rt(insn)); ++ break; ++ case fs1_op: ++ case fs2_op: ++ SPTOREG(rv.s, NDS32Insn_OPCODE_Rt(insn)); ++ break; ++ default: ++ return SIGILL; ++ } ++ ++ /* ++ * Update the fpu CSR register for this operation. ++ * If an exception is required, generate a tidy SIGFPE exception, ++ * without updating the result register. ++ * Note: cause exception bits do not accumulate, they are rewritten ++ * for each op; only the flag/sticky bits accumulate. ++ */ ++ ctx->fpcsr = (ctx->fpcsr & ~FPCSR_mskALL) | rfpcsr; ++ if ((ctx->fpcsr << 5) & ctx->fpcsr & FPCSR_mskALLE) { ++ return SIGFPE; ++ } ++ ++ return 0; ++} ++ ++int do_fpu_denorm(struct pt_regs *regs, struct fpu_struct *fpu) ++{ ++ int sig = 0; ++ ++ /* ++ * The 'ieee754_csr' is an alias of ++ * fpcsr->RM. No need to copy fpcsr->RM to ++ * ieee754_csr. But ieee754_csr.rm is ieee ++ * library modes. (not NDS32 rounding mode) ++ */ ++ /* convert to ieee library modes */ ++ ieee754_csr.rm = ieee_rm[ieee754_csr.rm]; ++ sig = fpuEmulate(regs, fpu); ++ /* revert to NDS32 rounding mode */ ++ ieee754_csr.rm = nds32_rm[ieee754_csr.rm]; ++ ++ return sig; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/fpu_emulator.h linux-3.4.110/arch/nds32/math-emu/fpu_emulator.h +--- linux-3.4.110.orig/arch/nds32/math-emu/fpu_emulator.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/fpu_emulator.h 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,36 @@ ++/* ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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. ++ * ++ * Further private data for which no space exists in mips_fpu_struct. ++ * This should be subsumed into the mips_fpu_struct structure as ++ * defined in processor.h as soon as the absurd wired absolute assembler ++ * offsets become dynamic at compile time. ++ * ++ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com ++ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. ++ */ ++#ifndef _ASM_FPU_EMULATOR_H ++#define _ASM_FPU_EMULATOR_H ++ ++struct fpu_emulator_stats { ++ unsigned int emulated; ++ unsigned int loads; ++ unsigned int stores; ++ unsigned int fpuops; ++ unsigned int errors; ++}; ++ ++extern struct fpu_emulator_stats fpuemustats; ++ ++#endif /* _ASM_FPU_EMULATOR_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/ieee754.c linux-3.4.110/arch/nds32/math-emu/ieee754.c +--- linux-3.4.110.orig/arch/nds32/math-emu/ieee754.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/ieee754.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,125 @@ ++/* ieee754 floating point arithmetic ++ * single and double precision ++ * ++ * BUGS ++ * not much dp done ++ * doesn't generate IEEE754_INEXACT ++ * ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754int.h" ++#include "ieee754sp.h" ++#include "ieee754dp.h" ++ ++#define DP_EBIAS 1023 ++#define DP_EMIN (-1022) ++#define DP_EMAX 1023 ++ ++#define SP_EBIAS 127 ++#define SP_EMIN (-126) ++#define SP_EMAX 127 ++ ++/* special constants ++*/ ++ ++#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__NDS32_EL__) ++#define SPSTR(s, b, m) {m, b, s} ++#define DPSTR(s, b, mh, ml) {ml, mh, b, s} ++#endif ++ ++#ifdef __NDS32_EB__ ++#define SPSTR(s, b, m) {s, b, m} ++#define DPSTR(s, b, mh, ml) {s, b, mh, ml} ++#endif ++ ++const struct ieee754dp_konst __ieee754dp_spcvals[] = { ++ DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* + zero */ ++ DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 0), /* - zero */ ++ DPSTR(0, DP_EBIAS, 0, 0), /* + 1.0 */ ++ DPSTR(1, DP_EBIAS, 0, 0), /* - 1.0 */ ++ DPSTR(0, 3 + DP_EBIAS, 0x40000, 0), /* + 10.0 */ ++ DPSTR(1, 3 + DP_EBIAS, 0x40000, 0), /* - 10.0 */ ++ DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* + infinity */ ++ DPSTR(1, DP_EMAX + 1 + DP_EBIAS, 0, 0), /* - infinity */ ++ DPSTR(0, DP_EMAX + 1 + DP_EBIAS, 0x7FFFF, 0xFFFFFFFF), /* + indef quiet Nan */ ++ DPSTR(0, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* + max */ ++ DPSTR(1, DP_EMAX + DP_EBIAS, 0xFFFFF, 0xFFFFFFFF), /* - max */ ++ DPSTR(0, DP_EMIN + DP_EBIAS, 0, 0), /* + min normal */ ++ DPSTR(1, DP_EMIN + DP_EBIAS, 0, 0), /* - min normal */ ++ DPSTR(0, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* + min denormal */ ++ DPSTR(1, DP_EMIN - 1 + DP_EBIAS, 0, 1), /* - min denormal */ ++ DPSTR(0, 31 + DP_EBIAS, 0, 0), /* + 1.0e31 */ ++ DPSTR(0, 63 + DP_EBIAS, 0, 0), /* + 1.0e63 */ ++}; ++ ++const struct ieee754sp_konst __ieee754sp_spcvals[] = { ++ SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 0), /* + zero */ ++ SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 0), /* - zero */ ++ SPSTR(0, SP_EBIAS, 0), /* + 1.0 */ ++ SPSTR(1, SP_EBIAS, 0), /* - 1.0 */ ++ SPSTR(0, 3 + SP_EBIAS, 0x200000), /* + 10.0 */ ++ SPSTR(1, 3 + SP_EBIAS, 0x200000), /* - 10.0 */ ++ SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0), /* + infinity */ ++ SPSTR(1, SP_EMAX + 1 + SP_EBIAS, 0), /* - infinity */ ++ SPSTR(0, SP_EMAX + 1 + SP_EBIAS, 0x3FFFFF), /* + indef quiet Nan */ ++ SPSTR(0, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* + max normal */ ++ SPSTR(1, SP_EMAX + SP_EBIAS, 0x7FFFFF), /* - max normal */ ++ SPSTR(0, SP_EMIN + SP_EBIAS, 0), /* + min normal */ ++ SPSTR(1, SP_EMIN + SP_EBIAS, 0), /* - min normal */ ++ SPSTR(0, SP_EMIN - 1 + SP_EBIAS, 1), /* + min denormal */ ++ SPSTR(1, SP_EMIN - 1 + SP_EBIAS, 1), /* - min denormal */ ++ SPSTR(0, 31 + SP_EBIAS, 0), /* + 1.0e31 */ ++ SPSTR(0, 63 + SP_EBIAS, 0), /* + 1.0e63 */ ++}; ++ ++int ieee754si_xcpt(int r, const char *op, ...) ++{ ++ struct ieee754xctx ax; ++ ++ if (!TSTX()) ++ return r; ++ ax.op = op; ++ ax.rt = IEEE754_RT_SI; ++ ax.rv.si = r; ++ va_start(ax.ap, op); ++ ieee754_xcpt(&ax); ++ va_end(ax.ap); ++ return ax.rv.si; ++} ++ ++s64 ieee754di_xcpt(s64 r, const char *op, ...) ++{ ++ struct ieee754xctx ax; ++ ++ if (!TSTX()) ++ return r; ++ ax.op = op; ++ ax.rt = IEEE754_RT_DI; ++ ax.rv.di = r; ++ va_start(ax.ap, op); ++ ieee754_xcpt(&ax); ++ va_end(ax.ap); ++ return ax.rv.di; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/ieee754d.c linux-3.4.110/arch/nds32/math-emu/ieee754d.c +--- linux-3.4.110.orig/arch/nds32/math-emu/ieee754d.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/ieee754d.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,134 @@ ++/* ++ * Some debug functions ++ * ++ * MIPS floating point support ++ * ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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. ++ * ++ * Nov 7, 2000 ++ * Modified to build and operate in Linux kernel environment. ++ * ++ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com ++ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. ++ */ ++ ++#include <linux/kernel.h> ++#include "ieee754.h" ++ ++#define DP_EBIAS 1023 ++#define DP_EMIN (-1022) ++#define DP_EMAX 1023 ++#define DP_FBITS 52 ++ ++#define SP_EBIAS 127 ++#define SP_EMIN (-126) ++#define SP_EMAX 127 ++#define SP_FBITS 23 ++ ++#define DP_MBIT(x) ((u64)1 << (x)) ++#define DP_HIDDEN_BIT DP_MBIT(DP_FBITS) ++#define DP_SIGN_BIT DP_MBIT(63) ++ ++#define SP_MBIT(x) ((u32)1 << (x)) ++#define SP_HIDDEN_BIT SP_MBIT(SP_FBITS) ++#define SP_SIGN_BIT SP_MBIT(31) ++ ++#define SPSIGN(sp) (sp.parts.sign) ++#define SPBEXP(sp) (sp.parts.bexp) ++#define SPMANT(sp) (sp.parts.mant) ++ ++#define DPSIGN(dp) (dp.parts.sign) ++#define DPBEXP(dp) (dp.parts.bexp) ++#define DPMANT(dp) (dp.parts.mant) ++ ++ieee754dp ieee754dp_dump(char *m, ieee754dp x) ++{ ++ int i; ++ ++ printk("%s", m); ++ printk("<%08x,%08x>\n", (unsigned)(x.bits >> 32), (unsigned)x.bits); ++ printk("\t="); ++ switch (ieee754dp_class(x)) { ++ case IEEE754_CLASS_QNAN: ++ case IEEE754_CLASS_SNAN: ++ printk("Nan %c", DPSIGN(x) ? '-' : '+'); ++ for (i = DP_FBITS - 1; i >= 0; i--) ++ printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0'); ++ break; ++ case IEEE754_CLASS_INF: ++ printk("%cInfinity", DPSIGN(x) ? '-' : '+'); ++ break; ++ case IEEE754_CLASS_ZERO: ++ printk("%cZero", DPSIGN(x) ? '-' : '+'); ++ break; ++ case IEEE754_CLASS_DNORM: ++ printk("%c0.", DPSIGN(x) ? '-' : '+'); ++ for (i = DP_FBITS - 1; i >= 0; i--) ++ printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0'); ++ printk("e%d", DPBEXP(x) - DP_EBIAS); ++ break; ++ case IEEE754_CLASS_NORM: ++ printk("%c1.", DPSIGN(x) ? '-' : '+'); ++ for (i = DP_FBITS - 1; i >= 0; i--) ++ printk("%c", DPMANT(x) & DP_MBIT(i) ? '1' : '0'); ++ printk("e%d", DPBEXP(x) - DP_EBIAS); ++ break; ++ default: ++ printk("Illegal/Unknown IEEE754 value class"); ++ } ++ printk("\n"); ++ return x; ++} ++ ++ieee754sp ieee754sp_dump(char *m, ieee754sp x) ++{ ++ int i; ++ ++ printk("%s=", m); ++ printk("<%08x>\n", (unsigned)x.bits); ++ printk("\t="); ++ switch (ieee754sp_class(x)) { ++ case IEEE754_CLASS_QNAN: ++ case IEEE754_CLASS_SNAN: ++ printk("Nan %c", SPSIGN(x) ? '-' : '+'); ++ for (i = SP_FBITS - 1; i >= 0; i--) ++ printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0'); ++ break; ++ case IEEE754_CLASS_INF: ++ printk("%cInfinity", SPSIGN(x) ? '-' : '+'); ++ break; ++ case IEEE754_CLASS_ZERO: ++ printk("%cZero", SPSIGN(x) ? '-' : '+'); ++ break; ++ case IEEE754_CLASS_DNORM: ++ printk("%c0.", SPSIGN(x) ? '-' : '+'); ++ for (i = SP_FBITS - 1; i >= 0; i--) ++ printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0'); ++ printk("e%d", SPBEXP(x) - SP_EBIAS); ++ break; ++ case IEEE754_CLASS_NORM: ++ printk("%c1.", SPSIGN(x) ? '-' : '+'); ++ for (i = SP_FBITS - 1; i >= 0; i--) ++ printk("%c", SPMANT(x) & SP_MBIT(i) ? '1' : '0'); ++ printk("e%d", SPBEXP(x) - SP_EBIAS); ++ break; ++ default: ++ printk("Illegal/Unknown IEEE754 value class"); ++ } ++ printk("\n"); ++ return x; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/ieee754dp.c linux-3.4.110/arch/nds32/math-emu/ieee754dp.c +--- linux-3.4.110.orig/arch/nds32/math-emu/ieee754dp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/ieee754dp.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,239 @@ ++/* IEEE754 floating point arithmetic ++ * double precision: common utilities ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754dp.h" ++ ++int ieee754dp_class(ieee754dp x) ++{ ++ COMPXDP; ++ EXPLODEXDP; ++ return xc; ++} ++ ++int ieee754dp_isnan(ieee754dp x) ++{ ++ return ieee754dp_class(x) >= IEEE754_CLASS_SNAN; ++} ++ ++int ieee754dp_issnan(ieee754dp x) ++{ ++ assert(ieee754dp_isnan(x)); ++ return ((DPMANT(x) & DP_MBIT(DP_MBITS - 1)) == DP_MBIT(DP_MBITS - 1)); ++} ++ ++ieee754dp ieee754dp_xcpt(ieee754dp r, const char *op, ...) ++{ ++ struct ieee754xctx ax; ++ if (!TSTX()) ++ return r; ++ ++ ax.op = op; ++ ax.rt = IEEE754_RT_DP; ++ ax.rv.dp = r; ++ va_start(ax.ap, op); ++ ieee754_xcpt(&ax); ++ va_end(ax.ap); ++ return ax.rv.dp; ++} ++ ++ieee754dp ieee754dp_nanxcpt(ieee754dp r, const char *op, ...) ++{ ++ struct ieee754xctx ax; ++ ++ assert(ieee754dp_isnan(r)); ++ ++ if (!ieee754dp_issnan(r)) /* QNAN does not cause invalid op !! */ ++ return r; ++ ++ if (!SETANDTESTCX(IEEE754_INVALID_OPERATION)) { ++ /* not enabled convert to a quiet NaN */ ++ DPMANT(r) &= (~DP_MBIT(DP_MBITS - 1)); ++ if (ieee754dp_isnan(r)) ++ return r; ++ else ++ return ieee754dp_indef(); ++ } ++ ++ ax.op = op; ++ ax.rt = 0; ++ ax.rv.dp = r; ++ va_start(ax.ap, op); ++ ieee754_xcpt(&ax); ++ va_end(ax.ap); ++ return ax.rv.dp; ++} ++ ++ieee754dp ieee754dp_bestnan(ieee754dp x, ieee754dp y) ++{ ++ assert(ieee754dp_isnan(x)); ++ assert(ieee754dp_isnan(y)); ++ ++ if (DPMANT(x) > DPMANT(y)) ++ return x; ++ else ++ return y; ++} ++ ++static u64 get_rounding(int sn, u64 xm) ++{ ++ /* inexact must round of 3 bits ++ */ ++ if (xm & (DP_MBIT(3) - 1)) { ++ switch (ieee754_csr.rm) { ++ case IEEE754_RZ: ++ break; ++ case IEEE754_RN: ++ xm += 0x3 + ((xm >> 3) & 1); ++ /* xm += (xm&0x8)?0x4:0x3 */ ++ break; ++ case IEEE754_RU: /* toward +Infinity */ ++ if (!sn) /* ?? */ ++ xm += 0x8; ++ break; ++ case IEEE754_RD: /* toward -Infinity */ ++ if (sn) /* ?? */ ++ xm += 0x8; ++ break; ++ } ++ } ++ return xm; ++} ++ ++/* generate a normal/denormal number with over,under handling ++ * sn is sign ++ * xe is an unbiased exponent ++ * xm is 3bit extended precision value. ++ */ ++ieee754dp ieee754dp_format(int sn, int xe, u64 xm) ++{ ++ assert(xm); /* we don't gen exact zeros (probably should) */ ++ ++ assert((xm >> (DP_MBITS + 1 + 3)) == 0); /* no execess */ ++ assert(xm & (DP_HIDDEN_BIT << 3)); ++ ++ if (xe < DP_EMIN) { ++ /* strip lower bits */ ++ int es = DP_EMIN - xe; ++ ++ if (ieee754_csr.nod) { ++ SETCX(IEEE754_UNDERFLOW); ++ SETCX(IEEE754_INEXACT); ++ ++ switch (ieee754_csr.rm) { ++ case IEEE754_RN: ++ return ieee754dp_zero(sn); ++ case IEEE754_RZ: ++ return ieee754dp_zero(sn); ++ case IEEE754_RU: /* toward +Infinity */ ++ if (sn == 0) ++ return ieee754dp_min(0); ++ else ++ return ieee754dp_zero(1); ++ case IEEE754_RD: /* toward -Infinity */ ++ if (sn == 0) ++ return ieee754dp_zero(0); ++ else ++ return ieee754dp_min(1); ++ } ++ } ++ ++ if (xe == DP_EMIN - 1 ++ && get_rounding(sn, xm) >> (DP_MBITS + 1 + 3)) { ++ /* Not tiny after rounding */ ++ SETCX(IEEE754_INEXACT); ++ xm = get_rounding(sn, xm); ++ xm >>= 1; ++ /* Clear grs bits */ ++ xm &= ~(DP_MBIT(3) - 1); ++ xe++; ++ } else { ++ /* sticky right shift es bits ++ */ ++ xm = XDPSRS(xm, es); ++ xe += es; ++ assert((xm & (DP_HIDDEN_BIT << 3)) == 0); ++ assert(xe == DP_EMIN); ++ } ++ } ++ if (xm & (DP_MBIT(3) - 1)) { ++ SETCX(IEEE754_INEXACT); ++ if ((xm & (DP_HIDDEN_BIT << 3)) == 0) { ++ SETCX(IEEE754_UNDERFLOW); ++ } ++ ++ /* inexact must round of 3 bits ++ */ ++ xm = get_rounding(sn, xm); ++ /* adjust exponent for rounding add overflowing ++ */ ++ if (xm >> (DP_MBITS + 3 + 1)) { ++ /* add causes mantissa overflow */ ++ xm >>= 1; ++ xe++; ++ } ++ } ++ /* strip grs bits */ ++ xm >>= 3; ++ ++ assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ ++ assert(xe >= DP_EMIN); ++ ++ if (xe > DP_EMAX) { ++ SETCX(IEEE754_OVERFLOW); ++ SETCX(IEEE754_INEXACT); ++ /* -O can be table indexed by (rm,sn) */ ++ switch (ieee754_csr.rm) { ++ case IEEE754_RN: ++ return ieee754dp_inf(sn); ++ case IEEE754_RZ: ++ return ieee754dp_max(sn); ++ case IEEE754_RU: /* toward +Infinity */ ++ if (sn == 0) ++ return ieee754dp_inf(0); ++ else ++ return ieee754dp_max(1); ++ case IEEE754_RD: /* toward -Infinity */ ++ if (sn == 0) ++ return ieee754dp_max(0); ++ else ++ return ieee754dp_inf(1); ++ } ++ } ++ /* gen norm/denorm/zero */ ++ ++ if ((xm & DP_HIDDEN_BIT) == 0) { ++ /* we underflow (tiny/zero) */ ++ assert(xe == DP_EMIN); ++ if (ieee754_csr.mx & IEEE754_UNDERFLOW) ++ SETCX(IEEE754_UNDERFLOW); ++ return builddp(sn, DP_EMIN - 1 + DP_EBIAS, xm); ++ } else { ++ assert((xm >> (DP_MBITS + 1)) == 0); /* no execess */ ++ assert(xm & DP_HIDDEN_BIT); ++ ++ return builddp(sn, xe + DP_EBIAS, xm & ~DP_HIDDEN_BIT); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/ieee754dp.h linux-3.4.110/arch/nds32/math-emu/ieee754dp.h +--- linux-3.4.110.orig/arch/nds32/math-emu/ieee754dp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/ieee754dp.h 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,83 @@ ++/* ++ * IEEE754 floating point ++ * double precision internal header file ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754int.h" ++ ++#define assert(expr) ((void)0) ++ ++/* 3bit extended double precision sticky right shift */ ++#define XDPSRS(v,rs) \ ++ ((rs > (DP_MBITS+3))?1:((v) >> (rs)) | ((v) << (64-(rs)) != 0)) ++ ++#define XDPSRSX1() \ ++ (xe++, (xm = (xm >> 1) | (xm & 1))) ++ ++#define XDPSRS1(v) \ ++ (((v) >> 1) | ((v) & 1)) ++ ++/* convert denormal to normalized with extended exponent */ ++#define DPDNORMx(m,e) \ ++ while( (m >> DP_MBITS) == 0) { m <<= 1; e--; } ++#define DPDNORMX DPDNORMx(xm, xe) ++#define DPDNORMY DPDNORMx(ym, ye) ++ ++static inline ieee754dp builddp(int s, int bx, u64 m) ++{ ++ ieee754dp r; ++ ++ assert((s) == 0 || (s) == 1); ++ assert((bx) >= DP_EMIN - 1 + DP_EBIAS ++ && (bx) <= DP_EMAX + 1 + DP_EBIAS); ++ assert(((m) >> DP_MBITS) == 0); ++ ++ r.parts.sign = s; ++ r.parts.bexp = bx; ++ r.parts.mant = m; ++ return r; ++} ++ ++extern int ieee754dp_isnan(ieee754dp); ++extern int ieee754dp_issnan(ieee754dp); ++extern int ieee754si_xcpt(int, const char *, ...); ++extern s64 ieee754di_xcpt(s64, const char *, ...); ++extern ieee754dp ieee754dp_xcpt(ieee754dp, const char *, ...); ++extern ieee754dp ieee754dp_nanxcpt(ieee754dp, const char *, ...); ++extern ieee754dp ieee754dp_bestnan(ieee754dp, ieee754dp); ++extern ieee754dp ieee754dp_format(int, int, u64); ++ ++ ++#define DPNORMRET2(s, e, m, name, a0, a1) \ ++{ \ ++ ieee754dp V = ieee754dp_format(s, e, m); \ ++ if(TSTX()) \ ++ return ieee754dp_xcpt(V, name, a0, a1); \ ++ else \ ++ return V; \ ++} ++ ++#define DPNORMRET1(s, e, m, name, a0) DPNORMRET2(s, e, m, name, a0, a0) +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/ieee754.h linux-3.4.110/arch/nds32/math-emu/ieee754.h +--- linux-3.4.110.orig/arch/nds32/math-emu/ieee754.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/ieee754.h 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,467 @@ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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. ++ * ++ * Nov 7, 2000 ++ * Modification to allow integration with Linux kernel ++ * ++ * Kevin D. Kissell, kevink@mips.com and Carsten Langgard, carstenl@mips.com ++ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. ++ */ ++#ifndef __ARCH_MIPS_MATH_EMU_IEEE754_H ++#define __ARCH_MIPS_MATH_EMU_IEEE754_H ++ ++#include <asm/byteorder.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++ ++/* ++ * Not very pretty, but the Linux kernel's normal va_list definition ++ * does not allow it to be used as a structure element, as it is here. ++ */ ++#ifndef _STDARG_H ++#include <stdarg.h> ++#endif ++ ++#ifdef __LITTLE_ENDIAN ++struct ieee754dp_konst { ++ unsigned mantlo:32; ++ unsigned manthi:20; ++ unsigned bexp:11; ++ unsigned sign:1; ++}; ++struct ieee754sp_konst { ++ unsigned mant:23; ++ unsigned bexp:8; ++ unsigned sign:1; ++}; ++ ++typedef union _ieee754dp { ++ struct ieee754dp_konst oparts; ++ struct { ++ u64 mant:52; ++ unsigned int bexp:11; ++ unsigned int sign:1; ++ } parts; ++ u64 bits; ++ double d; ++} ieee754dp; ++ ++typedef union _ieee754sp { ++ struct ieee754sp_konst parts; ++ float f; ++ u32 bits; ++} ieee754sp; ++#endif ++ ++#ifdef __BIG_ENDIAN ++struct ieee754dp_konst { ++ unsigned sign:1; ++ unsigned bexp:11; ++ unsigned manthi:20; ++ unsigned mantlo:32; ++}; ++ ++typedef union _ieee754dp { ++ struct ieee754dp_konst oparts; ++ struct { ++ unsigned int sign:1; ++ unsigned int bexp:11; ++ u64 mant:52; ++ } parts; ++ double d; ++ u64 bits; ++} ieee754dp; ++ ++struct ieee754sp_konst { ++ unsigned sign:1; ++ unsigned bexp:8; ++ unsigned mant:23; ++}; ++ ++typedef union _ieee754sp { ++ struct ieee754sp_konst parts; ++ float f; ++ u32 bits; ++} ieee754sp; ++#endif ++ ++/* ++ * single precision (often aka float) ++*/ ++int ieee754sp_finite(ieee754sp x); ++int ieee754sp_class(ieee754sp x); ++ ++ieee754sp ieee754sp_abs(ieee754sp x); ++ieee754sp ieee754sp_neg(ieee754sp x); ++ieee754sp ieee754sp_scalb(ieee754sp x, int); ++ieee754sp ieee754sp_logb(ieee754sp x); ++ ++/* x with sign of y */ ++ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y); ++ ++ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y); ++ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y); ++ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y); ++ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y); ++ ++ieee754sp ieee754sp_fint(int x); ++ieee754sp ieee754sp_funs(unsigned x); ++ieee754sp ieee754sp_flong(s64 x); ++ieee754sp ieee754sp_fulong(u64 x); ++ieee754sp ieee754sp_fdp(ieee754dp x); ++ ++int ieee754sp_tint(ieee754sp x); ++unsigned int ieee754sp_tuns(ieee754sp x); ++s64 ieee754sp_tlong(ieee754sp x); ++u64 ieee754sp_tulong(ieee754sp x); ++ ++int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cop, int sig); ++/* ++ * basic sp math ++ */ ++ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip); ++ieee754sp ieee754sp_frexp(ieee754sp x, int *exp); ++ieee754sp ieee754sp_ldexp(ieee754sp x, int exp); ++ ++ieee754sp ieee754sp_ceil(ieee754sp x); ++ieee754sp ieee754sp_floor(ieee754sp x); ++ieee754sp ieee754sp_trunc(ieee754sp x); ++ ++ieee754sp ieee754sp_sqrt(ieee754sp x); ++ ++/* ++ * double precision (often aka double) ++*/ ++int ieee754dp_finite(ieee754dp x); ++int ieee754dp_class(ieee754dp x); ++ ++/* x with sign of y */ ++ieee754dp ieee754dp_copysign(ieee754dp x, ieee754dp y); ++ ++ieee754dp ieee754dp_add(ieee754dp x, ieee754dp y); ++ieee754dp ieee754dp_sub(ieee754dp x, ieee754dp y); ++ieee754dp ieee754dp_mul(ieee754dp x, ieee754dp y); ++ieee754dp ieee754dp_div(ieee754dp x, ieee754dp y); ++ ++ieee754dp ieee754dp_abs(ieee754dp x); ++ieee754dp ieee754dp_neg(ieee754dp x); ++ieee754dp ieee754dp_scalb(ieee754dp x, int); ++ ++/* return exponent as integer in floating point format ++ */ ++ieee754dp ieee754dp_logb(ieee754dp x); ++ ++ieee754dp ieee754dp_fint(int x); ++ieee754dp ieee754dp_funs(unsigned x); ++ieee754dp ieee754dp_flong(s64 x); ++ieee754dp ieee754dp_fulong(u64 x); ++ieee754dp ieee754dp_fsp(ieee754sp x); ++ ++ieee754dp ieee754dp_ceil(ieee754dp x); ++ieee754dp ieee754dp_floor(ieee754dp x); ++ieee754dp ieee754dp_trunc(ieee754dp x); ++ ++int ieee754dp_tint(ieee754dp x); ++unsigned int ieee754dp_tuns(ieee754dp x); ++s64 ieee754dp_tlong(ieee754dp x); ++u64 ieee754dp_tulong(ieee754dp x); ++ ++int ieee754dp_cmp(ieee754dp x, ieee754dp y, int cop, int sig); ++/* ++ * basic sp math ++ */ ++ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip); ++ieee754dp ieee754dp_frexp(ieee754dp x, int *exp); ++ieee754dp ieee754dp_ldexp(ieee754dp x, int exp); ++ ++ieee754dp ieee754dp_ceil(ieee754dp x); ++ieee754dp ieee754dp_floor(ieee754dp x); ++ieee754dp ieee754dp_trunc(ieee754dp x); ++ ++ieee754dp ieee754dp_sqrt(ieee754dp x); ++ ++ ++ ++/* 5 types of floating point number ++*/ ++#define IEEE754_CLASS_NORM 0x00 ++#define IEEE754_CLASS_ZERO 0x01 ++#define IEEE754_CLASS_DNORM 0x02 ++#define IEEE754_CLASS_INF 0x03 ++#define IEEE754_CLASS_SNAN 0x04 ++#define IEEE754_CLASS_QNAN 0x05 ++ ++/* exception numbers */ ++#define IEEE754_INVALID_OPERATION 0x01 ++#define IEEE754_ZERO_DIVIDE 0x02 ++#define IEEE754_OVERFLOW 0x04 ++#define IEEE754_UNDERFLOW 0x08 ++#define IEEE754_INEXACT 0x10 ++ ++/* cmp operators ++*/ ++#define IEEE754_CLT 0x01 ++#define IEEE754_CEQ 0x02 ++#define IEEE754_CGT 0x04 ++#define IEEE754_CUN 0x08 ++ ++/* rounding mode ++*/ ++#define IEEE754_RN 0 /* round to nearest */ ++#define IEEE754_RZ 1 /* round toward zero */ ++#define IEEE754_RD 2 /* round toward -Infinity */ ++#define IEEE754_RU 3 /* round toward +Infinity */ ++ ++/* other naming */ ++#define IEEE754_RM IEEE754_RD ++#define IEEE754_RP IEEE754_RU ++ ++/* "normal" comparisons ++*/ ++static inline int ieee754sp_eq(ieee754sp x, ieee754sp y) ++{ ++ return ieee754sp_cmp(x, y, IEEE754_CEQ, 0); ++} ++ ++static inline int ieee754sp_ne(ieee754sp x, ieee754sp y) ++{ ++ return ieee754sp_cmp(x, y, ++ IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0); ++} ++ ++static inline int ieee754sp_lt(ieee754sp x, ieee754sp y) ++{ ++ return ieee754sp_cmp(x, y, IEEE754_CLT, 0); ++} ++ ++static inline int ieee754sp_le(ieee754sp x, ieee754sp y) ++{ ++ return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0); ++} ++ ++static inline int ieee754sp_gt(ieee754sp x, ieee754sp y) ++{ ++ return ieee754sp_cmp(x, y, IEEE754_CGT, 0); ++} ++ ++ ++static inline int ieee754sp_ge(ieee754sp x, ieee754sp y) ++{ ++ return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0); ++} ++ ++static inline int ieee754dp_eq(ieee754dp x, ieee754dp y) ++{ ++ return ieee754dp_cmp(x, y, IEEE754_CEQ, 0); ++} ++ ++static inline int ieee754dp_ne(ieee754dp x, ieee754dp y) ++{ ++ return ieee754dp_cmp(x, y, ++ IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0); ++} ++ ++static inline int ieee754dp_lt(ieee754dp x, ieee754dp y) ++{ ++ return ieee754dp_cmp(x, y, IEEE754_CLT, 0); ++} ++ ++static inline int ieee754dp_le(ieee754dp x, ieee754dp y) ++{ ++ return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0); ++} ++ ++static inline int ieee754dp_gt(ieee754dp x, ieee754dp y) ++{ ++ return ieee754dp_cmp(x, y, IEEE754_CGT, 0); ++} ++ ++static inline int ieee754dp_ge(ieee754dp x, ieee754dp y) ++{ ++ return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0); ++} ++ ++ ++/* ++ * Like strtod ++ */ ++ieee754dp ieee754dp_fstr(const char *s, char **endp); ++char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af); ++ ++ ++/* ++ * The control status register ++ */ ++struct _ieee754_csr { ++#ifdef __BIG_ENDIAN ++ unsigned pad0:12; ++ unsigned cx:7; /* exceptions this operation */ ++ unsigned nod:1; /* set 1 for no denormalised numbers */ ++ unsigned mx:5; /* exception enable mask */ ++ unsigned sx:5; /* exceptions total */ ++ unsigned rm:2; /* current rounding mode */ ++#endif ++#ifdef __LITTLE_ENDIAN ++ unsigned rm:2; /* current rounding mode */ ++ unsigned sx:5; /* exceptions total */ ++ unsigned mx:5; /* exception enable mask */ ++ unsigned nod:1; /* set 1 for no denormalised numbers */ ++ unsigned cx:7; /* exceptions this operation */ ++ unsigned pad0:12; ++#endif ++}; ++#define ieee754_csr (*(struct _ieee754_csr *)(¤t->thread.fpu.fpcsr)) ++ ++static inline unsigned ieee754_getrm(void) ++{ ++ return (ieee754_csr.rm); ++} ++static inline unsigned ieee754_setrm(unsigned rm) ++{ ++ return (ieee754_csr.rm = rm); ++} ++ ++/* ++ * get current exceptions ++ */ ++static inline unsigned ieee754_getcx(void) ++{ ++ return (ieee754_csr.cx); ++} ++ ++/* test for current exception condition ++ */ ++static inline int ieee754_cxtest(unsigned n) ++{ ++ return (ieee754_csr.cx & n); ++} ++ ++/* ++ * get sticky exceptions ++ */ ++static inline unsigned ieee754_getsx(void) ++{ ++ return (ieee754_csr.sx); ++} ++ ++/* clear sticky conditions ++*/ ++static inline unsigned ieee754_clrsx(void) ++{ ++ return (ieee754_csr.sx = 0); ++} ++ ++/* test for sticky exception condition ++ */ ++static inline int ieee754_sxtest(unsigned n) ++{ ++ return (ieee754_csr.sx & n); ++} ++ ++/* debugging */ ++ieee754sp ieee754sp_dump(char *s, ieee754sp x); ++ieee754dp ieee754dp_dump(char *s, ieee754dp x); ++ ++#define IEEE754_SPCVAL_PZERO 0 ++#define IEEE754_SPCVAL_NZERO 1 ++#define IEEE754_SPCVAL_PONE 2 ++#define IEEE754_SPCVAL_NONE 3 ++#define IEEE754_SPCVAL_PTEN 4 ++#define IEEE754_SPCVAL_NTEN 5 ++#define IEEE754_SPCVAL_PINFINITY 6 ++#define IEEE754_SPCVAL_NINFINITY 7 ++#define IEEE754_SPCVAL_INDEF 8 ++#define IEEE754_SPCVAL_PMAX 9 /* +max norm */ ++#define IEEE754_SPCVAL_NMAX 10 /* -max norm */ ++#define IEEE754_SPCVAL_PMIN 11 /* +min norm */ ++#define IEEE754_SPCVAL_NMIN 12 /* +min norm */ ++#define IEEE754_SPCVAL_PMIND 13 /* +min denorm */ ++#define IEEE754_SPCVAL_NMIND 14 /* +min denorm */ ++#define IEEE754_SPCVAL_P1E31 15 /* + 1.0e31 */ ++#define IEEE754_SPCVAL_P1E63 16 /* + 1.0e63 */ ++ ++extern const struct ieee754dp_konst __ieee754dp_spcvals[]; ++extern const struct ieee754sp_konst __ieee754sp_spcvals[]; ++#define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals) ++#define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals) ++ ++/* ++ * Return infinity with given sign ++ */ ++#define ieee754dp_inf(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) ++#define ieee754dp_zero(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) ++#define ieee754dp_one(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) ++#define ieee754dp_ten(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) ++#define ieee754dp_indef() (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF]) ++#define ieee754dp_max(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) ++#define ieee754dp_min(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) ++#define ieee754dp_mind(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) ++#define ieee754dp_1e31() (ieee754dp_spcvals[IEEE754_SPCVAL_P1E31]) ++#define ieee754dp_1e63() (ieee754dp_spcvals[IEEE754_SPCVAL_P1E63]) ++ ++#define ieee754sp_inf(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) ++#define ieee754sp_zero(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) ++#define ieee754sp_one(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) ++#define ieee754sp_ten(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) ++#define ieee754sp_indef() (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF]) ++#define ieee754sp_max(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) ++#define ieee754sp_min(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) ++#define ieee754sp_mind(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) ++#define ieee754sp_1e31() (ieee754sp_spcvals[IEEE754_SPCVAL_P1E31]) ++#define ieee754sp_1e63() (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63]) ++ ++/* ++ * Indefinite integer value ++ */ ++#define ieee754si_indef() INT_MAX ++#ifdef LONG_LONG_MAX ++#define ieee754di_indef() LONG_LONG_MAX ++#else ++#define ieee754di_indef() ((s64)(~0ULL>>1)) ++#endif ++ ++/* IEEE exception context, passed to handler */ ++struct ieee754xctx { ++ const char *op; /* operation name */ ++ int rt; /* result type */ ++ union { ++ ieee754sp sp; /* single precision */ ++ ieee754dp dp; /* double precision */ ++#ifdef IEEE854_XP ++ ieee754xp xp; /* extended precision */ ++#endif ++ int si; /* standard signed integer (32bits) */ ++ s64 di; /* extended signed integer (64bits) */ ++ } rv; /* default result format implied by op */ ++ va_list ap; ++}; ++ ++/* result types for xctx.rt */ ++#define IEEE754_RT_SP 0 ++#define IEEE754_RT_DP 1 ++#define IEEE754_RT_XP 2 ++#define IEEE754_RT_SI 3 ++#define IEEE754_RT_DI 4 ++ ++extern void ieee754_xcpt(struct ieee754xctx *xcp); ++ ++/* compat */ ++#define ieee754dp_fix(x) ieee754dp_tint(x) ++#define ieee754sp_fix(x) ieee754sp_tint(x) ++ ++#endif /* __ARCH_MIPS_MATH_EMU_IEEE754_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/ieee754int.h linux-3.4.110/arch/nds32/math-emu/ieee754int.h +--- linux-3.4.110.orig/arch/nds32/math-emu/ieee754int.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/ieee754int.h 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,165 @@ ++/* ++ * IEEE754 floating point ++ * common internal header file ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754.h" ++ ++#define DP_EBIAS 1023 ++#define DP_EMIN (-1022) ++#define DP_EMAX 1023 ++#define DP_MBITS 52 ++ ++#define SP_EBIAS 127 ++#define SP_EMIN (-126) ++#define SP_EMAX 127 ++#define SP_MBITS 23 ++ ++#define DP_MBIT(x) ((u64)1 << (x)) ++#define DP_HIDDEN_BIT DP_MBIT(DP_MBITS) ++#define DP_SIGN_BIT DP_MBIT(63) ++ ++#define SP_MBIT(x) ((u32)1 << (x)) ++#define SP_HIDDEN_BIT SP_MBIT(SP_MBITS) ++#define SP_SIGN_BIT SP_MBIT(31) ++ ++ ++#define SPSIGN(sp) (sp.parts.sign) ++#define SPBEXP(sp) (sp.parts.bexp) ++#define SPMANT(sp) (sp.parts.mant) ++ ++#define DPSIGN(dp) (dp.parts.sign) ++#define DPBEXP(dp) (dp.parts.bexp) ++#define DPMANT(dp) (dp.parts.mant) ++ ++#define CLPAIR(x, y) ((x)*6+(y)) ++ ++#define CLEARCX \ ++ (ieee754_csr.cx = 0) ++ ++#define SETCX(x) \ ++ (ieee754_csr.cx |= (x), ieee754_csr.sx |= (x)) ++ ++#define SETANDTESTCX(x) \ ++ (SETCX(x), ieee754_csr.mx & (x)) ++ ++#define TSTX() \ ++ (ieee754_csr.cx & ieee754_csr.mx) ++ ++ ++#define COMPXSP \ ++ unsigned xm; int xe; int xs; int xc ++ ++#define COMPYSP \ ++ unsigned ym; int ye; int ys; int yc ++ ++#define EXPLODESP(v, vc, vs, ve, vm) \ ++{\ ++ vs = SPSIGN(v);\ ++ ve = SPBEXP(v);\ ++ vm = SPMANT(v);\ ++ if(ve == SP_EMAX+1+SP_EBIAS){\ ++ if(vm == 0)\ ++ vc = IEEE754_CLASS_INF;\ ++ else if(vm & SP_MBIT(SP_MBITS-1)) \ ++ vc = IEEE754_CLASS_SNAN;\ ++ else \ ++ vc = IEEE754_CLASS_QNAN;\ ++ } else if(ve == SP_EMIN-1+SP_EBIAS) {\ ++ if(vm) {\ ++ ve = SP_EMIN;\ ++ vc = IEEE754_CLASS_DNORM;\ ++ } else\ ++ vc = IEEE754_CLASS_ZERO;\ ++ } else {\ ++ ve -= SP_EBIAS;\ ++ vm |= SP_HIDDEN_BIT;\ ++ vc = IEEE754_CLASS_NORM;\ ++ }\ ++} ++#define EXPLODEXSP EXPLODESP(x, xc, xs, xe, xm) ++#define EXPLODEYSP EXPLODESP(y, yc, ys, ye, ym) ++ ++ ++#define COMPXDP \ ++u64 xm; int xe; int xs; int xc ++ ++#define COMPYDP \ ++u64 ym; int ye; int ys; int yc ++ ++#define EXPLODEDP(v, vc, vs, ve, vm) \ ++{\ ++ vm = DPMANT(v);\ ++ vs = DPSIGN(v);\ ++ ve = DPBEXP(v);\ ++ if(ve == DP_EMAX+1+DP_EBIAS){\ ++ if(vm == 0)\ ++ vc = IEEE754_CLASS_INF;\ ++ else if(vm & DP_MBIT(DP_MBITS-1)) \ ++ vc = IEEE754_CLASS_SNAN;\ ++ else \ ++ vc = IEEE754_CLASS_QNAN;\ ++ } else if(ve == DP_EMIN-1+DP_EBIAS) {\ ++ if(vm) {\ ++ ve = DP_EMIN;\ ++ vc = IEEE754_CLASS_DNORM;\ ++ } else\ ++ vc = IEEE754_CLASS_ZERO;\ ++ } else {\ ++ ve -= DP_EBIAS;\ ++ vm |= DP_HIDDEN_BIT;\ ++ vc = IEEE754_CLASS_NORM;\ ++ }\ ++} ++#define EXPLODEXDP EXPLODEDP(x, xc, xs, xe, xm) ++#define EXPLODEYDP EXPLODEDP(y, yc, ys, ye, ym) ++ ++#define FLUSHDP(v, vc, vs, ve, vm) \ ++ if(vc==IEEE754_CLASS_DNORM) {\ ++ if(ieee754_csr.nod) {\ ++ SETCX(IEEE754_INEXACT);\ ++ vc = IEEE754_CLASS_ZERO;\ ++ ve = DP_EMIN-1+DP_EBIAS;\ ++ vm = 0;\ ++ v = ieee754dp_zero(vs);\ ++ }\ ++ } ++ ++#define FLUSHSP(v, vc, vs, ve, vm) \ ++ if(vc==IEEE754_CLASS_DNORM) {\ ++ if(ieee754_csr.nod) {\ ++ SETCX(IEEE754_INEXACT);\ ++ vc = IEEE754_CLASS_ZERO;\ ++ ve = SP_EMIN-1+SP_EBIAS;\ ++ vm = 0;\ ++ v = ieee754sp_zero(vs);\ ++ }\ ++ } ++ ++#define FLUSHXDP FLUSHDP(x, xc, xs, xe, xm) ++#define FLUSHYDP FLUSHDP(y, yc, ys, ye, ym) ++#define FLUSHXSP FLUSHSP(x, xc, xs, xe, xm) ++#define FLUSHYSP FLUSHSP(y, yc, ys, ye, ym) +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/ieee754m.c linux-3.4.110/arch/nds32/math-emu/ieee754m.c +--- linux-3.4.110.orig/arch/nds32/math-emu/ieee754m.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/ieee754m.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,55 @@ ++/* ++ * floor, trunc, ceil ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754.h" ++ ++ieee754dp ieee754dp_floor(ieee754dp x) ++{ ++ ieee754dp i; ++ ++ if (ieee754dp_lt(ieee754dp_modf(x, &i), ieee754dp_zero(0))) ++ return ieee754dp_sub(i, ieee754dp_one(0)); ++ else ++ return i; ++} ++ ++ieee754dp ieee754dp_ceil(ieee754dp x) ++{ ++ ieee754dp i; ++ ++ if (ieee754dp_gt(ieee754dp_modf(x, &i), ieee754dp_zero(0))) ++ return ieee754dp_add(i, ieee754dp_one(0)); ++ else ++ return i; ++} ++ ++ieee754dp ieee754dp_trunc(ieee754dp x) ++{ ++ ieee754dp i; ++ ++ (void)ieee754dp_modf(x, &i); ++ return i; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/ieee754sp.c linux-3.4.110/arch/nds32/math-emu/ieee754sp.c +--- linux-3.4.110.orig/arch/nds32/math-emu/ieee754sp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/ieee754sp.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,239 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++int ieee754sp_class(ieee754sp x) ++{ ++ COMPXSP; ++ EXPLODEXSP; ++ return xc; ++} ++ ++int ieee754sp_isnan(ieee754sp x) ++{ ++ return ieee754sp_class(x) >= IEEE754_CLASS_SNAN; ++} ++ ++int ieee754sp_issnan(ieee754sp x) ++{ ++ assert(ieee754sp_isnan(x)); ++ return (SPMANT(x) & SP_MBIT(SP_MBITS - 1)); ++} ++ ++ieee754sp ieee754sp_xcpt(ieee754sp r, const char *op, ...) ++{ ++ struct ieee754xctx ax; ++ ++ if (!TSTX()) ++ return r; ++ ++ ax.op = op; ++ ax.rt = IEEE754_RT_SP; ++ ax.rv.sp = r; ++ va_start(ax.ap, op); ++ ieee754_xcpt(&ax); ++ va_end(ax.ap); ++ return ax.rv.sp; ++} ++ ++ieee754sp ieee754sp_nanxcpt(ieee754sp r, const char *op, ...) ++{ ++ struct ieee754xctx ax; ++ ++ assert(ieee754sp_isnan(r)); ++ ++ if (!ieee754sp_issnan(r)) /* QNAN does not cause invalid op !! */ ++ return r; ++ ++ if (!SETANDTESTCX(IEEE754_INVALID_OPERATION)) { ++ /* not enabled convert to a quiet NaN */ ++ SPMANT(r) &= (~SP_MBIT(SP_MBITS - 1)); ++ if (ieee754sp_isnan(r)) ++ return r; ++ else ++ return ieee754sp_indef(); ++ } ++ ++ ax.op = op; ++ ax.rt = 0; ++ ax.rv.sp = r; ++ va_start(ax.ap, op); ++ ieee754_xcpt(&ax); ++ va_end(ax.ap); ++ return ax.rv.sp; ++} ++ ++ieee754sp ieee754sp_bestnan(ieee754sp x, ieee754sp y) ++{ ++ assert(ieee754sp_isnan(x)); ++ assert(ieee754sp_isnan(y)); ++ ++ if (SPMANT(x) > SPMANT(y)) ++ return x; ++ else ++ return y; ++} ++ ++static unsigned get_rounding(int sn, unsigned xm) ++{ ++ /* inexact must round of 3 bits ++ */ ++ if (xm & (SP_MBIT(3) - 1)) { ++ switch (ieee754_csr.rm) { ++ case IEEE754_RZ: ++ break; ++ case IEEE754_RN: ++ xm += 0x3 + ((xm >> 3) & 1); ++ /* xm += (xm&0x8)?0x4:0x3 */ ++ break; ++ case IEEE754_RU: /* toward +Infinity */ ++ if (!sn) /* ?? */ ++ xm += 0x8; ++ break; ++ case IEEE754_RD: /* toward -Infinity */ ++ if (sn) /* ?? */ ++ xm += 0x8; ++ break; ++ } ++ } ++ return xm; ++} ++ ++/* generate a normal/denormal number with over,under handling ++ * sn is sign ++ * xe is an unbiased exponent ++ * xm is 3bit extended precision value. ++ */ ++ieee754sp ieee754sp_format(int sn, int xe, unsigned xm) ++{ ++ assert(xm); /* we don't gen exact zeros (probably should) */ ++ ++ assert((xm >> (SP_MBITS + 1 + 3)) == 0); /* no execess */ ++ assert(xm & (SP_HIDDEN_BIT << 3)); ++ ++ if (xe < SP_EMIN) { ++ /* strip lower bits */ ++ int es = SP_EMIN - xe; ++ ++ if (ieee754_csr.nod) { ++ SETCX(IEEE754_UNDERFLOW); ++ SETCX(IEEE754_INEXACT); ++ ++ switch (ieee754_csr.rm) { ++ case IEEE754_RN: ++ return ieee754sp_zero(sn); ++ case IEEE754_RZ: ++ return ieee754sp_zero(sn); ++ case IEEE754_RU: /* toward +Infinity */ ++ if (sn == 0) ++ return ieee754sp_min(0); ++ else ++ return ieee754sp_zero(1); ++ case IEEE754_RD: /* toward -Infinity */ ++ if (sn == 0) ++ return ieee754sp_zero(0); ++ else ++ return ieee754sp_min(1); ++ } ++ } ++ ++ if (xe == SP_EMIN - 1 ++ && get_rounding(sn, xm) >> (SP_MBITS + 1 + 3)) { ++ /* Not tiny after rounding */ ++ SETCX(IEEE754_INEXACT); ++ xm = get_rounding(sn, xm); ++ xm >>= 1; ++ /* Clear grs bits */ ++ xm &= ~(SP_MBIT(3) - 1); ++ xe++; ++ } else { ++ /* sticky right shift es bits ++ */ ++ SPXSRSXn(es); ++ assert((xm & (SP_HIDDEN_BIT << 3)) == 0); ++ assert(xe == SP_EMIN); ++ } ++ } ++ if (xm & (SP_MBIT(3) - 1)) { ++ SETCX(IEEE754_INEXACT); ++ if ((xm & (SP_HIDDEN_BIT << 3)) == 0) { ++ SETCX(IEEE754_UNDERFLOW); ++ } ++ ++ /* inexact must round of 3 bits ++ */ ++ xm = get_rounding(sn, xm); ++ /* adjust exponent for rounding add overflowing ++ */ ++ if (xm >> (SP_MBITS + 1 + 3)) { ++ /* add causes mantissa overflow */ ++ xm >>= 1; ++ xe++; ++ } ++ } ++ /* strip grs bits */ ++ xm >>= 3; ++ ++ assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ ++ assert(xe >= SP_EMIN); ++ ++ if (xe > SP_EMAX) { ++ SETCX(IEEE754_OVERFLOW); ++ SETCX(IEEE754_INEXACT); ++ /* -O can be table indexed by (rm,sn) */ ++ switch (ieee754_csr.rm) { ++ case IEEE754_RN: ++ return ieee754sp_inf(sn); ++ case IEEE754_RZ: ++ return ieee754sp_max(sn); ++ case IEEE754_RU: /* toward +Infinity */ ++ if (sn == 0) ++ return ieee754sp_inf(0); ++ else ++ return ieee754sp_max(1); ++ case IEEE754_RD: /* toward -Infinity */ ++ if (sn == 0) ++ return ieee754sp_max(0); ++ else ++ return ieee754sp_inf(1); ++ } ++ } ++ /* gen norm/denorm/zero */ ++ ++ if ((xm & SP_HIDDEN_BIT) == 0) { ++ /* we underflow (tiny/zero) */ ++ assert(xe == SP_EMIN); ++ if (ieee754_csr.mx & IEEE754_UNDERFLOW) ++ SETCX(IEEE754_UNDERFLOW); ++ return buildsp(sn, SP_EMIN - 1 + SP_EBIAS, xm); ++ } else { ++ assert((xm >> (SP_MBITS + 1)) == 0); /* no execess */ ++ assert(xm & SP_HIDDEN_BIT); ++ ++ return buildsp(sn, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/ieee754sp.h linux-3.4.110/arch/nds32/math-emu/ieee754sp.h +--- linux-3.4.110.orig/arch/nds32/math-emu/ieee754sp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/ieee754sp.h 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,89 @@ ++/* ++ * IEEE754 floating point ++ * double precision internal header file ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754int.h" ++ ++#define assert(expr) ((void)0) ++ ++/* 3bit extended single precision sticky right shift */ ++#define SPXSRSXn(rs) \ ++ (xe += rs, \ ++ xm = (rs > (SP_MBITS+3))?1:((xm) >> (rs)) | ((xm) << (32-(rs)) != 0)) ++ ++#define SPXSRSX1() \ ++ (xe++, (xm = (xm >> 1) | (xm & 1))) ++ ++#define SPXSRSYn(rs) \ ++ (ye+=rs, \ ++ ym = (rs > (SP_MBITS+3))?1:((ym) >> (rs)) | ((ym) << (32-(rs)) != 0)) ++ ++#define SPXSRSY1() \ ++ (ye++, (ym = (ym >> 1) | (ym & 1))) ++ ++/* convert denormal to normalized with extended exponent */ ++#define SPDNORMx(m,e) \ ++ while( (m >> SP_MBITS) == 0) { m <<= 1; e--; } ++#define SPDNORMX SPDNORMx(xm, xe) ++#define SPDNORMY SPDNORMx(ym, ye) ++ ++static inline ieee754sp buildsp(int s, int bx, unsigned m) ++{ ++ ieee754sp r; ++ ++ assert((s) == 0 || (s) == 1); ++ assert((bx) >= SP_EMIN - 1 + SP_EBIAS ++ && (bx) <= SP_EMAX + 1 + SP_EBIAS); ++ assert(((m) >> SP_MBITS) == 0); ++ ++ r.parts.sign = s; ++ r.parts.bexp = bx; ++ r.parts.mant = m; ++ ++ return r; ++} ++ ++extern int ieee754sp_isnan(ieee754sp); ++extern int ieee754sp_issnan(ieee754sp); ++extern int ieee754si_xcpt(int, const char *, ...); ++extern s64 ieee754di_xcpt(s64, const char *, ...); ++extern ieee754sp ieee754sp_xcpt(ieee754sp, const char *, ...); ++extern ieee754sp ieee754sp_nanxcpt(ieee754sp, const char *, ...); ++extern ieee754sp ieee754sp_bestnan(ieee754sp, ieee754sp); ++extern ieee754sp ieee754sp_format(int, int, unsigned); ++ ++ ++#define SPNORMRET2(s, e, m, name, a0, a1) \ ++{ \ ++ ieee754sp V = ieee754sp_format(s, e, m); \ ++ if(TSTX()) \ ++ return ieee754sp_xcpt(V, name, a0, a1); \ ++ else \ ++ return V; \ ++} ++ ++#define SPNORMRET1(s, e, m, name, a0) SPNORMRET2(s, e, m, name, a0, a0) +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/ieee754xcpt.c linux-3.4.110/arch/nds32/math-emu/ieee754xcpt.c +--- linux-3.4.110.orig/arch/nds32/math-emu/ieee754xcpt.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/ieee754xcpt.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,48 @@ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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. ++ * ++ * ######################################################################## ++ */ ++ ++/************************************************************************** ++ * Nov 7, 2000 ++ * Added preprocessor hacks to map to Linux kernel diagnostics. ++ * ++ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com ++ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. ++ *************************************************************************/ ++ ++#include <linux/kernel.h> ++#include "ieee754.h" ++ ++/* ++ * Very naff exception handler (you can plug in your own and ++ * override this). ++ */ ++ ++static const char *const rtnames[] = { ++ "sp", "dp", "xp", "si", "di" ++}; ++ ++void ieee754_xcpt(struct ieee754xctx *xcp) ++{ ++ printk(KERN_DEBUG "floating point exception in \"%s\", type=%s\n", ++ xcp->op, rtnames[xcp->rt]); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/insn.h linux-3.4.110/arch/nds32/math-emu/insn.h +--- linux-3.4.110.orig/arch/nds32/math-emu/insn.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/insn.h 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,101 @@ ++#ifndef _ASM_INST_H ++#define _ASM_INST_H ++ ++#define cop0_op 0x35 ++ ++/* ++ * COP0 field of opcodes. ++ */ ++#define fs1_op 0x0 ++#define fs2_op 0x4 ++#define fd1_op 0x8 ++#define fd2_op 0xc ++ ++/* ++ * FS1 opcode. ++ */ ++enum fs1 { ++ fadds_op, fsubs_op, fcpynss_op, fcpyss_op, ++ fmadds_op, fmsubs_op, fcmovns_op, fcmovzs_op, ++ fnmadds_op, fnmsubs_op, ++ fmuls_op = 0xc, fdivs_op, ++ fs1_f2op_op = 0xf ++}; ++ ++/* ++ * FS1/F2OP opcode. ++ */ ++enum fs1_f2 { ++ fs2d_op, fsqrts_op, fabss_op = 0x5, ++ fui2s_op = 0x8, fsi2s_op = 0xc, ++ fs2ui_op = 0x10, fs2ui_z_op = 0x14, ++ fs2si_op = 0x18, fs2si_z_op = 0x1c ++}; ++ ++/* ++ * FS2 opcode. ++ */ ++enum fs2 { ++ fcmpeqs_op, fcmpeqs_e_op, fcmplts_op, fcmplts_e_op, ++ fcmples_op, fcmples_e_op, fcmpuns_op, fcmpuns_e_op ++}; ++ ++/* ++ * FD1 opcode. ++ */ ++enum fd1 { ++ faddd_op, fsubd_op, fcpynsd_op, fcpysd_op, ++ fmaddd_op, fmsubd_op, fcmovnd_op, fcmovzd_op, ++ fnmaddd_op, fnmsubd_op, ++ fmuld_op = 0xc, fdivd_op, fd1_f2op_op = 0xf ++}; ++ ++/* ++ * FD1/F2OP opcode. ++ */ ++enum fd1_f2 { ++ fd2s_op, fsqrtd_op, fabsd_op = 0x5, ++ fui2d_op = 0x8, fsi2d_op = 0xc, ++ fd2ui_op = 0x10, fd2ui_z_op = 0x14, ++ fd2si_op = 0x18, fd2si_z_op = 0x1c ++}; ++ ++/* ++ * FD2 opcode. ++ */ ++enum fd2 { ++ fcmpeqd_op, fcmpeqd_e_op, fcmpltd_op, fcmpltd_e_op, ++ fcmpled_op, fcmpled_e_op, fcmpund_op, fcmpund_e_op ++}; ++ ++ ++#define NDS32Insn(x) x ++ ++#define I_OPCODE_off 25 ++#define NDS32Insn_OPCODE(x) (NDS32Insn(x) >> I_OPCODE_off) ++ ++#define I_OPCODE_offRt 20 ++#define I_OPCODE_mskRt (0x1fUL << I_OPCODE_offRt) ++#define NDS32Insn_OPCODE_Rt(x) ((NDS32Insn(x) & I_OPCODE_mskRt) >> I_OPCODE_offRt) ++ ++#define I_OPCODE_offRa 15 ++#define I_OPCODE_mskRa (0x1fUL << I_OPCODE_offRa) ++#define NDS32Insn_OPCODE_Ra(x) ((NDS32Insn(x) & I_OPCODE_mskRa) >> I_OPCODE_offRa) ++ ++#define I_OPCODE_offRb 10 ++#define I_OPCODE_mskRb (0x1fUL << I_OPCODE_offRb) ++#define NDS32Insn_OPCODE_Rb(x) ((NDS32Insn(x) & I_OPCODE_mskRb) >> I_OPCODE_offRb) ++ ++#define I_OPCODE_offbit1014 10 ++#define I_OPCODE_mskbit1014 (0x1fUL << I_OPCODE_offbit1014) ++#define NDS32Insn_OPCODE_BIT1014(x) ((NDS32Insn(x) & I_OPCODE_mskbit1014) >> I_OPCODE_offbit1014) ++ ++#define I_OPCODE_offbit69 6 ++#define I_OPCODE_mskbit69 (0xfUL << I_OPCODE_offbit69) ++#define NDS32Insn_OPCODE_BIT69(x) ((NDS32Insn(x) & I_OPCODE_mskbit69) >> I_OPCODE_offbit69) ++ ++#define I_OPCODE_offCOP0 0 ++#define I_OPCODE_mskCOP0 (0x3fUL << I_OPCODE_offCOP0) ++#define NDS32Insn_OPCODE_COP0(x) ((NDS32Insn(x) & I_OPCODE_mskCOP0) >> I_OPCODE_offCOP0) ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/Makefile linux-3.4.110/arch/nds32/math-emu/Makefile +--- linux-3.4.110.orig/arch/nds32/math-emu/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/Makefile 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,13 @@ ++# ++# Makefile for the Linux/nds32 kernel FPU emulation. ++# ++ ++obj-y := fpuemu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \ ++ ieee754xcpt.o dp_frexp.o dp_modf.o dp_div.o dp_mul.o dp_sub.o \ ++ dp_add.o dp_fsp.o dp_cmp.o dp_logb.o dp_scalb.o dp_simple.o \ ++ dp_tint.o dp_fint.o dp_tlong.o dp_flong.o sp_frexp.o sp_modf.o \ ++ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_logb.o \ ++ sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \ ++ dp_sqrt.o sp_sqrt.o ++ ++EXTRA_CFLAGS += -Werror +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_add.c linux-3.4.110/arch/nds32/math-emu/sp_add.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_add.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_add.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,173 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++ieee754sp ieee754sp_add(ieee754sp x, ieee754sp y) ++{ ++ COMPXSP; ++ COMPYSP; ++ ++ EXPLODEXSP; ++ EXPLODEYSP; ++ ++ CLEARCX; ++ ++ FLUSHXSP; ++ FLUSHYSP; ++ ++ switch (CLPAIR(xc, yc)) { ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_nanxcpt(ieee754sp_indef(), "add", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): ++ return x; ++ ++ /* Infinity handling ++ */ ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): ++ if (xs == ys) ++ return x; ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_xcpt(ieee754sp_indef(), "add", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): ++ return x; ++ ++ /* Zero handling ++ */ ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): ++ if (xs == ys) ++ return x; ++ else ++ return ieee754sp_zero(ieee754_csr.rm == IEEE754_RD); ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): ++ return x; ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): ++ SPDNORMX; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): ++ SPDNORMY; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): ++ SPDNORMX; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): ++ break; ++ } ++ assert(xm & SP_HIDDEN_BIT); ++ assert(ym & SP_HIDDEN_BIT); ++ ++ /* provide guard,round and stick bit space */ ++ xm <<= 3; ++ ym <<= 3; ++ ++ if (xe > ye) { ++ /* have to shift y fraction right to align ++ */ ++ int s = xe - ye; ++ SPXSRSYn(s); ++ } else if (ye > xe) { ++ /* have to shift x fraction right to align ++ */ ++ int s = ye - xe; ++ SPXSRSXn(s); ++ } ++ assert(xe == ye); ++ assert(xe <= SP_EMAX); ++ ++ if (xs == ys) { ++ /* generate 28 bit result of adding two 27 bit numbers ++ * leaving result in xm,xs,xe ++ */ ++ xm = xm + ym; ++ xe = xe; ++ xs = xs; ++ ++ if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ ++ SPXSRSX1(); ++ } ++ } else { ++ if (xm >= ym) { ++ xm = xm - ym; ++ xe = xe; ++ xs = xs; ++ } else { ++ xm = ym - xm; ++ xe = xe; ++ xs = ys; ++ } ++ if (xm == 0) ++ return ieee754sp_zero(ieee754_csr.rm == IEEE754_RD); ++ ++ /* normalize in extended single precision */ ++ while ((xm >> (SP_MBITS + 3)) == 0) { ++ xm <<= 1; ++ xe--; ++ } ++ ++ } ++ SPNORMRET2(xs, xe, xm, "add", x, y); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_cmp.c linux-3.4.110/arch/nds32/math-emu/sp_cmp.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_cmp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_cmp.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,66 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++int ieee754sp_cmp(ieee754sp x, ieee754sp y, int cmp, int sig) ++{ ++ COMPXSP; ++ COMPYSP; ++ ++ EXPLODEXSP; ++ EXPLODEYSP; ++ FLUSHXSP; ++ FLUSHYSP; ++ CLEARCX; /* Even clear inexact flag here */ ++ ++ if (ieee754sp_isnan(x) || ieee754sp_isnan(y)) { ++ if (sig || xc == IEEE754_CLASS_SNAN || yc == IEEE754_CLASS_SNAN) ++ SETCX(IEEE754_INVALID_OPERATION); ++ if (cmp & IEEE754_CUN) ++ return 1; ++ if (cmp & (IEEE754_CLT | IEEE754_CGT)) { ++ if (sig && SETANDTESTCX(IEEE754_INVALID_OPERATION)) ++ return ieee754si_xcpt(0, "fcmpf", x); ++ } ++ return 0; ++ } else { ++ int vx = x.bits; ++ int vy = y.bits; ++ ++ if (vx < 0) ++ vx = -vx ^ SP_SIGN_BIT; ++ if (vy < 0) ++ vy = -vy ^ SP_SIGN_BIT; ++ ++ if (vx < vy) ++ return (cmp & IEEE754_CLT) != 0; ++ else if (vx == vy) ++ return (cmp & IEEE754_CEQ) != 0; ++ else ++ return (cmp & IEEE754_CGT) != 0; ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_div.c linux-3.4.110/arch/nds32/math-emu/sp_div.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_div.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_div.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,155 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++ieee754sp ieee754sp_div(ieee754sp x, ieee754sp y) ++{ ++ COMPXSP; ++ COMPYSP; ++ ++ EXPLODEXSP; ++ EXPLODEYSP; ++ ++ CLEARCX; ++ ++ FLUSHXSP; ++ FLUSHYSP; ++ ++ switch (CLPAIR(xc, yc)) { ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_nanxcpt(ieee754sp_indef(), "div", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): ++ return x; ++ ++ /* Infinity handling ++ */ ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): ++ return ieee754sp_zero(xs ^ ys); ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): ++ return ieee754sp_inf(xs ^ ys); ++ ++ /* Zero handling ++ */ ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_xcpt(ieee754sp_indef(), "div", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): ++ SETCX(IEEE754_ZERO_DIVIDE); ++ return ieee754sp_xcpt(ieee754sp_inf(xs ^ ys), "div", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): ++ return ieee754sp_zero(xs == ys ? 0 : 1); ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): ++ SPDNORMX; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): ++ SPDNORMY; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): ++ SPDNORMX; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): ++ break; ++ } ++ assert(xm & SP_HIDDEN_BIT); ++ assert(ym & SP_HIDDEN_BIT); ++ ++ /* provide rounding space */ ++ xm <<= 3; ++ ym <<= 3; ++ ++ { ++ /* now the dirty work */ ++ ++ unsigned rm = 0; ++ int re = xe - ye; ++ unsigned bm; ++ ++ for (bm = SP_MBIT(SP_MBITS + 2); bm; bm >>= 1) { ++ if (xm >= ym) { ++ xm -= ym; ++ rm |= bm; ++ if (xm == 0) ++ break; ++ } ++ xm <<= 1; ++ } ++ rm <<= 1; ++ if (xm) ++ rm |= 1; /* have remainder, set sticky */ ++ ++ assert(rm); ++ ++ /* normalise rm to rounding precision ? ++ */ ++ while ((rm >> (SP_MBITS + 3)) == 0) { ++ rm <<= 1; ++ re--; ++ } ++ ++ SPNORMRET2(xs == ys ? 0 : 1, re, rm, "div", x, y); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_fdp.c linux-3.4.110/arch/nds32/math-emu/sp_fdp.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_fdp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_fdp.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,76 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++ieee754sp ieee754sp_fdp(ieee754dp x) ++{ ++ COMPXDP; ++ ieee754sp nan; ++ ++ EXPLODEXDP; ++ ++ CLEARCX; ++ ++ FLUSHXDP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_nanxcpt(ieee754sp_indef(), "fdp"); ++ case IEEE754_CLASS_QNAN: ++ nan = buildsp(xs, SP_EMAX + 1 + SP_EBIAS, (u32) ++ (xm >> (DP_MBITS - SP_MBITS))); ++ if (!ieee754sp_isnan(nan)) ++ nan = ieee754sp_indef(); ++ return ieee754sp_nanxcpt(nan, "fdp", x); ++ case IEEE754_CLASS_INF: ++ return ieee754sp_inf(xs); ++ case IEEE754_CLASS_ZERO: ++ return ieee754sp_zero(xs); ++ case IEEE754_CLASS_DNORM: ++ /* can't possibly be sp representable */ ++ SETCX(IEEE754_UNDERFLOW); ++ SETCX(IEEE754_INEXACT); ++ if ((ieee754_csr.rm == IEEE754_RU && !xs) || ++ (ieee754_csr.rm == IEEE754_RD && xs)) ++ return ieee754sp_xcpt(ieee754sp_mind(xs), "fdp", x); ++ return ieee754sp_xcpt(ieee754sp_zero(xs), "fdp", x); ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ ++ { ++ u32 rm; ++ ++ /* convert from DP_MBITS to SP_MBITS+3 with sticky right shift ++ */ ++ rm = (xm >> (DP_MBITS - (SP_MBITS + 3))) | ++ ((xm << (64 - (DP_MBITS - (SP_MBITS + 3)))) != 0); ++ ++ SPNORMRET1(xs, xe, rm, "fdp", x); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_fint.c linux-3.4.110/arch/nds32/math-emu/sp_fint.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_fint.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_fint.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,78 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++ieee754sp ieee754sp_fint(int x) ++{ ++ unsigned xm; ++ int xe; ++ int xs; ++ ++ CLEARCX; ++ ++ if (x == 0) ++ return ieee754sp_zero(0); ++ if (x == 1 || x == -1) ++ return ieee754sp_one(x < 0); ++ if (x == 10 || x == -10) ++ return ieee754sp_ten(x < 0); ++ ++ xs = (x < 0); ++ if (xs) { ++ if (x == (1 << 31)) ++ xm = ((unsigned)1 << 31); /* max neg can't be safely negated */ ++ else ++ xm = -x; ++ } else { ++ xm = x; ++ } ++ xe = SP_MBITS + 3; ++ ++ if (xm >> (SP_MBITS + 1 + 3)) { ++ /* shunt out overflow bits ++ */ ++ while (xm >> (SP_MBITS + 1 + 3)) { ++ SPXSRSX1(); ++ } ++ } else { ++ /* normalize in grs extended single precision ++ */ ++ while ((xm >> (SP_MBITS + 3)) == 0) { ++ xm <<= 1; ++ xe--; ++ } ++ } ++ SPNORMRET1(xs, xe, xm, "fint", x); ++} ++ ++ieee754sp ieee754sp_funs(unsigned int u) ++{ ++ if ((int)u < 0) ++ return ieee754sp_add(ieee754sp_1e31(), ++ ieee754sp_fint(u & ~(1 << 31))); ++ return ieee754sp_fint(u); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_flong.c linux-3.4.110/arch/nds32/math-emu/sp_flong.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_flong.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_flong.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,77 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++ieee754sp ieee754sp_flong(s64 x) ++{ ++ u64 xm; /* <--- need 64-bit mantissa temp */ ++ int xe; ++ int xs; ++ ++ CLEARCX; ++ ++ if (x == 0) ++ return ieee754sp_zero(0); ++ if (x == 1 || x == -1) ++ return ieee754sp_one(x < 0); ++ if (x == 10 || x == -10) ++ return ieee754sp_ten(x < 0); ++ ++ xs = (x < 0); ++ if (xs) { ++ if (x == (1ULL << 63)) ++ xm = (1ULL << 63); /* max neg can't be safely negated */ ++ else ++ xm = -x; ++ } else { ++ xm = x; ++ } ++ xe = SP_MBITS + 3; ++ ++ if (xm >> (SP_MBITS + 1 + 3)) { ++ /* shunt out overflow bits ++ */ ++ while (xm >> (SP_MBITS + 1 + 3)) { ++ SPXSRSX1(); ++ } ++ } else { ++ /* normalize in grs extended single precision */ ++ while ((xm >> (SP_MBITS + 3)) == 0) { ++ xm <<= 1; ++ xe--; ++ } ++ } ++ SPNORMRET1(xs, xe, xm, "sp_flong", x); ++} ++ ++ieee754sp ieee754sp_fulong(u64 u) ++{ ++ if ((s64) u < 0) ++ return ieee754sp_add(ieee754sp_1e63(), ++ ieee754sp_flong(u & ~(1ULL << 63))); ++ return ieee754sp_flong(u); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_frexp.c linux-3.4.110/arch/nds32/math-emu/sp_frexp.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_frexp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_frexp.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,52 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++/* close to ieeep754sp_logb ++*/ ++ieee754sp ieee754sp_frexp(ieee754sp x, int *eptr) ++{ ++ COMPXSP; ++ CLEARCX; ++ EXPLODEXSP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ case IEEE754_CLASS_QNAN: ++ case IEEE754_CLASS_INF: ++ case IEEE754_CLASS_ZERO: ++ *eptr = 0; ++ return x; ++ case IEEE754_CLASS_DNORM: ++ SPDNORMX; ++ break; ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ *eptr = xe + 1; ++ return buildsp(xs, -1 + SP_EBIAS, xm & ~SP_HIDDEN_BIT); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_logb.c linux-3.4.110/arch/nds32/math-emu/sp_logb.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_logb.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_logb.c 2016-04-07 10:20:50.978082417 +0200 +@@ -0,0 +1,53 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++ieee754sp ieee754sp_logb(ieee754sp x) ++{ ++ COMPXSP; ++ ++ CLEARCX; ++ ++ EXPLODEXSP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ return ieee754sp_nanxcpt(x, "logb", x); ++ case IEEE754_CLASS_QNAN: ++ return x; ++ case IEEE754_CLASS_INF: ++ return ieee754sp_inf(0); ++ case IEEE754_CLASS_ZERO: ++ return ieee754sp_inf(1); ++ case IEEE754_CLASS_DNORM: ++ SPDNORMX; ++ break; ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ return ieee754sp_fint(xe); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_modf.c linux-3.4.110/arch/nds32/math-emu/sp_modf.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_modf.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_modf.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,79 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++/* modf function is always exact for a finite number ++*/ ++ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip) ++{ ++ COMPXSP; ++ ++ CLEARCX; ++ ++ EXPLODEXSP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ case IEEE754_CLASS_QNAN: ++ case IEEE754_CLASS_INF: ++ case IEEE754_CLASS_ZERO: ++ *ip = x; ++ return x; ++ case IEEE754_CLASS_DNORM: ++ /* far to small */ ++ *ip = ieee754sp_zero(xs); ++ return x; ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ if (xe < 0) { ++ *ip = ieee754sp_zero(xs); ++ return x; ++ } ++ if (xe >= SP_MBITS) { ++ *ip = x; ++ return ieee754sp_zero(xs); ++ } ++ /* generate ipart mantissa by clearing bottom bits ++ */ ++ *ip = buildsp(xs, xe + SP_EBIAS, ++ ((xm >> (SP_MBITS - xe)) << (SP_MBITS - xe)) & ++ ~SP_HIDDEN_BIT); ++ ++ /* generate fpart mantissa by clearing top bits ++ * and normalizing (must be able to normalize) ++ */ ++ xm = (xm << (32 - (SP_MBITS - xe))) >> (32 - (SP_MBITS - xe)); ++ if (xm == 0) ++ return ieee754sp_zero(xs); ++ ++ while ((xm >> SP_MBITS) == 0) { ++ xm <<= 1; ++ xe--; ++ } ++ return buildsp(xs, xe + SP_EBIAS, xm & ~SP_HIDDEN_BIT); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_mul.c linux-3.4.110/arch/nds32/math-emu/sp_mul.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_mul.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_mul.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,168 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++ieee754sp ieee754sp_mul(ieee754sp x, ieee754sp y) ++{ ++ COMPXSP; ++ COMPYSP; ++ ++ EXPLODEXSP; ++ EXPLODEYSP; ++ ++ CLEARCX; ++ ++ FLUSHXSP; ++ FLUSHYSP; ++ ++ switch (CLPAIR(xc, yc)) { ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_nanxcpt(ieee754sp_indef(), "mul", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): ++ return x; ++ ++ /* Infinity handling */ ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_xcpt(ieee754sp_indef(), "mul", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): ++ return ieee754sp_inf(xs ^ ys); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): ++ return ieee754sp_zero(xs ^ ys); ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): ++ SPDNORMX; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): ++ SPDNORMY; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): ++ SPDNORMX; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): ++ break; ++ } ++ /* rm = xm * ym, re = xe+ye basicly */ ++ assert(xm & SP_HIDDEN_BIT); ++ assert(ym & SP_HIDDEN_BIT); ++ ++ { ++ int re = xe + ye; ++ int rs = xs ^ ys; ++ unsigned rm; ++ ++ /* shunt to top of word */ ++ xm <<= 32 - (SP_MBITS + 1); ++ ym <<= 32 - (SP_MBITS + 1); ++ ++ /* multiply 32bits xm,ym to give high 32bits rm with stickness ++ */ ++ { ++ unsigned short lxm = xm & 0xffff; ++ unsigned short hxm = xm >> 16; ++ unsigned short lym = ym & 0xffff; ++ unsigned short hym = ym >> 16; ++ unsigned lrm; ++ unsigned hrm; ++ ++ lrm = lxm * lym; /* 16 * 16 => 32 */ ++ hrm = hxm * hym; /* 16 * 16 => 32 */ ++ ++ { ++ unsigned t = lxm * hym; /* 16 * 16 => 32 */ ++ { ++ unsigned at = lrm + (t << 16); ++ hrm += at < lrm; ++ lrm = at; ++ } ++ hrm = hrm + (t >> 16); ++ } ++ ++ { ++ unsigned t = hxm * lym; /* 16 * 16 => 32 */ ++ { ++ unsigned at = lrm + (t << 16); ++ hrm += at < lrm; ++ lrm = at; ++ } ++ hrm = hrm + (t >> 16); ++ } ++ rm = hrm | (lrm != 0); ++ } ++ ++ /* ++ * sticky shift down to normal rounding precision ++ */ ++ if ((int)rm < 0) { ++ rm = (rm >> (32 - (SP_MBITS + 1 + 3))) | ++ ((rm << (SP_MBITS + 1 + 3)) != 0); ++ re++; ++ } else { ++ rm = (rm >> (32 - (SP_MBITS + 1 + 3 + 1))) | ++ ((rm << (SP_MBITS + 1 + 3 + 1)) != 0); ++ } ++ assert(rm & (SP_HIDDEN_BIT << 3)); ++ ++ SPNORMRET2(rs, re, rm, "mul", x, y); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_scalb.c linux-3.4.110/arch/nds32/math-emu/sp_scalb.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_scalb.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_scalb.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,56 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++ieee754sp ieee754sp_scalb(ieee754sp x, int n) ++{ ++ COMPXSP; ++ ++ CLEARCX; ++ ++ EXPLODEXSP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ return ieee754sp_nanxcpt(x, "scalb", x, n); ++ case IEEE754_CLASS_QNAN: ++ case IEEE754_CLASS_INF: ++ case IEEE754_CLASS_ZERO: ++ return x; ++ case IEEE754_CLASS_DNORM: ++ SPDNORMX; ++ break; ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ SPNORMRET2(xs, xe + n, xm << 3, "scalb", x, n); ++} ++ ++ieee754sp ieee754sp_ldexp(ieee754sp x, int n) ++{ ++ return ieee754sp_scalb(x, n); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_simple.c linux-3.4.110/arch/nds32/math-emu/sp_simple.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_simple.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_simple.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,87 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++int ieee754sp_finite(ieee754sp x) ++{ ++ return SPBEXP(x) != SP_EMAX + 1 + SP_EBIAS; ++} ++ ++ieee754sp ieee754sp_copysign(ieee754sp x, ieee754sp y) ++{ ++ CLEARCX; ++ SPSIGN(x) = SPSIGN(y); ++ return x; ++} ++ ++ieee754sp ieee754sp_neg(ieee754sp x) ++{ ++ COMPXSP; ++ ++ EXPLODEXSP; ++ CLEARCX; ++ FLUSHXSP; ++ ++ /* ++ * Invert the sign ALWAYS to prevent an endless recursion on ++ * pow() in libc. ++ */ ++ /* quick fix up */ ++ SPSIGN(x) ^= 1; ++ ++ if (xc == IEEE754_CLASS_SNAN) { ++ ieee754sp y = ieee754sp_indef(); ++ SETCX(IEEE754_INVALID_OPERATION); ++ SPSIGN(y) = SPSIGN(x); ++ return ieee754sp_nanxcpt(y, "neg"); ++ } ++ ++ if (ieee754sp_isnan(x)) /* but not infinity */ ++ return ieee754sp_nanxcpt(x, "neg", x); ++ return x; ++} ++ ++ieee754sp ieee754sp_abs(ieee754sp x) ++{ ++ COMPXSP; ++ ++ EXPLODEXSP; ++ CLEARCX; ++ FLUSHXSP; ++ ++ if (xc == IEEE754_CLASS_SNAN) { ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_nanxcpt(ieee754sp_indef(), "abs"); ++ } ++ ++ if (ieee754sp_isnan(x)) /* but not infinity */ ++ return ieee754sp_nanxcpt(x, "abs", x); ++ ++ /* quick fix up */ ++ SPSIGN(x) = 0; ++ return x; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_sqrt.c linux-3.4.110/arch/nds32/math-emu/sp_sqrt.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_sqrt.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_sqrt.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,116 @@ ++/* IEEE754 floating point arithmetic ++ * single precision square root ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++ieee754sp ieee754sp_sqrt(ieee754sp x) ++{ ++ int ix, s, q, m, t, i; ++ unsigned int r; ++ COMPXSP; ++ ++ /* take care of Inf and NaN */ ++ ++ EXPLODEXSP; ++ CLEARCX; ++ FLUSHXSP; ++ ++ /* x == INF or NAN? */ ++ switch (xc) { ++ case IEEE754_CLASS_QNAN: ++ /* sqrt(Nan) = Nan */ ++ return ieee754sp_nanxcpt(x, "sqrt"); ++ case IEEE754_CLASS_SNAN: ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); ++ case IEEE754_CLASS_ZERO: ++ /* sqrt(0) = 0 */ ++ return x; ++ case IEEE754_CLASS_INF: ++ if (xs) { ++ /* sqrt(-Inf) = Nan */ ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); ++ } ++ /* sqrt(+Inf) = Inf */ ++ return x; ++ case IEEE754_CLASS_DNORM: ++ case IEEE754_CLASS_NORM: ++ if (xs) { ++ /* sqrt(-x) = Nan */ ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_nanxcpt(ieee754sp_indef(), "sqrt"); ++ } ++ break; ++ } ++ ++ ix = x.bits; ++ ++ /* normalize x */ ++ m = (ix >> 23); ++ if (m == 0) { /* subnormal x */ ++ for (i = 0; (ix & 0x00800000) == 0; i++) ++ ix <<= 1; ++ m -= i - 1; ++ } ++ m -= 127; /* unbias exponent */ ++ ix = (ix & 0x007fffff) | 0x00800000; ++ if (m & 1) /* odd m, double x to make it even */ ++ ix += ix; ++ m >>= 1; /* m = [m/2] */ ++ ++ /* generate sqrt(x) bit by bit */ ++ ix += ix; ++ q = s = 0; /* q = sqrt(x) */ ++ r = 0x01000000; /* r = moving bit from right to left */ ++ ++ while (r != 0) { ++ t = s + r; ++ if (t <= ix) { ++ s = t + r; ++ ix -= t; ++ q += r; ++ } ++ ix += ix; ++ r >>= 1; ++ } ++ ++ if (ix != 0) { ++ SETCX(IEEE754_INEXACT); ++ switch (ieee754_csr.rm) { ++ case IEEE754_RP: ++ q += 2; ++ break; ++ case IEEE754_RN: ++ q += (q & 1); ++ break; ++ } ++ } ++ ix = (q >> 1) + 0x3f000000; ++ ix += (m << 23); ++ x.bits = ix; ++ return x; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_sub.c linux-3.4.110/arch/nds32/math-emu/sp_sub.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_sub.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_sub.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,180 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++ieee754sp ieee754sp_sub(ieee754sp x, ieee754sp y) ++{ ++ COMPXSP; ++ COMPYSP; ++ ++ EXPLODEXSP; ++ EXPLODEYSP; ++ ++ CLEARCX; ++ ++ FLUSHXSP; ++ FLUSHYSP; ++ ++ switch (CLPAIR(xc, yc)) { ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_nanxcpt(ieee754sp_indef(), "sub", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): ++ case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): ++ return x; ++ ++ /* Infinity handling ++ */ ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): ++ if (xs != ys) ++ return x; ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754sp_xcpt(ieee754sp_indef(), "sub", x, y); ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): ++ return ieee754sp_inf(ys ^ 1); ++ ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): ++ return x; ++ ++ /* Zero handling ++ */ ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): ++ if (xs != ys) ++ return x; ++ else ++ return ieee754sp_zero(ieee754_csr.rm == IEEE754_RD); ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): ++ return x; ++ ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): ++ case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): ++ /* quick fix up */ ++ DPSIGN(y) ^= 1; ++ return y; ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): ++ SPDNORMX; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): ++ SPDNORMY; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): ++ SPDNORMX; ++ break; ++ ++ case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): ++ break; ++ } ++ /* flip sign of y and handle as add */ ++ ys ^= 1; ++ ++ assert(xm & SP_HIDDEN_BIT); ++ assert(ym & SP_HIDDEN_BIT); ++ ++ /* provide guard,round and stick bit space */ ++ xm <<= 3; ++ ym <<= 3; ++ ++ if (xe > ye) { ++ /* have to shift y fraction right to align ++ */ ++ int s = xe - ye; ++ SPXSRSYn(s); ++ } else if (ye > xe) { ++ /* have to shift x fraction right to align ++ */ ++ int s = ye - xe; ++ SPXSRSXn(s); ++ } ++ assert(xe == ye); ++ assert(xe <= SP_EMAX); ++ ++ if (xs == ys) { ++ /* generate 28 bit result of adding two 27 bit numbers ++ */ ++ xm = xm + ym; ++ xe = xe; ++ xs = xs; ++ ++ if (xm >> (SP_MBITS + 1 + 3)) { /* carry out */ ++ SPXSRSX1(); /* shift preserving sticky */ ++ } ++ } else { ++ if (xm >= ym) { ++ xm = xm - ym; ++ xe = xe; ++ xs = xs; ++ } else { ++ xm = ym - xm; ++ xe = xe; ++ xs = ys; ++ } ++ if (xm == 0) { ++ if (ieee754_csr.rm == IEEE754_RD) ++ return ieee754sp_zero(1); /* round negative inf. => sign = -1 */ ++ else ++ return ieee754sp_zero(0); /* other round modes => sign = 1 */ ++ } ++ /* normalize to rounding precision ++ */ ++ while ((xm >> (SP_MBITS + 3)) == 0) { ++ xm <<= 1; ++ xe--; ++ } ++ } ++ SPNORMRET2(xs, xe, xm, "sub", x, y); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_tint.c linux-3.4.110/arch/nds32/math-emu/sp_tint.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_tint.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_tint.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,125 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 <linux/kernel.h> ++#include "ieee754sp.h" ++ ++int ieee754sp_tint(ieee754sp x) ++{ ++ COMPXSP; ++ ++ CLEARCX; ++ ++ EXPLODEXSP; ++ FLUSHXSP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ case IEEE754_CLASS_QNAN: ++ case IEEE754_CLASS_INF: ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); ++ case IEEE754_CLASS_ZERO: ++ return 0; ++ case IEEE754_CLASS_DNORM: ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ if (xe >= 31) { ++ /* look for valid corner case */ ++ if (xe == 31 && xs && xm == SP_HIDDEN_BIT) ++ return -0x80000000; ++ /* Set invalid. We will only use overflow for floating ++ point overflow */ ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); ++ } ++ /* oh gawd */ ++ if (xe > SP_MBITS) { ++ xm <<= xe - SP_MBITS; ++ } else { ++ u32 residue; ++ int round; ++ int sticky; ++ int odd; ++ ++ if (xe < -1) { ++ residue = xm; ++ round = 0; ++ sticky = residue != 0; ++ xm = 0; ++ } else { ++ /* Shifting a u32 32 times does not work, ++ * so we do it in two steps. Be aware that xe ++ * may be -1 */ ++ residue = xm << (xe + 1); ++ residue <<= 31 - SP_MBITS; ++ round = (residue >> 31) != 0; ++ sticky = (residue << 1) != 0; ++ xm >>= SP_MBITS - xe; ++ } ++ odd = (xm & 0x1) != 0x0; ++ switch (ieee754_csr.rm) { ++ case IEEE754_RN: ++ if (round && (sticky || odd)) ++ xm++; ++ break; ++ case IEEE754_RZ: ++ break; ++ case IEEE754_RU: /* toward +Infinity */ ++ if ((round || sticky) && !xs) ++ xm++; ++ break; ++ case IEEE754_RD: /* toward -Infinity */ ++ if ((round || sticky) && xs) ++ xm++; ++ break; ++ } ++ if ((xm >> 31) != 0) { ++ /* This can happen after rounding */ ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754si_xcpt(ieee754si_indef(), "sp_tint", x); ++ } ++ if (round || sticky) ++ SETCX(IEEE754_INEXACT); ++ } ++ if (xs) ++ return -xm; ++ else ++ return xm; ++} ++ ++unsigned int ieee754sp_tuns(ieee754sp x) ++{ ++ ieee754sp hb = ieee754sp_1e31(); ++ ++ /* what if x < 0 ?? */ ++ if (ieee754sp_lt(x, hb)) ++ return (unsigned)ieee754sp_tint(x); ++ ++ return (unsigned)ieee754sp_tint(ieee754sp_sub(x, hb)) | ++ ((unsigned)1 << 31); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/math-emu/sp_tlong.c linux-3.4.110/arch/nds32/math-emu/sp_tlong.c +--- linux-3.4.110.orig/arch/nds32/math-emu/sp_tlong.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/math-emu/sp_tlong.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,119 @@ ++/* IEEE754 floating point arithmetic ++ * single precision ++ */ ++/* ++ * MIPS floating point support ++ * Copyright (C) 1994-2000 Algorithmics Ltd. ++ * http://www.algor.co.uk ++ * ++ * ######################################################################## ++ * ++ * This program is free software; you can distribute it and/or modify it ++ * under the terms of the GNU General Public License (Version 2) as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope 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 "ieee754sp.h" ++ ++s64 ieee754sp_tlong(ieee754sp x) ++{ ++ COMPXDP; /* <-- need 64-bit mantissa tmp */ ++ ++ CLEARCX; ++ ++ EXPLODEXSP; ++ FLUSHXSP; ++ ++ switch (xc) { ++ case IEEE754_CLASS_SNAN: ++ case IEEE754_CLASS_QNAN: ++ case IEEE754_CLASS_INF: ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); ++ case IEEE754_CLASS_ZERO: ++ return 0; ++ case IEEE754_CLASS_DNORM: ++ case IEEE754_CLASS_NORM: ++ break; ++ } ++ if (xe >= 63) { ++ /* look for valid corner case */ ++ if (xe == 63 && xs && xm == SP_HIDDEN_BIT) ++ return -0x8000000000000000LL; ++ /* Set invalid. We will only use overflow for floating ++ point overflow */ ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); ++ } ++ /* oh gawd */ ++ if (xe > SP_MBITS) { ++ xm <<= xe - SP_MBITS; ++ } else if (xe < SP_MBITS) { ++ u32 residue; ++ int round; ++ int sticky; ++ int odd; ++ ++ if (xe < -1) { ++ residue = xm; ++ round = 0; ++ sticky = residue != 0; ++ xm = 0; ++ } else { ++ residue = xm << (32 - SP_MBITS + xe); ++ round = (residue >> 31) != 0; ++ sticky = (residue << 1) != 0; ++ xm >>= SP_MBITS - xe; ++ } ++ odd = (xm & 0x1) != 0x0; ++ switch (ieee754_csr.rm) { ++ case IEEE754_RN: ++ if (round && (sticky || odd)) ++ xm++; ++ break; ++ case IEEE754_RZ: ++ break; ++ case IEEE754_RU: /* toward +Infinity */ ++ if ((round || sticky) && !xs) ++ xm++; ++ break; ++ case IEEE754_RD: /* toward -Infinity */ ++ if ((round || sticky) && xs) ++ xm++; ++ break; ++ } ++ if ((xm >> 63) != 0) { ++ /* This can happen after rounding */ ++ SETCX(IEEE754_INVALID_OPERATION); ++ return ieee754di_xcpt(ieee754di_indef(), "sp_tlong", x); ++ } ++ if (round || sticky) ++ SETCX(IEEE754_INEXACT); ++ } ++ if (xs) ++ return -xm; ++ else ++ return xm; ++} ++ ++u64 ieee754sp_tulong(ieee754sp x) ++{ ++ ieee754sp hb = ieee754sp_1e63(); ++ ++ /* what if x < 0 ?? */ ++ if (ieee754sp_lt(x, hb)) ++ return (u64) ieee754sp_tlong(x); ++ ++ return (u64) ieee754sp_tlong(ieee754sp_sub(x, hb)) | (1ULL << 63); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/mm/alignment.c linux-3.4.110/arch/nds32/mm/alignment.c +--- linux-3.4.110.orig/arch/nds32/mm/alignment.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/alignment.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,560 @@ ++/* ++ * linux/arch/nds32/mm/alignment.c ++ * ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/module.h> ++#include <linux/proc_fs.h> ++#include <linux/uaccess.h> ++ ++#include <asm/unaligned.h> ++ ++#ifdef CONFIG_PROC_FS ++extern struct proc_dir_entry *proc_dir_cpu; ++#endif ++ ++#define DEBUG(enable, tagged, ...) \ ++ do{ \ ++ if (enable) { \ ++ if (tagged) \ ++ printk(KERN_WARNING "[ %30s() ] ", __func__); \ ++ printk(KERN_WARNING __VA_ARGS__); \ ++ } \ ++ } while (0) ++ ++#define RT(inst) (((inst) >> 20) & 0x1FUL) ++#define RA(inst) (((inst) >> 15) & 0x1FUL) ++#define RB(inst) (((inst) >> 10) & 0x1FUL) ++#define SV(inst) (((inst) >> 8) & 0x3UL) ++#define IMM(inst) (((inst) >> 0) & 0x3FFFUL) ++ ++#define RA3(inst) (((inst) >> 3) & 0x7UL) ++#define RT3(inst) (((inst) >> 6) & 0x7UL) ++#define IMM3U(inst) (((inst) >> 0) & 0x7UL) ++ ++#define RA5(inst) (((inst) >> 0) & 0x1FUL) ++#define RT4(inst) (((inst) >> 5) & 0xFUL) ++ ++extern int (*do_unaligned_access) ++ (unsigned long entry, unsigned long addr, ++ unsigned long type, struct pt_regs * regs); ++extern int va_present(struct mm_struct *mm, unsigned long addr); ++extern int va_kernel_present(unsigned long addr); ++extern int va_readable(struct pt_regs *regs, unsigned long addr); ++extern int va_writable(struct pt_regs *regs, unsigned long addr); ++ ++static int mode = 0x3; ++module_param(mode, int, 1); ++ ++static inline unsigned long *idx_to_addr(struct pt_regs *regs, int idx) ++{ ++ /* this should be consistent with ptrace.h */ ++ if (idx >= 0 && idx <= 25) /* R0-R25 */ ++ return ®s->NDS32_r0 + idx; ++ else if (idx >= 28 && idx <= 30) /* FP, GP, LP */ ++ return ®s->NDS32_fp + (idx - 28); ++ else if (idx == 31) /* SP */ ++ return ®s->NDS32_sp; ++ else ++ return NULL; /* cause a segfault */ ++} ++ ++static inline unsigned long get_inst(unsigned long addr) ++{ ++ /* FIXME: consider 16-bit inst. */ ++ return be32_to_cpu(get_unaligned((u32 *) addr)); ++} ++ ++static inline unsigned long get_data(unsigned long addr, int len) ++{ ++ if (len == 4) ++ return get_unaligned((u32 *) addr); ++ else ++ return get_unaligned((u16 *) addr); ++} ++ ++static inline void set_data(unsigned long addr, unsigned long val, int len) ++{ ++ if (len == 4) ++ put_unaligned(val, (u32 *) addr); ++ else ++ put_unaligned(val, (u16 *) addr); ++} ++ ++static inline unsigned long sign_extend(unsigned long val, int len) ++{ ++ unsigned long ret = 0; ++ unsigned char *s, *t; ++ int i = 0; ++ ++ val = cpu_to_le32(val); ++ ++ s = (void *)&val; ++ t = (void *)&ret; ++ ++ while (i++ < len) ++ *t++ = *s++; ++ ++ if (((*(t - 1)) & 0x80) && (i < 4)) { ++ ++ while (i++ <= 4) ++ *t++ = 0xff; ++ } ++ ++ return le32_to_cpu(ret); ++} ++ ++static inline int do_16(unsigned long inst, struct pt_regs *regs) ++{ ++ int imm, regular, load, len, addr_mode, idx_mode; ++ unsigned long unaligned_addr, target_val, source_idx, target_idx, ++ shift = 0; ++ switch ((inst >> 9) & 0x3F) { ++ ++ case 0x12: /* LHI333 */ ++ imm = 1; ++ regular = 1; ++ load = 1; ++ len = 2; ++ addr_mode = 3; ++ idx_mode = 3; ++ break; ++ case 0x10: /* LWI333 */ ++ imm = 1; ++ regular = 1; ++ load = 1; ++ len = 4; ++ addr_mode = 3; ++ idx_mode = 3; ++ break; ++ case 0x11: /* LWI333.bi */ ++ imm = 1; ++ regular = 0; ++ load = 1; ++ len = 4; ++ addr_mode = 3; ++ idx_mode = 3; ++ break; ++ case 0x1A: /* LWI450 */ ++ imm = 0; ++ regular = 1; ++ load = 1; ++ len = 4; ++ addr_mode = 5; ++ idx_mode = 4; ++ break; ++ case 0x16: /* SHI333 */ ++ imm = 1; ++ regular = 1; ++ load = 0; ++ len = 2; ++ addr_mode = 3; ++ idx_mode = 3; ++ break; ++ case 0x14: /* SWI333 */ ++ imm = 1; ++ regular = 1; ++ load = 0; ++ len = 4; ++ addr_mode = 3; ++ idx_mode = 3; ++ break; ++ case 0x15: /* SWI333.bi */ ++ imm = 1; ++ regular = 0; ++ load = 0; ++ len = 4; ++ addr_mode = 3; ++ idx_mode = 3; ++ break; ++ case 0x1B: /* SWI450 */ ++ imm = 0; ++ regular = 1; ++ load = 0; ++ len = 4; ++ addr_mode = 5; ++ idx_mode = 4; ++ break; ++ ++ default: ++ return -EFAULT; ++ } ++ ++ if (addr_mode == 3) { ++ unaligned_addr = *idx_to_addr(regs, RA3(inst)); ++ source_idx = RA3(inst); ++ } else { ++ unaligned_addr = *idx_to_addr(regs, RA5(inst)); ++ source_idx = RA5(inst); ++ } ++ ++ if (idx_mode == 3) ++ target_idx = RT3(inst); ++ else ++ target_idx = RT4(inst); ++ ++ if (imm) ++ shift = IMM3U(inst) * len; ++ ++ if (regular) ++ unaligned_addr += shift; ++ else ++ *idx_to_addr(regs, source_idx) = unaligned_addr + shift; ++ ++ if (load) { ++ ++ if (!va_readable(regs, unaligned_addr)) ++ return -EACCES; ++ ++ if (!access_ok(VERIFY_READ, (void *)unaligned_addr, len)) ++ return -EACCES; ++ ++ *idx_to_addr(regs, target_idx) = get_data(unaligned_addr, len); ++ } else { ++ ++ if (!va_writable(regs, unaligned_addr)) ++ return -EACCES; ++ ++ if (!access_ok(VERIFY_WRITE, (void *)unaligned_addr, len)) ++ return -EACCES; ++ ++ target_val = *idx_to_addr(regs, target_idx); ++ set_data(unaligned_addr, target_val, len); ++ } ++ ++ regs->NDS32_ipc += 2; ++ ++ return 0; ++} ++ ++static inline int do_32(unsigned long inst, struct pt_regs *regs) ++{ ++ int imm, regular, load, len, sign_ext; ++ unsigned long unsligned_addr, target_val, shift; ++ ++ unsligned_addr = *idx_to_addr(regs, RA(inst)); ++ ++ switch ((inst >> 25) << 1) { ++ ++ case 0x02: /* LHI */ ++ imm = 1; ++ regular = 1; ++ load = 1; ++ len = 2; ++ sign_ext = 0; ++ break; ++ case 0x0A: /* LHI.bi */ ++ imm = 1; ++ regular = 0; ++ load = 1; ++ len = 2; ++ sign_ext = 0; ++ break; ++ case 0x22: /* LHSI */ ++ imm = 1; ++ regular = 1; ++ load = 1; ++ len = 2; ++ sign_ext = 1; ++ break; ++ case 0x2A: /* LHSI.bi */ ++ imm = 1; ++ regular = 0; ++ load = 1; ++ len = 2; ++ sign_ext = 1; ++ break; ++ case 0x04: /* LWI */ ++ imm = 1; ++ regular = 1; ++ load = 1; ++ len = 4; ++ sign_ext = 0; ++ break; ++ case 0x0C: /* LWI.bi */ ++ imm = 1; ++ regular = 0; ++ load = 1; ++ len = 4; ++ sign_ext = 0; ++ break; ++ case 0x12: /* SHI */ ++ imm = 1; ++ regular = 1; ++ load = 0; ++ len = 2; ++ sign_ext = 0; ++ break; ++ case 0x1A: /* SHI.bi */ ++ imm = 1; ++ regular = 0; ++ load = 0; ++ len = 2; ++ sign_ext = 0; ++ break; ++ case 0x14: /* SWI */ ++ imm = 1; ++ regular = 1; ++ load = 0; ++ len = 4; ++ sign_ext = 0; ++ break; ++ case 0x1C: /* SWI.bi */ ++ imm = 1; ++ regular = 0; ++ load = 0; ++ len = 4; ++ sign_ext = 0; ++ break; ++ ++ default: ++ switch (inst & 0xff) { ++ ++ case 0x01: /* LH */ ++ imm = 0; ++ regular = 1; ++ load = 1; ++ len = 2; ++ sign_ext = 0; ++ break; ++ case 0x05: /* LH.bi */ ++ imm = 0; ++ regular = 0; ++ load = 1; ++ len = 2; ++ sign_ext = 0; ++ break; ++ case 0x11: /* LHS */ ++ imm = 0; ++ regular = 1; ++ load = 1; ++ len = 2; ++ sign_ext = 1; ++ break; ++ case 0x15: /* LHS.bi */ ++ imm = 0; ++ regular = 0; ++ load = 1; ++ len = 2; ++ sign_ext = 1; ++ break; ++ case 0x02: /* LW */ ++ imm = 0; ++ regular = 1; ++ load = 1; ++ len = 4; ++ sign_ext = 0; ++ break; ++ case 0x06: /* LW.bi */ ++ imm = 0; ++ regular = 0; ++ load = 1; ++ len = 4; ++ sign_ext = 0; ++ break; ++ case 0x09: /* SH */ ++ imm = 0; ++ regular = 1; ++ load = 0; ++ len = 2; ++ sign_ext = 0; ++ break; ++ case 0x0D: /* SH.bi */ ++ imm = 0; ++ regular = 0; ++ load = 0; ++ len = 2; ++ sign_ext = 0; ++ break; ++ case 0x0A: /* SW */ ++ imm = 0; ++ regular = 1; ++ load = 0; ++ len = 4; ++ sign_ext = 0; ++ break; ++ case 0x0E: /* SW.bi */ ++ imm = 0; ++ regular = 0; ++ load = 0; ++ len = 4; ++ sign_ext = 0; ++ break; ++ ++ default: ++ return -EFAULT; ++ } ++ } ++ ++ if (imm) ++ shift = IMM(inst) * len; ++ else ++ shift = *idx_to_addr(regs, RB(inst)) << SV(inst); ++ ++ if (regular) ++ unsligned_addr += shift; ++ else ++ *idx_to_addr(regs, RA(inst)) = unsligned_addr + shift; ++ ++ if (load) { ++ ++ if (!va_readable(regs, unsligned_addr)) ++ return -EACCES; ++ ++ if (!access_ok(VERIFY_READ, (void *)unsligned_addr, len)) ++ return -EACCES; ++ ++ if (sign_ext) ++ *idx_to_addr(regs, RT(inst)) = ++ sign_extend(get_data(unsligned_addr, len), len); ++ else ++ *idx_to_addr(regs, RT(inst)) = ++ get_data(unsligned_addr, len); ++ } else { ++ ++ if (!va_writable(regs, unsligned_addr)) ++ return -EACCES; ++ ++ if (!access_ok(VERIFY_WRITE, (void *)unsligned_addr, len)) ++ return -EACCES; ++ ++ target_val = *idx_to_addr(regs, RT(inst)); ++ set_data(unsligned_addr, target_val, len); ++ } ++ ++ regs->NDS32_ipc += 4; ++ ++ return 0; ++} ++ ++static int _do_unaligned_access(unsigned long entry, unsigned long addr, ++ unsigned long type, struct pt_regs *regs) ++{ ++ unsigned long inst; ++ int ret = -EFAULT; ++ ++ if (user_mode(regs)) { ++ /* user mode */ ++ if (!va_present(current->mm, addr)) ++ return ret; ++ } else { ++ /* kernel mode */ ++ if (!va_kernel_present(addr)) ++ return ret; ++ } ++ ++ inst = get_inst(regs->NDS32_ipc); ++ ++ DEBUG(mode & 0x04, 1, ++ "Faulting Addr: 0x%08lx, PC: 0x%08lx [ 0x%08lx ]\n", addr, ++ regs->NDS32_ipc, inst); ++ ++ if ((user_mode(regs) && (mode & 0x01)) ++ || (!user_mode(regs) && (mode & 0x02))) { ++ ++ mm_segment_t seg = get_fs(); ++ ++ set_fs(KERNEL_DS); ++ ++ if (inst & 0x80000000) ++ ret = do_16((inst >> 16) & 0xffff, regs); ++ else ++ ret = do_32(inst, regs); ++ ++ set_fs(seg); ++ } ++ ++ return ret; ++} ++ ++#ifdef CONFIG_PROC_FS ++ ++static int proc_alignment_read(char *page, char **start, off_t off, int count, ++ int *eof, void *data) ++{ ++ char *p = page; ++ int len; ++ ++ p += sprintf(p, "(0x01) User Mode: %s\n", mode & 0x01 ? "on" : "off"); ++ p += sprintf(p, "(0x02) Kernel Mode: %s\n", mode & 0x02 ? "on" : "off"); ++ p += sprintf(p, "(0x04) Warning: %s\n", mode & 0x04 ? "on" : "off"); ++ ++ len = (p - page) - off; ++ if (len < 0) ++ len = 0; ++ ++ *eof = (len <= count) ? 1 : 0; ++ *start = page + off; ++ ++ return len; ++} ++ ++#define INPUTLEN 12 /* '0' + 'x' + 8digit + '\n' + '\0' */ ++ ++static int proc_alignment_write(struct file *file, const char __user * buffer, ++ unsigned long count, void *data) ++{ ++ unsigned long en; ++ char *endp; ++ char inbuf[INPUTLEN]; ++ ++ if (count > INPUTLEN - 1) ++ return -EFAULT; ++ ++ if (copy_from_user(inbuf, buffer, count)) ++ return -EFAULT; ++ ++ inbuf[count - 1] = '\0'; ++ ++ en = simple_strtoul(inbuf, &endp, 0); ++ if (en > 0x07) ++ return -EFAULT; ++ ++ mode = en & 0x7; ++ ++ return count; ++} ++ ++#endif /* CONFIG_PROC_FS */ ++ ++static int __init unaligned_access_init(void) ++{ ++#ifdef CONFIG_PROC_FS ++ static struct proc_dir_entry *res_alignment; ++ ++ if (!proc_dir_cpu) ++ if (!(proc_dir_cpu = proc_mkdir("cpu", NULL))) ++ return -ENOMEM; ++ ++ if (! ++ (res_alignment = ++ create_proc_entry("alignment", S_IWUSR | S_IRUGO, proc_dir_cpu))) ++ return -ENOMEM; ++ ++ res_alignment->read_proc = proc_alignment_read; ++ res_alignment->write_proc = proc_alignment_write; ++#endif ++ do_unaligned_access = _do_unaligned_access; ++ ++ return 0; ++} ++ ++static void __exit unaligned_access_exit(void) ++{ ++#ifdef CONFIG_PROC_FS ++ remove_proc_entry("alignment", proc_dir_cpu); ++#endif ++ do_unaligned_access = NULL; ++} ++ ++MODULE_AUTHOR("Roy Lee"); ++MODULE_DESCRIPTION("Unaligned Access Handler"); ++MODULE_LICENSE("GPL"); ++ ++module_init(unaligned_access_init); ++module_exit(unaligned_access_exit); +diff -Nur linux-3.4.110.orig/arch/nds32/mm/cacheflush.c linux-3.4.110/arch/nds32/mm/cacheflush.c +--- linux-3.4.110.orig/arch/nds32/mm/cacheflush.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/cacheflush.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,355 @@ ++#include <linux/mm.h> ++#include <linux/sched.h> ++#include <linux/fs.h> ++#include <linux/pagemap.h> ++#include <linux/module.h> ++#include <asm/cacheflush.h> ++#include <asm/proc-fns.h> ++#include <asm/shmparam.h> ++#include <asm/cache_info.h> ++ ++extern struct cache_info L1_cache_info[2]; ++ ++#ifdef CONFIG_CPU_CACHE_NONALIASING ++void flush_cache_mm(struct mm_struct *mm) ++{ ++} ++ ++void flush_cache_dup_mm(struct mm_struct *mm) ++{ ++} ++ ++void flush_cache_range(struct vm_area_struct *vma, ++ unsigned long start, unsigned long end) ++{ ++} ++ ++void flush_cache_page(struct vm_area_struct *vma, ++ unsigned long addr, unsigned long pfn) ++{ ++} ++ ++void flush_cache_vmap(unsigned long start, unsigned long end) ++{ ++} ++ ++void flush_cache_vunmap(unsigned long start, unsigned long end) ++{ ++} ++ ++void flush_dcache_page(struct page *page) ++{ ++ struct address_space *mapping; ++ ++ if (!PageHighMem(page)) { ++ mapping = page_mapping(page); ++ if (mapping && !mapping_mapped(mapping)) ++ set_bit(PG_dcache_dirty, &page->flags); ++ else ++ cpu_dcache_wbinval_page((unsigned long) ++ page_address(page)); ++ } else { ++ unsigned long kaddr = (unsigned long)kmap_atomic(page); ++ cpu_dcache_wbinval_page(kaddr); ++ kunmap_atomic((void *)kaddr); ++ } ++} ++ ++void copy_to_user_page(struct vm_area_struct *vma, struct page *page, ++ unsigned long vaddr, void *dst, void *src, int len) ++{ ++ unsigned long line_size, start, end; ++ ++ memcpy(dst, src, len); ++ if (vma->vm_flags & VM_EXEC) { ++ line_size = L1_cache_info[DCACHE].line_size; ++ start = (unsigned long)dst & ~(line_size - 1); ++ end = ++ ((unsigned long)dst + len + line_size - 1) & ~(line_size - ++ 1); ++ cpu_cache_wbinval_range(start, end, 1); ++ } ++} ++ ++void copy_from_user_page(struct vm_area_struct *vma, struct page *page, ++ unsigned long vaddr, void *dst, void *src, int len) ++{ ++ memcpy(dst, src, len); ++} ++ ++void flush_icache_range(unsigned long start, unsigned long end) ++{ ++ cpu_cache_wbinval_range(start, end, 1); ++} ++ ++void flush_icache_page(struct vm_area_struct *vma, struct page *page) ++{ ++} ++ ++void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, ++ pte_t * pte) ++{ ++ struct page *page; ++ unsigned long pfn = pte_pfn(*pte); ++ ++ if (!pfn_valid(pfn)) ++ return; ++ ++ if (vma->vm_mm == current->active_mm) ++ asm("mtsr %1, $mr2\ndsb\n" ++ "tlbop %0, RWR\nisb\n" ++ ::"r"(*pte), "r"(addr)); ++ ++ page = pfn_to_page(pfn); ++ ++ if ((test_and_clear_bit(PG_dcache_dirty, &page->flags)) || ++ (vma->vm_flags & VM_EXEC)) { ++ ++ if (!PageHighMem(page)) { ++ cpu_cache_wbinval_page((unsigned long) ++ page_address(page), ++ vma->vm_flags & VM_EXEC); ++ } else { ++ unsigned long kaddr = (unsigned long)kmap_atomic(page); ++ cpu_cache_wbinval_page(kaddr, vma->vm_flags & VM_EXEC); ++ kunmap_atomic((void *)kaddr); ++ } ++ } ++} ++#else ++int va_present(struct mm_struct *mm, unsigned long addr); ++ ++static inline unsigned long aliasing(unsigned long addr, unsigned long page) ++{ ++ return ((addr & PAGE_MASK) ^ page) & (REALSHMLBA - 1); ++} ++ ++static inline unsigned long kremap0(unsigned long uaddr, unsigned long pa) ++{ ++ unsigned long kaddr, pte; ++ ++#define BASE_ADDR0 0xffffc000 ++ kaddr = BASE_ADDR0 | (uaddr & L1_cache_info[DCACHE].aliasing_mask); ++ pte = (pa | PAGE_KERNEL); ++ asm("mtsr %1, $mr2\ndsb\n" ++ "tlbop %0, RWLK\nisb\n" ++ ::"r"(pte), "r"(kaddr)); ++ return kaddr; ++} ++ ++static inline void kunmap01(unsigned long kaddr) ++{ ++ asm volatile ("tlbop %0, UNLK\n\t" ++ "tlbop %0, INV\n\t" ++ ::"r" (kaddr)); ++} ++ ++static inline unsigned long kremap1(unsigned long uaddr, unsigned long pa) ++{ ++ unsigned long kaddr, pte; ++ ++#define BASE_ADDR1 0xffff8000 ++ kaddr = BASE_ADDR1 | (uaddr & L1_cache_info[DCACHE].aliasing_mask); ++ pte = (pa | PAGE_KERNEL); ++ asm("mtsr %1, $mr2\ndsb\n" ++ "tlbop %0, RWLK\nisb\n" ++ ::"r"(pte), "r"(kaddr)); ++ return kaddr; ++} ++ ++void flush_cache_mm(struct mm_struct *mm) ++{ ++ cpu_dcache_wbinval_all(); ++ cpu_icache_inval_all(); ++} ++ ++void flush_cache_dup_mm(struct mm_struct *mm) ++{ ++} ++ ++void flush_cache_range(struct vm_area_struct *vma, ++ unsigned long start, unsigned long end) ++{ ++ if ((end - start) > 8 * PAGE_SIZE) { ++ cpu_dcache_wbinval_all(); ++ if (vma->vm_flags & VM_EXEC) ++ cpu_icache_inval_all(); ++ return; ++ } ++ ++ while (start < end) { ++ if (va_present(vma->vm_mm, start)) ++ cpu_cache_wbinval_page(start, vma->vm_flags & VM_EXEC); ++ start += PAGE_SIZE; ++ } ++} ++ ++void flush_cache_page(struct vm_area_struct *vma, ++ unsigned long addr, unsigned long pfn) ++{ ++ unsigned long vto, flags; ++ ++ local_irq_save(flags); ++ vto = kremap0(addr, pfn << PAGE_SHIFT); ++ cpu_cache_wbinval_page(vto, vma->vm_flags & VM_EXEC); ++ kunmap01(vto); ++ local_irq_restore(flags); ++} ++ ++void flush_cache_vmap(unsigned long start, unsigned long end) ++{ ++ cpu_dcache_wbinval_all(); ++} ++ ++void flush_cache_vunmap(unsigned long start, unsigned long end) ++{ ++ cpu_dcache_wbinval_all(); ++} ++ ++void copy_user_highpage(struct page *to, struct page *from, ++ unsigned long vaddr, struct vm_area_struct *vma) ++{ ++ unsigned long vto, vfrom, flags, kto, kfrom, pfrom, pto; ++ kto = ((unsigned long)page_address(to) & PAGE_MASK); ++ kfrom = ((unsigned long)page_address(from) & PAGE_MASK); ++ pto = page_to_phys(to); ++ pfrom = page_to_phys(from); ++ ++ if (aliasing(vaddr, (unsigned long)kfrom)) ++ cpu_dcache_wb_page((unsigned long)kfrom); ++ if (aliasing(vaddr, (unsigned long)kto)) ++ cpu_dcache_inval_page((unsigned long)kto); ++ local_irq_save(flags); ++ vto = kremap0(vaddr, pto); ++ vfrom = kremap1(vaddr, pfrom); ++ copy_page((void *)vto, (void *)vfrom); ++ kunmap01(vfrom); ++ kunmap01(vto); ++ local_irq_restore(flags); ++} ++ ++EXPORT_SYMBOL(copy_user_highpage); ++ ++void clear_user_highpage(struct page *page, unsigned long vaddr) ++{ ++ unsigned long vto, flags, kto; ++ ++ kto = ((unsigned long)page_address(page) & PAGE_MASK); ++ ++ local_irq_save(flags); ++ if (aliasing(kto, vaddr) && kto != 0) { ++ cpu_dcache_inval_page(kto); ++ cpu_icache_inval_page(kto); ++ } ++ vto = kremap0(vaddr, page_to_phys(page)); ++ clear_page((void *)vto); ++ kunmap01(vto); ++ local_irq_restore(flags); ++} ++ ++EXPORT_SYMBOL(clear_user_highpage); ++ ++void flush_dcache_page(struct page *page) ++{ ++ struct address_space *mapping; ++ ++ mapping = page_mapping(page); ++ if (mapping && !mapping_mapped(mapping)) ++ set_bit(PG_dcache_dirty, &page->flags); ++ else { ++ int i, pc; ++ unsigned long vto, kaddr, flags; ++ cpu_dcache_wbinval_page((unsigned long)page_address(page)); ++ kaddr = (unsigned long)page_address(page); ++ pc = CACHE_SET(DCACHE) * CACHE_LINE_SIZE(DCACHE) / PAGE_SIZE; ++ for (i = 0; i < pc; i++) { ++ local_irq_save(flags); ++ vto = kremap0(kaddr + i * PAGE_SIZE, __pa(kaddr)); ++ cpu_dcache_wbinval_page(vto); ++ kunmap01(vto); ++ local_irq_restore(flags); ++ } ++ } ++} ++ ++void copy_to_user_page(struct vm_area_struct *vma, struct page *page, ++ unsigned long vaddr, void *dst, void *src, int len) ++{ ++ unsigned long line_size, start, end, vto, flags; ++ ++ local_irq_save(flags); ++ vto = kremap0(vaddr, page_to_phys(page)); ++ dst = (void *)(vto | (vaddr & (PAGE_SIZE - 1))); ++ memcpy(dst, src, len); ++ if (vma->vm_flags & VM_EXEC) { ++ line_size = L1_cache_info[DCACHE].line_size; ++ start = (unsigned long)dst & ~(line_size - 1); ++ end = ++ ((unsigned long)dst + len + line_size - 1) & ~(line_size - ++ 1); ++ cpu_cache_wbinval_range(start, end, 1); ++ } ++ kunmap01(vto); ++ local_irq_restore(flags); ++} ++ ++void copy_from_user_page(struct vm_area_struct *vma, struct page *page, ++ unsigned long vaddr, void *dst, void *src, int len) ++{ ++ unsigned long vto, flags; ++ ++ local_irq_save(flags); ++ vto = kremap0(vaddr, page_to_phys(page)); ++ src = (void *)(vto | (vaddr & (PAGE_SIZE - 1))); ++ memcpy(dst, src, len); ++ kunmap01(vto); ++ local_irq_restore(flags); ++} ++ ++void flush_anon_page(struct vm_area_struct *vma, ++ struct page *page, unsigned long vaddr) ++{ ++ if (!PageAnon(page)) ++ return; ++ ++ if (vma->vm_mm != current->active_mm) ++ return; ++ ++ cpu_cache_wbinval_page(vaddr & PAGE_MASK, vma->vm_flags & VM_EXEC); ++} ++ ++void flush_kernel_dcache_page(struct page *page) ++{ ++ cpu_dcache_wbinval_page((unsigned long)page_address(page)); ++} ++ ++void flush_icache_range(unsigned long start, unsigned long end) ++{ ++ cpu_cache_wbinval_range(start, end, 1); ++} ++ ++void flush_icache_page(struct vm_area_struct *vma, struct page *page) ++{ ++} ++ ++void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, ++ pte_t * pte) ++{ ++ struct page *page; ++ unsigned long pfn = pte_pfn(*pte); ++ ++ if (!pfn_valid(pfn)) ++ return; ++ ++ if (vma->vm_mm == current->active_mm) { ++ asm("mtsr %1, $mr2\ndsb\n" ++ "tlbop %0, RWR\nisb\n" ++ ::"r"(*pte), "r"(addr)); ++ } ++ ++ page = pfn_to_page(pfn); ++ if (test_and_clear_bit(PG_dcache_dirty, &page->flags) || ++ (vma->vm_flags & VM_EXEC)) ++ cpu_dcache_wbinval_page((unsigned long)page_address(page)); ++} ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/mm/cctl.c linux-3.4.110/arch/nds32/mm/cctl.c +--- linux-3.4.110.orig/arch/nds32/mm/cctl.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/cctl.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,284 @@ ++/* ++ * linux/arch/nds32/mm/cctl.c ++ * ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include "cctl.h" ++ ++#define DEBUG( enable, tagged, ...) \ ++ do{ \ ++ if( enable){ \ ++ if( tagged) \ ++ printk( "[ %30s() ] ", __func__); \ ++ printk( __VA_ARGS__); \ ++ } \ ++ } while( 0) ++ ++static int debug = 1; ++module_param(debug, int, 0); ++ ++static int proc_read_cache_en(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ ++ if (!strncmp(data, "ic_en", 7)) ++ return sprintf(page, "I-cache: %s\n", ++ (GET_CACHE_CTL() & CACHE_CTL_mskIC_EN) ? ++ "Enabled" : "Disabled"); ++ else ++ return sprintf(page, "D-cache: %s\n", ++ (GET_CACHE_CTL() & CACHE_CTL_mskDC_EN) ? ++ "Enabled" : "Disabled"); ++} ++ ++static int proc_write_cache_en(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ ++ unsigned long en, saved_gie; ++ char inbuf[INPUTLEN]; ++ ++ if (count > INPUTLEN - 1) ++ count = INPUTLEN - 1; ++ ++ if (copy_from_user(inbuf, buffer, count)) ++ return -EFAULT; ++ ++ inbuf[count] = '\0'; ++ ++ if (!sscanf(inbuf, "%lu", &en) || en > 1) ++ return -EFAULT; ++ ++ GIE_SAVE(&saved_gie); ++ ++ if (!strncmp(data, "ic_en", 7)) { ++ ++ if (en && !(GET_CACHE_CTL() & CACHE_CTL_mskIC_EN)) { ++ ++ SET_CACHE_CTL(GET_CACHE_CTL() | CACHE_CTL_mskIC_EN); ++ DEBUG(debug, 1, "I-cache: Enabled\n"); ++ } else if (!en && (GET_CACHE_CTL() & CACHE_CTL_mskIC_EN)) { ++ ++ SET_CACHE_CTL(GET_CACHE_CTL() & ~CACHE_CTL_mskIC_EN); ++ cpu_icache_inval_all(); ++ DEBUG(debug, 1, "I-cache: Disabled\n"); ++ } ++ } else { ++ if (en && !(GET_CACHE_CTL() & CACHE_CTL_mskDC_EN)) { ++ ++ SET_CACHE_CTL(GET_CACHE_CTL() | CACHE_CTL_mskDC_EN); ++ DEBUG(debug, 1, "D-cache: Enabled\n"); ++ } else if (!en && (GET_CACHE_CTL() & CACHE_CTL_mskDC_EN)) { ++ ++ SET_CACHE_CTL(GET_CACHE_CTL() & ~CACHE_CTL_mskDC_EN); ++ cpu_dcache_wbinval_all(); ++ DEBUG(debug, 1, "D-cache: Disabled\n"); ++ } ++ } ++ ++ GIE_RESTORE(saved_gie); ++ ++ return count; ++} ++ ++struct entry_struct proc_table_cache_en[] = { ++ ++ {"ic_en", 0644, proc_read_cache_en, proc_write_cache_en}, ++ {"dc_en", 0644, proc_read_cache_en, proc_write_cache_en}, ++ {NULL, 0, NULL, NULL} ++}; ++ ++static int sprint_cache_sdz(char *buf, unsigned long size, unsigned long way, ++ unsigned sdz) ++{ ++ ++ return sprintf(buf, "[%c] %luK x %lu\n[%c] %luK x %lu\n" ++ "[%c] %luK x %lu\n[%c] %luK x %lu\n", ++ (sdz == 0) ? '*' : ' ', (size / 1024), way, ++ (sdz == 1) ? '*' : ' ', (size / 1024), way / 2, ++ (sdz == 2) ? '*' : ' ', (size / 1024) / 2, way, ++ (sdz == 3) ? '*' : ' ', (size / 1024) / 2, way / 2); ++} ++ ++static int proc_read_cache_sdz(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ ++ if (!strncmp(data, "ic_sdz", 7)) { ++ ++ return sprint_cache_sdz(page, ++ CACHE_LINE_SIZE(ICACHE) * ++ CACHE_SET(ICACHE), CACHE_WAY(ICACHE), ++ (GET_SDZ_CTL() & SDZ_CTL_mskICDZ) >> ++ SDZ_CTL_offICDZ); ++ } else { ++ return sprint_cache_sdz(page, ++ CACHE_LINE_SIZE(DCACHE) * ++ CACHE_SET(DCACHE), CACHE_WAY(DCACHE), ++ (GET_SDZ_CTL() & SDZ_CTL_mskDCDZ) >> ++ SDZ_CTL_offDCDZ); ++ } ++} ++ ++static int proc_write_cache_sdz(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ ++ unsigned long mode, saved_gie, saved_cctl; ++ char inbuf[INPUTLEN]; ++ ++ if (count > INPUTLEN - 1) ++ count = INPUTLEN - 1; ++ ++ if (copy_from_user(inbuf, buffer, count)) ++ return -EFAULT; ++ ++ inbuf[count] = '\0'; ++ ++ if (!sscanf(inbuf, "%lu", &mode) || mode > 3) ++ return -EFAULT; ++ ++ GIE_SAVE(&saved_gie); ++ ++ saved_cctl = GET_CACHE_CTL(); ++ DEBUG(debug, 1, "saved_gie: %ld, saved_cctl: 0x%08lx\n", saved_gie, ++ saved_cctl); ++ ++ if (!strncmp(data, "ic_sdz", 7)) { ++ ++ DEBUG(debug, 1, "IC_SDZ: mode %ld\n", mode); ++ ++ if (mode == 2 || mode == 3) { ++ ++ if (CACHE_LINE_SIZE(ICACHE) * CACHE_SET(ICACHE) / 2 < ++ 4096) { ++ ++ GIE_RESTORE(saved_gie); ++ DEBUG(debug, 1, "Error: way size < 4096\n"); ++ return -1; ++ } ++ } ++ ++ /* turn off and flush cache */ ++ DEBUG(debug, 1, "turning off cache\n"); ++ SET_CACHE_CTL(saved_cctl & ~CACHE_CTL_mskIC_EN); ++ DEBUG(debug, 1, "flushing cache\n"); ++ cpu_icache_inval_all(); ++ ++ /* perform down size operation */ ++ DEBUG(debug, 1, "downsizing cache\n"); ++ SET_SDZ_CTL((GET_SDZ_CTL() & ~SDZ_CTL_mskICDZ) | ++ (mode << SDZ_CTL_offICDZ)); ++ } else { ++ ++ DEBUG(debug, 1, "DC_SDZ: mode %ld\n", mode); ++ ++ if (mode == 2 || mode == 3) { ++ ++ if (CACHE_LINE_SIZE(DCACHE) * CACHE_SET(DCACHE) / 2 < ++ 4096) { ++ ++ GIE_RESTORE(saved_gie); ++ DEBUG(debug, 1, "Error: way size < 4096\n"); ++ return -1; ++ } ++ } ++ ++ /* turn off and flush cache */ ++ DEBUG(debug, 1, "turning off cache\n"); ++ SET_CACHE_CTL(saved_cctl & ~CACHE_CTL_mskDC_EN); ++ DEBUG(debug, 1, "flushing cache\n"); ++ cpu_dcache_wbinval_all(); ++ ++ /* perform down size operation */ ++ DEBUG(debug, 1, "downsizing cache\n"); ++ SET_SDZ_CTL((GET_SDZ_CTL() & ~SDZ_CTL_mskDCDZ) | ++ (mode << SDZ_CTL_offDCDZ)); ++ } ++ ++ /* turn on cache ( if it was enabled) */ ++ DEBUG(debug, 1, "restoring saved_cctl : 0x%08lx\n", saved_cctl); ++ SET_CACHE_CTL(saved_cctl); ++ ++ DEBUG(debug, 1, "restoring saved_git: %ld\n", saved_gie); ++ GIE_RESTORE(saved_gie); ++ ++ return count; ++} ++ ++struct entry_struct proc_table_cache_sdz[] = { ++ ++ {"ic_sdz", 0644, proc_read_cache_sdz, proc_write_cache_sdz}, ++ {"dc_sdz", 0644, proc_read_cache_sdz, proc_write_cache_sdz}, ++ {NULL, 0, NULL, NULL} ++}; ++ ++static struct proc_dir_entry *proc_cctl; ++ ++static void create_seq_entry(struct entry_struct *e, mode_t mode, ++ struct proc_dir_entry *parent) ++{ ++ ++ struct proc_dir_entry *entry = create_proc_entry(e->name, mode, parent); ++ ++ if (entry) { ++ ++ entry->read_proc = e->readop; ++ entry->write_proc = e->writeop; ++ entry->data = e->name; ++ } ++} ++ ++static void install_proc_table(struct entry_struct *table) ++{ ++ ++ while (table->name) { ++ ++ create_seq_entry(table, table->perm, proc_cctl); ++ table++; ++ } ++} ++ ++static void remove_proc_table(struct entry_struct *table) ++{ ++ ++ while (table->name) { ++ ++ remove_proc_entry(table->name, proc_cctl); ++ table++; ++ } ++} ++ ++static int __init init_cctl(void) ++{ ++ ++ DEBUG(debug, 1, "CCTL module registered\n"); ++ ++ proc_cctl = proc_mkdir("cctl", NULL); ++ ++ install_proc_table(proc_table_cache_en); ++ install_proc_table(proc_table_cache_sdz); ++ ++ return 0; ++} ++ ++static void __exit cleanup_cctl(void) ++{ ++ ++ remove_proc_table(proc_table_cache_sdz); ++ remove_proc_table(proc_table_cache_en); ++ remove_proc_entry("cctl", NULL); ++ ++ DEBUG(debug, 1, "CCTL module unregistered\n"); ++} ++ ++module_init(init_cctl); ++module_exit(cleanup_cctl); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Userspace Cache Control Module"); +diff -Nur linux-3.4.110.orig/arch/nds32/mm/cctl.h linux-3.4.110/arch/nds32/mm/cctl.h +--- linux-3.4.110.orig/arch/nds32/mm/cctl.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/cctl.h 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,22 @@ ++#ifndef CCTL_H ++#define CCTL_H ++ ++#include <linux/module.h> ++#include <linux/blkdev.h> ++#include <linux/proc_fs.h> ++#include <asm/nds32.h> ++ ++#define INPUTLEN 32 ++ ++extern void cpu_icache_flush(void); ++extern void cpu_dcache_flush(void); ++ ++struct entry_struct{ ++ ++ char *name; ++ int perm; ++ read_proc_t *readop; ++ write_proc_t *writeop; ++}; ++ ++#endif /* CCTL_H */ +diff -Nur linux-3.4.110.orig/arch/nds32/mm/consistent.c linux-3.4.110/arch/nds32/mm/consistent.c +--- linux-3.4.110.orig/arch/nds32/mm/consistent.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/consistent.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,448 @@ ++/* ++ * linux/arch/nds32/mm/consistent.c ++ * ++ * Copyright (C) 2000-2004 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * DMA uncached mapping support. ++ */ ++#include <linux/dma-mapping.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <asm/cacheflush.h> ++#include <asm/tlbflush.h> ++#include <asm/pgtable.h> ++#include <linux/module.h> ++ ++/* ++ * This is the page table (2MB) covering uncached, DMA consistent allocations ++ */ ++static pte_t *consistent_pte; ++static DEFINE_RAW_SPINLOCK(consistent_lock); ++ ++/* ++ * VM region handling support. ++ * ++ * This should become something generic, handling VM region allocations for ++ * vmalloc and similar (ioremap, module space, etc). ++ * ++ * I envisage vmalloc()'s supporting vm_struct becoming: ++ * ++ * struct vm_struct { ++ * struct vm_region region; ++ * unsigned long flags; ++ * struct page **pages; ++ * unsigned int nr_pages; ++ * unsigned long phys_addr; ++ * }; ++ * ++ * get_vm_area() would then call vm_region_alloc with an appropriate ++ * struct vm_region head (eg): ++ * ++ * struct vm_region vmalloc_head = { ++ * .vm_list = LIST_HEAD_INIT(vmalloc_head.vm_list), ++ * .vm_start = VMALLOC_START, ++ * .vm_end = VMALLOC_END, ++ * }; ++ * ++ * However, vmalloc_head.vm_start is variable (typically, it is dependent on ++ * the amount of RAM found at boot time.) I would imagine that get_vm_area() ++ * would have to initialise this each time prior to calling vm_region_alloc(). ++ */ ++struct arch_vm_region { ++ struct list_head vm_list; ++ unsigned long vm_start; ++ unsigned long vm_end; ++ struct page *vm_pages; ++}; ++ ++static struct arch_vm_region consistent_head = { ++ .vm_list = LIST_HEAD_INIT(consistent_head.vm_list), ++ .vm_start = CONSISTENT_BASE, ++ .vm_end = CONSISTENT_END, ++}; ++ ++static struct arch_vm_region *vm_region_alloc(struct arch_vm_region *head, ++ size_t size, int gfp) ++{ ++ unsigned long addr = head->vm_start, end = head->vm_end - size; ++ unsigned long flags; ++ struct arch_vm_region *c, *new; ++ ++ new = kmalloc(sizeof(struct arch_vm_region), gfp); ++ if (!new) ++ goto out; ++ ++ raw_spin_lock_irqsave(&consistent_lock, flags); ++ ++ list_for_each_entry(c, &head->vm_list, vm_list) { ++ if ((addr + size) < addr) ++ goto nospc; ++ if ((addr + size) <= c->vm_start) ++ goto found; ++ addr = c->vm_end; ++ if (addr > end) ++ goto nospc; ++ } ++ ++found: ++ /* ++ * Insert this entry _before_ the one we found. ++ */ ++ list_add_tail(&new->vm_list, &c->vm_list); ++ new->vm_start = addr; ++ new->vm_end = addr + size; ++ ++ raw_spin_unlock_irqrestore(&consistent_lock, flags); ++ return new; ++ ++nospc: ++ raw_spin_unlock_irqrestore(&consistent_lock, flags); ++ kfree(new); ++out: ++ return NULL; ++} ++ ++static struct arch_vm_region *vm_region_find(struct arch_vm_region *head, ++ unsigned long addr) ++{ ++ struct arch_vm_region *c; ++ ++ list_for_each_entry(c, &head->vm_list, vm_list) { ++ if (c->vm_start == addr) ++ goto out; ++ } ++ c = NULL; ++out: ++ return c; ++} ++ ++#ifdef CONFIG_HUGETLB_PAGE ++#error ARM Coherent DMA allocator does not (yet) support huge TLB ++#endif ++ ++static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t * handle, ++ int gfp, pgprot_t prot) ++{ ++ struct page *page; ++ struct arch_vm_region *c; ++ unsigned long order; ++ unsigned int i; ++ u64 mask = ISA_DMA_THRESHOLD, limit; ++ ++ if (!consistent_pte) { ++ printk(KERN_ERR "%s: not initialised\n", __func__); ++ dump_stack(); ++ return NULL; ++ } ++ ++ if (dev) { ++ mask = dev->coherent_dma_mask; ++ ++ /* ++ * Sanity check the DMA mask - it must be non-zero, and ++ * must be able to be satisfied by a DMA allocation. ++ */ ++ if (mask == 0) { ++ dev_warn(dev, "coherent DMA mask is unset\n"); ++ goto no_page; ++ } ++ ++ if ((~mask) & ISA_DMA_THRESHOLD) { ++ dev_warn(dev, "coherent DMA mask %#llx is smaller " ++ "than system GFP_DMA mask %#llx\n", ++ mask, (unsigned long long)ISA_DMA_THRESHOLD); ++ goto no_page; ++ } ++ } ++ ++ /* ++ * Sanity check the allocation size. ++ */ ++ size = PAGE_ALIGN(size); ++ limit = (mask + 1) & ~mask; ++ if ((limit && size >= limit) || ++ size >= (CONSISTENT_END - CONSISTENT_BASE)) { ++ printk(KERN_WARNING "coherent allocation too big " ++ "(requested %#x mask %#llx)\n", size, mask); ++ goto no_page; ++ } ++ ++ order = get_order(size); ++ ++ if (mask != 0xffffffff) ++ gfp |= GFP_DMA; ++ ++ page = alloc_pages(gfp, order); ++ if (!page) ++ goto no_page; ++ ++ for (i = 1; i < (1 << order); i++) ++ atomic_set(&(page + i)->_count, 1); ++ ++ /* ++ * Invalidate any data that might be lurking in the ++ * kernel direct-mapped region for device DMA. ++ */ ++ { ++ unsigned long kaddr = (unsigned long)page_address(page); ++ memset(page_address(page), 0, size); ++ cpu_dma_wbinval_range(kaddr, kaddr + size); ++ } ++ ++ /* ++ * Allocate a virtual address in the consistent mapping region. ++ */ ++ c = vm_region_alloc(&consistent_head, size, ++ gfp & ~(__GFP_DMA | __GFP_HIGHMEM)); ++ if (c) { ++ pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start); ++ struct page *end = page + (1 << order); ++ ++ c->vm_pages = page; ++ ++ /* ++ * Set the "dma handle" ++ */ ++ *handle = page_to_dma(dev, page); ++ ++ do { ++ BUG_ON(!pte_none(*pte)); ++ ++ /* ++ * x86 does not mark the pages reserved... ++ */ ++ SetPageReserved(page); ++ set_pte(pte, mk_pte(page, prot)); ++ page++; ++ pte++; ++ } while (size -= PAGE_SIZE); ++ ++ /* ++ * Free the otherwise unused pages. ++ */ ++ while (page < end) { ++ __free_page(page); ++ page++; ++ } ++ ++ return (void *)c->vm_start; ++ } ++ ++ if (page) ++ __free_pages(page, order); ++no_page: ++ *handle = ~0; ++ return NULL; ++} ++ ++/* ++ * Allocate DMA-coherent memory space and return both the kernel remapped ++ * virtual and bus address for that space. ++ */ ++void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t * handle, ++ gfp_t gfp) ++{ ++ return __dma_alloc(dev, size, handle, gfp, ++ pgprot_noncached(PAGE_KERNEL)); ++} ++ ++EXPORT_SYMBOL(dma_alloc_coherent); ++ ++/* ++ * Allocate a writecombining region, in much the same way as ++ * dma_alloc_coherent above. ++ */ ++void *dma_alloc_writecombine(struct device *dev, size_t size, ++ dma_addr_t * handle, gfp_t gfp) ++{ ++ return __dma_alloc(dev, size, handle, gfp, ++ pgprot_writecombine(PAGE_KERNEL)); ++} ++ ++EXPORT_SYMBOL(dma_alloc_writecombine); ++ ++static int dma_mmap(struct device *dev, struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size) ++{ ++ unsigned long flags, user_size, kern_size; ++ struct arch_vm_region *c; ++ int ret = -ENXIO; ++ ++ user_size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; ++ ++ raw_spin_lock_irqsave(&consistent_lock, flags); ++ c = vm_region_find(&consistent_head, (unsigned long)cpu_addr); ++ raw_spin_unlock_irqrestore(&consistent_lock, flags); ++ ++ if (c) { ++ unsigned long off = vma->vm_pgoff; ++ ++ kern_size = (c->vm_end - c->vm_start) >> PAGE_SHIFT; ++ ++ if (off < kern_size && user_size <= (kern_size - off)) { ++ vma->vm_flags |= VM_RESERVED; ++ ret = remap_pfn_range(vma, vma->vm_start, ++ page_to_pfn(c->vm_pages) + off, ++ user_size << PAGE_SHIFT, ++ vma->vm_page_prot); ++ } ++ } ++ ++ return ret; ++} ++ ++int dma_mmap_coherent(struct device *dev, struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size) ++{ ++ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); ++ return dma_mmap(dev, vma, cpu_addr, dma_addr, size); ++} ++ ++EXPORT_SYMBOL(dma_mmap_coherent); ++ ++int dma_mmap_writecombine(struct device *dev, struct vm_area_struct *vma, ++ void *cpu_addr, dma_addr_t dma_addr, size_t size) ++{ ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++ return dma_mmap(dev, vma, cpu_addr, dma_addr, size); ++} ++ ++EXPORT_SYMBOL(dma_mmap_writecombine); ++ ++/* ++ * free a page as defined by the above mapping. ++ */ ++void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, ++ dma_addr_t handle) ++{ ++ struct arch_vm_region *c; ++ unsigned long flags, addr; ++ pte_t *ptep; ++ ++ size = PAGE_ALIGN(size); ++ ++ raw_spin_lock_irqsave(&consistent_lock, flags); ++ ++ c = vm_region_find(&consistent_head, (unsigned long)cpu_addr); ++ if (!c) ++ goto no_area; ++ ++ if ((c->vm_end - c->vm_start) != size) { ++ printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n", ++ __func__, c->vm_end - c->vm_start, size); ++ dump_stack(); ++ size = c->vm_end - c->vm_start; ++ } ++ ++ ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start); ++ addr = c->vm_start; ++ do { ++ pte_t pte = ptep_get_and_clear(&init_mm, addr, ptep); ++ unsigned long pfn; ++ ++ ptep++; ++ addr += PAGE_SIZE; ++ ++ if (!pte_none(pte) && pte_present(pte)) { ++ pfn = pte_pfn(pte); ++ ++ if (pfn_valid(pfn)) { ++ struct page *page = pfn_to_page(pfn); ++ ++ /* ++ * x86 does not mark the pages reserved... ++ */ ++ ClearPageReserved(page); ++ ++ __free_page(page); ++ continue; ++ } ++ } ++ ++ printk(KERN_CRIT "%s: bad page in kernel page table\n", ++ __func__); ++ } while (size -= PAGE_SIZE); ++ ++ flush_tlb_kernel_range(c->vm_start, c->vm_end); ++ ++ list_del(&c->vm_list); ++ ++ raw_spin_unlock_irqrestore(&consistent_lock, flags); ++ ++ kfree(c); ++ return; ++ ++no_area: ++ raw_spin_unlock_irqrestore(&consistent_lock, flags); ++ printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n", ++ __func__, cpu_addr); ++ dump_stack(); ++} ++ ++EXPORT_SYMBOL(dma_free_coherent); ++ ++/* ++ * Initialise the consistent memory allocation. ++ */ ++static int __init consistent_init(void) ++{ ++ pgd_t *pgd; ++ pmd_t *pmd; ++ pte_t *pte; ++ int ret = 0; ++ ++ do { ++ pgd = pgd_offset(&init_mm, CONSISTENT_BASE); ++ pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE); ++ if (!pmd) { ++ printk(KERN_ERR "%s: no pmd tables\n", __func__); ++ ret = -ENOMEM; ++ break; ++ } ++ /* The first level mapping may be created in somewhere. ++ * It's not necessary to warn here. */ ++ /* WARN_ON(!pmd_none(*pmd)); */ ++ ++ pte = pte_alloc_kernel(pmd, CONSISTENT_BASE); ++ if (!pte) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ consistent_pte = pte; ++ } while (0); ++ ++ return ret; ++} ++ ++core_initcall(consistent_init); ++ ++/* ++ * Make an area consistent for devices. ++ */ ++void consistent_sync(void *vaddr, size_t size, int direction) ++{ ++ unsigned long start = (unsigned long)vaddr; ++ unsigned long end = start + size; ++ ++ switch (direction) { ++ case DMA_FROM_DEVICE: /* invalidate only */ ++ cpu_dma_inval_range(start, end); ++ break; ++ case DMA_TO_DEVICE: /* writeback only */ ++ cpu_dma_wb_range(start, end); ++ break; ++ case DMA_BIDIRECTIONAL: /* writeback and invalidate */ ++ cpu_dma_wbinval_range(start, end); ++ break; ++ default: ++ BUG(); ++ } ++} ++ ++EXPORT_SYMBOL(consistent_sync); +diff -Nur linux-3.4.110.orig/arch/nds32/mm/extable.c linux-3.4.110/arch/nds32/mm/extable.c +--- linux-3.4.110.orig/arch/nds32/mm/extable.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/extable.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * linux/arch/nds32/mm/extable.c ++ * ++ * Copyright (C) 2009 Andes Technology Corporation ++ */ ++#include <linux/module.h> ++#include <asm/uaccess.h> ++ ++int fixup_exception(struct pt_regs *regs) ++{ ++ const struct exception_table_entry *fixup; ++ ++ fixup = search_exception_tables(instruction_pointer(regs)); ++ if (fixup) ++ regs->NDS32_ipc = fixup->fixup; ++ ++ return fixup != NULL; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/mm/fault.c linux-3.4.110/arch/nds32/mm/fault.c +--- linux-3.4.110.orig/arch/nds32/mm/fault.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/fault.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,507 @@ ++/* ++ * linux/arch/arm/mm/fault.c ++ * ++ * Copyright (C) 1995 Linus Torvalds ++ * Modifications for ARM processor (c) 1995-2004 Russell King ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++/* ============================================================================ ++ * ++ * linux/arch/nds32/mm/fault.c ++ * ++ * Copyright (C) 2007 Andes Technology Corporation ++ * This file is part of Linux and should be licensed under the GPL. ++ * See the file COPYING for conditions for redistribution. ++ * ++ * Abstract: ++ * ++ * This program is for NDS32 architecture, referred from ARM's ++ * implementation. ++ * ++ * Revision History: ++ * ++ * Nov.26.2007 Initial ported by Tom, Shawn, and Steven, ++ * patched for KGDB and refined code by Harry. ++ * ++ * Note: ++ * ++ * ============================================================================ ++ */ ++#include <linux/module.h> ++#include <linux/signal.h> ++#include <linux/ptrace.h> ++#include <linux/mm.h> ++#include <linux/init.h> ++#include <linux/hardirq.h> ++ ++#include <asm/system.h> ++#include <asm/pgtable.h> ++#include <asm/tlbflush.h> ++#include <asm/uaccess.h> ++ ++#include "fault.h" ++ ++/* ++ * This is useful to dump out the page tables associated with ++ * 'addr' in mm 'mm'. ++ */ ++void show_pte(struct mm_struct *mm, unsigned long addr) ++{ ++ pgd_t *pgd; ++ if (!mm) ++ mm = &init_mm; ++ ++ printk(KERN_ALERT "pgd = %p\n", mm->pgd); ++ pgd = pgd_offset(mm, addr); ++ printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd)); ++ ++ do { ++ pmd_t *pmd; ++ ++ if (pgd_none(*pgd)) ++ break; ++ ++ if (pgd_bad(*pgd)) { ++ printk("(bad)"); ++ break; ++ } ++ ++ pmd = pmd_offset(pgd, addr); ++#if PTRS_PER_PMD != 1 ++ printk(", *pmd=%08lx", pmd_val(*pmd)); ++#endif ++ ++ if (pmd_none(*pmd)) ++ break; ++ ++ if (pmd_bad(*pmd)) { ++ printk("(bad)"); ++ break; ++ } ++#ifndef CONFIG_HIGHMEM ++ { ++ pte_t *pte; ++ /* We must not map this if we have highmem enabled */ ++ pte = pte_offset_map(pmd, addr); ++ printk(", *pte=%08lx", pte_val(*pte)); ++ pte_unmap(pte); ++ } ++#endif ++ } while (0); ++ ++ printk("\n"); ++} ++ ++/* ++ * Oops. The kernel tried to access some page that wasn't present. ++ */ ++static void ++__do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, ++ struct pt_regs *regs) ++{ ++ /* ++ * Are we prepared to handle this kernel fault? ++ */ ++ if (fixup_exception(regs)) ++ return; ++ ++ /* ++ * No handler, we'll have to terminate things with extreme prejudice. ++ */ ++ bust_spinlocks(1); ++ printk(KERN_ALERT ++ "__do_kernel_fault: Unable to handle kernel %s at virtual address %08lx\n", ++ (addr < PAGE_SIZE) ? "NULL pointer dereference" : ++ "paging request", addr); ++ ++ show_pte(mm, addr); ++ die("Oops", regs, fsr); ++ bust_spinlocks(0); ++ do_exit(SIGKILL); ++} ++ ++/* ++ * Something tried to access memory that isn't in our memory map.. ++ * User mode accesses just cause a SIGSEGV ++ */ ++static void ++__do_user_fault(struct task_struct *tsk, unsigned long addr, ++ unsigned int fsr, int code, struct pt_regs *regs) ++{ ++ struct siginfo si; ++ ++#ifdef CONFIG_DEBUG_USER ++ if (user_debug & UDBG_SEGV) { ++ printk(KERN_DEBUG ++ "%s: unhandled page fault at 0x%08lx, code 0x%03x\n", ++ tsk->comm, addr, fsr); ++ show_pte(tsk->mm, addr); ++ show_regs(regs); ++ } ++#endif ++ ++ tsk->thread.address = addr; ++ tsk->thread.error_code = fsr; ++ tsk->thread.trap_no = 14; ++ si.si_signo = SIGSEGV; ++ si.si_errno = 0; ++ si.si_code = code; ++ si.si_addr = (void __user *)addr; ++ force_sig_info(SIGSEGV, &si, tsk); ++} ++ ++void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs) ++{ ++ struct task_struct *tsk = current; ++ struct mm_struct *mm = tsk->active_mm; ++ ++ /* ++ * If we are in kernel mode at this point, we ++ * have no context to handle this fault with. ++ */ ++ if (user_mode(regs)) { ++ __do_user_fault(tsk, addr, fsr, SEGV_MAPERR, regs); ++ } else { ++ __do_kernel_fault(mm, addr, fsr, regs); ++ } ++} ++ ++#define VM_FAULT_BADMAP 0x010000 ++#define VM_FAULT_BADACCESS 0x020000 ++ ++void do_page_fault(unsigned long entry, unsigned long addr, ++ unsigned int error_code, struct pt_regs *regs) ++{ ++ struct task_struct *tsk; ++ struct mm_struct *mm; ++ struct vm_area_struct *vma; ++ siginfo_t info; ++ int fault; ++ unsigned int mask = VM_READ | VM_WRITE | VM_EXEC; ++ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; ++ ++ error_code = error_code & (ITYPE_mskINST | ITYPE_mskETYPE); ++ tsk = current; ++ mm = tsk->mm; ++ info.si_code = SEGV_MAPERR; ++ /* ++ * We fault-in kernel-space virtual memory on-demand. The ++ * 'reference' page table is init_mm.pgd. ++ * ++ * NOTE! We MUST NOT take any locks for this case. We may ++ * be in an interrupt or a critical region, and should ++ * only copy the information from the master page table, ++ * nothing more. ++ */ ++ if (addr >= TASK_SIZE) { ++ if (user_mode(regs)) ++ goto bad_area_nosemaphore; ++ ++ if (addr >= TASK_SIZE && addr < VMALLOC_END && (entry == 2)) ++ goto vmalloc_fault; ++ else ++ goto no_context; ++ } ++ ++ /* ++ * If we're in an interrupt or have no user ++ * context, we must not take the fault.. ++ */ ++ if (unlikely(in_atomic() || !mm)) ++ goto no_context; ++ ++ /* ++ * As per x86, we may deadlock here. However, since the kernel only ++ * validly references user space from well defined areas of the code, ++ * we can bug out early if this is from code which shouldn't. ++ */ ++ if (unlikely(!down_read_trylock(&mm->mmap_sem))) { ++ if (!user_mode(regs) && ++ !search_exception_tables(instruction_pointer(regs))) ++ goto no_context; ++retry: ++ down_read(&mm->mmap_sem); ++ } else { ++ /* ++ * The above down_read_trylock() might have succeeded in which ++ * case, we'll have missed the might_sleep() from down_read(). ++ */ ++ might_sleep(); ++#ifdef CONFIG_DEBUG_VM ++ if (!user_mode(regs) && ++ !search_exception_tables(instruction_pointer(regs))) ++ goto no_context; ++#endif ++ } ++ ++ vma = find_vma(mm, addr); ++ ++ if (unlikely(!vma)) ++ goto bad_area; ++ ++ if (vma->vm_start <= addr) ++ goto good_area; ++ ++ if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) ++ goto bad_area; ++ ++ if (unlikely(expand_stack(vma, addr))) ++ goto bad_area; ++ ++ /* ++ * Ok, we have a good vm_area for this memory access, so ++ * we can handle it.. ++ */ ++ ++good_area: ++ info.si_code = SEGV_ACCERR; ++ ++ /* first do some preliminary protection checks */ ++ if (entry == 2) { ++ if (error_code & ITYPE_mskINST) ++ mask = VM_EXEC; ++ else { ++ mask = VM_READ | VM_WRITE; ++ if (vma->vm_flags & VM_WRITE) ++ flags |= FAULT_FLAG_WRITE; ++ } ++ } else if (entry == 3) { ++ switch (error_code & ITYPE_mskETYPE) { ++ case RD_PROT: ++ mask = VM_READ; ++ break; ++ case WRT_PROT: ++ mask = VM_WRITE; ++ flags |= FAULT_FLAG_WRITE; ++ break; ++ case NOEXEC: ++ mask = VM_EXEC; ++ break; ++ case PAGE_MODIFY: ++ mask = VM_WRITE; ++ flags |= FAULT_FLAG_WRITE; ++ break; ++ case ACC_BIT: ++ BUG(); ++ default: ++ break; ++ } ++ ++ } ++ if (!(vma->vm_flags & mask)) ++ goto bad_area; ++ ++ /* ++ * If for any reason at all we couldn't handle the fault, ++ * make sure we exit gracefully rather than endlessly redo ++ * the fault. ++ */ ++ ++ fault = handle_mm_fault(mm, vma, addr, flags); ++ ++ /* ++ * If we need to retry but a fatal signal is pending, handle the ++ * signal first. We do not need to release the mmap_sem because it ++ * would already be released in __lock_page_or_retry in mm/filemap.c. ++ */ ++ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) ++ return; ++ ++ if (unlikely(fault & VM_FAULT_ERROR)) { ++ if (fault & VM_FAULT_OOM) ++ goto out_of_memory; ++ else if (fault & VM_FAULT_SIGBUS) ++ goto do_sigbus; ++ BUG(); ++ } ++ ++ /* ++ * Major/minor page fault accounting is only done on the initial ++ * attempt. If we go through a retry, it is extremely likely that the ++ * page will be found in page cache at that point. ++ */ ++ if (flags & FAULT_FLAG_ALLOW_RETRY) { ++ if (fault & VM_FAULT_MAJOR) ++ tsk->maj_flt++; ++ else ++ tsk->min_flt++; ++ if (fault & VM_FAULT_RETRY) { ++ flags &= ~FAULT_FLAG_ALLOW_RETRY; ++ flags |= FAULT_FLAG_TRIED; ++ ++ /* No need to up_read(&mm->mmap_sem) as we would ++ * have already released it in __lock_page_or_retry ++ * in mm/filemap.c. ++ */ ++ goto retry; ++ } ++ } ++ ++ up_read(&mm->mmap_sem); ++ return; ++ ++ /* ++ * Something tried to access memory that isn't in our memory map.. ++ * Fix it, but check if it's kernel or user first.. ++ */ ++bad_area: ++ up_read(&mm->mmap_sem); ++ ++bad_area_nosemaphore: ++ ++ /* User mode accesses just cause a SIGSEGV */ ++ ++ if (user_mode(regs)) { ++ tsk->thread.address = addr; ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = 14; ++ info.si_signo = SIGSEGV; ++ info.si_errno = 0; ++ /* info.si_code has been set above */ ++ info.si_addr = (void *)addr; ++ force_sig_info(SIGSEGV, &info, tsk); ++ return; ++ } ++ ++no_context: ++ ++ /* Are we prepared to handle this kernel fault? ++ * ++ * (The kernel has valid exception-points in the source ++ * when it acesses user-memory. When it fails in one ++ * of those points, we find it in a table and do a jump ++ * to some fixup code that loads an appropriate error ++ * code) ++ */ ++ ++ { ++ const struct exception_table_entry *entry; ++ ++ if ((entry = ++ search_exception_tables(instruction_pointer(regs))) != ++ NULL) { ++ /* Adjust the instruction pointer in the stackframe */ ++ instruction_pointer(regs) = entry->fixup; ++ return; ++ } ++ } ++ ++ /* ++ * Oops. The kernel tried to access some bad page. We'll have to ++ * terminate things with extreme prejudice. ++ */ ++ ++ bust_spinlocks(1); ++ printk(KERN_ALERT ++ "Unable to handle kernel %s at virtual address %08lx\n", ++ (addr < PAGE_SIZE) ? "NULL pointer dereference" : ++ "paging request", addr); ++ ++ show_pte(mm, addr); ++ die("Oops", regs, error_code); ++ bust_spinlocks(0); ++ do_exit(SIGKILL); ++ ++ /* TODO: verify this necessity */ ++ return; ++ ++ /* ++ * We ran out of memory, or some other thing happened to us that made ++ * us unable to handle the page fault gracefully. ++ */ ++ ++out_of_memory: ++ up_read(&mm->mmap_sem); ++ if (!user_mode(regs)) ++ goto no_context; ++ pagefault_out_of_memory(); ++ return; ++ ++do_sigbus: ++ up_read(&mm->mmap_sem); ++ ++ /* Kernel mode? Handle exceptions or die */ ++ if (!user_mode(regs)) ++ goto no_context; ++ ++ /* ++ * Send a sigbus ++ */ ++ tsk->thread.address = addr; ++ tsk->thread.error_code = error_code; ++ tsk->thread.trap_no = 14; ++ info.si_signo = SIGBUS; ++ info.si_errno = 0; ++ info.si_code = BUS_ADRERR; ++ info.si_addr = (void *)addr; ++ force_sig_info(SIGBUS, &info, tsk); ++ ++ return; ++ ++vmalloc_fault: ++ { ++ /* ++ * Synchronize this task's top level page-table ++ * with the 'reference' page table. ++ * ++ * Use current_pgd instead of tsk->active_mm->pgd ++ * since the latter might be unavailable if this ++ * code is executed in a misfortunately run irq ++ * (like inside schedule() between switch_mm and ++ * switch_to...). ++ */ ++ ++ unsigned int index = pgd_index(addr); ++ pgd_t *pgd, *pgd_k; ++ pud_t *pud, *pud_k; ++ pmd_t *pmd, *pmd_k; ++ pte_t *pte_k; ++ ++ pgd = (pgd_t *) __va(GET_L1_PPTB()) + index; ++ pgd_k = init_mm.pgd + index; ++ ++ if (!pgd_present(*pgd_k)) ++ goto no_context; ++ ++ pud = pud_offset(pgd, addr); ++ pud_k = pud_offset(pgd_k, addr); ++ if (!pud_present(*pud_k)) ++ goto no_context; ++ ++ pmd = pmd_offset(pud, addr); ++ pmd_k = pmd_offset(pud_k, addr); ++ if (!pmd_present(*pmd_k)) ++ goto no_context; ++ ++ if (!pmd_present(*pmd)) { ++ set_pmd(pmd, *pmd_k); ++ /* TODO: need to do a cache flush like arm, ++ * maybe add at header file */ ++ } else ++ ++ BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k)); ++ ++ /* ++ * Since the vmalloc area is global, we don't ++ * need to copy individual PTE's, it is enough to ++ * copy the pgd pointer into the pte page of the ++ * root task. If that is there, we'll find our pte if ++ * it exists. ++ */ ++ ++ /* Make sure the actual PTE exists as well to ++ * catch kernel vmalloc-area accesses to non-mapped ++ * addres. If we don't do this, this will just ++ * silently loop forever. ++ */ ++ ++ pte_k = pte_offset_kernel(pmd_k, addr); ++ if (!pte_present(*pte_k)) ++ goto no_context; ++ ++ return; ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/mm/fault.h linux-3.4.110/arch/nds32/mm/fault.h +--- linux-3.4.110.orig/arch/nds32/mm/fault.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/fault.h 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,5 @@ ++void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs); ++ ++void show_pte(struct mm_struct *mm, unsigned long addr); ++ ++unsigned long search_exception_table(unsigned long addr); +diff -Nur linux-3.4.110.orig/arch/nds32/mm/highmem.c linux-3.4.110/arch/nds32/mm/highmem.c +--- linux-3.4.110.orig/arch/nds32/mm/highmem.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/highmem.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,76 @@ ++#include <linux/export.h> ++#include <linux/highmem.h> ++#include <linux/sched.h> ++#include <linux/smp.h> ++#include <linux/interrupt.h> ++#include <linux/bootmem.h> ++#include <asm/fixmap.h> ++#include <asm/tlbflush.h> ++ ++void *kmap(struct page *page) ++{ ++ unsigned long vaddr; ++ might_sleep(); ++ if (!PageHighMem(page)) ++ return page_address(page); ++ vaddr = (unsigned long)kmap_high(page); ++ return (void *)vaddr; ++} ++ ++EXPORT_SYMBOL(kmap); ++ ++void kunmap(struct page *page) ++{ ++ BUG_ON(in_interrupt()); ++ if (!PageHighMem(page)) ++ return; ++ kunmap_high(page); ++} ++ ++EXPORT_SYMBOL(kunmap); ++ ++/* ++ * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because ++ * no global lock is needed and because the kmap code must perform a global TLB ++ * invalidation when the kmap pool wraps. ++ * ++ * However when holding an atomic kmap is is not legal to sleep, so atomic ++ * kmaps are appropriate for short, tight code paths only. ++ */ ++void *kmap_atomic(struct page *page) ++{ ++ unsigned int idx; ++ unsigned long vaddr, pte; ++ int type; ++ ++ pagefault_disable(); ++ if (!PageHighMem(page)) ++ return page_address(page); ++ ++ type = kmap_atomic_idx_push(); ++ ++ idx = type + KM_TYPE_NR * smp_processor_id(); ++ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); ++ pte = (page_to_pfn(page) << PAGE_SHIFT) | (PAGE_KERNEL); ++ asm volatile ("mtsr %0, $TLB_VPN\n\t" ++ "dsb\n\t" ++ "tlbop %1, RWLK\n\t" ++ "isb\n\t" ++ ::"r" (vaddr), "r"(pte)); ++ return (void *)vaddr; ++} ++ ++EXPORT_SYMBOL(kmap_atomic); ++ ++void __kunmap_atomic(void *kvaddr) ++{ ++ if (kvaddr >= (void *)FIXADDR_START) { ++ kmap_atomic_idx_pop(); ++ asm volatile ("tlbop %0, UNLK\n\t" ++ "tlbop %0, INV\n\t" ++ ::"r" (kvaddr)); ++ } ++ pagefault_enable(); ++} ++ ++EXPORT_SYMBOL(__kunmap_atomic); +diff -Nur linux-3.4.110.orig/arch/nds32/mm/init.c linux-3.4.110/arch/nds32/mm/init.c +--- linux-3.4.110.orig/arch/nds32/mm/init.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/init.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,438 @@ ++/* ++ * linux/arch/nds32/mm/init.c ++ * ++ * Copyright (C) 1995-2002 Russell King ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/kernel.h> ++#include <linux/errno.h> ++#include <linux/swap.h> ++#include <linux/init.h> ++#include <linux/bootmem.h> ++#include <linux/mman.h> ++#include <linux/nodemask.h> ++#include <linux/initrd.h> ++#include <linux/highmem.h> ++#include <linux/memblock.h> ++ ++#include <asm/sections.h> ++#include <asm/mach-types.h> ++#include <asm/hardware.h> ++#include <asm/setup.h> ++#include <asm/tlb.h> ++#include <asm/page.h> ++ ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++ ++#include "mm.h" ++#include "../../kernel/signal.h" ++ ++#define TABLE_SIZE (PTRS_PER_PTE * sizeof(pte_t)) ++ ++DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); ++DEFINE_SPINLOCK(anon_alias_lock); ++extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; ++extern unsigned long phys_initrd_start; ++extern unsigned long phys_initrd_size; ++ ++/* ++ * empty_zero_page is a special page that is used for ++ * zero-initialized data and COW. ++ */ ++struct page *empty_zero_page; ++ ++void show_mem(unsigned int flags) ++{ ++ int free = 0, total = 0, reserved = 0; ++ int shared = 0, cached = 0, slab = 0, node; ++ ++ printk("Mem-info:\n"); ++ show_free_areas(flags); ++ printk("Free swap: %6ldkB\n", nr_swap_pages << (PAGE_SHIFT - 10)); ++ ++ for_each_online_node(node) { ++ struct page *page, *end; ++ ++ page = NODE_MEM_MAP(node); ++ end = page + NODE_DATA(node)->node_spanned_pages; ++ ++ do { ++ total++; ++ if (PageReserved(page)) ++ reserved++; ++ else if (PageSwapCache(page)) ++ cached++; ++ else if (PageSlab(page)) ++ slab++; ++ else if (!page_count(page)) ++ free++; ++ else ++ shared += page_count(page) - 1; ++ page++; ++ } while (page < end); ++ } ++ ++ printk("%d pages of RAM\n", total); ++ printk("%d free pages\n", free); ++ printk("%d reserved pages\n", reserved); ++ printk("%d slab pages\n", slab); ++ printk("%d pages shared\n", shared); ++ printk("%d pages swap cached\n", cached); ++} ++ ++struct node_info { ++ unsigned int start; ++ unsigned int end; ++ int bootmap_pages; ++}; ++ ++#define O_PFN_DOWN(x) ((x) >> PAGE_SHIFT) ++#define V_PFN_DOWN(x) O_PFN_DOWN(__pa(x)) ++ ++#define O_PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT) ++#define V_PFN_UP(x) O_PFN_UP(__pa(x)) ++ ++#define PFN_SIZE(x) ((x) >> PAGE_SHIFT) ++#define PFN_RANGE(s,e) PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \ ++ (((unsigned long)(s)) & PAGE_MASK)) ++#ifdef CONFIG_EARLY_PRINTK ++#include <asm/fixmap.h> ++ ++/* ++ * Using tlbop to create an early I/O mapping ++ */ ++void __iomem *__init early_io_map(phys_addr_t pa) ++{ ++ unsigned long va; ++ pa &= PAGE_MASK; ++ pa += pgprot_val(PAGE_DEVICE); ++ va = fix_to_virt(FIX_EARLY_DEBUG); ++ /* insert and lock this page to tlb entry directly */ ++ asm volatile ("mtsr %0, $TLB_VPN\n\t" ++ "dsb\n\t" ++ "tlbop %1, RWLK\n\t" "isb\n\t"::"r" (va), "r"(pa)); ++ return (void __iomem *)va; ++} ++ ++int __init early_io_unmap(void) ++{ ++ unsigned long va; ++ va = fix_to_virt(FIX_EARLY_DEBUG); ++ asm volatile ("tlbop %0, UNLK\n\t" ++ "tlbop %0, INV\n\t" "isb\n\t"::"r" (va)); ++ return 0; ++} ++ ++late_initcall(early_io_unmap); ++#endif ++ ++static void __init zone_sizes_init(void) ++{ ++ unsigned long zones_size[MAX_NR_ZONES]; ++ ++ /* Clear the zone sizes */ ++ memset(zones_size, 0, sizeof(zones_size)); ++ ++ zones_size[ZONE_NORMAL] = max_low_pfn; ++#ifdef CONFIG_HIGHMEM ++ zones_size[ZONE_HIGHMEM] = max_pfn; ++#endif ++ free_area_init_nodes(zones_size); ++ ++} ++ ++/* ++ * Map all physical memory under high_memory into kernel's address space. ++ * ++ * This is explicitly coded for two-level page tables, so if you need ++ * something else then this needs to change. ++ */ ++static void __init map_ram(void) ++{ ++ unsigned long v, p, e; ++ pgd_t *pge; ++ pud_t *pue; ++ pmd_t *pme; ++ pte_t *pte; ++ /* These mark extents of read-only kernel pages... ++ * ...from vmlinux.lds.S ++ */ ++ ++ p = (u32) memblock_start_of_DRAM() & PAGE_MASK; ++ e = min((u32) memblock_end_of_DRAM(), (u32) __pa(high_memory)); ++ ++ v = (u32) __va(p); ++ pge = pgd_offset_k(v); ++ ++ while (p < e) { ++ int j; ++ pue = pud_offset(pge, v); ++ pme = pmd_offset(pue, v); ++ ++ if ((u32) pue != (u32) pge || (u32) pme != (u32) pge) { ++ panic("%s: Kernel hardcoded for " ++ "two-level page tables", __func__); ++ } ++ ++ /* Alloc one page for holding PTE's... */ ++ pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); ++ set_pmd(pme, __pmd(__pa(pte) + _PAGE_KERNEL_TABLE)); ++ ++ /* Fill the newly allocated page with PTE'S */ ++ for (j = 0; p < e && j < PTRS_PER_PTE; ++ v += PAGE_SIZE, p += PAGE_SIZE, j++, pte++) { ++ /* Create mapping between p and v. */ ++ /* TODO: more fine grant for page access permission */ ++ set_pte(pte, __pte(p + pgprot_val(PAGE_KERNEL))); ++ } ++ ++ pge++; ++ } ++} ++ ++static void __init fixedrange_init(void) ++{ ++ unsigned long vaddr, phys, prot; ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *pte; ++ ++ /* ++ * Fixed mappings: ++ */ ++ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1); ++ pgd = swapper_pg_dir + pgd_index(vaddr); ++ pud = pud_offset(pgd, vaddr); ++ pmd = pmd_offset(pud, vaddr); ++ pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); ++ set_pmd(pmd, __pmd(__pa(pte) + _PAGE_KERNEL_TABLE)); ++ ++ /* create return_syscall mapping. */ ++ vaddr = __fix_to_virt(FIX_RETURN_SYSCALL); ++ phys = RETURN_SYSCALL_PA_BASE; ++ prot = PAGE_UXKRWX_V2; ++ pte = pte_offset_kernel(pmd, vaddr); ++ set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, prot)); ++ ++#ifdef CONFIG_HIGHMEM ++ /* ++ * Permanent kmaps: ++ */ ++ vaddr = PKMAP_BASE; ++ ++ pgd = swapper_pg_dir + pgd_index(vaddr); ++ pud = pud_offset(pgd, vaddr); ++ pmd = pmd_offset(pud, vaddr); ++ pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); ++ set_pmd(pmd, __pmd(__pa(pte) + _PAGE_KERNEL_TABLE)); ++ pkmap_page_table = pte; ++#endif /* CONFIG_HIGHMEM */ ++} ++ ++/* ++ * paging_init() sets up the page tables, initialises the zone memory ++ * maps, and sets up the zero page, bad page and bad page tables. ++ */ ++void __init paging_init(struct machine_desc *mdesc) ++{ ++ void *zero_page; ++ int i; ++ ++ printk(KERN_INFO "Setting up paging and PTEs.\n"); ++ ++#ifdef CONFIG_BLK_DEV_INITRD ++ if (phys_initrd_size) { ++ /* assume initrd is put on node 0 */ ++ reserve_bootmem_node(NODE_DATA(0), phys_initrd_start, ++ phys_initrd_size, BOOTMEM_DEFAULT); ++ initrd_start = __phys_to_virt(phys_initrd_start); ++ initrd_end = initrd_start + phys_initrd_size; ++ printk(KERN_INFO ++ "initrd_start at 0x%08lx, initrd_end at 0x%08lx\n", ++ initrd_start, initrd_end); ++ } ++#endif ++ ++ /* clear out the init_mm.pgd that will contain the kernel's mappings */ ++ for (i = 0; i < PTRS_PER_PGD; i++) ++ swapper_pg_dir[i] = __pgd(1); ++ ++ map_ram(); ++ ++ if (mdesc->map_io) ++ mdesc->map_io(); ++ ++ fixedrange_init(); ++ ++ /* allocate space for empty_zero_page */ ++ zero_page = alloc_bootmem_low_pages(PAGE_SIZE); ++ memset(zero_page, 0, PAGE_SIZE); ++ ++ zone_sizes_init(); ++ ++ empty_zero_page = virt_to_page(zero_page); ++#ifdef CONFIG_NO_KERNEL_LARGE_PAGE ++ SET_MMU_CTL(GET_MMU_CTL() & ~0x400); ++#endif ++#ifdef CONFIG_SMP ++ cpu_dcache_wbinval_all(); ++#endif ++ flush_dcache_page(empty_zero_page); ++} ++ ++static inline int free_area(unsigned long addr, unsigned long end, char *s) ++{ ++ unsigned int size = (end - addr) >> 10; ++ int pages = 0; ++ ++ for (; addr < end; addr += PAGE_SIZE) { ++ struct page *page = virt_to_page(addr); ++ ClearPageReserved(page); ++ init_page_count(page); ++ free_page(addr); ++ totalram_pages++; ++ pages++; ++ } ++ ++ if (size && s) ++ printk(KERN_INFO "free_area: Freeing %s memory: %dK\n", s, ++ size); ++ ++ return pages; ++} ++ ++/* Free the reserved page into the buddy system, so it gets managed. */ ++static inline void __free_reserved_page(struct page *page) ++{ ++ ClearPageReserved(page); ++ init_page_count(page); ++ __free_page(page); ++} ++ ++#ifdef CONFIG_HIGHMEM ++void free_highmem_page(struct page *page) ++{ ++ __free_reserved_page(page); ++ totalram_pages++; ++ totalhigh_pages++; ++} ++#endif ++ ++static inline void __init free_highmem(void) ++{ ++#ifdef CONFIG_HIGHMEM ++ unsigned long pfn; ++ for (pfn = PFN_UP(__pa(high_memory)); pfn < max_pfn; pfn++) { ++ phys_addr_t paddr = (phys_addr_t) pfn << PAGE_SHIFT; ++ if (!memblock_is_reserved(paddr)) ++ free_highmem_page(pfn_to_page(pfn)); ++ } ++#endif ++} ++ ++static void __init set_max_mapnr_init(void) ++{ ++ max_mapnr = max_pfn; ++} ++ ++/* ++ * mem_init() marks the free areas in the mem_map and tells us how much ++ * memory is free. This is done after various parts of the system have ++ * claimed their memory after the kernel image. ++ */ ++void __init mem_init(void) ++{ ++ phys_addr_t memory_start = memblock_start_of_DRAM(); ++ BUG_ON(!mem_map); ++ set_max_mapnr_init(); ++ ++ free_highmem(); ++ ++ /* this will put all low memory onto the freelists */ ++ totalram_pages += free_all_bootmem(); ++ ++ printk(KERN_INFO "virtual kernel memory layout:\n" ++ " fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n" ++#ifdef CONFIG_HIGHMEM ++ " pkmap : 0x%08lx - 0x%08lx (%4ld kB)\n" ++#endif ++ " consist : 0x%08lx - 0x%08lx (%4ld MB)\n" ++ " vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n" ++ " lowmem : 0x%08lx - 0x%08lx (%4ld MB)\n" ++ " .init : 0x%08lx - 0x%08lx (%4ld kB)\n" ++ " .data : 0x%08lx - 0x%08lx (%4ld kB)\n" ++ " .text : 0x%08lx - 0x%08lx (%4ld kB)\n", ++ FIXADDR_START, FIXADDR_TOP, (FIXADDR_TOP - FIXADDR_START) >> 10, ++#ifdef CONFIG_HIGHMEM ++ PKMAP_BASE, PKMAP_BASE + LAST_PKMAP * PAGE_SIZE, ++ (LAST_PKMAP * PAGE_SIZE) >> 10, ++#endif ++ CONSISTENT_BASE, CONSISTENT_END, ++ ((CONSISTENT_END) - (CONSISTENT_BASE)) >> 20, VMALLOC_START, ++ (unsigned long)VMALLOC_END, (VMALLOC_END - VMALLOC_START) >> 20, ++ (unsigned long)__va(memory_start), (unsigned long)high_memory, ++ ((unsigned long)high_memory - ++ (unsigned long)__va(memory_start)) >> 20, ++ (unsigned long)&__init_begin, (unsigned long)&__init_end, ++ ((unsigned long)&__init_end - ++ (unsigned long)&__init_begin) >> 10, (unsigned long)&_etext, ++ (unsigned long)&_edata, ++ ((unsigned long)&_edata - (unsigned long)&_etext) >> 10, ++ (unsigned long)&_text, (unsigned long)&_etext, ++ ((unsigned long)&_etext - (unsigned long)&_text) >> 10); ++ ++ /* ++ * Check boundaries twice: Some fundamental inconsistencies can ++ * be detected at build time already. ++ */ ++#define __FIXADDR_TOP (-PAGE_SIZE) ++#ifdef CONFIG_HIGHMEM ++ BUILD_BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE > FIXADDR_START); ++ BUILD_BUG_ON((CONSISTENT_END) > PKMAP_BASE); ++#endif ++ BUILD_BUG_ON(VMALLOC_END > CONSISTENT_BASE); ++#define high_memory (-128UL << 20) ++ BUILD_BUG_ON(VMALLOC_START >= VMALLOC_END); ++#undef high_memory ++#undef __FIXADDR_TOP ++ ++#ifdef CONFIG_HIGHMEM ++ BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE > FIXADDR_START); ++ BUG_ON(CONSISTENT_END > PKMAP_BASE); ++#endif ++ BUG_ON(VMALLOC_END > CONSISTENT_BASE); ++ BUG_ON(VMALLOC_START >= VMALLOC_END); ++ BUG_ON((unsigned long)high_memory > VMALLOC_START); ++ ++ return; ++} ++ ++void free_initmem(void) ++{ ++ free_area((unsigned long)(&__init_begin), ++ (unsigned long)(&__init_end), "init"); ++} ++ ++#ifdef CONFIG_BLK_DEV_INITRD ++static int keep_initrd; ++ ++void free_initrd_mem(unsigned long start, unsigned long end) ++{ ++ if (!keep_initrd) ++ free_area(start, end, "initrd"); ++} ++ ++static int __init keepinitrd_setup(char *__unused) ++{ ++ keep_initrd = 1; ++ return 1; ++} ++ ++__setup("keepinitrd", keepinitrd_setup); ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/mm/ioremap.c linux-3.4.110/arch/nds32/mm/ioremap.c +--- linux-3.4.110.orig/arch/nds32/mm/ioremap.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/ioremap.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,89 @@ ++/* ++ * linux/arch/nds32/mm/ioremap.c ++ * ++ * Re-map IO memory to kernel address space so that we can access it. ++ * ++ * (C) Copyright 1995 1996 Linus Torvalds ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * Hacked for ARM by Phil Blundell <philb@gnu.org> ++ * Hacked to allow all architectures to build, and various cleanups ++ * by Russell King ++ * ++ * This allows a driver to remap an arbitrary region of bus memory into ++ * virtual space. One should *only* use readl, writel, memcpy_toio and ++ * so on with such remapped areas. ++ * ++ * Because the ARM only has a 32-bit address space we can't address the ++ * whole of the (physical) PCI space at once. PCI huge-mode addressing ++ * allows us to circumvent this restriction by splitting PCI space into ++ * two 2GB chunks and mapping only one at a time into processor memory. ++ * We use MMU protection domains to trap any attempt to access the bank ++ * that is not currently mapped. (This isn't fully implemented yet.) ++ */ ++#include <linux/module.h> ++#include <linux/vmalloc.h> ++#include <linux/io.h> ++#include <asm/cacheflush.h> ++ ++/* ++ * Remap an arbitrary physical address space into the kernel virtual ++ * address space. Needed when the kernel wants to access high addresses ++ * directly. ++ * ++ * NOTE! We need to allow non-page-aligned mappings too: we will obviously ++ * have to convert them into an offset in a page-aligned mapping, but the ++ * caller shouldn't need to know that small detail. ++ * ++ * 'flags' are the extra L_PTE_ flags that you want to specify for this ++ * mapping. See include/asm-arm/proc-armv/pgtable.h for more information. ++ */ ++void __iomem *__ioremap(unsigned long phys_addr, size_t size, ++ unsigned long flags, unsigned long align) ++{ ++ struct vm_struct *area; ++ unsigned long addr, offset, last_addr; ++ pgprot_t prot; ++ ++ /* Don't allow wraparound or zero size */ ++ last_addr = phys_addr + size - 1; ++ if (!size || last_addr < phys_addr) ++ return NULL; ++ ++ /* ++ * Mappings have to be page-aligned ++ */ ++ offset = phys_addr & ~PAGE_MASK; ++ phys_addr &= PAGE_MASK; ++ size = PAGE_ALIGN(last_addr + 1) - phys_addr; ++ ++ /* ++ * Ok, go for it.. ++ */ ++ area = get_vm_area(size, VM_IOREMAP); ++ if (!area) ++ return NULL; ++ ++ area->phys_addr = phys_addr; ++ addr = (unsigned long)area->addr; ++ /* TODO: verify this value for ioremap */ ++ prot = __pgprot(_PAGE_V | _PAGE_M_KRW | _PAGE_D | ++ _PAGE_G | _PAGE_C_DEV | flags); ++ /* TODO: verify this use generic ioremap_page_range instead of ++ * self's remap_area_pages */ ++ if (ioremap_page_range(addr, addr + size, phys_addr, prot)) { ++ vunmap((void *)addr); ++ return NULL; ++ } ++ return (__force void __iomem *)(offset + (char *)addr); ++ ++} ++ ++EXPORT_SYMBOL(__ioremap); ++ ++void __iounmap(void __iomem * addr) ++{ ++ vunmap((void *)(PAGE_MASK & (unsigned long)addr)); ++} ++ ++EXPORT_SYMBOL(__iounmap); +diff -Nur linux-3.4.110.orig/arch/nds32/mm/Makefile linux-3.4.110/arch/nds32/mm/Makefile +--- linux-3.4.110.orig/arch/nds32/mm/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/Makefile 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,24 @@ ++# ++# Makefile for the linux arm-specific parts of the memory manager. ++# ++ ++obj-y := consistent.o extable.o \ ++ fault.o init.o ioremap.o mmap.o \ ++ mm-nds32.o cacheflush.o ++ ++obj-y += proc-n12.o ++obj-$(CONFIG_CCTL) += cctl.o ++obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o ++ifneq ($(CONFIG_CPU_NO_CONTEXT_ID), y) ++obj-y += tlb.o ++endif ++gcc_ver :=$(shell $(CC) -E -dM -xc /dev/null | grep __VERSION__ | sed 's/\#define __VERSION__ //') ++ifeq ($(shell expr `echo $(gcc_ver)` \>= 4.9.2 ), 1) ++CFLAGS_proc-n12.o += -fomit-frame-pointer ++else ++CFLAGS_proc-n12.o += -fomit-frame-pointer -mno-16bit ++endif ++obj-$(CONFIG_HIGHMEM) += highmem.o ++ifdef CONFIG_FUNCTION_TRACER ++CFLAGS_REMOVE_proc-n12.o = -pg ++endif +diff -Nur linux-3.4.110.orig/arch/nds32/mm/mmap.c linux-3.4.110/arch/nds32/mm/mmap.c +--- linux-3.4.110.orig/arch/nds32/mm/mmap.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/mmap.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,101 @@ ++/* ++ * linux/arch/nds32/mm/mmap.c ++ * ++ * Copyright (C) 2009 Andes Technology Corporation ++ */ ++#include <linux/sched.h> ++#include <linux/mman.h> ++#include <linux/shm.h> ++ ++#define COLOUR_ALIGN(addr,pgoff) \ ++ ((((addr)+REALSHMLBA-1)&~(REALSHMLBA-1)) + \ ++ (((pgoff)<<PAGE_SHIFT) & (REALSHMLBA-1))) ++ ++/* ++ * We need to ensure that shared mappings are correctly aligned to ++ * avoid aliasing issues with VIPT caches. We need to ensure that ++ * a specific page of an object is always mapped at a multiple of ++ * SHMLBA bytes. ++ * ++ * We unconditionally provide this function for all cases, however ++ * in the VIVT case, we optimise out the alignment rules. ++ */ ++unsigned long ++arch_get_unmapped_area(struct file *filp, unsigned long addr, ++ unsigned long len, unsigned long pgoff, ++ unsigned long flags) ++{ ++ struct mm_struct *mm = current->mm; ++ struct vm_area_struct *vma; ++ unsigned long start_addr; ++ int do_align = 0; ++#ifdef CONFIG_CPU_CACHE_NONALIASING ++ int aliasing = 0; ++#else ++ int aliasing = 1; ++#endif ++ ++ /* ++ * We only need to do colour alignment if either the I or D ++ * caches alias. ++ */ ++ if (aliasing) ++ do_align = filp || (flags & MAP_SHARED); ++ ++ /* ++ * We should enforce the MAP_FIXED case. However, currently ++ * the generic kernel code doesn't allow us to handle this. ++ */ ++ if (flags & MAP_FIXED) { ++ if (aliasing && flags & MAP_SHARED && addr & (REALSHMLBA - 1)) ++ return -EINVAL; ++ return addr; ++ } ++ ++ if (len > TASK_SIZE) ++ return -ENOMEM; ++ ++ if (addr) { ++ if (do_align) ++ addr = COLOUR_ALIGN(addr, pgoff); ++ else ++ addr = PAGE_ALIGN(addr); ++ ++ vma = find_vma(mm, addr); ++ if (TASK_SIZE - len >= addr && ++ (!vma || addr + len <= vma->vm_start)) ++ return addr; ++ } ++ start_addr = addr = mm->free_area_cache; ++ ++full_search: ++ if (do_align) ++ addr = COLOUR_ALIGN(addr, pgoff); ++ else ++ addr = PAGE_ALIGN(addr); ++ ++ for (vma = find_vma(mm, addr);; vma = vma->vm_next) { ++ /* At this point: (!vma || addr < vma->vm_end). */ ++ if (TASK_SIZE - len < addr) { ++ /* ++ * Start a new search - just in case we missed ++ * some holes. ++ */ ++ if (start_addr != TASK_UNMAPPED_BASE) { ++ start_addr = addr = TASK_UNMAPPED_BASE; ++ goto full_search; ++ } ++ return -ENOMEM; ++ } ++ if (!vma || addr + len <= vma->vm_start) { ++ /* ++ * Remember the place where we stopped the search: ++ */ ++ mm->free_area_cache = addr + len; ++ return addr; ++ } ++ addr = vma->vm_end; ++ if (do_align) ++ addr = COLOUR_ALIGN(addr, pgoff); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/mm/mm.h linux-3.4.110/arch/nds32/mm/mm.h +--- linux-3.4.110.orig/arch/nds32/mm/mm.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/mm.h 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,19 @@ ++/* the upper-most page table pointer */ ++ ++#ifdef CONFIG_MMU ++ ++extern pmd_t *top_pmd; ++ ++#define TOP_PTE(x) pte_offset_kernel(top_pmd, x) ++ ++static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt) ++{ ++ return pmd_offset(pgd, virt); ++} ++ ++static inline pmd_t *pmd_off_k(unsigned long virt) ++{ ++ return pmd_off(pgd_offset_k(virt), virt); ++} ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/mm/mm-nds32.c linux-3.4.110/arch/nds32/mm/mm-nds32.c +--- linux-3.4.110.orig/arch/nds32/mm/mm-nds32.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/mm-nds32.c 2016-04-07 10:20:50.982082572 +0200 +@@ -0,0 +1,267 @@ ++/* ++ * linux/arch/nds32/mm/mm-nds32.c ++ * ++ * Copyright (C) 1998-2002 Russell King ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * Page table sludge for Andes N10/N12 processor architectures. ++ */ ++#include <linux/module.h> ++#include <linux/mm.h> ++#include <linux/bootmem.h> ++#include <linux/init_task.h> ++ ++#include <asm/pgalloc.h> ++#include <asm/pgtable.h> ++#include <asm/setup.h> ++#include <asm/fixmap.h> ++ ++#include <asm/mach/map.h> ++#include "./../kernel/signal.h" ++ ++extern void _text, _stext, _etext; ++extern void *high_memory; ++ ++#define FIRST_KERNEL_PGD_NR (USER_PTRS_PER_PGD) ++ ++/* ++ * need to get a 4k page for level 1 ++ */ ++ ++pgd_t *get_pgd_slow(struct mm_struct *mm) ++{ ++ pgd_t *new_pgd, *init_pgd; ++ int i; ++ ++ new_pgd = (pgd_t *) __get_free_pages(GFP_KERNEL, 0); //M order 0: one page ++ if (!new_pgd) ++ return NULL; ++ for (i = 0; i < PTRS_PER_PGD; i++) { ++ (*new_pgd) = 1; ++ new_pgd++; ++ } ++ new_pgd -= PTRS_PER_PGD; ++ ++ init_pgd = pgd_offset_k(0); ++ ++ memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, ++ (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); ++ ++ cpu_dcache_wb_range((unsigned long)new_pgd, ++ (unsigned long)new_pgd + ++ PTRS_PER_PGD * sizeof(pgd_t)); ++ inc_zone_page_state(virt_to_page((unsigned long *)new_pgd), ++ NR_PAGETABLE); ++ ++ return new_pgd; ++} ++ ++void free_pgd_slow(struct mm_struct *mm, pgd_t * pgd) ++{ ++ pmd_t *pmd; ++ struct page *pte; ++ ++ if (!pgd) ++ return; ++ ++ pmd = (pmd_t *) pgd; ++ if (pmd_none(*pmd)) ++ goto free; ++ if (pmd_bad(*pmd)) { ++ pmd_ERROR(*pmd); ++ pmd_clear(pmd); ++ goto free; ++ } ++ ++ pte = pmd_page(*pmd); ++ pmd_clear(pmd); ++ dec_zone_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE); ++ pte_free(mm, pte); ++ pmd_free(mm, pmd); ++free: ++ free_pages((unsigned long)pgd, 0); ++} ++ ++/* ++ * Add a PAGE mapping between VIRT and PHYS in domain ++ * DOMAIN with protection PROT. Note that due to the ++ * way we map the PTEs, we must allocate two PTE_SIZE'd ++ * blocks - one for the Linux pte table, and one for ++ * the hardware pte table. ++ */ ++static inline void ++alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, ++ pgprot_t prot) ++{ ++ pmd_t *pmdp; ++ pte_t *ptep; ++ ++ pmdp = pmd_offset(pgd_offset_k(virt), virt); //L1PTE ++ if (pmd_none(*pmdp)) { //must not or 0xc0000000 ++ ptep = alloc_bootmem_low_pages(PTRS_PER_PTE * sizeof(pte_t)); ++ set_pmd(pmdp, __mk_pmd(ptep, 0)); ++ } ++ ptep = pte_offset_kernel(pmdp, virt); //L2PTE ++ set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot)); ++} ++ ++/* ++ * Clear any PGD mapping. On a two-level page table system, ++ * the clearance is done by the middle-level functions (pmd) ++ * rather than the top-level (pgd) functions. ++ */ ++static inline void clear_mapping(unsigned long virt) ++{ ++ pmd_clear(pmd_offset(pgd_offset_k(virt), virt)); ++} ++ ++struct mem_types { ++ unsigned int prot_pte; ++ unsigned int prot_l1; ++}; ++ ++static struct mem_types mem_types[] __initdata = { ++ [MT_DEVICE] = { ++ .prot_pte = 0x9f, //_KERNPG_TABLE, ++ .prot_l1 = PMD_TYPE_TABLE, ++ }, ++ [MT_CACHECLEAN] = { ++ .prot_l1 = PMD_TYPE_TABLE, ++ .prot_pte = 0x0, //_KERNPG_TABLE, ++ }, ++ [MT_MINICLEAN] = { ++ .prot_l1 = PMD_TYPE_TABLE, ++ .prot_pte = 0x0, // _KERNPG_TABLE, ++ }, ++ [MT_CACHE_L1] = { ++ .prot_pte = PAGE_CACHE_L1, ++ .prot_l1 = PMD_TYPE_TABLE, ++ }, ++ [MT_UXKRWX_V1] = { ++ .prot_pte = PAGE_UXKRWX_V1, ++ .prot_l1 = PMD_TYPE_TABLE, ++ }, ++ [MT_UXKRWX_V2] = { ++ .prot_pte = PAGE_UXKRWX_V2, ++ .prot_l1 = PMD_TYPE_TABLE, ++ }, ++ [MT_MEMORY] = { ++ .prot_pte = PAGE_MEMORY, ++ .prot_l1 = PMD_TYPE_TABLE, ++ }, ++ [MT_ROM] = { ++ .prot_l1 = PMD_TYPE_TABLE, ++ .prot_pte = 0x2bb, // _KERNPG_TABLE, ++ }, ++ [MT_ILM] = { ++ .prot_l1 = PMD_TYPE_TABLE, ++ .prot_pte = 0x2b7, // _KERNPG_TABLE, ++ }, ++ [MT_DLM] = { ++ .prot_l1 = PMD_TYPE_TABLE, ++ .prot_pte = 0x297, // _KERNPG_TABLE, ++ } ++}; ++ ++/* ++ * Create the page directory entries and any necessary ++ * page tables for the mapping specified by `md'. We ++ * are able to cope here with varying sizes and address ++ * offsets, and we take full advantage of sections. ++ */ ++static void __init create_mapping(struct map_desc *md) ++{ ++ unsigned long virt, length; ++ int prot_l1; ++ pgprot_t prot_pte; ++ long off; ++ ++ printk("virt:0x%08lx,phys:%08lx,size:%08lx,pte:%08x\n", ++ md->virtual, md->physical, md->length, ++ __pgprot(mem_types[md->type].prot_pte)); ++ ++ if (md->virtual < TASK_SIZE) { ++ printk(KERN_WARNING "BUG: not creating mapping area for " ++ "0x%08lx at 0x%08lx in user region, next frame\n", ++ md->physical, md->virtual); ++ panic("In :%s, line:%d", __func__, __LINE__); ++ return; ++ } ++ ++ if ((md->type == MT_DEVICE || md->type == MT_ROM) && ++ md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) { ++ printk(KERN_WARNING "BUG: mapping area for 0x%08lx at 0x%08lx " ++ "overlaps vmalloc space, next frame\n", ++ md->physical, md->virtual); ++ panic("In :%s, line:%d", __func__, __LINE__); ++ } ++ ++ prot_pte = __pgprot(mem_types[md->type].prot_pte); ++ prot_l1 = mem_types[md->type].prot_l1; ++ virt = md->virtual; ++ off = md->physical - virt; ++ ++ length = md->length; ++ if (mem_types[md->type].prot_l1 == 1 && ++ (virt & 0xfffff || (virt + off) & 0xfffff ++ || (virt + length) & 0xfffff)) { ++ printk(KERN_WARNING ++ "BUG: map area for 0x%08lx at 0x%08lx can not " ++ "be mapped using pages, ignoring. next frame\n", ++ md->physical, md->virtual); ++ panic("In :%s, line:%d", __func__, __LINE__); ++ return; ++ } ++ ++ while (length >= PAGE_SIZE) { ++#ifdef CONFIG_SMP ++ if (((virt >= (unsigned long)&_text) ++ && (virt < (unsigned long)&_etext)) ++ || ((virt >= 0xc0000000) && (virt < 0xc0008000))) ++ prot_pte = __pgprot(mem_types[MT_CACHE_L1].prot_pte); ++#endif ++ alloc_init_page(virt, virt + off, prot_l1, prot_pte); ++ virt += PAGE_SIZE; ++ length -= PAGE_SIZE; ++ } ++} ++ ++/* ++ * In order to soft-boot, we need to insert a 1:1 mapping in place of ++ * the user-mode pages. This will then ensure that we have predictable ++ * results when turning the mmu off ++ */ ++void setup_mm_for_reboot(char mode) ++{ ++ unsigned long pmdval; ++ pgd_t *pgd; ++ pmd_t *pmd; ++ int i; ++ ++ if (current->mm && current->mm->pgd) ++ pgd = current->mm->pgd; ++ else ++ pgd = init_mm.pgd; ++ ++ for (i = 0; i < USER_PTRS_PER_PGD; i++) { ++ pmdval = (i << PGDIR_SHIFT); ++ pmd = pmd_offset(pgd + i, i << PGDIR_SHIFT); ++ set_pmd(pmd, __pmd(pmdval)); ++ } ++} ++ ++/* ++ * Create the architecture specific mappings ++ */ ++void __init iotable_init(struct map_desc *io_desc, int nr) ++{ ++ int i; ++ ++ for (i = 0; i < nr; i++) { ++ create_mapping(io_desc + i); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/mm/proc-n12.c linux-3.4.110/arch/nds32/mm/proc-n12.c +--- linux-3.4.110.orig/arch/nds32/mm/proc-n12.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/proc-n12.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,845 @@ ++/* ++ * linux/arch/nds32/mm/proc-nds32.c ++ * ++ * Copyright (C) 2006 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ++ * These are the low level assembler for performing cache and TLB ++ * functions on the nds32. ++ * ++ */ ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/mm.h> ++#include <asm/nds32.h> ++#include <asm/pgtable.h> ++#include <asm/tlbflush.h> ++#include <asm/cacheflush.h> ++#ifdef CONFIG_CACHE_L2 ++#include <asm/l2_cache.h> ++#endif ++#include <nds32_intrinsic.h> ++ ++#include <asm/cache_info.h> ++extern struct cache_info L1_cache_info[2]; ++ ++#ifdef CONFIG_CACHE_L2 ++void n12_L2cache_inval(void) ++{ ++ unsigned long cmd = CCTL_CMD_L2_IX_INVAL | CCTL_ALL_CMD; ++ ++ L2_CMD_RDY(); ++ L2C_W_REG(L2_CCTL_CMD_OFF, cmd); ++ L2_CMD_RDY(); ++ L2C_W_REG(L2_CCTL_CMD_OFF, CCTL_CMD_L2_SYNC); ++ L2_CMD_RDY(); ++} ++ ++void n12_L2cache_wb(void) ++{ ++ unsigned long cmd = CCTL_CMD_L2_IX_WB | CCTL_ALL_CMD; ++ ++ L2_CMD_RDY(); ++ L2C_W_REG(L2_CCTL_CMD_OFF, cmd); ++ L2_CMD_RDY(); ++ L2C_W_REG(L2_CCTL_CMD_OFF, CCTL_CMD_L2_SYNC); ++ L2_CMD_RDY(); ++} ++#endif ++ ++int va_kernel_present(unsigned long addr) ++{ ++ pmd_t *pmd; ++ pte_t *ptep, pte; ++ int ret = 0; ++ ++ pmd = pmd_offset(pgd_offset_k(addr), addr); ++ if (!pmd_none(*pmd)) { ++ ptep = pte_offset_map(pmd, addr); ++ pte = *ptep; ++ if (pte_present(pte)) ++ ret = 1; ++ } ++ return ret; ++} ++ ++int va_present(struct mm_struct *mm, unsigned long addr) ++{ ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *ptep, pte; ++ int ret = 0; ++ ++ pgd = pgd_offset(mm, addr); ++ if (!pgd_none(*pgd)) { ++ pud = pud_offset(pgd, addr); ++ if (!pud_none(*pud)) { ++ pmd = pmd_offset(pud, addr); ++ if (!pmd_none(*pmd)) { ++ ptep = pte_offset_map(pmd, addr); ++ pte = *ptep; ++ if (pte_present(pte)) ++ ret = 1; ++ } ++ } ++ } ++ return ret; ++ ++} ++ ++int va_readable(struct pt_regs *regs, unsigned long addr) ++{ ++ struct mm_struct *mm = current->mm; ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *ptep, pte; ++ int ret = 0; ++ ++ if (user_mode(regs)) { ++ /* user mode */ ++ pgd = pgd_offset(mm, addr); ++ if (!pgd_none(*pgd)) { ++ pud = pud_offset(pgd, addr); ++ if (!pud_none(*pud)) { ++ pmd = pmd_offset(pud, addr); ++ if (!pmd_none(*pmd)) { ++ ptep = pte_offset_map(pmd, addr); ++ pte = *ptep; ++ if (pte_present(pte) && pte_read(pte)) ++ ret = 1; ++ } ++ } ++ } ++ } else { ++ /* superuser mode is always readable, so we can only ++ * check it is present or not*/ ++ pmd = pmd_offset(pgd_offset_k(addr), addr); ++ if (!pmd_none(*pmd)) { ++ ptep = pte_offset_map(pmd, addr); ++ pte = *ptep; ++ if (pte_present(pte)) ++ ret = 1; ++ } ++ } ++ return ret; ++} ++ ++int va_writable(struct pt_regs *regs, unsigned long addr) ++{ ++ struct mm_struct *mm = current->mm; ++ pgd_t *pgd; ++ pud_t *pud; ++ pmd_t *pmd; ++ pte_t *ptep, pte; ++ int ret = 0; ++ ++ if (user_mode(regs)) { ++ /* user mode */ ++ pgd = pgd_offset(mm, addr); ++ if (!pgd_none(*pgd)) { ++ pud = pud_offset(pgd, addr); ++ if (!pud_none(*pud)) { ++ pmd = pmd_offset(pud, addr); ++ if (!pmd_none(*pmd)) { ++ ptep = pte_offset_map(pmd, addr); ++ pte = *ptep; ++ if (pte_present(pte) && pte_write(pte)) ++ ret = 1; ++ } ++ } ++ } ++ } else { ++ /* superuser mode */ ++ pmd = pmd_offset(pgd_offset_k(addr), addr); ++ if (!pmd_none(*pmd)) { ++ ptep = pte_offset_map(pmd, addr); ++ pte = *ptep; ++ if (pte_present(pte) && pte_kernel_write(pte)) ++ ret = 1; ++ } ++ } ++ return ret; ++} ++ ++#if 0 ++static inline void flush_fill_buffer(void) ++{ ++ unsigned long kaddr, pte, flags; ++ ++ local_irq_save(flags); ++#define BASE_ADDR2 0xffff4000 ++ kaddr = BASE_ADDR2; ++ pte = (0x6000 | _PAGE_V | _PAGE_M_KRW | _PAGE_G | _PAGE_C_DEV); ++ asm("tlbop %0, INV\nisb\n"::"r"(kaddr)); ++ asm("mtsr %1, $mr2\ndsb\n" ++ "tlbop %0, RWR\nisb\n"::"r"(pte), "r"(kaddr)); ++asm("lmw.bi $r0, [%0], $r1\n"::"r"(kaddr):"$r0", "$r1"); ++ local_irq_restore(flags); ++} ++#else ++static inline void flush_fill_buffer(void) ++{ ++} ++#endif ++ ++/* ++ * All ++ */ ++void n12_icache_inval_all(void) ++{ ++ unsigned long end, line_size; ++ ++ line_size = L1_cache_info[ICACHE].line_size; ++ end = ++ line_size * L1_cache_info[ICACHE].ways * L1_cache_info[ICACHE].sets; ++ ++ do { ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1I_IX_INVAL"::"r" (end)); ++ } while (end > 0); ++} ++ ++void n12_dcache_inval_all(void) ++{ ++#ifdef CONFIG_PLAT_AG102 ++ __asm__ volatile ("\n\tcctl L1D_INVALALL"); ++#else ++ unsigned long end, line_size; ++ ++ line_size = L1_cache_info[DCACHE].line_size; ++ end = ++ line_size * L1_cache_info[DCACHE].ways * L1_cache_info[DCACHE].sets; ++ ++ do { ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_INVAL"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_INVAL"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_INVAL"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_INVAL"::"r" (end)); ++ } while (end > 0); ++#endif ++} ++ ++void n12_dcache_wb_all(void) ++{ ++#ifdef __NDS32_BASELINE_V3 ++#ifdef CONFIG_CACHE_L2 ++ __nds32__cctl_l1d_wball_alvl(); ++#else ++ __nds32__cctl_l1d_wball_one_lvl(); ++#endif ++#else ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ unsigned long end, line_size; ++ ++ line_size = L1_cache_info[DCACHE].line_size; ++ end = ++ line_size * L1_cache_info[DCACHE].ways * L1_cache_info[DCACHE].sets; ++ ++ do { ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_WB"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_WB"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_WB"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_WB"::"r" (end)); ++ } while (end > 0); ++#endif ++#endif ++} ++ ++void n12_dcache_wbinval_all(void) ++{ ++ unsigned long end, line_size; ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ unsigned long saved_gie; ++#endif ++ ++ line_size = L1_cache_info[DCACHE].line_size; ++ end = ++ line_size * L1_cache_info[DCACHE].ways * L1_cache_info[DCACHE].sets; ++ ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ GIE_SAVE(&saved_gie); ++#endif ++#ifdef __NDS32_BASELINE_V3 ++#ifdef CONFIG_CACHE_L2 ++ __nds32__cctl_l1d_wball_alvl(); ++#else ++ __nds32__cctl_l1d_wball_one_lvl(); ++#endif ++ __nds32__cctl_l1d_invalall(); ++#else ++ do { ++ end -= line_size; ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_WB"::"r" (end)); ++#endif ++#ifndef CONFIG_PLAT_AG102 ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_INVAL"::"r" (end)); ++#endif ++ end -= line_size; ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_WB"::"r" (end)); ++#endif ++#ifndef CONFIG_PLAT_AG102 ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_INVAL"::"r" (end)); ++#endif ++ end -= line_size; ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_WB"::"r" (end)); ++#endif ++#ifndef CONFIG_PLAT_AG102 ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_INVAL"::"r" (end)); ++#endif ++ end -= line_size; ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_WB"::"r" (end)); ++#endif ++#ifndef CONFIG_PLAT_AG102 ++ __asm__ volatile ("\n\tcctl %0, L1D_IX_INVAL"::"r" (end)); ++#endif ++ } while (end > 0); ++#ifdef CONFIG_PLAT_AG102 ++ __asm__ volatile ("\n\tcctl L1D_INVALALL"); ++#endif ++#endif ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ GIE_RESTORE(saved_gie); ++#endif ++} ++ ++/* ++ * Page ++ */ ++void n12_icache_inval_page(unsigned long start) ++{ ++ unsigned long line_size, end; ++ ++ line_size = L1_cache_info[ICACHE].line_size; ++ end = start + PAGE_SIZE; ++ ++ do { ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (end)); ++ } while (end != start); ++} ++ ++void n12_dcache_inval_page(unsigned long start) ++{ ++ unsigned long line_size, end; ++ ++ line_size = L1_cache_info[DCACHE].line_size; ++ end = start + PAGE_SIZE; ++ ++ flush_fill_buffer(); ++ do { ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); ++ } while (end != start); ++} ++ ++void n12_dcache_wb_page(unsigned long start) ++{ ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ unsigned long line_size, end; ++ ++ line_size = L1_cache_info[DCACHE].line_size; ++ end = start + PAGE_SIZE; ++ ++ flush_fill_buffer(); ++ do { ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); ++ end -= line_size; ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); ++ } while (end != start); ++#endif ++} ++ ++void n12_dcache_wbinval_page(unsigned long start) ++{ ++ unsigned long line_size, end; ++ ++ line_size = L1_cache_info[DCACHE].line_size; ++ end = start + PAGE_SIZE; ++ ++ flush_fill_buffer(); ++ do { ++ end -= line_size; ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); ++#endif ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); ++ end -= line_size; ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); ++#endif ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); ++ end -= line_size; ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); ++#endif ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); ++ end -= line_size; ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (end)); ++#endif ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (end)); ++ } while (end != start); ++} ++ ++void n12_cache_wbinval_page(unsigned long page, int flushi) ++{ ++ n12_dcache_wbinval_page(page); ++ if (flushi) ++ n12_icache_inval_page(page); ++} ++ ++/* These functions are used to invalidate cache by idx instead of ++ * virtual address. User can use virtual address to do this purpose. ++ * It supports 4way and 32KB cache size with 32bytes cacheline size. */ ++#include <nds32_intrinsic.h> ++//#define WB_WITH_IDX ++inline unsigned long va2idx(unsigned long va, unsigned int cache_type, ++ unsigned long *way_offset) ++{ ++ unsigned char set_bits, way_bits, line_bits; ++ unsigned int idx; ++ set_bits = L1_cache_info[cache_type].set_bits; ++ way_bits = L1_cache_info[cache_type].way_bits; ++ line_bits = L1_cache_info[cache_type].line_bits; ++ *way_offset = set_bits + line_bits; ++ ++ idx = (va & (((1 << set_bits) - 1) << line_bits)); ++ return idx; ++} ++ ++static inline void n12_dcache_inval_idx(unsigned long p) ++{ ++ unsigned long idx, i, way_offset; ++ unsigned char ways; ++ ways = L1_cache_info[DCACHE].ways; ++ ++ /* Unroll loop. Not support 2 ways invalidate. */ ++ if (ways == 2) ++ panic("This way size is not supported. ways:%u, %s\n", ways, ++ __func__); ++ idx = va2idx(p, DCACHE, &way_offset); ++ for (i = 0; i < ways / 4; i++) { ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_INVAL, ++ (idx | i << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_INVAL, ++ (idx | (i + 1) << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_INVAL, ++ (idx | (i + 2) << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_INVAL, ++ (idx | (i + 3) << way_offset)); ++ } ++} ++ ++static inline void n12_dcache_wb_idx(unsigned long p) ++{ ++ unsigned long idx, i, way_offset; ++ unsigned char ways; ++ ways = L1_cache_info[DCACHE].ways; ++ ++ /* Unroll the loop. Not support 2 ways invalidate. */ ++ if (ways == 2) ++ panic("This way size is not supported. ways:%d, %s\n", ways, ++ __func__); ++ idx = va2idx(p, DCACHE, &way_offset); ++ for (i = 0; i < ways / 4; i++) { ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_WB, ++ (idx | i << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_INVAL, ++ (idx | i << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_WB, ++ (idx | (i + 1) << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_INVAL, ++ (idx | (i + 1) << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_WB, ++ (idx | (i + 2) << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_INVAL, ++ (idx | (i + 2) << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_WB, ++ (idx | (i + 3) << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_INVAL, ++ (idx | (i + 3) << way_offset)); ++ } ++} ++ ++static inline void n12_dcache_wbinval_idx(unsigned long p) ++{ ++ unsigned long idx, i, way_offset; ++ unsigned char ways; ++ ways = L1_cache_info[DCACHE].ways; ++ ++ /* Unroll the loop. Not support 2 ways invalidate. */ ++ if (ways == 2) ++ panic("This way size is not supported. ways:%d, %s\n", ways, ++ __func__); ++ idx = va2idx(p, DCACHE, &way_offset); ++ for (i = 0; i < ways / 4; i++) { ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_WB, ++ (idx | i << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_WB, ++ (idx | (i + 1) << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_WB, ++ (idx | (i + 2) << way_offset)); ++ __nds32__cctlidx_wbinval(NDS32_CCTL_L1D_IX_WB, ++ (idx | (i + 3) << way_offset)); ++ } ++} ++ ++/* ++ * Range ++ */ ++void n12_icache_inval_range(unsigned long start, unsigned long end) ++{ ++ unsigned long line_size; ++ ++ line_size = L1_cache_info[ICACHE].line_size; ++ ++ while (end > start) { ++ __asm__ volatile ("\n\tcctl %0, L1I_VA_INVAL"::"r" (start)); ++ start += line_size; ++ } ++} ++ ++void n12_dcache_inval_range(unsigned long start, unsigned long end) ++{ ++ unsigned long line_size; ++ ++ line_size = L1_cache_info[DCACHE].line_size; ++ ++ flush_fill_buffer(); ++ while (end > start) { ++#ifdef WB_WITH_IDX ++ n12_dcache_inval_idx(start); ++#else ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (start)); ++#endif ++ start += line_size; ++ } ++} ++ ++void n12_dcache_wb_range(unsigned long start, unsigned long end) ++{ ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++ unsigned long line_size; ++ ++ line_size = L1_cache_info[DCACHE].line_size; ++ ++ flush_fill_buffer(); ++ while (end > start) { ++#ifdef WB_WITH_IDX ++ n12_dcache_wb_idx(start); ++#else ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (start)); ++#endif ++ start += line_size; ++ } ++#endif ++} ++ ++void n12_dcache_wbinval_range(unsigned long start, unsigned long end) ++{ ++ unsigned long line_size; ++ ++ line_size = L1_cache_info[DCACHE].line_size; ++ ++ flush_fill_buffer(); ++ while (end > start) { ++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH ++#ifdef WB_WITH_IDX ++ n12_dcache_wbinval_idx(start); ++#else ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_WB"::"r" (start)); ++#endif ++#endif ++ __asm__ volatile ("\n\tcctl %0, L1D_VA_INVAL"::"r" (start)); ++ start += line_size; ++ } ++} ++ ++void n12_cache_wbinval_range(unsigned long start, unsigned long end, int flushi) ++{ ++ n12_dcache_wbinval_range(start, end); ++ if (flushi) ++ n12_icache_inval_range(start, end); ++} ++ ++void n12_cache_wbinval_range_check(struct vm_area_struct *vma, ++ unsigned long start, unsigned long end) ++{ ++ unsigned long line_size, t_start, t_end; ++ int flushi; ++ ++ flushi = vma->vm_flags & VM_EXEC; ++ line_size = L1_cache_info[DCACHE].line_size; ++ start = start & ~(line_size - 1); ++ end = (end + line_size - 1) & ~(line_size - 1); ++ ++ if ((end - start) > (8 * PAGE_SIZE)) { ++ n12_dcache_wbinval_all(); ++ if (flushi) ++ n12_icache_inval_all(); ++ return; ++ } ++ ++ t_start = (start + PAGE_SIZE) & PAGE_MASK; ++ t_end = ((end - 1) & PAGE_MASK); ++ ++ if ((start & PAGE_MASK) == t_end) { ++ if (va_present(vma->vm_mm, start)) ++ n12_cache_wbinval_range(start, end, flushi); ++ return; ++ } ++ ++ if (va_present(vma->vm_mm, start)) ++ n12_cache_wbinval_range(start, t_start, flushi); ++ ++ if (va_present(vma->vm_mm, end - 1)) ++ n12_cache_wbinval_range(t_end, end, flushi); ++ ++ while (t_start < t_end) { ++ if (va_present(vma->vm_mm, t_start)) ++ n12_cache_wbinval_page(t_start, flushi); ++ t_start += PAGE_SIZE; ++ } ++} ++ ++/* ++ * DMA ++ */ ++void n12_dma_wb_range(unsigned long start, unsigned long end) ++{ ++ unsigned long line_size; ++ line_size = L1_cache_info[DCACHE].line_size; ++ start = start & (~(line_size - 1)); ++ end = (end + line_size - 1) & (~(line_size - 1)); ++ if (unlikely(start == end)) ++ return; ++ ++ n12_dcache_wb_range(start, end); ++ ++#ifdef CONFIG_CACHE_L2 ++ { ++ unsigned long p_start = __pa(start); ++ unsigned long p_end = __pa(end); ++ unsigned long cmd; ++ //TODO Can Use PAGE Mode to optimize if range large than PAGE_SIZE ++ line_size = L2_CACHE_LINE_SIZE(); ++ cmd = ++ (p_start & ~(line_size - 1)) | CCTL_CMD_L2_PA_WB | ++ CCTL_SINGLE_CMD; ++ do { ++ L2_CMD_RDY(); ++ L2C_W_REG(L2_CCTL_CMD_OFF, cmd); ++ cmd += line_size; ++ p_start += line_size; ++ } while (p_end > p_start); ++ cmd = CCTL_CMD_L2_SYNC; ++ L2_CMD_RDY(); ++ L2C_W_REG(L2_CCTL_CMD_OFF, cmd); ++ L2_CMD_RDY(); ++ ++ } ++#endif ++} ++ ++#ifdef CONFIG_CACHE_L2 ++void n12_l2dcache_wbinval_range(unsigned long start, unsigned long end) ++{ ++ unsigned long p_start; ++ unsigned long p_end; ++ unsigned long cmd; ++ unsigned long line_size; ++ ++ p_start = __pa(start); ++ p_end = __pa(end); ++ //TODO Can Use PAGE Mode to optimize if range large than PAGE_SIZE ++ line_size = L2_CACHE_LINE_SIZE(); ++ cmd = ++ (p_start & ~(line_size - 1)) | CCTL_CMD_L2_PA_WBINVAL | ++ CCTL_SINGLE_CMD; ++ do { ++ L2_CMD_RDY(); ++ L2C_W_REG(L2_CCTL_CMD_OFF, cmd); ++ cmd += line_size; ++ p_start += line_size; ++ } while (p_end > p_start); ++ cmd = CCTL_CMD_L2_SYNC; ++ L2_CMD_RDY(); ++ L2C_W_REG(L2_CCTL_CMD_OFF, cmd); ++ L2_CMD_RDY(); ++ ++} ++#endif ++ ++void n12_dma_inval_range(unsigned long start, unsigned long end) ++{ ++ unsigned long line_size; ++ unsigned long old_start = start; ++ unsigned long old_end = end; ++ line_size = L1_cache_info[DCACHE].line_size; ++ start = start & (~(line_size - 1)); ++ end = (end + line_size - 1) & (~(line_size - 1)); ++ if (unlikely(start == end)) ++ return; ++ if (start != old_start) { ++ n12_dcache_wbinval_range(start, start + line_size); ++#ifdef CONFIG_CACHE_L2 ++ n12_l2dcache_wbinval_range(start, start + line_size); ++#endif ++ } ++ if (end != old_end) { ++ n12_dcache_wbinval_range(end - line_size, end); ++#ifdef CONFIG_CACHE_L2 ++ n12_l2dcache_wbinval_range(end - line_size, end); ++#endif ++ } ++ n12_dcache_inval_range(start, end); ++#ifdef CONFIG_CACHE_L2 ++ unsigned long p_start = __pa(start); ++ unsigned long p_end = __pa(end); ++ unsigned long cmd; ++ //TODO Can Use PAGE Mode to optimize if range large than PAGE_SIZE ++ line_size = L2_CACHE_LINE_SIZE(); ++ cmd = ++ (p_start & ~(line_size - 1)) | CCTL_CMD_L2_PA_INVAL | ++ CCTL_SINGLE_CMD; ++ do { ++ L2_CMD_RDY(); ++ L2C_W_REG(L2_CCTL_CMD_OFF, cmd); ++ cmd += line_size; ++ p_start += line_size; ++ } while (p_end > p_start); ++ cmd = CCTL_CMD_L2_SYNC; ++ L2_CMD_RDY(); ++ L2C_W_REG(L2_CCTL_CMD_OFF, cmd); ++ L2_CMD_RDY(); ++#endif ++ ++} ++ ++void n12_dma_wbinval_range(unsigned long start, unsigned long end) ++{ ++ unsigned long line_size; ++ line_size = L1_cache_info[DCACHE].line_size; ++ start = start & (~(line_size - 1)); ++ end = (end + line_size - 1) & (~(line_size - 1)); ++ if (unlikely(start == end)) ++ return; ++ ++ n12_dcache_wbinval_range(start, end); ++#ifdef CONFIG_CACHE_L2 ++ { ++ unsigned long p_start = __pa(start); ++ unsigned long p_end = __pa(end); ++ unsigned long cmd; ++ //TODO Can Use PAGE Mode to optimize if range large than PAGE_SIZE ++ line_size = L2_CACHE_LINE_SIZE(); ++ cmd = ++ (p_start & ~(line_size - 1)) | CCTL_CMD_L2_PA_WBINVAL | ++ CCTL_SINGLE_CMD; ++ do { ++ L2_CMD_RDY(); ++ L2C_W_REG(L2_CCTL_CMD_OFF, cmd); ++ cmd += line_size; ++ p_start += line_size; ++ } while (p_end > p_start); ++ cmd = CCTL_CMD_L2_SYNC; ++ L2_CMD_RDY(); ++ L2C_W_REG(L2_CCTL_CMD_OFF, cmd); ++ L2_CMD_RDY(); ++ ++ } ++#endif ++} ++ ++void n12_proc_init(void) ++{ ++} ++ ++void n12_proc_fin(void) ++{ ++} ++ ++void n12_do_idle(void) ++{ ++ STANDBY(no_wake_grant); ++} ++ ++void n12_reset(unsigned long reset) ++{ ++ GIE_DISABLE(); ++ SET_CACHE_CTL(GET_CACHE_CTL() & ++ ~(CACHE_CTL_mskIC_EN | CACHE_CTL_mskDC_EN)); ++ n12_dcache_wbinval_all(); ++ n12_icache_inval_all(); ++ ++ __asm__ __volatile__("jr.toff %0\n\t"::"r"(reset)); ++} ++ ++void n12_switch_mm(struct mm_struct *mm) ++{ ++ unsigned long cid; ++#ifndef CONFIG_CPU_NO_CONTEXT_ID ++ cid = GET_TLB_MISC(); ++ cid = (cid & ~TLB_MISC_mskCID) | mm->context.id; ++ SET_TLB_MISC(cid); ++#endif ++ SET_L1_PPTB(__pa(mm->pgd)); ++ //workaround N10 single-entry cache flush issue ++ //the following line can be removed once the issue is fixed. ++ __asm__ __volatile__("tlbop %0, INV"::"r"(cid)); ++ __nds32__isb(); ++#ifdef CONFIG_CPU_NO_CONTEXT_ID ++ local_flush_tlb_mm(mm); ++#endif ++} +diff -Nur linux-3.4.110.orig/arch/nds32/mm/tlb.c linux-3.4.110/arch/nds32/mm/tlb.c +--- linux-3.4.110.orig/arch/nds32/mm/tlb.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/mm/tlb.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,47 @@ ++#include <linux/spinlock_types.h> ++#include <linux/mm.h> ++#include <linux/sched.h> ++#include <asm/nds32.h> ++#include <nds32_intrinsic.h> ++ ++unsigned int cpu_last_cid = { TLB_MISC_mskCID + (2 << TLB_MISC_offCID) }; ++ ++DEFINE_SPINLOCK(cid_lock); ++ ++void local_flush_tlb_range(struct vm_area_struct *vma, ++ unsigned long start, unsigned long end) ++{ ++ unsigned long flags, ocid, ncid; ++ ++ if ((end - start) > 0x400000) { ++ asm("tlbop FLUA"); ++ __nds32__isb(); ++ return; ++ } ++ ++ spin_lock_irqsave(&cid_lock, flags); ++ ocid = GET_TLB_MISC(); ++ ncid = (ocid & ~TLB_MISC_mskCID) | vma->vm_mm->context.id; ++ SET_TLB_MISC(ncid); ++ while (start < end) { ++ asm("tlbop %0, INV"::"r"(start)); ++ __nds32__isb(); ++ start += PAGE_SIZE; ++ } ++ SET_TLB_MISC(ocid); ++ spin_unlock_irqrestore(&cid_lock, flags); ++} ++ ++void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) ++{ ++ unsigned long flags, ocid, ncid; ++ ++ spin_lock_irqsave(&cid_lock, flags); ++ ocid = GET_TLB_MISC(); ++ ncid = (ocid & ~TLB_MISC_mskCID) | vma->vm_mm->context.id; ++ SET_TLB_MISC(ncid); ++ asm("tlbop %0, INV"::"r"(addr)); ++ __nds32__isb(); ++ SET_TLB_MISC(ocid); ++ spin_unlock_irqrestore(&cid_lock, flags); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/oprofile/common.c linux-3.4.110/arch/nds32/oprofile/common.c +--- linux-3.4.110.orig/arch/nds32/oprofile/common.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/oprofile/common.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,104 @@ ++/* ++ * 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) 2004, 2005 Ralf Baechle ++ * Copyright (C) 2005 MIPS Technologies, Inc. ++ * Copyright (C) 2008 Andes Technology Corporation ++ */ ++#include <linux/errno.h> ++#include <linux/init.h> ++#include <linux/oprofile.h> ++#include <linux/smp.h> ++ ++#include "op_impl.h" ++ ++extern struct op_nds32_model op_model_nds32_ops __attribute__ ((weak)); ++ ++static struct op_nds32_model *model; ++ ++static struct op_counter_config ctr[20]; ++ ++static int op_nds32_setup(void) ++{ ++ /* Pre-compute the values to stuff in the hardware registers. */ ++ model->reg_setup(ctr); ++ ++ /* Configure the registers on all cpus. */ ++ on_each_cpu(model->cpu_setup, NULL, 1); ++ ++ return 0; ++} ++ ++static int op_nds32_create_files(struct super_block *sb, struct dentry *root) ++{ ++ int i; ++ ++ for (i = 0; i < model->num_counters; ++i) { ++ struct dentry *dir; ++ char buf[4]; ++ ++ snprintf(buf, sizeof buf, "%d", i); ++ dir = oprofilefs_mkdir(sb, root, buf); ++ ++ oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled); ++ oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event); ++ oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count); ++ oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel); ++ oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user); ++ oprofilefs_create_ulong(sb, dir, "exl", &ctr[i].exl); ++ /* Dummy. */ ++ oprofilefs_create_ulong(sb, dir, "unit_mask", ++ &ctr[i].unit_mask); ++ } ++ ++ return 0; ++} ++ ++static int op_nds32_start(void) ++{ ++ on_each_cpu(model->cpu_start, NULL, 1); ++ ++ return 0; ++} ++ ++static void op_nds32_stop(void) ++{ ++ /* Disable performance monitoring for all counters. */ ++ on_each_cpu(model->cpu_stop, NULL, 1); ++} ++ ++int __init oprofile_arch_init(struct oprofile_operations *ops) ++{ ++ struct op_nds32_model *lmodel = NULL; ++ int res; ++ ++ lmodel = &op_model_nds32_ops; ++ ++ if (!lmodel) ++ return -ENODEV; ++ ++ res = lmodel->init(); ++ if (res) ++ return res; ++ ++ model = lmodel; ++ ++ ops->create_files = op_nds32_create_files; ++ ops->setup = op_nds32_setup; ++ ops->start = op_nds32_start; ++ ops->stop = op_nds32_stop; ++ ops->cpu_type = lmodel->cpu_type; ++ ++ printk(KERN_INFO "oprofile: using %s performance monitoring.\n", ++ lmodel->cpu_type); ++ ++ return 0; ++} ++ ++void oprofile_arch_exit(void) ++{ ++ if (model) ++ model->exit(); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/oprofile/Makefile linux-3.4.110/arch/nds32/oprofile/Makefile +--- linux-3.4.110.orig/arch/nds32/oprofile/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/oprofile/Makefile 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,11 @@ ++EXTRA_CFLAGS := ++ ++obj-$(CONFIG_OPROFILE) += oprofile.o ++ ++DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ ++ oprof.o cpu_buffer.o buffer_sync.o \ ++ event_buffer.o oprofile_files.o \ ++ oprofilefs.o oprofile_stats.o \ ++ timer_int.o ) ++ ++oprofile-y := $(DRIVER_OBJS) common.o op_model_nds32.o +diff -Nur linux-3.4.110.orig/arch/nds32/oprofile/op_impl.h linux-3.4.110/arch/nds32/oprofile/op_impl.h +--- linux-3.4.110.orig/arch/nds32/oprofile/op_impl.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/oprofile/op_impl.h 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,42 @@ ++/** ++ * @file arch/alpha/oprofile/op_impl.h ++ * ++ * @remark Copyright 2002 OProfile authors ++ * @remark Read the file COPYING ++ * ++ * @author Richard Henderson <rth@twiddle.net> ++ */ ++ ++#ifndef OP_IMPL_H ++#define OP_IMPL_H 1 ++ ++struct pt_regs; ++ ++extern int null_perf_irq(struct pt_regs *regs); ++extern int (*perf_irq)(struct pt_regs *regs); ++ ++/* Per-counter configuration as set via oprofilefs. */ ++struct op_counter_config { ++ unsigned long enabled; ++ unsigned long event; ++ unsigned long count; ++ /* Dummies because I am too lazy to hack the userspace tools. */ ++ unsigned long kernel; ++ unsigned long user; ++ unsigned long exl; ++ unsigned long unit_mask; ++}; ++ ++/* Per-architecture configury and hooks. */ ++struct op_nds32_model { ++ void (*reg_setup) (struct op_counter_config *); ++ void (*cpu_setup) (void * dummy); ++ int (*init)(void); ++ void (*exit)(void); ++ void (*cpu_start)(void *args); ++ void (*cpu_stop)(void *args); ++ char *cpu_type; ++ unsigned char num_counters; ++}; ++ ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/oprofile/op_model_nds32.c linux-3.4.110/arch/nds32/oprofile/op_model_nds32.c +--- linux-3.4.110.orig/arch/nds32/oprofile/op_model_nds32.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/oprofile/op_model_nds32.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,400 @@ ++/* ++ * 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) 2004, 2005 by Ralf Baechle ++ * Copyright (C) 2005 by MIPS Technologies, Inc. ++ * Copyright (C) 2007 Andes Technology Corporation ++ */ ++#include <linux/oprofile.h> ++#include <linux/interrupt.h> ++#include <linux/smp.h> ++#include <asm/irq_regs.h> ++#include <asm/nds32.h> ++#include <asm/uaccess.h> ++#include <asm/pfm.h> ++ ++#include "op_impl.h" ++ ++#ifdef CONFIG_PLAT_AG102 ++#include <asm/amic.h> ++#define NDS32_PERFCNTR_IRQA 23 ++#define NDS32_PERFCNTR_IRQB 22 ++#else ++#define NDS32_PERFCNTR_IRQA 10 ++#endif ++#define NDS32_PERFCTL_EN(num) (1 << num) ++#define NDS32_PERFCTL_INTEN (1UL << 3) ++#define NDS32_PERFCTL_OVERFLOW (1UL << 6) ++#define NDS32_PERFCTL_NOKERNEL (1UL << 9) ++#define NDS32_PERFCTL_NOUSER (1UL << 12) ++#define NDS32_PERFCTL_EVENT_0(event) (event << 15) ++#define NDS32_PERFCTL_EVENT_1(event) (event << 16) ++#define NDS32_PERFCTL_EVENT_2(event) (event << 22) ++ ++static unsigned long long ov0, ov1, ov2; ++static int syscall = 0; ++ ++struct pmu_counter { ++ volatile unsigned long ovf; ++ unsigned long reset_counter; ++}; ++ ++enum { PFMC0, PFMC1, PFMC2, MAX_COUNTERS }; ++ ++static struct pmu_counter results[MAX_COUNTERS]; ++ ++static inline unsigned int read_perfcntr(int counter) ++{ ++ switch (counter) { ++ case PFMC0: ++ return GET_PFMC0(); ++ break; ++ case PFMC1: ++ return GET_PFMC1(); ++ break; ++ case PFMC2: ++ return GET_PFMC2(); ++ break; ++ default: ++ printk(KERN_ERR ++ "Oprofile read_perfcntr: CPU has no %d performance counters\n", ++ counter); ++ } ++ ++ return 0; ++} ++ ++static inline unsigned int read_perfctrl(void) ++{ ++ return GET_PFM_CTL(); ++} ++ ++static inline void write_perfcntr(int counter, unsigned int value) ++{ ++ switch (counter) { ++ case PFMC0: ++ SET_PFMC0(value); ++ break; ++ case PFMC1: ++ SET_PFMC1(value); ++ break; ++ case PFMC2: ++ SET_PFMC2(value); ++ break; ++ default: ++ printk(KERN_ERR ++ "Oprofile write_perfcntr: CPU has no %d performance counters\n", ++ counter); ++ } ++} ++ ++static inline void write_perfctrl(unsigned int value) ++{ ++ SET_PFM_CTL(value); ++} ++ ++struct op_nds32_model op_model_nds32_ops; ++ ++static struct nds32_register_config { ++ unsigned int control[3]; ++ unsigned int counter[3]; ++} reg; ++ ++/* Compute all of the registers in preparation for enabling profiling. */ ++ ++static void nds32_reg_setup(struct op_counter_config *ctr) ++{ ++ unsigned int counters = op_model_nds32_ops.num_counters; ++ int i; ++ ++ /* Compute the performance counter control word. */ ++ /* For now count kernel and user mode */ ++ for (i = 0; i < counters; i++) { ++ reg.control[i] = 0; ++ reg.counter[i] = 0; ++ ++ if (!ctr[i].enabled) ++ continue; ++ ++ switch (i) { ++ case 0: ++ reg.control[i] = NDS32_PERFCTL_EVENT_0(ctr[i].event) | ++ (NDS32_PERFCTL_INTEN << i); ++ break; ++ case 1: ++ reg.control[i] = NDS32_PERFCTL_EVENT_1(ctr[i].event) | ++ (NDS32_PERFCTL_INTEN << i); ++ break; ++ case 2: ++ reg.control[i] = NDS32_PERFCTL_EVENT_2(ctr[i].event) | ++ (NDS32_PERFCTL_INTEN << i); ++ break; ++ default: ++ printk(KERN_ERR ++ "Oprofile nds32_reg_setup: CPU has no %d performance counters\n", ++ i); ++ } ++ if (!(ctr[i].kernel)) ++ reg.control[i] |= (NDS32_PERFCTL_NOKERNEL << i); ++ if (!(ctr[i].user)) ++ reg.control[i] |= (NDS32_PERFCTL_NOUSER << i); ++ reg.counter[i] = -ctr[i].count; ++ } ++} ++ ++/* Program all of the registers in preparation for enabling profiling. */ ++ ++static void nds32_cpu_setup(void *args) ++{ ++ unsigned int counters = op_model_nds32_ops.num_counters; ++ ++ switch (counters) { ++ case 3: ++ write_perfcntr(2, reg.counter[2]); ++ case 2: ++ write_perfcntr(1, reg.counter[1]); ++ case 1: ++ write_perfcntr(0, reg.counter[0]); ++ } ++ write_perfctrl(0); ++} ++ ++/* Start all counters on current CPU */ ++static void nds32_cpu_start(void *args) ++{ ++ unsigned int counters = op_model_nds32_ops.num_counters; ++ unsigned int value = 0; ++ ++ switch (counters) { ++ case 3: ++ if (reg.control[2]) ++ value |= (NDS32_PERFCTL_EN(2) | reg.control[2]); ++ case 2: ++ if (reg.control[1]) ++ value |= (NDS32_PERFCTL_EN(1) | reg.control[1]); ++ case 1: ++ if (reg.control[0]) ++ value |= (NDS32_PERFCTL_EN(0) | reg.control[0]); ++ } ++ write_perfctrl(value); ++} ++ ++/* Stop all counters on current CPU */ ++static void nds32_cpu_stop(void *args) ++{ ++ write_perfctrl(0); ++} ++ ++static irqreturn_t nds32_perfcount_handler(int irq, void *dev_id) ++{ ++ unsigned int control, i; ++ ++ control = read_perfctrl(); ++ write_perfctrl(0); ++ ++ if (syscall) { ++ if (control & PFM_CTL_mskOVF0) ++ ov0++; ++ if (control & PFM_CTL_mskOVF1) ++ ov1++; ++ if (control & PFM_CTL_mskOVF2) ++ ov2++; ++ } else { ++ for (i = 0; i < MAX_COUNTERS; i++) { ++ if ((control & (NDS32_PERFCTL_INTEN << i)) ++ && (control & (NDS32_PERFCTL_OVERFLOW << i))) { ++ oprofile_add_sample(get_irq_regs(), i); ++ write_perfcntr(i, reg.counter[i]); ++ break; ++ } ++ } ++ } ++ write_perfctrl(control); ++ ++ return IRQ_HANDLED; ++} ++ ++static inline int n_counters(void) ++{ ++ return 3; ++} ++ ++static inline void reset_counters(int counters) ++{ ++ switch (counters) { ++ case 3: ++ write_perfcntr(2, 0); ++ case 2: ++ write_perfcntr(1, 0); ++ case 1: ++ write_perfcntr(0, 0); ++ } ++ write_perfctrl(0); ++} ++ ++static int __init nds32_init(void) ++{ ++ int counters, ret; ++ ++ counters = n_counters(); ++ if (counters == 0) { ++ printk(KERN_ERR "Oprofile: CPU has no performance counters\n"); ++ return -ENODEV; ++ } ++ ++ reset_counters(counters); ++ ++ op_model_nds32_ops.num_counters = counters; ++ op_model_nds32_ops.cpu_type = "nds32"; ++ ++ ret = ++ request_irq(NDS32_PERFCNTR_IRQA, nds32_perfcount_handler, ++ IRQF_SHARED, "NDS32 PERFCNTR", (void *)results); ++ if (ret < 0) { ++ printk(KERN_ERR "oprofile: unable to request IRQ%d\n", ++ NDS32_PERFCNTR_IRQA); ++ return ret; ++ } ++#ifdef CONFIG_PLAT_AG102 ++ unsigned int tmp; ++ /* Set NDS32_PERFCNTR_IRQA to bind on core A */ ++ tmp = ++ *(volatile unsigned long *)(AMIC_VA_BASE + CPUID0 + ++ ((NDS32_PERFCNTR_IRQA >> 4) << 2)); ++ tmp &= ~(0x11 << ((NDS32_PERFCNTR_IRQA & ~0x10) * 2)); ++ *(volatile unsigned long *)(AMIC_VA_BASE + CPUID0 + ++ ((NDS32_PERFCNTR_IRQA >> 4) << 2)) = tmp; ++ tmp = ++ (*(volatile unsigned long *)(AMIC_VA_BASE + CPUDC)) & ~(1 << ++ NDS32_PERFCNTR_IRQA); ++ *(volatile unsigned long *)(AMIC_VA_BASE + CPUDC) = tmp; ++ ++ ret = ++ request_irq(NDS32_PERFCNTR_IRQB, nds32_perfcount_handler, ++ IRQF_SHARED, "NDS32 PERFCNTR", (void *)results); ++ if (ret < 0) { ++ printk(KERN_ERR "oprofile: unable to request IRQ%d\n", ++ NDS32_PERFCNTR_IRQB); ++ return ret; ++ } ++ /* Set NDS32_PERFCNTR_IRQB to bind on core B */ ++ tmp = ++ *(volatile unsigned long *)(AMIC_VA_BASE + CPUID0 + ++ ((NDS32_PERFCNTR_IRQB >> 4) << 2)); ++ tmp &= ~(0x11 << ((NDS32_PERFCNTR_IRQB & ~0x10) * 2)); ++ tmp |= 1 << ((NDS32_PERFCNTR_IRQB & ~0x10) * 2); ++ *(volatile unsigned long *)(AMIC_VA_BASE + CPUID0 + ++ ((NDS32_PERFCNTR_IRQB >> 4) << 2)) = tmp; ++ tmp = ++ (*(volatile unsigned long *)(AMIC_VA_BASE + CPUDC)) & ~(1 << ++ NDS32_PERFCNTR_IRQB); ++ *(volatile unsigned long *)(AMIC_VA_BASE + CPUDC) = tmp; ++#endif ++ ++ return 0; ++} ++ ++static void nds32_exit(void) ++{ ++ reset_counters(op_model_nds32_ops.num_counters); ++ ++ free_irq(NDS32_PERFCNTR_IRQA, results); ++#ifdef CONFIG_PLAT_AG102 ++ free_irq(NDS32_PERFCNTR_IRQB, results); ++#endif ++} ++ ++void sys_pfmctl(int event0, int event1, int event2, int start) ++{ ++ unsigned int ctl = 0; ++ ++ if (start) { ++ syscall = 1; ++ if (event0 >= 0) ++ ctl |= ++ (NDS32_PERFCTL_EVENT_0(event0) | ++ (NDS32_PERFCTL_INTEN << 0) | NDS32_PERFCTL_EN(0)); ++ if (event1 >= 0) ++ ctl |= ++ (NDS32_PERFCTL_EVENT_1(event1) | ++ (NDS32_PERFCTL_INTEN << 1) | NDS32_PERFCTL_EN(1)); ++ if (event2 >= 0) ++ ctl |= ++ (NDS32_PERFCTL_EVENT_2(event2) | ++ (NDS32_PERFCTL_INTEN << 2) | NDS32_PERFCTL_EN(2)); ++ } else { ++ syscall = 0; ++ if (event0 >= 0) ++ ctl &= ++ ~((NDS32_PERFCTL_INTEN << 0) | NDS32_PERFCTL_EN(0)); ++ if (event1 >= 0) ++ ctl &= ++ ~((NDS32_PERFCTL_INTEN << 1) | NDS32_PERFCTL_EN(1)); ++ if (event2 >= 0) ++ ctl &= ++ ~((NDS32_PERFCTL_INTEN << 2) | NDS32_PERFCTL_EN(2)); ++ } ++ ++ write_perfctrl(ctl); ++ ++} ++ ++int sys_getpfm(struct pcounter __user * p) ++{ ++ struct pcounter pfm; ++ unsigned int control; ++ ++ control = read_perfctrl(); ++ write_perfctrl(0); ++ ++ pfm.pfm0 = ov0 << 32 | GET_PFMC0(); ++ pfm.pfm1 = ov1 << 32 | GET_PFMC1(); ++ pfm.pfm2 = ov2 << 32 | GET_PFMC2(); ++ ++ if (copy_to_user(p, &pfm, sizeof(pfm))) ++ return -EFAULT; ++ ++ write_perfctrl(control); ++ ++ return 0; ++} ++ ++int sys_setpfm(int pfm0, int pfm1, int pfm2, struct pcounter __user * p) ++{ ++ struct pcounter pfm; ++ unsigned int control; ++ ++ control = read_perfctrl(); ++ write_perfctrl(0); ++ ++ if (copy_from_user(&pfm, p, sizeof(pfm))) ++ return -EFAULT; ++ ++ if (pfm0) { ++ SET_PFMC0((unsigned int)(pfm.pfm0 & 0xffffffff)); ++ ov0 = pfm.pfm0 >> 32; ++ } ++ if (pfm1) { ++ SET_PFMC1((unsigned int)(pfm.pfm1 & 0xffffffff)); ++ ov1 = pfm.pfm1 >> 32; ++ } ++ if (pfm2) { ++ SET_PFMC2((unsigned int)(pfm.pfm2 & 0xffffffff)); ++ ov2 = pfm.pfm2 >> 32; ++ } ++ ++ write_perfctrl(control); ++ ++ return 0; ++} ++ ++struct op_nds32_model op_model_nds32_ops = { ++ .reg_setup = nds32_reg_setup, ++ .cpu_setup = nds32_cpu_setup, ++ .init = nds32_init, ++ .exit = nds32_exit, ++ .cpu_start = nds32_cpu_start, ++ .cpu_stop = nds32_cpu_stop, ++}; +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag101/cpu-fcs.c linux-3.4.110/arch/nds32/platforms/ag101/cpu-fcs.c +--- linux-3.4.110.orig/arch/nds32/platforms/ag101/cpu-fcs.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag101/cpu-fcs.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,401 @@ ++/* ++ * linux/arch/nds32/platforms/ag101/cpu-fcs.c ++ * ++ * Copyright (C) 2002,2003 Intrinsyc Software ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * History: ++ * 31-Jul-2002 : Initial version [FB] ++ * 29-Jan-2003 : added PXA255 support [FB] ++ * 20-Apr-2003 : ported to v2.5 (Dustin McIntire, Sensoria Corp.) ++ * 18-Jun-2008 : ported to NDS32 architecture ( Roy Lee, Andestech Corp.) ++ * ++ * Note: ++ * This driver may change the memory bus clock rate, but will not do any ++ * platform specific access timing changes... for example if you have flash ++ * memory connected to CS0, you will need to register a platform specific ++ * notifier which will adjust the memory access strobes to maintain a ++ * minimum strobe width. ++ * ++ */ ++#include <linux/module.h> ++#include <linux/cpufreq.h> ++#include <linux/interrupt.h> ++ ++#include <asm/hardware.h> ++#include <asm/localmem.h> ++#include <asm/system.h> ++#include <asm/nds32.h> ++#include <asm/irq_regs.h> ++ ++#define NDS32_FCS_IRQ 8 ++#define AG101_MIN_FREQ 100000 ++#define AG101_MAX_FREQ 400000 ++#define OSC_KHZ 10000 /* 10 MHz AG101 */ ++ ++#define USE_CACHE 0 ++struct ag101_freq_struct { ++ ++ unsigned int khz; /* cpu_clk in khz */ ++ unsigned int pll; /* pll mul */ ++ unsigned int div; /* ahb div */ ++ unsigned int frange; /* pll1 freq range */ ++}; ++ ++struct ag101_freq_struct ag101_run_freqs[] = { ++ ++ /* khz , pll, div, frange pll/cpu/ahb/apb */ ++ {100000, 10, 2, 0}, /* 400/400/050/025 */ ++ {200000, 20, 4, 1}, /* 400/400/050/025 */ ++ {300000, 30, 6, 2}, /* 400/400/050/025 */ ++ {400000, 40, 8, 2}, /* 400/400/050/025 */ ++ {500000, 50, 10, 3}, /* 500/500/050/025 */ ++ {0,} ++}; ++ ++#define NUM_RUN_FREQS ARRAY_SIZE( ag101_run_freqs) ++static struct cpufreq_frequency_table ag101_run_freq_table[NUM_RUN_FREQS + 1]; ++ ++/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */ ++static struct ag101_freq_struct ag101_turbo_freqs[] = { ++ ++ /* khz , pll, div, frange pll/cpu/ahb/apb */ ++ {100000, 10, 2, 0}, /* 400/400/050/025 */ ++ {200000, 20, 4, 1}, /* 400/400/050/025 */ ++ {300000, 30, 6, 2}, /* 400/400/050/025 */ ++ {400000, 40, 8, 2}, /* 400/400/050/025 */ ++ {500000, 50, 10, 3}, /* 500/500/050/025 */ ++ {0,} ++}; ++ ++#define NUM_TURBO_FREQS ARRAY_SIZE( ag101_turbo_freqs) ++static struct cpufreq_frequency_table ag101_turbo_freq_table[NUM_TURBO_FREQS + ++ 1]; ++ ++/* Generic helper function get CPU clocks in kHz */ ++unsigned int ag101_cpufreq_get(unsigned int dummy) ++{ ++ ++ unsigned int mul = (REG32(PMU_FTPMU010_VA_BASE + 0x30) >> 3UL) & 0x01ff; /* pll1 mul */ ++ return OSC_KHZ * mul; ++} ++ ++/* find a valid frequency point */ ++static int ag101_verify_policy(struct cpufreq_policy *policy) ++{ ++ ++ struct cpufreq_frequency_table *ag101_freqs_table; ++ ++ if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { ++ ++ ag101_freqs_table = ag101_run_freq_table; ++ } else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) { ++ ++ ag101_freqs_table = ag101_turbo_freq_table; ++ } else { ++ printk ++ ("CPU PXA: Unknown policy found. Using CPUFREQ_POLICY_PERFORMANCE\n"); ++ ag101_freqs_table = ag101_run_freq_table; ++ } ++ ++ printk("Verified CPU policy: %dKhz min to %dKhz max\n", policy->min, ++ policy->max); ++ ++ return cpufreq_frequency_table_verify(policy, ag101_freqs_table); ++} ++ ++static int cal_edivahbclk(int div) ++{ ++ ++ switch (div) { ++ ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ return --div; ++ case 8: ++ return 8; ++ case 10: ++ return 9; ++ case 12: ++ return 10; ++ case 14: ++ return 11; ++ case 15: ++ return 12; ++ case 18: ++ return 13; ++ case 20: ++ return 14; ++ default: ++ printk("Error: No such CPU/AHB frequency ratio %d", div); ++ } ++ ++ return 9; ++} ++ ++void start_fcs(unsigned int pll, unsigned int frange, unsigned int div) ++{ ++ ++ /* PDLLCR0 */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x30) &= ~0x00003ff8; /* clear PLL1NS and PLL1FRANG fields */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x30) |= (pll << 3); /* set PLL1NS */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x30) |= (frange << 12); /* set PLL1FRANG */ ++ ++ /* PMODE */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x0c) &= ~0x000000ff; /* clear EDIVAHBCLK field */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x0c) |= (div << 4); /* set EDIVAHBCLK [7:4] */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x0c) |= (1UL << 2); /* [2]: FCS */ ++ ++ __asm__ __volatile__("msync all"); ++ __asm__ __volatile__("isb"); ++ __asm__ __volatile__("standby wake_grant"); ++ REG32(PMU_FTPMU010_VA_BASE + 0x30) |= (1UL << 16); /* PDLLCR0 bit[16]==1:disable dll */ ++} ++ ++void end_fcs(void) ++{ ++ ++ /* Leave this function as a place marker. */ ++} ++ ++static int nds32_fcs_handler(int irq, void *dev_id) ++{ ++ ++ REG32(PMU_FTPMU010_VA_BASE + 0x20) = (1UL << 17); /* Clear IntFCS PMSR[17] */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x0c) &= ~(1UL << 2); /* Power Mode Register */ ++ ++ return 1; ++} ++ ++static int ag101_speedstep(int idx) ++{ ++ ++ unsigned int pll, frange, div; ++ unsigned long flags = 0; ++ int irq, saved_irq_mask; ++ void (*do_fcs) (unsigned int pll, unsigned int frange, ++ unsigned int div); ++ ++#if USE_CACHE ++ ++ int i; ++ int line_size = CACHE_LINE_SIZE(ICACHE); ++ unsigned long start = ((unsigned long)start_fcs) & ~(line_size - 1); ++ unsigned long end = ++ (((unsigned long)end_fcs) + line_size) & ~(line_size - 1); ++ ++ printk("&start_fcs(): 0x%08lx, aligned to: 0x%08lx\n", ++ (unsigned long)start_fcs, start); ++ printk("&end_fcs(): 0x%08lx, aligned to: 0x%08lx\n", ++ (unsigned long)end_fcs, end); ++ ++ for (i = start; i <= end; i += CACHE_LINE_SIZE(ICACHE)) ++ __asm__ volatile ("\n\tcctl %0, L1I_VA_FILLCK":: ++ "r" (i):"memory"); ++ ++ do_fcs = start_fcs; ++#else ++ unsigned long buf, aligned_buf, len = PAGE_SIZE; ++ ++ buf = (unsigned long)kmalloc(0x100000 + 1000, GFP_KERNEL); ++ if (!buf) ++ printk("Error: kmalloc( base) failed\n"); ++ ++ aligned_buf = (buf + 0x100000 - 1) & 0xFFF00000; ++ ++ if (sys_lmmap(LM_ILM, aligned_buf, aligned_buf + 0x1000, 0, NULL)) { ++ printk("Error: lmmap failed, can't scale frequency.\n"); ++#ifdef CONFIG_CPU_FREQ_DEBUG ++ WARN_ON(1); ++#endif ++ return 0; ++ } ++ ++ if (((GET_ILMB() & ILMB_mskILMSZ) >> ILMB_offILMSZ) == 9) ++ len = 0x400; ++ else if (((GET_ILMB() & ILMB_mskILMSZ) >> ILMB_offILMSZ) == 10) ++ len = 0x800; ++ memcpy((unsigned char *)aligned_buf, (unsigned char *)start_fcs, len); ++ ++ do_fcs = (void *)aligned_buf; ++#endif ++ pll = ag101_run_freqs[idx].pll; ++ div = cal_edivahbclk(ag101_run_freqs[idx].div); ++ frange = ag101_run_freqs[idx].frange; ++ ++ irq = ++ request_irq(NDS32_FCS_IRQ, nds32_fcs_handler, ++ IRQF_DISABLED | IRQF_TRIGGER_FALLING, ++ "NDS32 Frequency Change Sequence", ++ (void *)ag101_run_freqs); ++ if (irq < 0) ++ printk(KERN_ERR "Error: unable to request FCS IRQ%d\n", ++ NDS32_FCS_IRQ); ++ ++ local_irq_save(flags); ++ ++ saved_irq_mask = REG32(INTC_FTINTC010_VA_BASE + 0x04); ++ REG32(INTC_FTINTC010_VA_BASE + 0x04) = (1UL << NDS32_FCS_IRQ); ++ ++ do_fcs(pll, frange, div); ++ ++ REG32(INTC_FTINTC010_VA_BASE + 0x04) = saved_irq_mask; ++ ++ local_irq_restore(flags); ++ free_irq(NDS32_FCS_IRQ, ag101_run_freqs); ++ ++#if USE_CACHE ++ for (i = start; i <= end; i += CACHE_LINE_SIZE(ICACHE)) ++ __asm__ volatile ("\n\tcctl %0, L1I_VA_ULCK"::"r" (i):"memory"); ++#else ++ if (sys_lmunmap(aligned_buf, 0)) ++ printk("Error: lmunmap failed\n"); ++ ++ kfree((void *)buf); ++#endif ++ return 1; ++} ++ ++static int ag101_set_target(struct cpufreq_policy *policy, ++ unsigned int target_freq, unsigned int relation) ++{ ++ ++ unsigned int idx; ++ struct cpufreq_frequency_table *ag101_freqs_table; ++ struct ag101_freq_struct *ag101_freq_settings; ++ struct cpufreq_freqs freqs; ++ ++ /* Get the current policy */ ++ if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { ++ ++ ag101_freq_settings = ag101_run_freqs; ++ ag101_freqs_table = ag101_run_freq_table; ++ } else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) { ++ ++ ag101_freq_settings = ag101_turbo_freqs; ++ ag101_freqs_table = ag101_turbo_freq_table; ++ } else { ++ printk ++ ("Unknown FCS policy found. Using CPUFREQ_POLICY_PERFORMANCE\n"); ++ ag101_freq_settings = ag101_run_freqs; ++ ag101_freqs_table = ag101_run_freq_table; ++ } ++ ++ /* Lookup the next frequency */ ++ if (cpufreq_frequency_table_target ++ (policy, ag101_freqs_table, target_freq, relation, &idx)) ++ return -EINVAL; ++ ++ freqs.old = policy->cur; ++ freqs.new = ag101_freq_settings[idx].khz; ++ freqs.cpu = policy->cpu; ++ ++ /* ++ * Tell everyone what we're about to do... ++ * you should add a notify client with any platform specific ++ * Vcc changing capability ++ */ ++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ ++ if (freqs.new != freqs.old) { ++ if (!ag101_speedstep(idx)) ++ return -ENODEV; ++ } ++ ++ /* ++ * Tell everyone what we've just done... ++ * you should add a notify client with any platform specific ++ * SDRAM refresh timer adjustments ++ */ ++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++ ++ return 0; ++} ++ ++static int ag101_cpufreq_init(struct cpufreq_policy *policy) ++{ ++ ++ int i; ++ /* set default policy and cpuinfo */ ++ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; ++ policy->policy = CPUFREQ_POLICY_PERFORMANCE; ++ policy->cpuinfo.max_freq = AG101_MAX_FREQ; ++ policy->cpuinfo.min_freq = AG101_MIN_FREQ; ++ policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */ ++ policy->cur = ag101_cpufreq_get(0); /* current freq */ ++ policy->min = policy->max = policy->cur; ++ ++ /* Generate the run cpufreq_frequency_table struct */ ++ for (i = 0; i < NUM_RUN_FREQS; i++) { ++ ++ ag101_run_freq_table[i].frequency = ag101_run_freqs[i].khz; ++ ag101_run_freq_table[i].index = i; ++ } ++ ++ ag101_run_freq_table[i].frequency = CPUFREQ_TABLE_END; ++ ++ /* Generate the turbo cpufreq_frequency_table struct */ ++ for (i = 0; i < NUM_TURBO_FREQS; i++) { ++ ++ ag101_turbo_freq_table[i].frequency = ag101_turbo_freqs[i].khz; ++ ag101_turbo_freq_table[i].index = i; ++ } ++ ++ ag101_turbo_freq_table[i].frequency = CPUFREQ_TABLE_END; ++ ++ printk("CPU frequency change support initialized\n"); ++ ++ return 0; ++} ++ ++static struct cpufreq_driver ag101_cpufreq_driver = { ++ ++ .verify = ag101_verify_policy, ++ .target = ag101_set_target, ++ .init = ag101_cpufreq_init, ++ .get = ag101_cpufreq_get, ++ .name = "AG101", ++}; ++ ++static int __init ag101_cpu_init(void) ++{ ++ ++ if (CPU_IS_N1213_43U1HA0() || CPU_IS_N1213_43U1HB0()) { ++ ++ /* Clear IntFS, IntFCS and irq8 */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x20) = (1UL << 16); ++ return cpufreq_register_driver(&ag101_cpufreq_driver); ++ } else ++ return -ENODEV; ++} ++ ++static void __exit ag101_cpu_exit(void) ++{ ++ ++ if (CPU_IS_N1213_43U1HA0() || CPU_IS_N1213_43U1HB0()) ++ cpufreq_unregister_driver(&ag101_cpufreq_driver); ++} ++ ++MODULE_AUTHOR("Andes Technology Corporation"); ++MODULE_DESCRIPTION("CPU frequency changing driver for the AG101 architecture"); ++MODULE_LICENSE("GPL"); ++module_init(ag101_cpu_init); ++module_exit(ag101_cpu_exit); +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag101/devices.c linux-3.4.110/arch/nds32/platforms/ag101/devices.c +--- linux-3.4.110.orig/arch/nds32/platforms/ag101/devices.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag101/devices.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,94 @@ ++#include <linux/serial_8250.h> ++#include <asm/mach-types.h> ++#include <asm/sizes.h> ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/spec.h> ++#include <asm/intc.h> ++#include <asm/timer.h> ++ ++const struct map_desc platform_io_desc[] __initdata = { ++ {UART0_VA_BASE, UART0_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {UART1_VA_BASE, UART1_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {INTC_FTINTC010_0_VA_BASE, INTC_FTINTC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {TIMER_FTTMR010_0_VA_BASE, TIMER_FTTMR010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {SSP_FTSSP010_0_VA_BASE, SSP_FTSSP010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {PMU_FTPMU010_0_VA_BASE, PMU_FTPMU010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {MAC_FTMAC100_0_VA_BASE, MAC_FTMAC100_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {SDC_FTSDC010_0_VA_BASE, SDC_FTSDC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {RTC_FTRTC010_0_VA_BASE, RTC_FTRTC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {WDT_FTWDT010_0_VA_BASE, WDT_FTWDT010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {GPIO_FTGPIO010_0_VA_BASE, GPIO_FTGPIO010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {CFC_FTCFC010_0_VA_BASE, CFC_FTCFC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {LCD_FTLCDC100_0_VA_BASE, LCD_FTLCDC100_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {I2C_FTI2C010_0_VA_BASE, I2C_FTI2C010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {DMAC_FTDMAC020_0_VA_BASE, DMAC_FTDMAC020_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {APBBRG_FTAPBBRG020S_0_VA_BASE, APBBRG_FTAPBBRG020S_0_PA_BASE, ++ PAGE_SIZE, MT_DEVICE_NCB}, ++ {KMI_FTKBC010_0_VA_BASE, KMI_FTKBC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCNB}, ++ {KMI_FTKBC010_1_VA_BASE, KMI_FTKBC010_1_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCNB}, ++ {USB_FUSB220_0_VA_BASE, USB_FUSB220_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCNB}, ++ {PCIIO_0_VA_BASE, PCIIO_0_PA_BASE, 0x000FF000, MT_DEVICE_NCB}, ++ {PCIC_FTPCI100_0_VA_BASE, PCIC_FTPCI100_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {LED_VA_BASE, LED_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {SDMC_FTSDMC021_VA_BASE, SDMC_FTSDMC021_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {L2CC_VA_BASE, L2CC_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB} ++}; ++ ++static void __init platform_map_io(void) ++{ ++ iotable_init((struct map_desc *)platform_io_desc, ++ ARRAY_SIZE(platform_io_desc)); ++} ++ ++static struct uart_port uart0 = { ++ .membase = (void __iomem *)UART0_VA_BASE, ++ .irq = UART0_IRQ, ++ .uartclk = CONFIG_UART_CLK, ++ .regshift = 2, ++ .iotype = UPIO_MEM, ++ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, ++ .line = 0, ++ .mapbase = UART0_PA_BASE, ++}; ++ ++static struct uart_port uart1 = { ++ .membase = (void __iomem *)UART1_VA_BASE, ++ .irq = UART1_IRQ, ++ .uartclk = CONFIG_UART_CLK, ++ .regshift = 2, ++ .iotype = UPIO_MEM, ++ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, ++ .line = 1, ++ .mapbase = UART1_PA_BASE, ++}; ++ ++void ag101_calc_ahb_clk(void); ++static void __init soc_init(void) ++{ ++ ag101_calc_ahb_clk(); ++ early_serial_setup(&uart0); ++ early_serial_setup(&uart1); ++} ++ ++MACHINE_START(FARADAY, PLATFORM_NAME) ++ .param_offset = BOOT_PARAMETER_PA_BASE,.map_io = platform_map_io,.init_irq = platform_init_irq,.timer = &platform_timer, /* defined in timer.c */ ++ .init_machine = soc_init, MACHINE_END +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag101/fia320.c linux-3.4.110/arch/nds32/platforms/ag101/fia320.c +--- linux-3.4.110.orig/arch/nds32/platforms/ag101/fia320.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag101/fia320.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,103 @@ ++/* ++ * linux/arch/nds32/platforms/ag101/fia320.c ++ * ++ * Faraday A320D Platform Dependent Functions ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ChangeLog ++ * ++ * Luke Lee 09/26/2005 Created ++ * Peter Liao 09/29/2005 Port dynamically getting AHB clock ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/pm.h> ++#include <linux/sched.h> ++#include <linux/irq.h> ++ ++#include <asm/hardware.h> ++#include <asm/spec.h> ++ ++#ifdef CONFIG_AUTO_SYS_CLK ++#include <nds32_intrinsic.h> ++#define AG101B0 (0x0c020003) ++ ++/* ++ * Table for ahb divisor, PMODE[07:04] ++ */ ++static const int ahb_div[16] = { ++ 1, 2, 3, 4, 5, 6, 3, 5, ++ 8, 10, 12, 14, 15, 18, 20, -1 ++}; ++ ++/* ag101_get_ahb_clk() ++ * ++ * return AHB clock in Hz. ++ */ ++static int ahbclk; ++void ag101_calc_ahb_clk(void) ++{ ++ /* ++ * FIXME: We should not put AG101 term in here, Harry@Oct.23.2007 ++ */ ++ const unsigned int osc = 10; // OSC in MHz ++ unsigned int mul, div, cpu, pll; ++ unsigned int ahb = 0; // ahb clk in Hz ++ unsigned int cpu_ver; ++ ++ mul = (REG32(PMU_FTPMU010_0_VA_BASE + 0x30) >> 3) & 0x01ff; // pll1 mul ++ div = (REG32(PMU_FTPMU010_0_VA_BASE + 0x4) >> 8) & 0x000f; // pll1 div ++ ahb = (REG32(PMU_FTPMU010_0_VA_BASE + 0x4) >> 4) & 0x000f; // ahb div ++ div += 1; ++ ++ pll = (osc * mul / div); // depend on OSC. ++ ++ //AG101B0 PLL divider fix ++ cpu_ver = __nds32__mfsr(NDS32_SR_CPU_VER); ++ if (AG101B0 == cpu_ver) ++ pll >>= 1; ++ ++ if (-1 != ahb_div[ahb]) { ++ if ((ahb == 6) || (ahb == 7)) // special cases for 3:2 & 5:2 ++ cpu = pll >> 1; // divide by 2 ++ else ++ cpu = pll; ++ ++ ahb = pll / ahb_div[ahb]; // become ahb clk in MHz. ++ ++ printk("AG101 auto-detected AHB clock: CPU/AHB=%uMHz/%uMHz\n", ++ cpu, ahb); ++ ahb *= 1000000; // become ahb clk in Hz. ++ ahbclk = (int)ahb; ++ } else { ++ printk("Unknown AHB divisor:0x%x\n", ahb); ++ ahbclk = 0; ++ } ++ ++ ahbclk = (int)ahb; ++} ++ ++int ag101_get_ahb_clk(void) ++{ ++ return ahbclk; ++} ++ ++EXPORT_SYMBOL(ag101_get_ahb_clk); ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag101/freq-scaling.c linux-3.4.110/arch/nds32/platforms/ag101/freq-scaling.c +--- linux-3.4.110.orig/arch/nds32/platforms/ag101/freq-scaling.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag101/freq-scaling.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,367 @@ ++/* ++ * linux/arch/nds32/platforms/ag101/cpu-fcs.c ++ * ++ * Copyright (C) 2002,2003 Intrinsyc Software ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * History: ++ * 31-Jul-2002 : Initial version [FB] ++ * 29-Jan-2003 : added PXA255 support [FB] ++ * 20-Apr-2003 : ported to v2.5 (Dustin McIntire, Sensoria Corp.) ++ * 18-Jun-2008 : ported to NDS32 architecture ( Roy Lee, Andestech Corp.) ++ * ++ * Note: ++ * This driver may change the memory bus clock rate, but will not do any ++ * platform specific access timing changes... for example if you have flash ++ * memory connected to CS0, you will need to register a platform specific ++ * notifier which will adjust the memory access strobes to maintain a ++ * minimum strobe width. ++ * ++ */ ++#include <linux/module.h> ++#include <linux/cpufreq.h> ++#include <linux/interrupt.h> ++ ++#include <asm/hardware.h> ++#include <asm/localmem.h> ++#include <asm/system.h> ++#include <asm/nds32.h> ++#include <asm/irq_regs.h> ++ ++#define NDS32_FCS_IRQ 8 ++#define AG101_MIN_FREQ 70000 ++#define AG101_MAX_FREQ 420000 ++#define OSC_KHZ 10000 /* 10 MHz AG101 */ ++ ++#define USE_CACHE 0 ++struct ag101_freq_struct { ++ ++ unsigned int khz; /* cpu_clk in khz */ ++ unsigned int sf; /* scaling factor */ ++ unsigned int cr; /* clock ratio */ ++}; ++ ++struct ag101_freq_struct ag101_run_freqs[] = { ++ ++ /* khz , sf, cr pll/cpu/ahb/apb */ ++ {AG101_MAX_FREQ / 6, 6, 1}, /* 420/070/070/035 */ ++ {AG101_MAX_FREQ / 1, 1, 6}, /* 420/420/070/035 */ ++ {0} ++}; ++ ++#define NUM_RUN_FREQS ARRAY_SIZE( ag101_run_freqs) ++static struct cpufreq_frequency_table ag101_run_freq_table[NUM_RUN_FREQS + 1]; ++ ++/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */ ++static struct ag101_freq_struct ag101_turbo_freqs[] = { ++ ++ /* khz , sf, cr pll/cpu/ahb/apb */ ++ {AG101_MAX_FREQ / 6, 6, 1}, /* 420/070/070/035 */ ++ {AG101_MAX_FREQ / 1, 1, 6}, /* 420/420/070/035 */ ++ {0} ++}; ++ ++#define NUM_TURBO_FREQS ARRAY_SIZE( ag101_turbo_freqs) ++static struct cpufreq_frequency_table ag101_turbo_freq_table[NUM_TURBO_FREQS + ++ 1]; ++ ++/* Generic helper function get CPU clocks in kHz */ ++unsigned int ag101_cpufreq_get(unsigned int dummy) ++{ ++ ++ unsigned int pll = (REG32(PMU_FTPMU010_VA_BASE + 0x30) >> 3UL) & 0x01ff; /* pll */ ++ unsigned int sf = (REG32(PMU_FTPMU010_VA_BASE + 0x0c) >> 8UL) & 0x0f; /* scaling factor */ ++ ++ return OSC_KHZ * pll / (sf + 1); ++} ++ ++/* find a valid frequency point */ ++static int ag101_verify_policy(struct cpufreq_policy *policy) ++{ ++ ++ struct cpufreq_frequency_table *ag101_freqs_table; ++ ++ if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { ++ ++ ag101_freqs_table = ag101_run_freq_table; ++ } else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) { ++ ++ ag101_freqs_table = ag101_turbo_freq_table; ++ } else { ++ printk ++ ("CPU PXA: Unknown policy found. Using CPUFREQ_POLICY_PERFORMANCE\n"); ++ ag101_freqs_table = ag101_run_freq_table; ++ } ++ ++ printk("Verified CPU policy: %dKhz min to %dKhz max\n", policy->min, ++ policy->max); ++ ++ return cpufreq_frequency_table_verify(policy, ag101_freqs_table); ++} ++ ++void start_fcs(unsigned int sf, unsigned cr) ++{ ++ ++ /* set EFSF in PMODE [11:8] */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x0c) &= ~(0xfUL << 8); ++ REG32(PMU_FTPMU010_VA_BASE + 0x0c) |= (sf << 8); ++ ++ /* set EDIVAHBCLK [7:4] */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x0c) &= ~(0xffUL << 0); ++ REG32(PMU_FTPMU010_VA_BASE + 0x0c) |= (cr << 4); ++ ++ /* PMR[1]: scaling mode */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x0c) |= (1UL << 1); ++ ++ __asm__ __volatile__("msync all"); ++ __asm__ __volatile__("isb"); ++ __asm__ __volatile__("standby wake_grant"); ++ // REG32( PMU_FTPMU010_VA_BASE + 0x30) |= ( 1UL << 16); /* PDLLCR0 bit[16]==1:disable dll */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x0c) &= ~(1UL << 1); /* Power Mode Register */ ++} ++ ++void end_fcs(void) ++{ ++ ++ /* Leave this function as a place marker. */ ++} ++ ++static int cal_edivahbclk(int div) ++{ ++ ++ switch (div) { ++ ++ case 1: ++ case 2: ++ case 3: ++ case 4: ++ case 5: ++ case 6: ++ return --div; ++ case 8: ++ return 8; ++ case 10: ++ return 9; ++ case 12: ++ return 10; ++ case 14: ++ return 11; ++ case 15: ++ return 12; ++ case 18: ++ return 13; ++ case 20: ++ return 14; ++ default: ++ printk("Error: No such CPU/AHB frequency ratio %d", div); ++ } ++ ++ return 9; ++} ++ ++static int ag101_speedstep(int idx) ++{ ++ ++ unsigned int sf, cr; ++ unsigned long flags = 0; ++ void (*do_fcs) (unsigned int efsf, unsigned int edivhbaclk); ++ ++#if USE_CACHE ++ ++ int i; ++ int line_size = CACHE_LINE_SIZE(ICACHE); ++ unsigned long start = ((unsigned long)start_fcs) & ~(line_size - 1); ++ unsigned long end = ++ (((unsigned long)end_fcs) + line_size) & ~(line_size - 1); ++ ++ printk("&start_fcs(): 0x%08lx, aligned to: 0x%08lx\n", ++ (unsigned long)start_fcs, start); ++ printk("&end_fcs(): 0x%08lx, aligned to: 0x%08lx\n", ++ (unsigned long)end_fcs, end); ++ ++ for (i = start; i <= end; i += CACHE_LINE_SIZE(ICACHE)) ++ __asm__ volatile ("\n\tcctl %0, L1I_VA_FILLCK":: ++ "r" (i):"memory"); ++ ++ do_fcs = start_fcs; ++#else ++ unsigned long buf, aligned_buf, len = PAGE_SIZE; ++ ++ buf = (unsigned long)kmalloc(0x100000 + 1000, GFP_KERNEL); ++ if (!buf) ++ printk("Error: kmalloc( base) failed\n"); ++ ++ aligned_buf = (buf + 0x100000 - 1) & 0xFFF00000; ++ ++ if (sys_lmmap(LM_ILM, aligned_buf, aligned_buf + 0x1000, 0, NULL)) { ++ printk("Error: lmmap failed, can't scale frequency.\n"); ++#ifdef CONFIG_CPU_FREQ_DEBUG ++ WARN_ON(1); ++#endif ++ return 0; ++ } ++ ++ if (((GET_ILMB() & ILMB_mskILMSZ) >> ILMB_offILMSZ) == 9) ++ len = 0x400; ++ else if (((GET_ILMB() & ILMB_mskILMSZ) >> ILMB_offILMSZ) == 10) ++ len = 0x800; ++ memcpy((unsigned char *)aligned_buf, (unsigned char *)start_fcs, len); ++ ++ do_fcs = (void *)aligned_buf; ++#endif ++ sf = ag101_run_freqs[idx].sf - 1; ++ cr = cal_edivahbclk(ag101_run_freqs[idx].cr); ++ ++ local_irq_save(flags); ++ do_fcs(sf, cr); ++ local_irq_restore(flags); ++ ++#if USE_CACHE ++ for (i = start; i <= end; i += CACHE_LINE_SIZE(ICACHE)) ++ __asm__ volatile ("\n\tcctl %0, L1I_VA_ULCK"::"r" (i):"memory"); ++#else ++ if (sys_lmunmap(aligned_buf, 0)) ++ printk("Error: lmunmap failed\n"); ++ ++ kfree((void *)buf); ++#endif ++ return 1; ++} ++ ++static int ag101_set_target(struct cpufreq_policy *policy, ++ unsigned int target_freq, unsigned int relation) ++{ ++ ++ unsigned int idx; ++ struct cpufreq_frequency_table *ag101_freqs_table; ++ struct ag101_freq_struct *ag101_freq_settings; ++ struct cpufreq_freqs freqs; ++ ++ /* Get the current policy */ ++ if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) { ++ ++ ag101_freq_settings = ag101_run_freqs; ++ ag101_freqs_table = ag101_run_freq_table; ++ } else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) { ++ ++ ag101_freq_settings = ag101_turbo_freqs; ++ ag101_freqs_table = ag101_turbo_freq_table; ++ } else { ++ printk ++ ("Unknown FCS policy found. Using CPUFREQ_POLICY_PERFORMANCE\n"); ++ ag101_freq_settings = ag101_run_freqs; ++ ag101_freqs_table = ag101_run_freq_table; ++ } ++ ++ /* Lookup the next frequency */ ++ if (cpufreq_frequency_table_target ++ (policy, ag101_freqs_table, target_freq, relation, &idx)) ++ return -EINVAL; ++ ++ freqs.old = policy->cur; ++ freqs.new = ag101_freq_settings[idx].khz; ++ freqs.cpu = policy->cpu; ++ ++ /* ++ * Tell everyone what we're about to do... ++ * you should add a notify client with any platform specific ++ * Vcc changing capability ++ */ ++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ ++ if (freqs.new != freqs.old) { ++ ++ if (!ag101_speedstep(idx)) ++ return -ENODEV; ++ } ++ ++ /* ++ * Tell everyone what we've just done... ++ * you should add a notify client with any platform specific ++ * SDRAM refresh timer adjustments ++ */ ++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++ ++ return 0; ++} ++ ++static int ag101_cpufreq_init(struct cpufreq_policy *policy) ++{ ++ ++ int i; ++ /* set default policy and cpuinfo */ ++ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; ++ policy->policy = CPUFREQ_POLICY_PERFORMANCE; ++ policy->cpuinfo.max_freq = AG101_MAX_FREQ; ++ policy->cpuinfo.min_freq = AG101_MIN_FREQ; ++ policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */ ++ policy->cur = ag101_cpufreq_get(0); /* current freq */ ++ policy->min = policy->max = policy->cur; ++ ++ /* Generate the run cpufreq_frequency_table struct */ ++ for (i = 0; i < NUM_RUN_FREQS; i++) { ++ ++ ag101_run_freq_table[i].frequency = ag101_run_freqs[i].khz; ++ ag101_run_freq_table[i].index = i; ++ } ++ ++ ag101_run_freq_table[i].frequency = CPUFREQ_TABLE_END; ++ ++ /* Generate the turbo cpufreq_frequency_table struct */ ++ for (i = 0; i < NUM_TURBO_FREQS; i++) { ++ ++ ag101_turbo_freq_table[i].frequency = ag101_turbo_freqs[i].khz; ++ ag101_turbo_freq_table[i].index = i; ++ } ++ ++ ag101_turbo_freq_table[i].frequency = CPUFREQ_TABLE_END; ++ ++ printk("CPU frequency change support initialized\n"); ++ ++ return 0; ++} ++ ++static struct cpufreq_driver ag101_cpufreq_driver = { ++ ++ .verify = ag101_verify_policy, ++ .target = ag101_set_target, ++ .init = ag101_cpufreq_init, ++ .get = ag101_cpufreq_get, ++ .name = "AG101", ++}; ++ ++static int __init ag101_cpu_init(void) ++{ ++ ++ if (CPU_IS_N1213_43U1HA0() || CPU_IS_N1213_43U1HB0()) ++ return cpufreq_register_driver(&ag101_cpufreq_driver); ++ else ++ return -ENODEV; ++} ++ ++static void __exit ag101_cpu_exit(void) ++{ ++ ++ if (CPU_IS_N1213_43U1HA0() || CPU_IS_N1213_43U1HB0()) ++ cpufreq_unregister_driver(&ag101_cpufreq_driver); ++} ++ ++MODULE_AUTHOR("Andes Technology Corporation"); ++MODULE_DESCRIPTION("CPU frequency changing driver for the AG101 architecture"); ++MODULE_LICENSE("GPL"); ++module_init(ag101_cpu_init); ++module_exit(ag101_cpu_exit); +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag101/Kconfig linux-3.4.110/arch/nds32/platforms/ag101/Kconfig +--- linux-3.4.110.orig/arch/nds32/platforms/ag101/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag101/Kconfig 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,9 @@ ++menu "AG101 Platform Options" ++ ++config AUTO_SYS_CLK ++ bool "Automatic AHB Clock Detection" ++ default y ++ help ++ Automatic detection of AHB clock ++ ++endmenu +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag101/Makefile linux-3.4.110/arch/nds32/platforms/ag101/Makefile +--- linux-3.4.110.orig/arch/nds32/platforms/ag101/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag101/Makefile 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,5 @@ ++obj-y = devices.o ++obj-$(CONFIG_AUTO_SYS_CLK) += fia320.o ++obj-$(CONFIG_PM) += pm.o sleep.o ++obj-$(CONFIG_AG101_CPU_FREQ_FCS) += cpu-fcs.o ++obj-$(CONFIG_AG101_CPU_FREQ_SCALING_MODE) += freq-scaling.o +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag101/pm.c linux-3.4.110/arch/nds32/platforms/ag101/pm.c +--- linux-3.4.110.orig/arch/nds32/platforms/ag101/pm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag101/pm.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,190 @@ ++/* ++ * AG101 Power Management Routines ++ * ++ * Copyright (c) 2007 Harry Pan <harry@andestech.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License. ++ * ++ * Abstract: ++ * ++ * This program is for AG101 power management routines. ++ * It is initail referred from 2.6.11 SA1100 PM driver. ++ * ++ * Revision History: ++ * ++ * Jul.13.2007 Initial code by Harry. ++ */ ++#include <linux/init.h> ++#include <linux/suspend.h> ++#include <linux/errno.h> ++#include <linux/time.h> ++#include <linux/delay.h> ++ ++#include <asm/hardware.h> ++#include <asm/memory.h> ++#include <asm/system.h> ++#include <asm/mach/time.h> ++#include <asm/cacheflush.h> ++ ++extern void ag101_cpu_sleep(void); ++extern void ag101_cpu_resume(void); ++extern void ag101_cpu_resume2(void); ++ ++#include <asm/timer.h> ++/* ++ * AG101 PMU sleep mode handler. ++ */ ++void ag101_pmu_sleep(void) ++{ ++ int i; ++ static int irq_saves[3]; ++ ++ irq_saves[0] = REG32(INTC_FTINTC010_VA_BASE + 0x4); ++ irq_saves[1] = REG32(INTC_FTINTC010_VA_BASE + 0xc); ++ irq_saves[2] = REG32(INTC_FTINTC010_VA_BASE + 0x10); ++ ++ /* save SDRAM settings */ ++ for (i = 0; i < 0x30; i += 4) ++ REG32(PMU_FTPMU010_VA_BASE + 0x50 + i) = REG32(SDMC_FTSDMC021_VA_BASE + i); //SDRAMC ++ ++ /* set resume return address */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x88) = ++ virt_to_phys(ag101_cpu_resume) | 0x10000000; ++ REG32(PMU_FTPMU010_VA_BASE + 0x8c) = (u32) ag101_cpu_resume2; ++ REG32(PMU_FTPMU010_VA_BASE + 0x80) = GET_L1_PPTB(); ++ ++ /* setup wakeup sources */ ++ REG32(PMU_FTPMU010_VA_BASE + 0x14) |= -1; ++ REG32(PMU_FTPMU010_VA_BASE + 0x10) |= 0x1fff; ++ ++ cpu_dcache_wbinval_all(); ++ cpu_icache_inval_all(); ++ SET_CACHE_CTL(GET_CACHE_CTL() & ~CACHE_CTL_mskDC_EN); ++ ag101_cpu_sleep(); ++ ++#ifndef CONFIG_ANDES_PAGE_SIZE_8KB ++ ++ if (CPU_IS_N1213_43U1HA0()) { ++ int tmp = 0; ++ /* Downsize cache to bypass cache aliasing issue */ ++ ++ if ((CACHE_SET(ICACHE) * CACHE_LINE_SIZE(ICACHE)) > 4096) ++ tmp = 0x02 << SDZ_CTL_offICDZ; ++ ++ if ((CACHE_SET(DCACHE) * CACHE_LINE_SIZE(DCACHE)) > 4096) ++ tmp |= 0x02 << SDZ_CTL_offDCDZ; ++ ++ SET_SDZ_CTL(tmp); ++ ISB(); ++ } ++#endif ++ ++ SET_CACHE_CTL(GET_CACHE_CTL() | CACHE_CTL_mskDC_EN); ++ REG32(INTC_FTINTC010_VA_BASE + 0x4) = irq_saves[0]; ++ REG32(INTC_FTINTC010_VA_BASE + 0xc) = irq_saves[1]; ++ REG32(INTC_FTINTC010_VA_BASE + 0x10) = irq_saves[2]; ++} ++ ++static int ag101_pm_valid(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_ON: ++ case PM_SUSPEND_STANDBY: ++ case PM_SUSPEND_MEM: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++ ++static int ag101_pm_begin(suspend_state_t state) ++{ ++ /* TBD if we need it */ ++ return 0; ++} ++ ++static unsigned long irq_save; ++static inline void setup_wakeup_event(void) ++{ ++ REG32(GPIO_FTGPIO010_VA_BASE + 0x20) = 1; ++ irq_save = REG32(INTC_FTINTC010_VA_BASE + 0x4); ++ REG32(INTC_FTINTC010_VA_BASE + 0x4) &= ~(1 << 19); ++ REG32(INTC_FTINTC010_VA_BASE + 0x4) |= 1 << 13; ++} ++ ++static inline void remove_wakeup_event(void) ++{ ++ REG32(GPIO_FTGPIO010_VA_BASE + 0x30) = 1; ++ REG32(GPIO_FTGPIO010_VA_BASE + 0x20) = 0; ++ REG32(INTC_FTINTC010_VA_BASE + 0x4) = irq_save; ++} ++ ++static inline void cpu_standby(void) ++{ ++ asm __volatile__("standby no_wake_grant"); ++} ++ ++static int ag101_pm_enter(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_STANDBY: ++ setup_wakeup_event(); ++ cpu_standby(); ++ remove_wakeup_event(); ++ return 0; ++ case PM_SUSPEND_MEM: ++ ag101_pmu_sleep(); ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++/* ++ * Called after processes are frozen, but before we shutdown devices. ++ */ ++static int ag101_pm_prepare(void) ++{ ++ /* TBD if we need it */ ++ return 0; ++} ++ ++/* ++ * Called after devices are wakeuped, but before processes are thawed. ++ */ ++static void ag101_pm_finish(void) ++{ ++ /* TBD if we need it */ ++} ++ ++static void ag101_pm_end(void) ++{ ++ /* TBD if we need it */ ++} ++ ++/* ++ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk. ++ */ ++static struct platform_suspend_ops ag101_pm_ops = { ++ .valid = ag101_pm_valid, ++ .begin = ag101_pm_begin, ++ .prepare = ag101_pm_prepare, ++ .enter = ag101_pm_enter, ++ .finish = ag101_pm_finish, ++ .end = ag101_pm_end, ++}; ++ ++static int __init ag101_pm_init(void) ++{ ++ printk("PM driver init\n"); ++ suspend_set_ops(&ag101_pm_ops); ++ REG32(GPIO_FTGPIO010_VA_BASE + 0x30) = 1; ++ REG32(INTC_FTINTC010_VA_BASE + 0x0c) &= ~(1 << 13); ++ REG32(INTC_FTINTC010_VA_BASE + 0x10) &= ~(1 << 13); ++ ++ return 0; ++} ++ ++late_initcall(ag101_pm_init); +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag101/sleep.S linux-3.4.110/arch/nds32/platforms/ag101/sleep.S +--- linux-3.4.110.orig/arch/nds32/platforms/ag101/sleep.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag101/sleep.S 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,118 @@ ++/* ++ * AG101 Assembler Sleep/WakeUp Management Routines ++ * ++ * Copyright (c) 2007 Harry Pan <harry@andestech.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License. ++ * ++ * Abstract: ++ * ++ * This program is for AG101 suspend/wakeup. ++ * ++ * Revision History: ++ * ++ * Jul.13.2007 Initial code by Harry. ++ */ ++#include <linux/linkage.h> ++#include <asm/assembler.h> ++#include <asm/hardware.h> ++#include <asm/spec.h> ++ ++ .text ++ ++/* ag101_cpu_suspend() ++ * ++ * Causes AG101 to enter sleep state ++ */ ++ ++ENTRY(ag101_cpu_sleep) ++ pushm $r0, $r30 ++ mfusr $r0, $d0.lo ! $d0 lo byte ++ mfusr $r1, $d0.hi ! $d0 hi byte ++ mfusr $r2, $d1.lo ! $d1 lo byte ++ mfusr $r3, $d1.hi ! $d1 hi byte ++ mfsr $r4, $mr0 ++ mfsr $r5, $mr1 ++ mfsr $r6, $mr4 ++ mfsr $r7, $mr6 ++ mfsr $r8, $mr7 ++ mfsr $r9, $mr8 ++ mfsr $r10, $ir0 ++ mfsr $r11, $ir1 ++ mfsr $r12, $ir2 ++ mfsr $r13, $ir3 ++ mfsr $r14, $ir9 ++ mfsr $r15, $ir10 ++ mfsr $r16, $ir12 ++ mfsr $r17, $ir13 ++ mfsr $r18, $ir14 ++ mfsr $r19, $ir15 ++ pushm $r0, $r19 ++ ++ sethi $r0, hi20(PMU_FTPMU010_0_VA_BASE + 0x84) ++ ori $r2, $r0, lo12(PMU_FTPMU010_0_VA_BASE + 0x84) ++ swi $r31, [$r2] ++ ++ lwi $r2, [$r0+#0x0c] ! sleep mode ++ ori $r2, $r2, #1 ++ swi $r2, [$r0+#0x0c] ! sleep mode ++ standby wake_grant ++1: ++ b 1b ! loop waiting for sleep ++ ++/* ag101_cpu_resume() ++ * ++ * Entry point from boot code back to kernel. ++ * ++ */ ++ ++ENTRY(ag101_cpu_resume) ++ mfsr $r2, $mr0 ++ ori $r2, $r2, #0x6 ++#ifdef CONFIG_ANDES_PAGE_SIZE_8KB ++ ori $r2, $r2, #0x1 ++#endif ++ mtsr $r2, $mr0 ++ ++ sethi $r2, hi20(PMU_FTPMU010_0_PA_BASE + 0x80) ++ ori $r2, $r2, lo12(PMU_FTPMU010_0_PA_BASE + 0x80) ++ lwi $r3, [$r2] ++ lwi $r4, [$r2 + 0xc] ++ mtsr $r3, $mr1 ++ ++ mfsr $r0, $mr8 ++ ori $r0, $r0, #0x1 ++ mtsr $r0, $mr8 ++ ++ sethi $r2, hi20(AHB_ATFAHBC020S_0_PA_BASE + 0x88) ++ ori $r2, $r2, lo12(AHB_ATFAHBC020S_0_PA_BASE + 0x88) ++ movi $r3, #0x1 ++ swi $r3, [$r2] ++ ++ jral.ton $r4, $r4 ++ ++ENTRY(ag101_cpu_resume2) ++ popm $r0, $r19 ++ mtusr $r0, $d0.lo ! $d0 lo byte ++ mtusr $r1, $d0.hi ! $d0 hi byte ++ mtusr $r2, $d1.lo ! $d1 lo byte ++ mtusr $r3, $d1.hi ! $d1 hi byte ++ mtsr $r4, $mr0 ++ mtsr $r5, $mr1 ++ mtsr $r6, $mr4 ++ mtsr $r7, $mr6 ++ mtsr $r8, $mr7 ++ mtsr $r9, $mr8 ++ mtsr $r10, $ir0 ++ mtsr $r11, $ir1 ++ mtsr $r12, $ir2 ++ mtsr $r13, $ir3 ++ mtsr $r14, $ir9 ++ mtsr $r15, $ir10 ++ mtsr $r16, $ir12 ++ mtsr $r17, $ir13 ++ mtsr $r18, $ir14 ++ mtsr $r19, $ir15 ++ popm $r0, $r30 ++ ret +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag101p/devices.c linux-3.4.110/arch/nds32/platforms/ag101p/devices.c +--- linux-3.4.110.orig/arch/nds32/platforms/ag101p/devices.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag101p/devices.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,104 @@ ++#include <linux/serial_8250.h> ++#include <asm/mach-types.h> ++#include <asm/sizes.h> ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/spec.h> ++#include <asm/timer.h> ++ ++const struct map_desc platform_io_desc[] __initdata = { ++ {UART0_VA_BASE, UART0_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {UART1_VA_BASE, UART1_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {INTC_FTINTC010_0_VA_BASE, INTC_FTINTC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {TIMER_FTTMR010_0_VA_BASE, TIMER_FTTMR010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {SSP_FTSSP010_0_VA_BASE, SSP_FTSSP010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {PMU_FTPMU010_0_VA_BASE, PMU_FTPMU010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {MAC_FTMAC100_0_VA_BASE, MAC_FTMAC100_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {SDC_FTSDC010_0_VA_BASE, SDC_FTSDC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {RTC_FTRTC010_0_VA_BASE, RTC_FTRTC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {WDT_FTWDT010_0_VA_BASE, WDT_FTWDT010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {GPIO_FTGPIO010_0_VA_BASE, GPIO_FTGPIO010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {CFC_FTCFC010_0_VA_BASE, CFC_FTCFC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {LCD_FTLCDC100_0_VA_BASE, LCD_FTLCDC100_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {I2C_FTI2C010_0_VA_BASE, I2C_FTI2C010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {DMAC_FTDMAC020_0_VA_BASE, DMAC_FTDMAC020_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {APBBRG_FTAPBBRG020S_0_VA_BASE, APBBRG_FTAPBBRG020S_0_PA_BASE, ++ PAGE_SIZE, MT_DEVICE_NCB}, ++ {USB_FOTG2XX_0_VA_BASE, USB_FOTG2XX_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {PCIIO_0_VA_BASE, PCIIO_0_PA_BASE, (0x000FF000 & PAGE_MASK), ++ MT_DEVICE_NCB}, ++ {PCIC_FTPCI100_0_VA_BASE, PCIC_FTPCI100_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {AHB_ATFAHBC020S_0_VA_BASE, AHB_ATFAHBC020S_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {LED_VA_BASE, LED_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {SDMC_FTSDMC021_VA_BASE, SDMC_FTSDMC021_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {L2CC_VA_BASE, L2CC_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB} ++}; ++ ++static void __init platform_map_io(void) ++{ ++ iotable_init((struct map_desc *)platform_io_desc, ++ ARRAY_SIZE(platform_io_desc)); ++} ++ ++static struct uart_port uart0 = { ++ .membase = (void __iomem *)UART0_VA_BASE, ++ .irq = UART0_IRQ, ++ .uartclk = CONFIG_UART_CLK, ++ .regshift = 2, ++ .iotype = UPIO_MEM, ++ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, ++ .line = 0, ++ .mapbase = UART0_PA_BASE, ++}; ++ ++static struct uart_port uart1 = { ++ .membase = (void __iomem *)UART1_VA_BASE, ++ .irq = UART1_IRQ, ++ .uartclk = CONFIG_UART_CLK, ++ .regshift = 2, ++ .iotype = UPIO_MEM, ++ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, ++ .line = 1, ++ .mapbase = UART1_PA_BASE, ++}; ++ ++static void __init soc_init(void) ++{ ++ early_serial_setup(&uart0); ++ early_serial_setup(&uart1); ++} ++ ++MACHINE_START(FARADAY, PLATFORM_NAME) ++ .param_offset = BOOT_PARAMETER_PA_BASE, ++ .map_io = platform_map_io, ++ .init_irq = platform_init_irq, ++ .timer = &platform_timer, /* defined in timer.c */ ++ .init_machine = soc_init, ++MACHINE_END static struct platform_device usb_dev_otg_host = { ++ .name = "fotg-ehci", ++}; ++ ++static int __init fotg_init(void) ++{ ++ platform_device_register(&usb_dev_otg_host); ++ return 0; ++} ++ ++device_initcall(fotg_init); +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag101p/interrupt-latency.c linux-3.4.110/arch/nds32/platforms/ag101p/interrupt-latency.c +--- linux-3.4.110.orig/arch/nds32/platforms/ag101p/interrupt-latency.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag101p/interrupt-latency.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,197 @@ ++/* ++ * interrupt_latency v1.0 11/25/01 ++ * www.embeddedlinuxinterfacing.com ++ * ++ * The original location of this code is ++ * http://www.embeddedlinuxinterfacing.com/chapters/11/ ++ * ++ * Copyright (C) 2001 by Craig Hollabaugh ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Library 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 ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library 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 ++ */ ++ ++/* ++ * interrupt_latency.c is based on procfs_example.c by Erik Mouw. ++ * For more information, please see, The Linux Kernel Procfs Guide, Erik Mouw ++ * http://kernelnewbies.org/documents/kdoc/procfs-guide/lkprocfsguide.html ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/proc_fs.h> ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <nds32_intrinsic.h> ++ ++#define ILT_MODULE_VERSION "1.0" ++#define MODULE_NAME "interrupt_latency" ++ ++#define USE_PFM ++static int interruptcount = 0; ++#ifdef USE_PFM ++static unsigned int start_cycle = 0, finish_cycle = 0; ++static unsigned int start_inst = 0, finish_inst = 0; ++static unsigned int start_int = 0, finish_int = 0; ++#else ++static struct timeval tv1, tv2; /* do_gettimeofday fills these */ ++#endif ++ ++#define INTERRUPT 9 ++ ++static struct proc_dir_entry *interrupt_latency_file; ++ ++/* ++ * function interrupt_interrupt_latency ++ * This function is the interrupt handler for interrupt 7. It sets the tv2 ++ * structure using do_gettimeofday. It then deasserts D7. ++ */ ++static irqreturn_t interrupt_interrupt_latency(int irq, void *dev_id) ++{ ++ unsigned int ir15, pfm_ctl; ++#ifdef USE_PFM ++ /* disable counter */ ++ pfm_ctl = 0x4410000; //cycles, instructions and icache misses ++ //pfm_ctl = 0x4c0000; //instructions and interrupts ++ //pfm_ctl = 0x4510000; //icache accesses and misses ++ __nds32__mtsr(pfm_ctl, NDS32_SR_PFM_CTL); //instructions and interrupts ++ finish_cycle = __nds32__mfsr(NDS32_SR_PFMC0); ++ finish_inst = __nds32__mfsr(NDS32_SR_PFMC2); ++ finish_int = __nds32__mfsr(NDS32_SR_PFMC1); ++#else ++ do_gettimeofday(&tv2); ++#endif ++ /* deassert the interrupt signal */ ++ ir15 = __nds32__mfsr(NDS32_SR_INT_PEND); ++ __nds32__mtsr((~0x10000) & ir15, NDS32_SR_INT_PEND); ++ __nds32__dsb(); ++ ++ interruptcount++; ++ return IRQ_HANDLED; ++} ++ ++/* ++ * function proc_read_interrupt_latency ++ * The kernel executes this function when a read operation occurs on ++ * /proc/interrupt_latency. This function sets the tv1 structure. It asserts ++ * D7 which should immediately cause interrupt 7 to occur. The handler ++ * records tv2 and deasserts D7. This function returns the time differential ++ * between tv2 and tv1. ++ */ ++static int proc_read_interrupt_latency(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ unsigned int ir15, pfm_ctl; ++#ifdef USE_PFM ++ //pfm_ctl = 0x4c0007; ++ //pfm_ctl = 0x4510007; ++ pfm_ctl = 0x4410007; ++ start_cycle = __nds32__mfsr(NDS32_SR_PFMC0); ++ start_inst = __nds32__mfsr(NDS32_SR_PFMC2); ++ start_int = __nds32__mfsr(NDS32_SR_PFMC1); ++ __nds32__mtsr(pfm_ctl, NDS32_SR_PFM_CTL); ++#else ++ do_gettimeofday(&tv1); ++#endif ++ /* assert the interrupt signal */ ++ ir15 = __nds32__mfsr(NDS32_SR_INT_PEND); ++ __nds32__mtsr(0x10000 | ir15, NDS32_SR_INT_PEND); ++ __nds32__dsb(); ++ ++#ifdef USE_PFM ++ len = ++ sprintf(page, ++ "Cnt0 %11u Start %11u Finish %11u Cycles %11u\n" ++ "Cnt2 %11u Start %11u Finish %11u icache miss %11u\n" ++ "Cnt1 %11u Start %11u Finish %11u Instructions %11u\n" ++ "Count %11i\n", ((pfm_ctl & 0x8000) >> 15), start_cycle, ++ finish_cycle, (finish_cycle - start_cycle), ++ ((pfm_ctl & 0xfc00000) >> 22), start_inst, finish_inst, ++ (finish_inst - start_inst), ((pfm_ctl & 0x3f0000) >> 16), ++ start_int, finish_int, (finish_int - start_int), ++ interruptcount); ++#else ++ len = sprintf(page, "Start %9i.%06i\nFinish %9i.%06i\nLatency %17i\n\ ++Count %19i\n", (int)tv1.tv_sec, (int)tv1.tv_usec, (int)tv2.tv_sec, (int)tv2.tv_usec, (int)(tv2.tv_usec - tv1.tv_usec), interruptcount); ++#endif ++ *eof = 1; ++ return len; ++} ++ ++/* ++ * function init_interrupt_latency ++ * This function creates the /proc directory entry interrupt_latency. It ++ * also configures the parallel port then requests interrupt 7 from Linux. ++ */ ++static int __init init_interrupt_latency(void) ++{ ++ int rv = 0; ++ unsigned int ir14; ++ ++ interrupt_latency_file = ++ create_proc_entry("interrupt_latency", 0444, NULL); ++ if (interrupt_latency_file == NULL) { ++ return -ENOMEM; ++ } ++ ++ interrupt_latency_file->data = NULL; ++ interrupt_latency_file->read_proc = &proc_read_interrupt_latency; ++ interrupt_latency_file->write_proc = NULL; ++ ++ /* request interrupt from linux */ ++ rv = request_irq(INTERRUPT, interrupt_interrupt_latency, IRQF_DISABLED, ++ "interrupt_latency", (void *)NULL); ++ if (rv) { ++ printk("Can't get interrupt %d\n", INTERRUPT); ++ goto no_interrupt_latency; ++ } ++ ++ /* unmask SWI */ ++ ir14 = __nds32__mfsr(NDS32_SR_INT_MASK); ++ __nds32__mtsr((0x10000 | ir14), NDS32_SR_INT_MASK); ++ __nds32__dsb(); ++ ++ /* everything initialized */ ++ printk(KERN_INFO "%s %s initialized\n", MODULE_NAME, ++ ILT_MODULE_VERSION); ++ return 0; ++ ++ /* remove the proc entry on error */ ++no_interrupt_latency: ++ remove_proc_entry("interrupt_latency", NULL); ++ return 0; ++} ++ ++/* ++ * function cleanup_interrupt_latency ++ * This function frees interrupt then removes the /proc directory entry ++ * interrupt_latency. ++ */ ++static void __exit cleanup_interrupt_latency(void) ++{ ++ /* free the interrupt */ ++ free_irq(INTERRUPT, (void *)NULL); ++ ++ remove_proc_entry("interrupt_latency", NULL); ++ ++ printk(KERN_INFO "%s %s removed\n", MODULE_NAME, ILT_MODULE_VERSION); ++} ++ ++module_init(init_interrupt_latency); ++module_exit(cleanup_interrupt_latency); ++ ++MODULE_DESCRIPTION("interrupt_latency proc module"); +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag101p/Kconfig linux-3.4.110/arch/nds32/platforms/ag101p/Kconfig +--- linux-3.4.110.orig/arch/nds32/platforms/ag101p/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag101p/Kconfig 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,11 @@ ++menu "AG101P Platform Options" ++config CACHE_L2 ++bool "Support L2 cache" ++ default n ++ ++config MEASURE_INTERRUPT_LATENCY ++ bool "Measure interrupt latency" ++ default n ++ help ++ Enable measuring interrupt latency with software interrupt ++endmenu +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag101p/Makefile linux-3.4.110/arch/nds32/platforms/ag101p/Makefile +--- linux-3.4.110.orig/arch/nds32/platforms/ag101p/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag101p/Makefile 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,2 @@ ++obj-y = devices.o ++obj-$(CONFIG_MEASURE_INTERRUPT_LATENCY) += interrupt-latency.o +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag102/ahbclkcal.c linux-3.4.110/arch/nds32/platforms/ag102/ahbclkcal.c +--- linux-3.4.110.orig/arch/nds32/platforms/ag102/ahbclkcal.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag102/ahbclkcal.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,216 @@ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/pm.h> ++#include <linux/sched.h> ++#include <linux/irq.h> ++ ++#include <asm/hardware.h> ++#include <asm/spec.h> ++#ifdef CONFIG_AUTO_SYS_CLK ++ ++#define OSCH3_CLK 33000000 ++#define OSCH_CLK 25000000 ++#define MHZ 1000000 ++/* ++ * Table for ahb divisor, PMODE[07:04] ++ */ ++static const int ahb_div[16] = { ++ 1, 2, 3, 4, 5, 6, 3, 5, ++ 8, 10, 12, 14, 15, 18, 20, -1 ++}; ++ ++/* ag102_get_ahb_clk() ++ * ++ * return AHB clock in Hz. ++ */ ++static int ahbclk; ++void ag102_calc_ahb_clk(void) ++{ ++ unsigned int pcs1_param; ++ unsigned int pcs4_param; ++ unsigned int pcs5_param; ++ unsigned int main_PLL_div; ++ unsigned int main_PLL_out; ++ unsigned int ratio; ++ unsigned int main_PLL_N; ++ unsigned int main_PLL_M = 1; ++ unsigned int F_core0; ++ unsigned int F_core1; ++ unsigned int F_l2cc; ++ unsigned int F_ddr2; ++ unsigned int F_ahb; ++ unsigned int F_apb; ++ unsigned int F_pci; ++ ++ pcs1_param = REG32(PCU_VA_BASE + 0xa4); //pcs1 parameter register, for core/ahb/apb clk ratio setting ++ main_PLL_div = (pcs1_param >> 4) & 0x3; ++ ratio = pcs1_param & 0xf; ++ ++ pcs4_param = REG32(PCU_VA_BASE + 0x104); //pcs4 parameter register, for main PLL setting ++ main_PLL_N = pcs4_param & 0xff; ++ main_PLL_out = (OSCH3_CLK * main_PLL_N / main_PLL_M) >> main_PLL_div; ++ ++ pcs5_param = REG32(PCU_VA_BASE + 0x124); //pcs5 parameter register, for PCI PLL/DLL setting ++ ++ switch (ratio) { ++ case 0: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0; ++ F_l2cc = F_core0 >> 1; ++ F_ddr2 = F_core0 >> 1; ++ F_ahb = F_core0 >> 2; ++ F_apb = F_ahb >> 1; ++ break; ++ ++ case 1: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0; ++ F_l2cc = F_core0 >> 1; ++ F_ddr2 = F_core0 >> 1; ++ F_ahb = F_core0 >> 3; ++ F_apb = F_ahb >> 1; ++ break; ++ ++ case 2: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0 >> 1; ++ F_l2cc = F_core0 >> 1; ++ F_ddr2 = F_core0 >> 1; ++ F_ahb = F_core0 >> 2; ++ F_apb = F_ahb >> 1; ++ break; ++ ++ case 3: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0 >> 1; ++ F_l2cc = F_core0 >> 1; ++ F_ddr2 = F_core0 >> 1; ++ F_ahb = F_core0 >> 3; ++ F_apb = F_ahb >> 1; ++ break; ++ ++ case 4: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0 >> 2; ++ F_l2cc = F_core0 >> 2; ++ F_ddr2 = F_core0 >> 1; ++ F_ahb = F_core0 >> 2; ++ F_apb = F_ahb >> 1; ++ break; ++ case 5: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0 >> 2; ++ F_l2cc = F_core0 >> 2; ++ F_ddr2 = F_core0 >> 1; ++ F_ahb = F_core0 >> 3; ++ F_apb = F_ahb >> 1; ++ break; ++ ++ case 6: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0; ++ F_l2cc = F_core0; ++ F_ddr2 = F_core0 >> 1; ++ F_ahb = F_core0 >> 2; ++ F_apb = F_ahb >> 1; ++ break; ++ ++ case 7: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0; ++ F_l2cc = F_core0; ++ F_ddr2 = F_core0 >> 1; ++ F_ahb = F_core0 >> 3; ++ F_apb = F_ahb >> 1; ++ break; ++ ++ case 8: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0; ++ F_l2cc = F_core0 >> 1; ++ F_ddr2 = OSCH_CLK * 24 / 2; ++ F_ahb = F_core0 >> 2; ++ F_apb = F_ahb >> 1; ++ break; ++ ++ case 9: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0; ++ F_l2cc = F_core0 >> 1; ++ F_ddr2 = OSCH_CLK * 24 / 2; ++ F_ahb = F_core0 >> 3; ++ F_apb = F_ahb >> 1; ++ break; ++ case 10: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0 >> 1; ++ F_l2cc = F_core0 >> 1; ++ F_ddr2 = OSCH_CLK * 24 / 2; ++ F_ahb = F_core0 >> 2; ++ F_apb = F_ahb >> 1; ++ break; ++ ++ case 11: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0 >> 1; ++ F_l2cc = F_core0 >> 1; ++ F_ddr2 = OSCH_CLK * 24 / 2; ++ F_ahb = F_core0 >> 3; ++ F_apb = F_ahb >> 1; ++ break; ++ ++ case 12: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0 >> 2; ++ F_l2cc = F_core0 >> 2; ++ F_ddr2 = OSCH_CLK * 24 / 2; ++ F_ahb = F_core0 >> 2; ++ F_apb = F_ahb >> 1; ++ break; ++ ++ case 13: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0 >> 2; ++ F_l2cc = F_core0 >> 2; ++ F_ddr2 = OSCH_CLK * 24 / 2; ++ F_ahb = F_core0 >> 3; ++ F_apb = F_ahb >> 1; ++ break; ++ ++ case 14: ++ F_core0 = main_PLL_out; ++ F_core1 = F_core0; ++ F_l2cc = F_core0; ++ F_ddr2 = F_core0; ++ F_ahb = F_core0; ++ F_apb = F_ahb; ++ break; ++ default: // 15 ++ F_core0 = OSCH3_CLK; ++ F_core1 = F_core0; ++ F_l2cc = F_core0; ++ F_ddr2 = F_core0; ++ F_ahb = F_core0; ++ F_apb = F_ahb; ++ break; ++ } ++ ++ F_pci = OSCH_CLK * 24 / 9; ++ if ((pcs5_param & 0x800) == 0) ++ F_pci = F_pci >> 1; ++ ++ ahbclk = (int)F_ahb; ++} ++ ++int ag102_get_ahb_clk(void) ++{ ++ //return ahbclk+MHZ; ++ return ahbclk; ++} ++ ++EXPORT_SYMBOL(ag102_get_ahb_clk); ++#else ++void ag102_calc_ahb_clk(void) ++{ ++} ++#endif +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag102/devices.c linux-3.4.110/arch/nds32/platforms/ag102/devices.c +--- linux-3.4.110.orig/arch/nds32/platforms/ag102/devices.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag102/devices.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,181 @@ ++#include <linux/serial_8250.h> ++#include <asm/mach-types.h> ++#include <asm/sizes.h> ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/timer.h> ++#include <linux/platform_device.h> ++#include <linux/usb/g_hid.h> ++ ++extern void amic_init(void); ++ ++const struct map_desc platform_io_desc[] __initdata = { ++ {UART0_VA_BASE, UART0_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {UART1_VA_BASE, UART1_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {AMIC_VA_BASE, AMIC_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {GMAC_VA_BASE, GMAC_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {APBBR_VA_BASE, APBBR_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {TIMER_VA_BASE, TIMER_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {L2CC_VA_BASE, L2CC_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {PCIIO_0_VA_BASE, PCIIO_0_PA_BASE, 0x0000F000, MT_DEVICE_NCB}, ++ {PCIC_FTPCI100_0_VA_BASE, PCIC_FTPCI100_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {SDC_FTSDC010_0_VA_BASE, SDC_FTSDC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {RTC_FTRTC010_0_VA_BASE, RTC_FTRTC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {WDT_FTWDT010_0_VA_BASE, WDT_FTWDT010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {I2C_FTI2C010_0_VA_BASE, I2C_FTI2C010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {GPIO_FTGPIO010_0_VA_BASE, GPIO_FTGPIO010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {PCU_VA_BASE, PCU_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {LPC_IO_VA_BASE, LPC_IO_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {LPC_REG_VA_BASE, LPC_REG_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {DMAC_FTDMAC020_0_VA_BASE, DMAC_FTDMAC020_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {GPU_VA_BASE, GPU_PA_BASE, SZ_64K, MT_DEVICE_NCB}, ++ {IDE_FTIDE020_VA_BASE, IDE_FTIDE020_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {USB_FOTG2XX_0_VA_BASE, USB_FOTG2XX_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {CFC_FTCFC010_0_VA_BASE, CFC_FTCFC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {SSP_FTSSP010_0_VA_BASE, SSP_FTSSP010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {SPI_FTSSP010_0_VA_BASE, SPI_FTSSP010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {DDR2C_VA_BASE, DDR2C_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {AHB_ATFAHBC020S_0_VA_BASE, AHB_ATFAHBC020S_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB} ++ //{ GPIO_VA_BASE, GPIO_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB } ++}; ++ ++/* hid descriptor for a keyboard */ ++static struct hidg_func_descriptor my_hid_data = { ++ .subclass = 0, /* No subclass */ ++ .protocol = 1, /* Keyboard */ ++ .report_length = 8, ++ .report_desc_length = 63, ++ .report_desc = { ++ 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ ++ 0x09, 0x06, /* USAGE (Keyboard) */ ++ 0xa1, 0x01, /* COLLECTION (Application) */ ++ 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ ++ 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */ ++ 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */ ++ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ ++ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ ++ 0x75, 0x01, /* REPORT_SIZE (1) */ ++ 0x95, 0x08, /* REPORT_COUNT (8) */ ++ 0x81, 0x02, /* INPUT (Data,Var,Abs) */ ++ 0x95, 0x01, /* REPORT_COUNT (1) */ ++ 0x75, 0x08, /* REPORT_SIZE (8) */ ++ 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ ++ 0x95, 0x05, /* REPORT_COUNT (5) */ ++ 0x75, 0x01, /* REPORT_SIZE (1) */ ++ 0x05, 0x08, /* USAGE_PAGE (LEDs) */ ++ 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ ++ 0x29, 0x05, /* USAGE_MAXIMUM (Kana) */ ++ 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ ++ 0x95, 0x01, /* REPORT_COUNT (1) */ ++ 0x75, 0x03, /* REPORT_SIZE (3) */ ++ 0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */ ++ 0x95, 0x06, /* REPORT_COUNT (6) */ ++ 0x75, 0x08, /* REPORT_SIZE (8) */ ++ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ ++ 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */ ++ 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ ++ 0x19, 0x00, /* USAGE_MINIMUM (Reserved) */ ++ 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */ ++ 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ ++ 0xc0 /* END_COLLECTION */ ++ } ++}; ++ ++static struct platform_device my_hid = { ++ .name = "hidg", ++ .id = 0, ++ .num_resources = 0, ++ .resource = 0, ++ .dev.platform_data = &my_hid_data, ++}; ++ ++static void __init platform_map_io(void) ++{ ++ iotable_init((struct map_desc *)platform_io_desc, ++ ARRAY_SIZE(platform_io_desc)); ++} ++ ++static struct resource ftgmac100_resources[] = { ++ [0] = { ++ .start = GMAC_PA_BASE, ++ .end = GMAC_PA_BASE + SZ_4K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = GMAC_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device ftgmac100_device = { ++ .name = "ftgmac100", ++ .id = 0, ++ .num_resources = ARRAY_SIZE(ftgmac100_resources), ++ .resource = ftgmac100_resources, ++}; ++ ++static int __init devices_init(void) ++{ ++ platform_device_register(&ftgmac100_device); ++ platform_device_register(&my_hid); ++ return 0; ++} ++ ++arch_initcall(devices_init); ++ ++static struct uart_port uart0 = { ++ .membase = (void __iomem *)UART0_VA_BASE, ++ .irq = UART0_IRQ, ++ .uartclk = CONFIG_UART_CLK, ++ .regshift = 2, ++ .iotype = UPIO_MEM, ++ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, ++ .line = 0, ++ .mapbase = UART0_PA_BASE, ++}; ++ ++static struct uart_port uart1 = { ++ .membase = (void __iomem *)UART1_VA_BASE, ++ .irq = UART1_IRQ, ++ .uartclk = CONFIG_UART_CLK, ++ .regshift = 2, ++ .iotype = UPIO_MEM, ++ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, ++ .line = 1, ++ .mapbase = UART1_PA_BASE, ++}; ++ ++void ag102_calc_ahb_clk(void); ++static void __init soc_init(void) ++{ ++ ag102_calc_ahb_clk(); ++ early_serial_setup(&uart0); ++ early_serial_setup(&uart1); ++} ++ ++MACHINE_START(FARADAY, PLATFORM_NAME) ++ .param_offset = BOOT_PARAMETER_PA_BASE,.map_io = platform_map_io,.init_irq = amic_init,.timer = &platform_timer, /* defined in timer.c */ ++.init_machine = soc_init, ++ MACHINE_END static struct platform_device usb_dev_otg_host = { ++ .name = "fotg-ehci", ++}; ++ ++static int __init fotg_init(void) ++{ ++ platform_device_register(&usb_dev_otg_host); ++ return 0; ++} ++ ++device_initcall(fotg_init); +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag102/freq-scaling.c linux-3.4.110/arch/nds32/platforms/ag102/freq-scaling.c +--- linux-3.4.110.orig/arch/nds32/platforms/ag102/freq-scaling.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag102/freq-scaling.c 2016-04-07 10:20:50.986082726 +0200 +@@ -0,0 +1,512 @@ ++/* ++ * linux/arch/nds32/platforms/ag102/cpu-fcs.c ++ * ++ * Copyright (C) 2002,2003 Intrinsyc Software ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * History: ++ * 31-Jul-2002 : Initial version [FB] ++ * 29-Jan-2003 : added PXA255 support [FB] ++ * 20-Apr-2003 : ported to v2.5 (Dustin McIntire, Sensoria Corp.) ++ * 18-Jun-2008 : ported to NDS32 architecture ( Roy Lee, Andestech Corp.) ++ * 13-Oct-2010 : ported to NDS32 AG102 architecture(Gavin Guo, Andestech Corp.) ++ * ++ * Note: ++ * This driver may change the memory bus clock rate, but will not do any ++ * platform specific access timing changes... for example if you have flash ++ * memory connected to CS0, you will need to register a platform specific ++ * notifier which will adjust the memory access strobes to maintain a ++ * minimum strobe width. ++ * ++ */ ++#include <linux/module.h> ++#include <linux/cpufreq.h> ++#include <linux/interrupt.h> ++ ++#include <linux/delay.h> ++#include <asm/hardware.h> ++#include <asm/localmem.h> ++#include <asm/system.h> ++#include <asm/nds32.h> ++#include <asm/irq_regs.h> ++#include "pcu.h" ++ ++void __ddr_fsc_lock_start(); ++void __ddr_fsc_lock_end(); ++#define AG102_MIN_FREQ 200000000 ++#define AG102_MAX_FREQ 1000000000 ++#define OSCH3_CLK 33000000 /* 33MHz AG102 */ ++ ++struct ag102_freq_struct { ++ unsigned int khz; /* cpu_clk in khz */ ++ unsigned int sf; /* scaling factor */ ++ unsigned int cr; /* clock ratio */ ++}; ++ ++struct ag102_freq_struct ag102_run_freqs[] = { ++ /* khz sf, cr */ ++ {OSCH3_CLK * 7, 7, 0}, /* CPUA 231MHz */ ++ {OSCH3_CLK * 8, 8, 0}, /* CPUA 264MHz */ ++ {OSCH3_CLK * 9, 9, 0}, ++ {OSCH3_CLK * 10, 10, 0}, ++ {OSCH3_CLK * 11, 11, 0}, ++ {OSCH3_CLK * 12, 12, 0}, ++ {OSCH3_CLK * 13, 13, 0}, ++ {OSCH3_CLK * 14, 14, 0}, ++ {OSCH3_CLK * 15, 15, 0}, ++ {OSCH3_CLK * 16, 16, 0}, ++ /* ++ * {OSCH3_CLK * 17, 17, 0}, ++ * {OSCH3_CLK * 18, 18, 0}, ++ * {OSCH3_CLK * 19, 19, 0}, ++ * {OSCH3_CLK * 20, 20, 0}, ++ * {OSCH3_CLK * 21, 21, 0}, ++ * {OSCH3_CLK * 22, 22, 0}, ++ * {OSCH3_CLK * 23, 23, 0}, ++ * {OSCH3_CLK * 24, 24, 0}, ++ * {OSCH3_CLK * 25, 25, 0}, ++ * {OSCH3_CLK * 26, 26, 0}, ++ * {OSCH3_CLK * 27, 27, 0}, ++ * {OSCH3_CLK * 28, 28, 0}, ++ * {OSCH3_CLK * 29, 29, 0}, ++ * {OSCH3_CLK * 30, 30, 0}, ++ */ ++ {0} /* The last 30 is CPUA 1000MHz */ ++}; ++ ++#define NUM_RUN_FREQS ARRAY_SIZE(ag102_run_freqs) ++static struct cpufreq_frequency_table ag102_run_freq_table[NUM_RUN_FREQS + 1]; ++ ++/* Generic helper function get CPU clocks in kHz */ ++unsigned int ag102_cpufreq_get(unsigned int dummy) ++{ ++ unsigned int main_PLL_M = 1; ++ unsigned int main_PLL_out; ++ unsigned int main_PLL_div; ++ unsigned int ratio; ++ unsigned int main_PLL_N; ++ unsigned int pcs1_param; ++ unsigned int pcs4_param; ++ ++ pcs1_param = PCU_GET_REG(PCS1_ST2); ++ main_PLL_div = PCU_EXTRACT(PCS1_ST2, DIV, pcs1_param); ++ ratio = PCU_EXTRACT(PCS1_ST2, RATIO, pcs1_param); ++ ++ pcs4_param = PCU_GET_REG(PCS4_ST2); ++ main_PLL_N = PCU_EXTRACT(PCS4_ST2, N_FACTOR, pcs4_param); ++ main_PLL_out = (OSCH3_CLK * main_PLL_N / main_PLL_M) >> main_PLL_div; ++ ++ printk("CPU frequency is %d\n", main_PLL_out); ++ return main_PLL_out; ++} ++ ++/* find a valid frequency point */ ++static int ag102_verify_policy(struct cpufreq_policy *policy) ++{ ++ printk("Verified CPU policy: %dKhz min to %dKhz max\n", policy->min, ++ policy->max); ++ return cpufreq_frequency_table_verify(policy, ag102_run_freq_table); ++} ++ ++void wakeup_and_ddr_train(void) ++{ ++ unsigned int csr_reg; ++ unsigned long ddr2_va_base = DDR2C_VA_BASE; ++ /* issue standby */ ++ /*standby(PCU_STBY_WAIT_DONE); */ ++ __asm__ __volatile__("__fcs_stby:"); ++ __asm__ __volatile__("standby wait_done"); ++ /* Fill the inline assembly codes into Cache to avoid SDRAM access before the data training is done */ ++ __asm__ __volatile__("__ddr_fsc_lock_start:\n" ++ "li $p0, %0 \n" ++ "lwi $p1, [$p0 + 0x1f0] \n" ++ "ori $p1, $p1, 0x100 \n" ++ "swi $p1, [$p0 + 0x1f0] ! DLL Reset \n" ++ "msync \n" ++ "isb \n" ++ "1: \n" ++ "lwi $p1, [$p0 + 0x1f0] \n" ++ "andi $p1, $p1, 0x100 \n" ++ "bnez $p1, 1b ! Wait until DLL reset is done\n" ++ "__trigger_dt:\n" ++ "li $p0, %1 \n" ++ "lwi $p1, [$p0] \n" ++ "li $p0, 0x40000000 \n" ++ "or $p1, $p1, $p0 \n" ++ "li $p0, %2 \n" ++ "swi $p1, [$p0] ! Trigger data training\n" ++ "msync \n" ++ "isb \n" ++ "li $p0, %3 \n" ++ "__wait_init_0:\n" ++ "lwi $p1, [$p0 + 0xc] \n" ++ "srli $p1, $p1, 23 \n" ++ "andi $p1, $p1, 0x1 \n" ++ "bnez $p1, __wait_init_0 ! Wait until init bit in CSR == 0\n" ++ "lwi $p1, [$p0 + 0xc] \n" ++ "srli $p1, $p1, 20 \n" ++ "andi $p1, $p1, 0x1 \n" ++ "beqz $p1, __dt_pass ! Monitor data training result\n" ++ "li $p0, 0xff942000 \n" ++ "li $p1, 0x45 \n" ++ "swi $p1, [$p0] ! put 'E' to UART\n" ++ "li $p1, 0x52 \n" ++ "swi $p1, [$p0] ! put 'R' to UART\n" ++ "li $p1, 0x52 \n" ++ "swi $p1, [$p0] ! put 'R' to UART\n" ++ "li $p1, 0x4f \n" ++ "swi $p1, [$p0] ! put 'O' to UART\n" ++ "li $p1, 0x52 \n" ++ "swi $p1, [$p0] ! put 'R' to UART\n" ++ "li $p1, 0xd \n" ++ "swi $p1, [$p0] ! put '\\r' to UART\n" ++ "li $p1, 0xa \n" ++ "swi $p1, [$p0] ! put '\\n' to UART\n" ++ "j __ddr_fsc_lock_end \n" ++ "__dt_pass:\n" ++ "li $p0, 0xff942000 \n" ++ "li $p1, 0x50 \n" ++ "swi $p1, [$p0] ! put 'P' to UART\n" ++ "li $p1, 'A \n" ++ "swi $p1, [$p0] ! put 'A' to UART\n" ++ "li $p1, 0x53 \n" ++ "swi $p1, [$p0] ! put 'S' to UART\n" ++ "li $p1, 0x53 \n" ++ "swi $p1, [$p0] ! put 'S' to UART\n" ++ "li $p1, '\\r \n" ++ "swi $p1, [$p0] ! put '\\r' to UART\n" ++ "li $p1, '\\n \n" ++ "swi $p1, [$p0] ! put '\\n' to UART\n" ++ "__ddr_fsc_lock_end: \n":: ++ "r" ++ (ddr2_va_base), ++ "r" ++ (ddr2_va_base), ++ "r"(ddr2_va_base), "r"(ddr2_va_base)); ++ ++ csr_reg = GET_REG(DDR2C_VA_BASE + 0xc); ++ if (csr_reg & 0x100000) { ++ printk("\n###### Data training error ######\nCSR = 0x%x\n\n", ++ csr_reg); ++ } ++} ++ ++void check_status() ++{ ++ unsigned int reg_value_tmp; ++ ++ /* ++ * CPU will continue if it is waked up ++ * => check status ++ */ ++ reg_value_tmp = PCU_GET_REG(BSM_STATUS); ++ if (PCU_EXTRACT(BSM_STATUS, STS, reg_value_tmp) != PCS_BSM_DONE) { ++ printk("ERROR: BSM status is not expected:0x%x\n", ++ reg_value_tmp); ++ } ++ PCU_SET_REG(BSM_STATUS, 0x0); // write to clear the status ++ ++ /* ++ * Maybe we will need the following code in the future ++ * if (pcs1_used) { ++ * reg_value_tmp = PCU_GET_REG(PCS1_ST1); ++ * if (PCU_EXTRACT(PCS1_ST1, STS, reg_value_tmp) != PCS_STS_DONE) { ++ * printk("ERROR: PCS1 status is not expected:0x%x\n", reg_value_tmp); ++ * printk("DEBUG: PCS1 status 2 is 0x%x\n", PCU_GET_REG(PCS1_ST2)); ++ * } ++ * PCU_SET_REG(PCS1_ST1, 0x0); // write to clear the status ++ * pcs1_used = 0; ++ * } ++ */ ++ ++ /* if (pcs4_used) { */ ++ reg_value_tmp = PCU_GET_REG(PCS4_ST1); ++ if (PCU_EXTRACT(PCS4_ST1, STS, reg_value_tmp) != PCS_STS_DONE) { ++ printk("ERROR: PCS4 status is not expected:0x%x\n", ++ reg_value_tmp); ++ printk("DEBUG: PCS4 status 2 is 0x%x\n", PCU_GET_REG(PCS4_ST2)); ++ } ++ PCU_SET_REG(PCS4_ST1, 0x0); /* write to clear the status */ ++ /* pcs4_used = 0; */ ++ /* } */ ++ ++} ++ ++void start_fcs(unsigned int pll_n_factor, unsigned org_div_param) ++{ ++ unsigned int pll_range; ++ unsigned int pcs4_prmtr; ++ ++ /* ++ * We must keep the frequency between 266~533. ++ * because this is the frequency having been tested. ++ */ ++ if (org_div_param == 0) { ++ if ((pll_n_factor < 7) || (pll_n_factor > 16)) { /* 266~533 */ ++ printk("\npll_n_factor:%d, org_div_param:%d\n", ++ pll_n_factor, org_div_param); ++ printk ++ ("The input is not accepted! Please input the other value\n"); ++ return; ++ } ++ } else { /* div = 1(the divsior is 2), (pll_n_factor*33MHz/2) */ ++ if (pll_n_factor < 16) { /* (533/2~1000/2) */ ++ printk("\npll_n_factor:%d, org_div_param:%d\n", ++ pll_n_factor, org_div_param); ++ printk ++ ("The input is not accepted! Please input the other value\n"); ++ return; ++ } ++ ++ } ++ /* Setup the pll_range, pcu need to know the frequency which we setup */ ++ if (org_div_param == 0) { ++ if (pll_n_factor <= 15) { ++ pll_range = 2; ++ } else ++ pll_range = 3; ++ } else if (org_div_param == 1) { ++ if (pll_n_factor >= 16 && pll_n_factor <= 30) { ++ pll_range = 2; ++ } else ++ pll_range = 3; ++ } ++ ++ printk("\npll_n_factor:%d, org_div_param:%d, pll_range:%d\n", ++ pll_n_factor, org_div_param, pll_range); ++ /* PCS4 */ ++ PCU_SET_REG(PCS4_CFG, 0); /* stop */ ++ pcs4_prmtr = PCU_PREPARE(PCS4_PARA, IE, 1) | PCU_PREPARE(PCS4_PARA, CMD, PCS_CMD_NOP) | PCU_PREPARE(PCS4_PARA, SYNC, 1) | PCU_PREPARE(PCS4_PARA, PWDN, 0) | PCU_PREPARE(PCS4_PARA, RANGE, pll_range) | /* PLL range */ ++ pll_n_factor; /* PLL N factor */ ++ PCU_SET_REG(PCS4_PARA, pcs4_prmtr); ++ ++ /* BSM */ ++ PCU_SET_REG(BSM_CTRL, PCU_PREPARE(BSM_CTRL, IE, 1) | PCU_PREPARE(BSM_CTRL, CMD, PCS_CMD_SCALING | PCS_CMD_DRAM_SF) | PCU_PREPARE(BSM_CTRL, SYNC, 1) | PCU_PREPARE(BSM_CTRL, LINK0, 4) | /* scaling link start */ ++ PCU_PREPARE(BSM_CTRL, LINK1, 0x0)); /* wakeup link start */ ++ wakeup_and_ddr_train(); ++ check_status(); ++} ++ ++void end_fcs(void) ++{ ++ /* Leave this function as a place marker. */ ++} ++ ++#define LPS_PREC 8 ++void calibration() ++{ ++ unsigned long ticks, loopbit, lpj; ++ int lps_precision = LPS_PREC; ++ ++ lpj = (1 << 12); ++ ++ printk(KERN_INFO "Calibrating delay loop... "); ++ while ((lpj <<= 1) != 0) { ++ /* wait for "start of" clock tick */ ++ ticks = jiffies; ++ while (ticks == jiffies) ++ /* nothing */ ; ++ /* Go .. */ ++ ticks = jiffies; ++ __delay(lpj); ++ ticks = jiffies - ticks; ++ if (ticks) ++ break; ++ } ++ ++ /* ++ * Do a binary approximation to get lpj set to ++ * equal one clock (up to lps_precision bits) ++ */ ++ lpj >>= 1; ++ loopbit = lpj; ++ while (lps_precision-- && (loopbit >>= 1)) { ++ lpj |= loopbit; ++ ticks = jiffies; ++ while (ticks == jiffies) ++ /* nothing */ ; ++ ticks = jiffies; ++ __delay(lpj); ++ if (jiffies != ticks) /* longer than 1 tick */ ++ lpj &= ~loopbit; ++ } ++ ++ printk(KERN_CONT "%lu.%02lu BogoMIPS modified(lpj=%lu)\n", ++ lpj / (500000 / HZ), (lpj / (5000 / HZ)) % 100, lpj); ++} ++ ++static int ag102_speedstep(int idx) ++{ ++ unsigned int j; ++ char ch = 'a'; ++ unsigned int sf, cr; ++ unsigned long flags = 0; ++ unsigned long org_div_param; ++ void (*do_fcs) (unsigned int efsf, unsigned int edivhbaclk); ++ int i; ++ int line_size = CACHE_LINE_SIZE(ICACHE); ++ unsigned long start = ++ ((unsigned long)__ddr_fsc_lock_start) & ~(line_size - 1); ++ unsigned long end = ++ (((unsigned long)__ddr_fsc_lock_end) + line_size) & ~(line_size - ++ 1); ++ ++ printk("&__ddr_fsc_lock_start(): 0x%08lx, aligned to: 0x%08lx\n", ++ (unsigned long)__ddr_fsc_lock_start, start); ++ printk("&__ddr_fsc_lock_end(): 0x%08lx, aligned to: 0x%08lx\n", ++ (unsigned long)__ddr_fsc_lock_end, end); ++ ++ for (i = start; i <= end; i += CACHE_LINE_SIZE(ICACHE)) ++ __asm__ volatile ("\n\tcctl %0, L1I_VA_FILLCK":: ++ "r" (i):"memory"); ++ ++ do_fcs = start_fcs; ++ org_div_param = (PCU_GET_REG(PCS1_ST2) >> 4) & 0x3; ++ sf = ag102_run_freqs[idx].sf; ++ if (org_div_param == 1) ++ sf *= 2; ++#if 0 ++ calibration(); ++ printk("pcu read value,before frequency scaling:"); ++ ag102_cpufreq_get(0); ++#endif ++ local_irq_save(flags); ++ do_fcs(sf, org_div_param); ++ local_irq_restore(flags); ++#if 0 ++ printk("\npcu read value,after frequency scaling:"); ++ ag102_cpufreq_get(0); ++#endif ++ ++ for (i = start; i <= end; i += CACHE_LINE_SIZE(ICACHE)) ++ __asm__ volatile ("\n\tcctl %0, L1I_VA_ULCK"::"r" (i):"memory"); ++ ++ return 1; ++} ++ ++static int ag102_set_target(struct cpufreq_policy *policy, ++ unsigned int target_freq, unsigned int relation) ++{ ++ unsigned int idx, i, j; ++ char ch = 'a'; ++ struct cpufreq_frequency_table *ag102_freqs_table; ++ struct ag102_freq_struct *ag102_freq_settings; ++ struct cpufreq_freqs freqs; ++ ++ ag102_freq_settings = ag102_run_freqs; ++ ag102_freqs_table = ag102_run_freq_table; ++ ++ if (target_freq > AG102_MAX_FREQ || target_freq < AG102_MIN_FREQ) { ++ printk ++ ("\nThe frequency you input is illegal!!Please enter the frequency between %d ~ %d\n", ++ AG102_MIN_FREQ, AG102_MAX_FREQ); ++ return -EINVAL; ++ } ++ ++ /* Lookup the next frequency */ ++ if (cpufreq_frequency_table_target ++ (policy, ag102_freqs_table, target_freq, relation, &idx)) ++ return -EINVAL; ++ ++ freqs.old = policy->cur; ++ freqs.new = ag102_freq_settings[idx].khz; ++ freqs.cpu = policy->cpu; ++ ++ /* ++ * Tell everyone what we're about to do... ++ * you should add a notify client with any platform specific ++ * Vcc changing capability ++ */ ++ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); ++ ++ if (freqs.new != freqs.old) { ++ ++ if (!ag102_speedstep(idx)) ++ return -ENODEV; ++ } ++ ++ /* ++ * Tell everyone what we've just done... ++ * you should add a notify client with any platform specific ++ * SDRAM refresh timer adjustments ++ */ ++ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); ++#if 0 ++ printk("After CPUFREQ_POSTCHANGE, scaling:\n"); ++ calibration(); ++ printk("Speed test..."); ++ for (i = 0; i < 26; i++) { ++ for (j = 0; j < 500000000; j++) ; ++ printk("%c", ch); ++ ch += 1; ++ } ++ printk("\n"); ++#endif ++ return 0; ++} ++ ++static int ag102_cpufreq_init(struct cpufreq_policy *policy) ++{ ++ int i; ++ /* set default policy and cpuinfo */ ++ policy->governor = CPUFREQ_DEFAULT_GOVERNOR; ++ policy->policy = CPUFREQ_POLICY_PERFORMANCE; ++ policy->cpuinfo.max_freq = AG102_MAX_FREQ; ++ policy->cpuinfo.min_freq = AG102_MIN_FREQ; ++ policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */ ++ policy->cur = ag102_cpufreq_get(0); /* current freq */ ++ policy->min = AG102_MIN_FREQ; ++ policy->max = AG102_MAX_FREQ; ++ ++ /* Generate the run cpufreq_frequency_table struct */ ++ for (i = 0; i < NUM_RUN_FREQS; i++) { ++ ++ ag102_run_freq_table[i].frequency = ag102_run_freqs[i].khz; ++ ag102_run_freq_table[i].index = i; ++ } ++ ++ ag102_run_freq_table[i].frequency = CPUFREQ_TABLE_END; ++ ++ printk("CPU frequency change support initialized\n"); ++ ++ return 0; ++} ++ ++static struct cpufreq_driver ag102_cpufreq_driver = { ++ ++ .verify = ag102_verify_policy, ++ .target = ag102_set_target, ++ .init = ag102_cpufreq_init, ++ .get = ag102_cpufreq_get, ++ .name = "AG102", ++}; ++ ++static int __init ag102_cpu_init(void) ++{ ++ return cpufreq_register_driver(&ag102_cpufreq_driver); ++} ++ ++static void __exit ag102_cpu_exit(void) ++{ ++ cpufreq_unregister_driver(&ag102_cpufreq_driver); ++} ++ ++MODULE_AUTHOR("Andes Technology Corporation"); ++MODULE_DESCRIPTION("CPU frequency changing driver for the AG102 architecture"); ++MODULE_LICENSE("GPL"); ++module_init(ag102_cpu_init); ++module_exit(ag102_cpu_exit); +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag102/gmac.h linux-3.4.110/arch/nds32/platforms/ag102/gmac.h +--- linux-3.4.110.orig/arch/nds32/platforms/ag102/gmac.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag102/gmac.h 2016-04-07 10:20:51.002083345 +0200 +@@ -0,0 +1,354 @@ ++#ifdef CONFIG_PLAT_AG102 ++#include <asm/spec-ag102.h> ++#else ++#include <asm/spec-ag101.h> ++#endif ++ ++#ifndef __GMAC_H ++#define __GMAC_H ++ ++// ====================================================== ++// GMAC register definition ++// ====================================================== ++// GMAC register ++// ++//#define CPE_GMAC_BASE 0xFF90B000 //VA Base ++#define CPE_DDR2_MEM_BASE 0x00000000 ++ ++#define BIT_MASK(bit_h, bit_l) ((((UINT32)0x1<<(1+bit_h-bit_l))-(UINT32)0x1)<<bit_l) ++ ++#define GMAC_REG_ISR (GMAC_VA_BASE+0x0) // interrupt sataus register ++#define GMAC_REG_IME (GMAC_VA_BASE+0x4) // interrupt enable register ++#define GMAC_REG_MAC_MADR (GMAC_VA_BASE+0x8) // mac most signification address ++#define GMAC_REG_MAC_LADR (GMAC_VA_BASE+0xc) // mac least signification address ++#define GMAC_REG_NPTXPD (GMAC_VA_BASE+0x18) // normal priority poll demand ++#define GMAC_REG_RXPD (GMAC_VA_BASE+0x1c) // receive poll demand ++#define GMAC_REG_HPTXPD (GMAC_VA_BASE+0x28) // high priority poll demand ++#define GMAC_REG_NPTXR_BADR (GMAC_VA_BASE+0x20) // normal proprity tx ring base ++#define GMAC_REG_RXR_BADR (GMAC_VA_BASE+0x24) // rx ring base ++#define GMAC_REG_HPTXR_BADR (GMAC_VA_BASE+0x28) // high priority tx ring base ++#define GMAC_REG_DBLAC (GMAC_VA_BASE+0x38) // DMA burst lenght and arbitration control ++#define GMAC_REG_DMAFIFOS (GMAC_VA_BASE+0x3c) // DMA FIFO status ++#define GMAC_REG_REVR (GMAC_VA_BASE+0x40) // revision ++#define GMAC_REG_FEAR (GMAC_VA_BASE+0x44) // feature register ++#define GMAC_REG_TPAFCR (GMAC_VA_BASE+0x48) // Tramsmit Prority Arbitration and FIFO control ++#define GMAC_REG_MACCR (GMAC_VA_BASE+0x50) // mac control register ++#define GMAC_REG_MACSR (GMAC_VA_BASE+0x54) // mac status register ++#define GMAC_REG_PHYCR (GMAC_VA_BASE+0x60) // phy control register ++#define GMAC_REG_PHYDATA (GMAC_VA_BASE+0x64) // phy data register ++#define GMAC_REG_WOLCR (GMAC_VA_BASE+0x70) // wake-on-lan control register ++#define GMAC_REG_WOLSR (GMAC_VA_BASE+0x74) // wake-on-lan status register ++#define GMAC_REG_WFCRC (GMAC_VA_BASE+0x78) // wake-up frame CRC register ++#define GMAC_REG_WFBM1 (GMAC_VA_BASE+0x80) // wake-up frame byte mask 1st ++#define GMAC_REG_WFBM2 (GMAC_VA_BASE+0x84) // wake-up frame byte mask 2nd ++#define GMAC_REG_WFBM3 (GMAC_VA_BASE+0x88) // wake-up frame byte mask 3rd ++#define GMAC_REG_WFBM4 (GMAC_VA_BASE+0x8c) // wake-up frame byte mask 4th ++#define GMAC_REG_RXR_PTR (GMAC_VA_BASE+0x98) // ++#define GMAC_REG_TPKT_CNT (GMAC_VA_BASE+0xa0) // tx packet count ++#define GMAC_REG_TMCOL_SCOL (GMAC_VA_BASE+0xa4) // tx mcol and scol count ++#define GMAC_REG_TECOL_FAIL (GMAC_VA_BASE+0xa8) // tx ecol and fail count ++#define GMAC_REG_TLCOL_URUN (GMAC_VA_BASE+0xac) // tx lcol and urun count ++#define GMAC_REG_RPKT_CNT (GMAC_VA_BASE+0xb0) // rx packet count ++#define GMAC_REG_BROPKT_CNT (GMAC_VA_BASE+0xb4) // broad cast packet count ++#define GMAC_REG_MULPKT_CNT (GMAC_VA_BASE+0xb8) // multicast packet count ++#define GMAC_REG_RPF_AEP (GMAC_VA_BASE+0xbc) // ++#define GMAC_REG_RUNT_CNT (GMAC_VA_BASE+0xc0) // rx runt packet ++#define GMAC_REG_CRCER_FLT (GMAC_VA_BASE+0xc4) // crc error and FLT ++#define GMAC_REG_RCOL_LOST (GMAC_VA_BASE+0xc8) // rx lost and collision count ++ ++// interrupt enable ++#define GMAC_IME_PHY_STS_CHG_MASK (BIT_MASK(9, 9)) // ++#define GMAC_IME_PHY_STS_CHG_OFFSET (9) ++#define GMAC_IME_AHB_ERR_MASK (BIT_MASK(8, 8)) // ++#define GMAC_IME_AHB_ERR_OFFSET (8) ++#define GMAC_IME_TPKT_LOST_MASK (BIT_MASK(7, 7)) // ++#define GMAC_IME_TPKT_LOST_OFFSET (7) ++#define GMAC_IME_TXBUF_UNAVA_MASK (BIT_MASK(6, 6)) // ++#define GMAC_IME_TXBUF_UNAVA_OFFSET (6) ++#define GMAC_IME_TPKT2F_MASK (BIT_MASK(5, 5)) // ++#define GMAC_IME_TPKT2F_OFFSET (5) ++#define GMAC_IME_TPKT2B_MASK (BIT_MASK(4, 4)) // ++#define GMAC_IME_TPKT2B_OFFSET (4) ++#define GMAC_IME_RPKT_LOST_MASK (BIT_MASK(3, 3)) // ++#define GMAC_IME_RPKT_LOST_OFFSET (3) ++#define GMAC_IME_RXBUF_UNAVA_MASK (BIT_MASK(2, 2)) // ++#define GMAC_IME_RXBUF_UNAVA_OFFSET (2) ++#define GMAC_IME_RPKT2F_MASK (BIT_MASK(1, 1)) // ++#define GMAC_IME_RPKT2F_OFFSET (1) ++#define GMAC_IME_RPKT2B_MASK (BIT_MASK(0, 0)) // ++#define GMAC_IME_RPKT2B_OFFSET (0) ++ ++ ++// interrupt status ++#define GMAC_ISR_PHY_STS_CHG_MASK (BIT_MASK(9, 9)) // ++#define GMAC_ISR_PHY_STS_CHG_OFFSET (9) ++#define GMAC_ISR_AHB_ERR_MASK (BIT_MASK(8, 8)) // ++#define GMAC_ISR_AHB_ERR_OFFSET (8) ++#define GMAC_ISR_TPKT_LOST_MASK (BIT_MASK(7, 7)) // ++#define GMAC_ISR_TPKT_LOST_OFFSET (7) ++#define GMAC_ISR_TXBUF_UNAVA_MASK (BIT_MASK(6, 6)) // ++#define GMAC_ISR_TXBUF_UNAVA_OFFSET (6) ++#define GMAC_ISR_TPKT2F_MASK (BIT_MASK(5, 5)) // ++#define GMAC_ISR_TPKT2F_OFFSET (5) ++#define GMAC_ISR_TPKT2B_MASK (BIT_MASK(4, 4)) // ++#define GMAC_ISR_TPKT2B_OFFSET (4) ++#define GMAC_ISR_RPKT_LOST_MASK (BIT_MASK(3, 3)) // ++#define GMAC_ISR_RPKT_LOST_OFFSET (3) ++#define GMAC_ISR_RXBUF_UNAVA_MASK (BIT_MASK(2, 2)) // ++#define GMAC_ISR_RXBUF_UNAVA_OFFSET (2) ++#define GMAC_ISR_RPKT2F_MASK (BIT_MASK(1, 1)) // ++#define GMAC_ISR_RPKT2F_OFFSET (1) ++#define GMAC_ISR_RPKT2B_MASK (BIT_MASK(0, 0)) // ++#define GMAC_ISR_RPKT2B_OFFSET (0) ++ ++//bit field for TPAFCR control ++#define GMAC_TPAFCR_TFIFO_SIZE_MASK (BIT_MASK(29, 27)) // ++#define GMAC_TPAFCR_TFIFO_SIZE_OFFSET (27) ++#define GMAC_TPAFCR_RFIFO_SIZE_MASK (BIT_MASK(26, 24)) // ++#define GMAC_TPAFCR_RFIFO_SIZE_OFFSET (24) ++#define GMAC_TPAFCR_EARLY_TXTHR_MASK (BIT_MASK(23, 16)) // ++#define GMAC_TPAFCR_EARLY_TXTHR_OFFSET (16) ++#define GMAC_TPAFCR_EARLY_RXTHR_MASK (BIT_MASK(15, 8)) // ++#define GMAC_TPAFCR_EARLY_RXTHR_OFFSET (8) ++#define GMAC_TPAFCR_HPKT_THR_MASK (BIT_MASK(7, 4)) // ++#define GMAC_TPAFCR_HPKT_THR_OFFSET (4) ++#define GMAC_TPAFCR_NPKT_THR_MASK (BIT_MASK(3, 0)) // ++#define GMAC_TPAFCR_NPKT_THR_OFFSET (0) ++ ++//bit field for MAC control ++#define GMAC_MACCR_SW_RST_MASK (BIT_MASK(31, 31)) // ++#define GMAC_MACCR_SW_RST_OFFSET (31) ++#define GMAC_MACCR_DIRECT_PATH_MASK (BIT_MASK(21, 21)) // ++#define GMAC_MACCR_DIRECT_PATH_OFFSET (21) ++#define GMAC_MACCR_SPEED_MASK (BIT_MASK(19, 19)) // ++#define GMAC_MACCR_SPEED_OFFSET (19) ++#define GMAC_MACCR_DISCARD_CRCERR_MASK (BIT_MASK(18, 18)) // ++#define GMAC_MACCR_DISCARD_CRCERR_OFFSET (18) ++#define GMAC_MACCR_BROADPKT_EN_MASK (BIT_MASK(17, 17)) // ++#define GMAC_MACCR_BROADPKT_EN_OFFSET (17) ++#define GMAC_MACCR_RX_MULTIPKT_EN_MASK (BIT_MASK(16, 16)) // ++#define GMAC_MACCR_RX_MULTIPKT_EN_OFFSET (16) ++#define GMAC_MACCR_RX_HT_EN_MASK (BIT_MASK(15, 15)) // ++#define GMAC_MACCR_RX_HT_EN_OFFSET (15) ++#define GMAC_MACCR_RX_ALLADR_MASK (BIT_MASK(14, 14)) // ++#define GMAC_MACCR_RX_ALLADR_OFFSET (14) ++#define GMAC_MACCR_JUMBO_LF_MASK (BIT_MASK(13, 13)) // ++#define GMAC_MACCR_JUMBO_LF_OFFSET (13) ++#define GMAC_MACCR_RX_RUNT_MASK (BIT_MASK(12, 12)) // ++#define GMAC_MACCR_RX_RUNT_OFFSET (12) ++#define GMAC_MACCR_CRC_APD_MASK (BIT_MASK(10, 10)) // ++#define GMAC_MACCR_CRC_APD_OFFSET (10) ++#define GMAC_MACCR_GMAC_MODE_MASK (BIT_MASK(9, 9)) // ++#define GMAC_MACCR_GMAC_MODE_OFFSET (9) ++#define GMAC_MACCR_FULLDUP_MASK (BIT_MASK(8, 8)) // ++#define GMAC_MACCR_FULLDUP_OFFSET (8) ++#define GMAC_MACCR_ENRX_IN_HALFTX_MASK (BIT_MASK(7, 7)) // ++#define GMAC_MACCR_ENRX_IN_HALFTX_OFFSET (7) ++#define GMAC_MACCR_LOOP_EN_MASK (BIT_MASK(6, 6)) // ++#define GMAC_MACCR_LOOP_EN_OFFSET (6) ++#define GMAC_MACCR_HPTXR_EN_MASK (BIT_MASK(5, 5)) // ++#define GMAC_MACCR_HPTXR_EN_OFFSET (5) ++#define GMAC_MACCR_REMOVE_VLAN_MASK (BIT_MASK(4, 4)) // ++#define GMAC_MACCR_REMOVE_VLAN_OFFSET (4) ++#define GMAC_MACCR_RXMAC_EN_MASK (BIT_MASK(3, 3)) // ++#define GMAC_MACCR_RXMAC_EN_OFFSET (3) ++#define GMAC_MACCR_TXMAC_EN_MASK (BIT_MASK(2, 2)) // ++#define GMAC_MACCR_TXMAC_EN_OFFSET (2) ++#define GMAC_MACCR_RXDMA_EN_MASK (BIT_MASK(1, 1)) // ++#define GMAC_MACCR_RXDMA_EN_OFFSET (1) ++#define GMAC_MACCR_TXDMA_EN_MASK (BIT_MASK(0, 0)) // ++#define GMAC_MACCR_TXDMA_EN_OFFSET (0) ++ ++//bit field for PHY control ++#define GMAC_PHYCR_MIIWR_MASK (BIT_MASK(27, 27)) // ++#define GMAC_PHYCR_MIIWR_OFFSET (27) ++#define GMAC_PHYCR_MIIRD_MASK (BIT_MASK(26, 26)) // ++#define GMAC_PHYCR_MIIRD_OFFSET (26) ++#define GMAC_PHYCR_REGAD_MASK (BIT_MASK(25, 21)) // register address ++#define GMAC_PHYCR_REGAD_OFFSET (21) ++#define GMAC_PHYCR_PHYAD_MASK (BIT_MASK(20, 16)) // phy address ++#define GMAC_PHYCR_PHYAD_OFFSET (16) ++#define GMAC_PHYCR_MDC_CYCTHR_MASK (BIT_MASK(5, 0)) // cycle threshold ++#define GMAC_PHYCR_MDC_CYCTHR_OFFSET (0) ++ ++//bit field for PHY data ++#define GMAC_PHYDATA_MIIRDATA_MASK (BIT_MASK(31, 16)) // read data ++#define GMAC_PHYDATA_MIIRDATA_OFFSET (16) ++#define GMAC_PHYDATA_MIIWDATA_MASK (BIT_MASK(15, 0)) // write data ++#define GMAC_PHYDATA_MIIWDATA_OFFSET (0) ++ ++//bit field for WOLCR ++#define GMAC_WOLCR_WOL_TYPE_MASK (BIT_MASK(258, 24)) // ++#define GMAC_WOLCR_WOL_TYPE_OFFSET (24) ++#define GMAC_WOLCR_SW_PDNPHY_MASK (BIT_MASK(18, 18)) // ++#define GMAC_WOLCR_SW_PDNPHY_OFFSET (18) ++#define GMAC_WOLCR_WAKEUP_SEL_MASK (BIT_MASK(17, 16)) // ++#define GMAC_WOLCR_WAKEUP_SEL_OFFSET (16) ++#define GMAC_WOLCR_PWRSAV_MASK (BIT_MASK(15, 15)) // ++#define GMAC_WOLCR_PWRSAV_OFFSET (15) ++#define GMAC_WOLCR_WAKEUP4_EN_MASK (BIT_MASK(6, 6)) // ++#define GMAC_WOLCR_WAKEUP4_EN_OFFSET (6) ++#define GMAC_WOLCR_WAKEUP3_EN_MASK (BIT_MASK(5, 5)) // ++#define GMAC_WOLCR_WAKEUP3_EN_OFFSET (5) ++#define GMAC_WOLCR_WAKEUP2_EN_MASK (BIT_MASK(4, 4)) // ++#define GMAC_WOLCR_WAKEUP2_EN_OFFSET (4) ++#define GMAC_WOLCR_WAKEUP1_EN_MASK (BIT_MASK(3, 3)) // ++#define GMAC_WOLCR_WAKEUP1_EN_OFFSET (3) ++#define GMAC_WOLCR_MAGICPKT_EN_MASK (BIT_MASK(2, 2)) // ++#define GMAC_WOLCR_MAGICPKT_EN_OFFSET (2) ++#define GMAC_WOLCR_LINKCHG1_EN_MASK (BIT_MASK(1, 1)) // read data ++#define GMAC_WOLCR_LINKCHG1_EN_OFFSET (1) ++#define GMAC_WOLCR_LINKCHG0_EN_MASK (BIT_MASK(0, 0)) // write data ++#define GMAC_WOLCR_LINKCHG0_EN_OFFSET (0) ++ ++//bit field for WOLSR ++#define GMAC_WOLSR_WAKEUP4_STS_MASK (BIT_MASK(6, 6)) // ++#define GMAC_WOLSR_WAKEUP4_STS_OFFSET (6) ++#define GMAC_WOLSR_WAKEUP3_STS_MASK (BIT_MASK(5, 5)) // ++#define GMAC_WOLSR_WAKEUP3_STS_OFFSET (5) ++#define GMAC_WOLSR_WAKEUP2_STS_MASK (BIT_MASK(4, 4)) // ++#define GMAC_WOLSR_WAKEUP2_STS_OFFSET (4) ++#define GMAC_WOLSR_WAKEUP1_STS_MASK (BIT_MASK(3, 3)) // ++#define GMAC_WOLSR_WAKEUP1_STS_OFFSET (3) ++#define GMAC_WOLSR_MAGICPKT_STS_MASK (BIT_MASK(2, 2)) // ++#define GMAC_WOLSR_MAGICPKT_STS_OFFSET (2) ++#define GMAC_WOLSR_LINKCHG1_STS_MASK (BIT_MASK(1, 1)) // read data ++#define GMAC_WOLSR_LINKCHG1_STS_OFFSET (1) ++#define GMAC_WOLSR_LINKCHG0_STS_MASK (BIT_MASK(0, 0)) // write data ++#define GMAC_WOLSR_LINKCHG0_STS_OFFSET (0) ++ ++// feature ++#define GMAC_FEAR_TFIFO_RSIZE_MASK (BIT_MASK(5, 3)) // tx fifo size ++#define GMAC_FEAR_TFIFO_RSIZE_OFFSET (3) ++#define GMAC_FEAR_RFIFO_RSIZE_MASK (BIT_MASK(2, 0)) // rx fufo size ++#define GMAC_FEAR_RFIFO_RSIZE_OFFSET (0) ++ ++// ====================================================== ++// GMAC access macro ++// ====================================================== ++#define GMAC_SET_FIELD(reg, field, value) SET_FIELD(GMAC_REG_##reg, GMAC_##reg##_##field##_##MASK, GMAC_##reg##_##field##_##OFFSET, value) ++#define GMAC_GET_FIELD(reg, field) GET_FIELD(GMAC_REG_##reg, GMAC_##reg##_##field##_##MASK, GMAC_##reg##_##field##_##OFFSET) ++#define GMAC_TEST_FIELD(reg, field) TEST_FIELD(GMAC_REG_##reg, GMAC_##reg##_##field##_##MASK) ++ ++#define GMAC_SET_REG(reg, value) SET_REG(GMAC_REG_##reg, value) ++#define GMAC_GET_REG(reg) GET_REG(GMAC_REG_##reg) ++#define GMAC_TEST_BIT(reg, field, value) VAR_TEST_BIT(value, GMAC_##reg##_##field##_##MASK) ++ ++#define GMAC_EXTRACT(reg, field, value) EXTRACT_FIELD(value, GMAC_##reg##_##field##_##MASK, GMAC_##reg##_##field##_##OFFSET ) ++#define GMAC_PREPARE(reg, field, value) PREPARE_FIELD(value, GMAC_##reg##_##field##_##MASK, GMAC_##reg##_##field##_##OFFSET ) ++ ++#define GMAC_DEFAULT(reg, field) PREPARE_FIELD(GMAC_##reg##_##field##_##DEFAULT, GMAC_##reg##_##field##_##MASK, GMAC_##reg##_##field##_##OFFSET ) ++ ++#define GMAC_TEST_SIG(var, sig) VAR_TEST_BIT(var, GMAC_ISR_SIG_##sig) ++#define GMAC_SET_SIG(var, sig) VAR_SET_BIT(var, GMAC_ISR_SIG_##sig) ++#define GMAC_CLR_SIG(var, sig) VAR_CLR_BIT(var, GMAC_ISR_SIG_##sig) ++ ++#define FTGMAC100_MEM_BASE (CPE_DDR2_MEM_BASE + 0x00700000) //new: higher space of RAM ++#define FTGMAC100_TXR_BASE (FTGMAC100_MEM_BASE) // 2048 des., 4 byte, 4 DWs ++#define FTGMAC100_RXR_BASE (FTGMAC100_MEM_BASE+ 4096*4*4*2) // offset 2 BASE ADDRESS ++#define FTGMAC100_TXBUF_BASE (FTGMAC100_MEM_BASE+ 0x100000) // offset 2 SIZE ADDRESS ++#define FTGMAC100_RXBUF_BASE (FTGMAC100_MEM_BASE+ 0x400000) // offset 3 SIZE ADDRESS ++ ++#define FTGMAC100_DESCRIPTOR_BYTE 16 ++#define FTGMAC100_RXBUF_SIZE 1024 ++ ++//#define GMAC_DAH (0xef12) ++//#define GMAC_DAL (0x3456789a) ++#define GMAC_DAH (0x5555) ++#define GMAC_DAL (0x55555555) ++ ++// ====================================================== ++// DAVICOM DM9161A PHY register definition ++// ====================================================== ++#define DVC_PHY_ID (0x0181b8a0) ++#define DVC_PHY_ADDR (0x0) ++#define DVC_PHY_REG_CTL (0) ++#define DVC_PHY_REG_STS (1) ++#define DVC_PHY_REG_CFG (17) ++#define DVC_PHY_REG_CTL_SW_RST (0x1<<15) ++#define DVC_PHY_REG_CTL_AN_EN (0x1<<12) ++#define DVC_PHY_REG_CTL_AN_RST (0x1<<9) ++#define DVC_PHY_REG_CTL_LOOPBACK (0x1<<14) ++ ++// ====================================================== ++// Marvell 88E1119R GPHY register definition ++// ====================================================== ++#define MAR_GPHY_ID (0x01410e80) ++#define MAR_GPHY_ADDR (0x1f) ++#define MAR_GPHY_REG_CTL (0) ++#define MAR_GPHY_REG_STS (1) ++#define MAR_GPHY_REG_ID0 (2) ++#define MAR_GPHY_REG_ID1 (3) ++#define MAR_GPHY_REG_LPA (5) ++#define MAR_GPHY_REG_COP_CTL (16) // page 0 ++#define MAR_GPHY_REG_MAC1 (16) // page 2 ++#define MAR_GPHY_REG_LED_CTL (16) // page 3 ++#define MAR_GPHY_REG_PKT_GEN (16) // page 6 ++#define MAR_GPHY_REG_COP_STS1 (17) // page 0 ++#define MAR_GPHY_REG_LED_POLAR (17) // page 3 ++#define MAR_GPHY_REG_COP_STS2 (19) // page 0 ++#define MAR_GPHY_REG_MAC2 (21) // page 2 ++#define MAR_GPHY_REG_MAC_INT_EN (18) // page 0 ++#define MAR_GPHY_REG_MAC_STS (19) // page 2 ++#define MAR_GPHY_REG_PAGE (22) ++ ++#define MAR_GPHY_REG_CTL_SW_RST (0x1<<15) ++#define MAR_GPHY_REG_CTL_AN_EN (0x1<<12) ++#define MAR_GPHY_REG_CTL_START_AN (0x1<<9) ++#define MAR_GPHY_REG_CTL_FULL_DUP (0x1<<8) ++#define MAR_GPHY_REG_CTL_LOOPBACK (0x1<<14) ++#define MAR_GPHY_REG_CTL_SPEED ((0x1<<13)|(0x1<<6)) ++#define MAR_GPHY_REG_CTL_SPEED_1000M (0x1<<6) ++#define MAR_GPHY_REG_CTL_SPEED_100M (0x1<<13) ++#define MAR_GPHY_REG_CTL_SPEED_10M (0x0) ++#define MAR_GPHY_REG_STS_AN_COMPLETE (0x1<<5) ++#define MAR_GPHY_REG_MAC1_CLK125_DIS (0x1<<2) ++#define MAR_GPHY_REG_MAC2_SPEED (0x7) ++#define MAR_GPHY_REG_MAC2_SPEED_1000M (0x6) ++#define MAR_GPHY_REG_MAC2_SPEED_100M (0x1) //(0x5) ++#define MAR_GPHY_REG_MAC2_SPEED_10M (0x4) ++#define MAR_GPHY_REG_MAC2_LINE_LOOPBACK (0x1<<14) ++#define MAR_GPHY_REG_EN_STUB (0x1<<5) ++ ++typedef struct { ++ UINT8 speed; // 0=10Mbps, 1=100Mbps, 2=1000Mbps ++ UINT8 duplex; // 0=half, 1=full ++} ETH_PHY_STAT; ++ ++ ++INT32 gmac_test_main(); ++INT32 gmac_stress_main(UINT32 test_item, UINT32 test_cnt); ++INT32 gmac_phy_check(); ++INT32 gmac_phy_pwr_ctl(UINT32 pwr); ++ ++void eth_mac_init(ETH_PHY_STAT *phy_stat); ++void eth_mac_config(UINT32 type); ++void eth_mac_register_dump(); ++INT32 eth_mac_interrupt_setup(); ++ ++INT32 eth_phy_detect(UINT32* phy_addr, UINT32* phy_id); ++INT32 eth_phy_hook_driver (UINT32 phy_id); ++ ++void eth_phy_init_mar(UINT32 phy_addr); ++void eth_phy_init_dvc(UINT32 phy_addr); ++//typedef void (*FP_ETH_PHY_INIT)(UINT32 phy_addr); ++ ++void eth_phy_config_dvc(UINT32 type, UINT32 phy_addr); ++void eth_phy_config_mar(UINT32 type, UINT32 phy_addr); ++//typedef void (*FP_ETH_PHY_CONFIG)(UINT32 type, UINT32 phy_addr); ++ ++UINT32 eth_phy_stat_dvc(UINT32 phy_addr, ETH_PHY_STAT *phy_stat); ++UINT32 eth_phy_stat_mar(UINT32 phy_addr, ETH_PHY_STAT *phy_stat); ++//typedef UINT32 (*FP_ETH_PHY_STAT)(UINT32 phy_addr, ETH_PHY_STAT *phy_stat); ++ ++//typedef UINT32 (*FP_ETH_PHY_REG_READ)(UINT32 phy_addr, UINT32 phy_page, UINT32 phy_reg, UINT32 *phy_data); ++//typedef UINT32 (*FP_ETH_PHY_REG_WRITE)(UINT32 phy_addr, UINT32 phy_page, UINT32 phy_reg, UINT32 phy_data); ++ ++//extern FP_ETH_PHY_CONFIG eth_phy_config; ++//extern FP_ETH_PHY_INIT eth_phy_init; ++//extern FP_ETH_PHY_STAT eth_phy_stat; ++//extern FP_ETH_PHY_REG_WRITE eth_phy_reg_write; ++//extern FP_ETH_PHY_REG_READ eth_phy_reg_read; ++ ++ ++#endif // __GMAC_H +\ No newline at end of file +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag102/Kconfig linux-3.4.110/arch/nds32/platforms/ag102/Kconfig +--- linux-3.4.110.orig/arch/nds32/platforms/ag102/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag102/Kconfig 2016-04-07 10:20:51.002083345 +0200 +@@ -0,0 +1,16 @@ ++menu "AG102 Platform Options" ++ ++config CACHE_L2 ++ bool "Support L2 cache" ++ default y ++ ++config LPC ++ bool "LPC support" ++ ++config AUTO_SYS_CLK ++ bool "Automatic AHB Clock Detection" ++ default y ++ help ++ Automatic detection of AHB clock ++ ++endmenu +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag102/lpc.c linux-3.4.110/arch/nds32/platforms/ag102/lpc.c +--- linux-3.4.110.orig/arch/nds32/platforms/ag102/lpc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag102/lpc.c 2016-04-07 10:20:51.002083345 +0200 +@@ -0,0 +1,230 @@ ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/delay.h> ++ ++#include <asm/spec.h> ++ ++#define LPC_REG_SCR 0x10 ++#define LPC_REG_SIR 0x14 ++#define LPC_REG_SIMR 0x18 ++ ++/* ++ * Level trigger IRQ chip methods ++ */ ++ ++static void lpc_level_unmask_irq(unsigned int irq) ++{ ++ unsigned int val; ++// *(volatile unsigned int *) (LPC_REG_BASE + LPC_REG_SIR) = ++// 1 << (irq - PLATFORM_LPC_IRQ_BASE); ++ val = *(volatile unsigned int *)(LPC_REG_VA_BASE + LPC_REG_SIMR); ++ val &= ~(1 << (irq - PLATFORM_LPC_IRQ_BASE)); ++ *(volatile unsigned int *)(LPC_REG_VA_BASE + LPC_REG_SIMR) = val; ++} ++ ++static void lpc_level_mask_irq(unsigned int irq) ++{ ++ unsigned int val; ++ val = *(volatile unsigned int *)(LPC_REG_VA_BASE + LPC_REG_SIMR); ++ val |= 1 << (irq - PLATFORM_LPC_IRQ_BASE); ++ *(volatile unsigned int *)(LPC_REG_VA_BASE + LPC_REG_SIMR) = val; ++} ++ ++static void lpc_level_ack_irq(unsigned int irq) ++{ ++ *(volatile unsigned int *)(LPC_REG_VA_BASE + LPC_REG_SIR) = ++ 1 << (irq - PLATFORM_LPC_IRQ_BASE); ++} ++ ++static struct irq_chip lpc_simple_chip = { ++ .ack = lpc_level_ack_irq, ++ .mask = lpc_level_mask_irq, ++ .unmask = lpc_level_unmask_irq, ++}; ++ ++void lpc_irq_rounter(unsigned int irq, struct irq_desc *desc) ++{ ++ unsigned int lpc_status; ++ unsigned int lpc_mask; ++ unsigned int lpc_irq; ++ int i; ++ struct irq_desc *lpc_desc; ++ ++ desc->chip->mask(irq); ++ desc->chip->ack(irq); ++ ++ lpc_status = *(volatile unsigned int *)(LPC_REG_VA_BASE + LPC_REG_SIR); ++ lpc_mask = *(volatile unsigned int *)(LPC_REG_VA_BASE + LPC_REG_SIMR); ++ *(volatile unsigned int *)(LPC_REG_VA_BASE + LPC_REG_SIMR) = 0xffffffff; ++ for (i = 0; i < PLATFORM_LPC_IRQ_TOTALCOUNT; i++) { ++ if (!(~lpc_mask & (1 << i) & lpc_status)) ++ continue; ++ lpc_irq = PLATFORM_LPC_IRQ_BASE + i; ++ lpc_desc = irq_desc + lpc_irq; ++ lpc_desc->handle_irq(lpc_irq, lpc_desc); ++ *(volatile unsigned int *)(LPC_REG_VA_BASE + LPC_REG_SIR) = ++ 1 << i; ++ } ++ *(volatile unsigned int *)(LPC_REG_VA_BASE + LPC_REG_SIMR) = lpc_mask; ++ ++ desc->chip->unmask(irq); ++} ++ ++int __init lpc_init_irq(void) ++{ ++ int i; ++ ++ *(volatile unsigned int *)(LPC_REG_VA_BASE + LPC_REG_SCR) = 0x1f3; ++ /* Register all IRQ */ ++ for (i = PLATFORM_LPC_IRQ_BASE; ++ i < PLATFORM_LPC_IRQ_BASE + PLATFORM_LPC_IRQ_TOTALCOUNT; i++) { ++ // level trigger ++ set_irq_chip(i, &lpc_simple_chip); ++ set_irq_handler(i, handle_simple_irq); ++ ++ } ++ set_irq_chained_handler(LPC_IRQ, lpc_irq_rounter); ++ ++ return 0; ++} ++ ++device_initcall(lpc_init_irq); ++ ++#define ITE_ADDR 0x2e ++#define ITE_DATA 0x2f ++void outlpc(unsigned int addr, unsigned int data) ++{ ++ *(volatile unsigned int *)(LPC_IO_VA_BASE + 4 * addr) = data; ++} ++ ++unsigned int inlpc(unsigned int addr) ++{ ++ return *(volatile unsigned int *)(LPC_IO_VA_BASE + 4 * addr); ++} ++ ++int __init ite8717_init(void) ++{ ++ unsigned char data1, data2; ++ unsigned int count; ++ /* enter configure mode */ ++ outlpc(ITE_ADDR, 0x87); ++ outlpc(ITE_ADDR, 0x01); ++ outlpc(ITE_ADDR, 0x55); ++ outlpc(ITE_ADDR, 0x55); ++ /* check chip */ ++ outlpc(ITE_ADDR, 0x20); ++ data1 = inlpc(ITE_DATA); ++ outlpc(ITE_ADDR, 0x21); ++ data2 = inlpc(ITE_DATA); ++ if ((data1 != 0x87) && (data2 != 0x17)) ++ goto not_found; ++ /* earlyio program */ ++ outlpc(ITE_ADDR, 0x07); // LDN=0 -> FDC ++ outlpc(ITE_DATA, 0x00); ++ outlpc(ITE_ADDR, 0x30); // Enable FDC ++ outlpc(ITE_DATA, 0x01); ++ outlpc(ITE_ADDR, 0xf1); // Set (Index 0F1h) = 90h ++ outlpc(ITE_DATA, 0x80); ++ ++ outlpc(0x64, 0xaa); // Send KBC self-test command ++ count = 0; ++ do { ++ if (count++ > 0x10000) ++ break; ++ data1 = ~inlpc(0x64); ++ } while (data1 & 0x01); ++ data2 = inlpc(0x60); ++ outlpc(0x64, 0xcb); // Set PS2 mode ++ count = 0; ++ do { ++ if (count++ > 0x10000) ++ break; ++ data1 = inlpc(0x64); ++ } while (data1 & 0x02); ++ outlpc(0x60, 0x01); ++ count = 0; ++ do { ++ if (count++ > 0x10000) ++ break; ++ data1 = inlpc(0x64); ++ } while (data1 & 0x02); ++ outlpc(0x64, 0x60); // 60h = write 8042 command byte ++ count = 0; ++ do { ++ if (count++ > 0x10000) ++ break; ++ data1 = inlpc(0x64); ++ } while (data1 & 0x02); ++ outlpc(0x60, 0x45); // AT interface, keyboard enabled, system flag ++ count = 0; ++ do { ++ if (count++ > 0x10000) ++ break; ++ data1 = inlpc(0x64); ++ } while (data1 & 0x02); ++ outlpc(0x64, 0xae); ++ count = 0; ++ do { ++ if (count++ > 0x10000) ++ break; ++ data1 = ~inlpc(0x64); ++ } while (data1 & 0x01); ++ outlpc(ITE_ADDR, 0x23); ++ outlpc(ITE_DATA, 0x00); ++ ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x04); ++ outlpc(ITE_ADDR, 0xf0); ++ data1 = inlpc(ITE_DATA); ++ data1 &= 0x18; ++ data1 |= 0x0; ++ outlpc(ITE_DATA, data1); ++ outlpc(ITE_ADDR, 0xf2); ++ data1 = inlpc(ITE_DATA); ++ data1 &= 0x2e; ++ data1 |= 0xa; ++ outlpc(ITE_DATA, data1); ++ outlpc(ITE_ADDR, 0xf4); ++ data1 = inlpc(ITE_DATA); ++ data1 &= 0xaf; ++ data1 |= 0x80; ++ outlpc(ITE_DATA, data1); ++ outlpc(ITE_ADDR, 0xf5); ++ data1 = inlpc(ITE_DATA); ++ data1 &= 0x3f; ++ data1 |= 0x0; ++ outlpc(ITE_DATA, data1); ++ /* initialize all device */ ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x04); ++ outlpc(ITE_ADDR, 0x30); ++ outlpc(ITE_DATA, 0x01); ++#if 1 ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x05); ++ outlpc(ITE_ADDR, 0xf0); ++ outlpc(ITE_DATA, 0x4e); ++ outlpc(ITE_ADDR, 0x71); ++ outlpc(ITE_DATA, 0x01); ++#endif ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x06); ++ outlpc(ITE_ADDR, 0x30); ++ outlpc(ITE_DATA, 0x01); ++#if 1 ++ outlpc(ITE_ADDR, 0xf0); ++ outlpc(ITE_DATA, 0x01); ++ outlpc(ITE_ADDR, 0x71); ++ outlpc(ITE_DATA, 0x01); ++#endif ++ ++ /* exit configure mode */ ++ outlpc(ITE_ADDR, 0x02); ++ outlpc(ITE_DATA, 0x02); ++ return 0; ++not_found: ++ printk("ITE8717 not found\n"); ++ return -1; ++} ++ ++subsys_initcall(ite8717_init); +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag102/Makefile linux-3.4.110/arch/nds32/platforms/ag102/Makefile +--- linux-3.4.110.orig/arch/nds32/platforms/ag102/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag102/Makefile 2016-04-07 10:20:51.002083345 +0200 +@@ -0,0 +1,5 @@ ++obj-y += devices.o ahbclkcal.o ++obj-$(CONFIG_LPC) += lpc.o ++obj-$(CONFIG_PM) += pm.o sleep.o ++obj-$(CONFIG_AG102_CPU_FREQ_FCS) += cpu-fcs.o ++obj-$(CONFIG_AG102_CPU_FREQ_SCALING_MODE) += freq-scaling.o +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag102/pcu.h linux-3.4.110/arch/nds32/platforms/ag102/pcu.h +--- linux-3.4.110.orig/arch/nds32/platforms/ag102/pcu.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag102/pcu.h 2016-04-07 10:20:51.002083345 +0200 +@@ -0,0 +1,1887 @@ ++#ifndef __PCU_H ++#define __PCU_H ++#include <asm/spec.h> ++#define CPE_PCU_BASE PCU_VA_BASE ++//Data type ++typedef enum Bool { ++ FALSE, ++ TRUE ++} BOOL; ++ ++typedef enum { ++ SUCCESS=0, ++ FAIL ++} STATUS; ++ ++typedef unsigned char UINT8; ++typedef char INT8; ++typedef unsigned short UINT16; ++typedef short INT16; ++typedef unsigned int UINT32; ++typedef int INT32; ++typedef unsigned long long UINT64; ++typedef long long INT64; ++ ++//Registion IO operation macro ++#define REG32(a) (*(volatile UINT32 *)(a)) ++#define REG16(a) (*(volatile UINT16 *)(a)) ++#define REG8(a) (*(volatile UINT8 *)(a)) ++ ++#define inb(a) REG8(a) ++#define inhw(a) REG16(a) ++#define inw(a) REG32(a) ++ ++#define outb(a, v) (REG8(a) = (UINT8)(v)) ++#define outhw(a, v) (REG16(a) = (UINT16)(v)) ++#define outw(a, v) (REG32(a) = (UINT32)(v)) ++ ++ ++// Register bit operation macro ++#define ANDES_BIT_MASK(bit_h, bit_l) ((((UINT32)0x1<<(1+bit_h-bit_l))-(UINT32)0x1)<<bit_l) ++ ++ ++#define SET_BIT(addr, bit) do { outw(addr, (inw(addr) | (0x1<<(bit)))); } while(0) ++#define CLR_BIT(addr, bit) do { outw(addr, (inw(addr) & (~(0x1<<(bit))))); } while(0) ++ ++#define SET_FIELD(addr, mask, offset, value) do {\ ++ outw(addr, ((inw(addr) & (~mask)) | (((value) << (offset)) &(mask)))); \ ++ } while (0) ++#define GET_FIELD(addr, mask, offset) ((inw(addr)&(mask))>> (offset)) ++ ++#define TEST_FIELD(addr, mask) (inw(addr)&(mask)) ++ ++#define SET_REG(addr, value) do { outw(addr, value); } while (0) ++#define GET_REG(addr) (inw(addr)) ++ ++#define CHECK_FIELD(value, mask) ( (value)&(mask) ) ++#define EXTRACT_FIELD(value, mask, offset) ( ((value)&(mask))>>(offset) ) ++#define PREPARE_FIELD(value, mask, offset) ( ((value)<<(offset))&(mask) ) ++ ++ ++// Variable bit operation macro ++#define VAR_TEST_BIT(var, sig) ((var)&(sig)) ++#define VAR_SET_BIT(var, sig) ((var) = (var)|(sig)) ++#define VAR_CLR_BIT(var, sig) ((var) = (var)&(~(sig))) ++// ============================ ++// PCU register definition ++// ============================ ++#define PCU_REG_VER (CPE_PCU_BASE+0x000) //version ++#define PCU_REG_SPINFO (CPE_PCU_BASE+0x004) //scartch pad information ++#define PCU_REG_SOCID (CPE_PCU_BASE+0x010) //SoC ID ++#define PCU_REG_AHB_CFG (CPE_PCU_BASE+0x014) //AHB device configuration ++#define PCU_REG_APB_CFG (CPE_PCU_BASE+0x018) //APB device configuration ++#define PCU_REG_DCSR0 (CPE_PCU_BASE+0x020) //driving capability and slew rate control 0 ++#define PCU_REG_DCSR1 (CPE_PCU_BASE+0x024) //driving capability and slew rate control 1 ++#define PCU_REG_DCSR2 (CPE_PCU_BASE+0x028) //driving capability and slew rate control 2 ++#define PCU_REG_MFPS0 (CPE_PCU_BASE+0x030) //multi-function port setting 0 ++#define PCU_REG_MFPS1 (CPE_PCU_BASE+0x034) //multi-function port setting 1 ++#define PCU_REG_DMA_SEL (CPE_PCU_BASE+0x038) //dma engin selection ++#define PCU_REG_OSC_CTRL (CPE_PCU_BASE+0x040) //OSC control register ++#define PCU_REG_PWM_DIV (CPE_PCU_BASE+0x044) //PWM clock divider value ++#define PCU_REG_MISC (CPE_PCU_BASE+0x048) //misc register ++#define PCU_REG_BSM_CTRL (CPE_PCU_BASE+0x080) //BSM control register ++#define PCU_REG_BSM_STATUS (CPE_PCU_BASE+0x084) //BSM status ++#define PCU_REG_WAKEUP_SEN (CPE_PCU_BASE+0x088) //wakeup event signal sensitivity ++#define PCU_REG_WAKEUP_STATUS (CPE_PCU_BASE+0x08c) //wakeup event status ++#define PCU_REG_RESET_TIMER (CPE_PCU_BASE+0x090) //reset timer register ++#define PCU_REG_INTR (CPE_PCU_BASE+0x094) //interrup register ++#define PCU_REG_PCS1_CFG (CPE_PCU_BASE+0x0a0) ++#define PCU_REG_PCS1_PARA (CPE_PCU_BASE+0x0a4) ++#define PCU_REG_PCS1_ST1 (CPE_PCU_BASE+0x0a8) ++#define PCU_REG_PCS1_ST2 (CPE_PCU_BASE+0x0ac) ++#define PCU_REG_PCS1_PDD (CPE_PCU_BASE+0x0b0) ++#define PCU_REG_PCS2_CFG (CPE_PCU_BASE+0x0c0) ++#define PCU_REG_PCS2_PARA (CPE_PCU_BASE+0x0c4) ++#define PCU_REG_PCS2_ST1 (CPE_PCU_BASE+0x0c8) ++#define PCU_REG_PCS2_ST2 (CPE_PCU_BASE+0x0cc) ++#define PCU_REG_PCS2_PDD (CPE_PCU_BASE+0x0d0) ++#define PCU_REG_PCS3_CFG (CPE_PCU_BASE+0x0e0) ++#define PCU_REG_PCS3_PARA (CPE_PCU_BASE+0x0e4) ++#define PCU_REG_PCS3_ST1 (CPE_PCU_BASE+0x0e8) ++#define PCU_REG_PCS3_ST2 (CPE_PCU_BASE+0x0ec) ++#define PCU_REG_PCS3_PDD (CPE_PCU_BASE+0x0f0) ++#define PCU_REG_PCS4_CFG (CPE_PCU_BASE+0x100) ++#define PCU_REG_PCS4_PARA (CPE_PCU_BASE+0x104) ++#define PCU_REG_PCS4_ST1 (CPE_PCU_BASE+0x108) ++#define PCU_REG_PCS4_ST2 (CPE_PCU_BASE+0x10c) ++#define PCU_REG_PCS4_PDD (CPE_PCU_BASE+0x110) ++#define PCU_REG_PCS5_CFG (CPE_PCU_BASE+0x120) ++#define PCU_REG_PCS5_PARA (CPE_PCU_BASE+0x124) ++#define PCU_REG_PCS5_ST1 (CPE_PCU_BASE+0x128) ++#define PCU_REG_PCS5_ST2 (CPE_PCU_BASE+0x12c) ++#define PCU_REG_PCS5_PDD (CPE_PCU_BASE+0x130) ++#define PCU_REG_PCS6_CFG (CPE_PCU_BASE+0x140) ++#define PCU_REG_PCS6_PARA (CPE_PCU_BASE+0x144) ++#define PCU_REG_PCS6_ST1 (CPE_PCU_BASE+0x148) ++#define PCU_REG_PCS6_ST2 (CPE_PCU_BASE+0x14c) ++#define PCU_REG_PCS6_PDD (CPE_PCU_BASE+0x150) ++#define PCU_REG_PCS7_CFG (CPE_PCU_BASE+0x160) ++#define PCU_REG_PCS7_PARA (CPE_PCU_BASE+0x164) ++#define PCU_REG_PCS7_ST1 (CPE_PCU_BASE+0x168) ++#define PCU_REG_PCS7_ST2 (CPE_PCU_BASE+0x16c) ++#define PCU_REG_PCS7_PDD (CPE_PCU_BASE+0x170) ++#define PCU_REG_PCS8_CFG (CPE_PCU_BASE+0x180) ++#define PCU_REG_PCS8_PARA (CPE_PCU_BASE+0x184) ++#define PCU_REG_PCS8_ST1 (CPE_PCU_BASE+0x188) ++#define PCU_REG_PCS8_ST2 (CPE_PCU_BASE+0x18c) ++#define PCU_REG_PCS8_PDD (CPE_PCU_BASE+0x190) ++#define PCU_REG_PCS9_CFG (CPE_PCU_BASE+0x1a0) ++#define PCU_REG_PCS9_PARA (CPE_PCU_BASE+0x1a4) ++#define PCU_REG_PCS9_ST1 (CPE_PCU_BASE+0x1a8) ++#define PCU_REG_PCS9_ST2 (CPE_PCU_BASE+0x1ac) ++#define PCU_REG_PCS9_PDD (CPE_PCU_BASE+0x1b0) ++ ++#define PCU_SCRATCH_OFFSET_SHIFT (8) ++#define PCU_SCRATCH_SIZE_SHIFT (2) // in byte, 2 means (1<<2) = 4 bytes ++#define PCU_REG_SCRATCH_MEM (CPE_PCU_BASE+ (PCU_SPINFO_OFFSET_DEFAULT<<PCU_SCRATCH_OFFSET_SHIFT) ) ++ ++// revision register ++#define PCU_VER_VER_MASK (ANDES_BIT_MASK(31, 16)) ++#define PCU_VER_VER_OFFSET (16) ++#define PCU_VER_VER_DEFAULT (0x1) ++#define PCU_VER_PCSNO_MASK (ANDES_BIT_MASK(7, 0)) ++#define PCU_VER_PCSNO_OFFSET (0) ++#define PCU_VER_PCSNO_DEFAULT (0x9) ++#define PCU_VER_DEFAULT ((PCU_VER_VER_DEFAULT << PCU_VER_VER_OFFSET ) |\ ++ (PCU_VER_PCSNO_DEFAULT << PCU_VER_PCSNO_OFFSET)) ++ ++//scratch pad info ++#define PCU_SPINFO_OFFSET_MASK (ANDES_BIT_MASK(11, 8)) ++#define PCU_SPINFO_OFFSET_OFFSET (8) ++#define PCU_SPINFO_OFFSET_DEFAULT (0x4) ++#define PCU_SPINFO_SIZE_MASK (ANDES_BIT_MASK(7, 0)) ++#define PCU_SPINFO_SIZE_OFFSET (0) ++#define PCU_SPINFO_SIZE_DEFAULT (0x40) ++#define PCU_SPINFO_DEFAULT ((PCU_SPINFO_OFFSET_DEFAULT << PCU_SPINFO_OFFSET_OFFSET) |\ ++ (PCU_SPINFO_SIZE_DEFAULT << PCU_SPINFO_SIZE_OFFSET )) ++ ++// revision register ++#define PCU_SOCID_DEV_MASK (ANDES_BIT_MASK(31, 16)) ++#define PCU_SOCID_DEV_OFFSET (16) ++#define PCU_SOCID_DEV_DEFAULT (0x102) ++#define PCU_SOCID_MAJ_MASK (ANDES_BIT_MASK(15, 4)) ++#define PCU_SOCID_MAJ_OFFSET (4) ++#define PCU_SOCID_MAJ_DEFAULT (0x1) ++#define PCU_SOCID_MIN_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_SOCID_MIN_OFFSET (0) ++#define PCU_SOCID_MIN_DEFAULT (0x0) ++#define PCU_SOCID_DEFAULT ((PCU_SOCID_DEV_DEFAULT << PCU_SOCID_DEV_OFFSET) |\ ++ (PCU_SOCID_MAJ_DEFAULT << PCU_SOCID_MAJ_OFFSET) |\ ++ (PCU_SOCID_MIN_DEFAULT << PCU_SOCID_MIN_OFFSET)) ++ ++// AHB configuration ++#define PCU_AHB_CFG_AHB2AHB_MEM3_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_AHB_CFG_AHB2AHB_MEM3_OFFSET (31) ++#define PCU_AHB_CFG_AHB2AHB_MEM3_DEFAULT (0x1) ++#define PCU_AHB_CFG_AHB2AHB_MEM2_MASK (ANDES_BIT_MASK(30, 30)) ++#define PCU_AHB_CFG_AHB2AHB_MEM2_OFFSET (30) ++#define PCU_AHB_CFG_AHB2AHB_MEM2_DEFAULT (0x1) ++#define PCU_AHB_CFG_AHB2AHB_MEM1_MASK (ANDES_BIT_MASK(29, 29)) ++#define PCU_AHB_CFG_AHB2AHB_MEM1_OFFSET (29) ++#define PCU_AHB_CFG_AHB2AHB_MEM1_DEFAULT (0x1) ++#define PCU_AHB_CFG_AHB2AHB_MEM0_MASK (ANDES_BIT_MASK(28, 28)) ++#define PCU_AHB_CFG_AHB2AHB_MEM0_OFFSET (28) ++#define PCU_AHB_CFG_AHB2AHB_MEM0_DEFAULT (0x1) ++#define PCU_AHB_CFG_AHB2AHB_REG_MASK (ANDES_BIT_MASK(27, 27)) ++#define PCU_AHB_CFG_AHB2AHB_REG_OFFSET (27) ++#define PCU_AHB_CFG_AHB2AHB_REG_DEFAULT (0x1) ++#define PCU_AHB_CFG_L2CC_MASK (ANDES_BIT_MASK(20, 20)) ++#define PCU_AHB_CFG_L2CC_OFFSET (20) ++#define PCU_AHB_CFG_L2CC_DEFAULT (0x1) ++#define PCU_AHB_CFG_PCI_MEM_MASK (ANDES_BIT_MASK(19, 19)) ++#define PCU_AHB_CFG_PCI_MEM_OFFSET (19) ++#define PCU_AHB_CFG_PCI_MEM_DEFAULT (0x1) ++#define PCU_AHB_CFG_PCI_IO_MASK (ANDES_BIT_MASK(18, 18)) ++#define PCU_AHB_CFG_PCI_IO_OFFSET (18) ++#define PCU_AHB_CFG_PCI_IO_DEFAULT (0x1) ++#define PCU_AHB_CFG_LPC_REG_MASK (ANDES_BIT_MASK(17, 17)) ++#define PCU_AHB_CFG_LPC_REG_OFFSET (17) ++#define PCU_AHB_CFG_LPC_REG_DEFAULT (0x1) ++#define PCU_AHB_CFG_LPC_IO_MASK (ANDES_BIT_MASK(16, 16)) ++#define PCU_AHB_CFG_LPC_IO_OFFSET (16) ++#define PCU_AHB_CFG_LPC_IO_DEFAULT (0x1) ++#define PCU_AHB_CFG_INTC_MASK (ANDES_BIT_MASK(15, 15)) ++#define PCU_AHB_CFG_INTC_OFFSET (15) ++#define PCU_AHB_CFG_INTC_DEFAULT (0x1) ++#define PCU_AHB_CFG_USB_MASK (ANDES_BIT_MASK(14, 14)) ++#define PCU_AHB_CFG_USB_OFFSET (14) ++#define PCU_AHB_CFG_USB_DEFAULT (0x1) ++#define PCU_AHB_CFG_IDE_MASK (ANDES_BIT_MASK(13, 13)) ++#define PCU_AHB_CFG_IDE_OFFSET (13) ++#define PCU_AHB_CFG_IDE_DEFAULT (0x1) ++#define PCU_AHB_CFG_GMAC_MASK (ANDES_BIT_MASK(12, 12)) ++#define PCU_AHB_CFG_GMAC_OFFSET (12) ++#define PCU_AHB_CFG_GMAC_DEFAULT (0x1) ++#define PCU_AHB_CFG_GPU_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_AHB_CFG_GPU_OFFSET (9) ++#define PCU_AHB_CFG_GPU_DEFAULT (0x1) ++#define PCU_AHB_CFG_DLM2_MASK (ANDES_BIT_MASK(8, 8)) ++#define PCU_AHB_CFG_DLM2_OFFSET (8) ++#define PCU_AHB_CFG_DLM2_DEFAULT (0x1) ++#define PCU_AHB_CFG_DMAC_MASK (ANDES_BIT_MASK(7, 7)) ++#define PCU_AHB_CFG_DMAC_OFFSET (7) ++#define PCU_AHB_CFG_DMAC_DEFAULT (0x1) ++#define PCU_AHB_CFG_DDR2_MEM_MASK (ANDES_BIT_MASK(6, 6)) ++#define PCU_AHB_CFG_DDR2_MEM_OFFSET (6) ++#define PCU_AHB_CFG_DDR2_MEM_DEFAULT (0x1) ++#define PCU_AHB_CFG_DDR2C_MASK (ANDES_BIT_MASK(5, 5)) ++#define PCU_AHB_CFG_DDR2C_OFFSET (5) ++#define PCU_AHB_CFG_DDR2C_DEFAULT (0x1) ++#define PCU_AHB_CFG_SPI_MASK (ANDES_BIT_MASK(4, 4)) ++#define PCU_AHB_CFG_SPI_OFFSET (4) ++#define PCU_AHB_CFG_SPI_DEFAULT (0x1) ++#define PCU_AHB_CFG_DLM1_MASK (ANDES_BIT_MASK(3, 3)) ++#define PCU_AHB_CFG_DLM1_OFFSET (3) ++#define PCU_AHB_CFG_DLM1_DEFAULT (0x1) ++#define PCU_AHB_CFG_APB_MASK (ANDES_BIT_MASK(2, 2)) ++#define PCU_AHB_CFG_APB_OFFSET (2) ++#define PCU_AHB_CFG_APB_DEFAULT (0x1) ++#define PCU_AHB_CFG_APBREG_MASK (ANDES_BIT_MASK(1, 1)) ++#define PCU_AHB_CFG_APBREG_OFFSET (1) ++#define PCU_AHB_CFG_APBREG_DEFAULT (0x1) ++#define PCU_AHB_CFG_AHBC_MASK (ANDES_BIT_MASK(0, 0)) ++#define PCU_AHB_CFG_AHBC_OFFSET (0) ++#define PCU_AHB_CFG_AHBC_DEFAULT (0x1) ++#define PCU_AHB_CFG_DEFAULT ((PCU_AHB_CFG_AHB2AHB_MEM3_DEFAULT << PCU_AHB_CFG_AHB2AHB_MEM3_OFFSET) |\ ++ (PCU_AHB_CFG_AHB2AHB_MEM2_DEFAULT << PCU_AHB_CFG_AHB2AHB_MEM2_OFFSET) |\ ++ (PCU_AHB_CFG_AHB2AHB_MEM1_DEFAULT << PCU_AHB_CFG_AHB2AHB_MEM1_OFFSET) |\ ++ (PCU_AHB_CFG_AHB2AHB_MEM0_DEFAULT << PCU_AHB_CFG_AHB2AHB_MEM0_OFFSET) |\ ++ (PCU_AHB_CFG_AHB2AHB_REG_DEFAULT << PCU_AHB_CFG_AHB2AHB_REG_OFFSET ) |\ ++ (PCU_AHB_CFG_L2CC_DEFAULT << PCU_AHB_CFG_L2CC_OFFSET ) |\ ++ (PCU_AHB_CFG_PCI_MEM_DEFAULT << PCU_AHB_CFG_PCI_MEM_OFFSET ) |\ ++ (PCU_AHB_CFG_PCI_IO_DEFAULT << PCU_AHB_CFG_PCI_IO_OFFSET ) |\ ++ (PCU_AHB_CFG_LPC_REG_DEFAULT << PCU_AHB_CFG_LPC_REG_OFFSET ) |\ ++ (PCU_AHB_CFG_LPC_IO_DEFAULT << PCU_AHB_CFG_LPC_IO_OFFSET ) |\ ++ (PCU_AHB_CFG_INTC_DEFAULT << PCU_AHB_CFG_INTC_OFFSET ) |\ ++ (PCU_AHB_CFG_USB_DEFAULT << PCU_AHB_CFG_USB_OFFSET ) |\ ++ (PCU_AHB_CFG_IDE_DEFAULT << PCU_AHB_CFG_IDE_OFFSET ) |\ ++ (PCU_AHB_CFG_GMAC_DEFAULT << PCU_AHB_CFG_GMAC_OFFSET ) |\ ++ (PCU_AHB_CFG_GPU_DEFAULT << PCU_AHB_CFG_GPU_OFFSET ) |\ ++ (PCU_AHB_CFG_DLM2_DEFAULT << PCU_AHB_CFG_DLM2_OFFSET ) |\ ++ (PCU_AHB_CFG_DMAC_DEFAULT << PCU_AHB_CFG_DMAC_OFFSET ) |\ ++ (PCU_AHB_CFG_DDR2_MEM_DEFAULT << PCU_AHB_CFG_DDR2_MEM_OFFSET ) |\ ++ (PCU_AHB_CFG_DDR2C_DEFAULT << PCU_AHB_CFG_DDR2C_OFFSET ) |\ ++ (PCU_AHB_CFG_SPI_DEFAULT << PCU_AHB_CFG_SPI_OFFSET ) |\ ++ (PCU_AHB_CFG_DLM1_DEFAULT << PCU_AHB_CFG_DLM1_OFFSET ) |\ ++ (PCU_AHB_CFG_APB_DEFAULT << PCU_AHB_CFG_APB_OFFSET ) |\ ++ (PCU_AHB_CFG_APBREG_DEFAULT << PCU_AHB_CFG_APBREG_OFFSET ) |\ ++ (PCU_AHB_CFG_AHBC_DEFAULT << PCU_AHB_CFG_AHBC_OFFSET )) ++ ++// APB configuration ++#define PCU_APB_CFG_PWM_MASK (ANDES_BIT_MASK(23, 23)) ++#define PCU_APB_CFG_PWM_OFFSET (23) ++#define PCU_APB_CFG_PWM_DEFAULT (0x1) ++#define PCU_APB_CFG_I2C_MASK (ANDES_BIT_MASK(22, 22)) ++#define PCU_APB_CFG_I2C_OFFSET (22) ++#define PCU_APB_CFG_I2C_DEFAULT (0x1) ++#define PCU_APB_CFG_GPIO_MASK (ANDES_BIT_MASK(20, 20)) ++#define PCU_APB_CFG_GPIO_OFFSET (20) ++#define PCU_APB_CFG_GPIO_DEFAULT (0x1) ++#define PCU_APB_CFG_RTC_MASK (ANDES_BIT_MASK(19, 19)) ++#define PCU_APB_CFG_RTC_OFFSET (19) ++#define PCU_APB_CFG_RTC_DEFAULT (0x1) ++#define PCU_APB_CFG_WDT_MASK (ANDES_BIT_MASK(18, 18)) ++#define PCU_APB_CFG_WDT_OFFSET (18) ++#define PCU_APB_CFG_WDT_DEFAULT (0x1) ++#define PCU_APB_CFG_TMR_MASK (ANDES_BIT_MASK(17, 17)) ++#define PCU_APB_CFG_TMR_OFFSET (17) ++#define PCU_APB_CFG_TMR_DEFAULT (0x1) ++#define PCU_APB_CFG_PCU_MASK (ANDES_BIT_MASK(16, 16)) ++#define PCU_APB_CFG_PCU_OFFSET (16) ++#define PCU_APB_CFG_PCU_DEFAULT (0x1) ++#define PCU_APB_CFG_UART2_MASK (ANDES_BIT_MASK(8, 8)) ++#define PCU_APB_CFG_UART2_OFFSET (8) ++#define PCU_APB_CFG_UART2_DEFAULT (0x1) ++#define PCU_APB_CFG_AC97I2C_MASK (ANDES_BIT_MASK(6, 6)) ++#define PCU_APB_CFG_AC97I2C_OFFSET (6) ++#define PCU_APB_CFG_AC97I2C_DEFAULT (0x1) ++#define PCU_APB_CFG_SDC_MASK (ANDES_BIT_MASK(5, 5)) ++#define PCU_APB_CFG_SDC_OFFSET (5) ++#define PCU_APB_CFG_SDC_DEFAULT (0x1) ++#define PCU_APB_CFG_UART1_MASK (ANDES_BIT_MASK(3, 3)) ++#define PCU_APB_CFG_UART1_OFFSET (3) ++#define PCU_APB_CFG_UART1_DEFAULT (0x1) ++#define PCU_APB_CFG_SSP_MASK (ANDES_BIT_MASK(2, 2)) ++#define PCU_APB_CFG_SSP_OFFSET (2) ++#define PCU_APB_CFG_SSP_DEFAULT (0x1) ++#define PCU_APB_CFG_CFC_MASK (ANDES_BIT_MASK(1, 1)) ++#define PCU_APB_CFG_CFC_OFFSET (1) ++#define PCU_APB_CFG_CFC_DEFAULT (0x1) ++#define PCU_APB_CFG_DEFAULT ((PCU_APB_CFG_PWM_DEFAULT << PCU_APB_CFG_PWM_OFFSET ) |\ ++ (PCU_APB_CFG_I2C_DEFAULT << PCU_APB_CFG_I2C_OFFSET ) |\ ++ (PCU_APB_CFG_GPIO_DEFAULT << PCU_APB_CFG_GPIO_OFFSET ) |\ ++ (PCU_APB_CFG_RTC_DEFAULT << PCU_APB_CFG_RTC_OFFSET ) |\ ++ (PCU_APB_CFG_WDT_DEFAULT << PCU_APB_CFG_WDT_OFFSET ) |\ ++ (PCU_APB_CFG_TMR_DEFAULT << PCU_APB_CFG_TMR_OFFSET ) |\ ++ (PCU_APB_CFG_PCU_DEFAULT << PCU_APB_CFG_PCU_OFFSET ) |\ ++ (PCU_APB_CFG_UART2_DEFAULT << PCU_APB_CFG_UART2_OFFSET ) |\ ++ (PCU_APB_CFG_AC97I2C_DEFAULT << PCU_APB_CFG_AC97I2C_OFFSET) |\ ++ (PCU_APB_CFG_SDC_DEFAULT << PCU_APB_CFG_SDC_OFFSET ) |\ ++ (PCU_APB_CFG_UART1_DEFAULT << PCU_APB_CFG_UART1_OFFSET ) |\ ++ (PCU_APB_CFG_SSP_DEFAULT << PCU_APB_CFG_SSP_OFFSET ) |\ ++ (PCU_APB_CFG_CFC_DEFAULT << PCU_APB_CFG_CFC_OFFSET )) ++ ++// Driving Capability and Slew Rate ++#define PCU_DCSR0_GPU_MASK (ANDES_BIT_MASK(22, 20)) ++#define PCU_DCSR0_GPU_OFFSET (20) ++#define PCU_DCSR0_GPU_DEFAULT (0xb) ++#define PCU_DCSR0_GMAC_MASK (ANDES_BIT_MASK(19, 16)) ++#define PCU_DCSR0_GMAC_OFFSET (16) ++#define PCU_DCSR0_GMAC_DEFAULT (0x3) ++#define PCU_DCSR0_ULPI_MASK (ANDES_BIT_MASK(15, 12)) ++#define PCU_DCSR0_ULPI_OFFSET (12) ++#define PCU_DCSR0_ULPI_DEFAULT (0xb) ++#define PCU_DCSR0_LPC_MASK (ANDES_BIT_MASK(11, 8)) ++#define PCU_DCSR0_LPC_OFFSET (8) ++#define PCU_DCSR0_LPC_DEFAULT (0xb) ++#define PCU_DCSR0_PCIAHB_MASK (ANDES_BIT_MASK(4, 0)) ++#define PCU_DCSR0_PCIAHB_OFFSET (0) ++#define PCU_DCSR0_PCIAHB_DEFAULT (0xb) ++#define PCU_DCSR1_I2C_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_DCSR1_I2C_OFFSET (0) ++#define PCU_DCSR1_I2C_DEFAULT (0x9) ++#define PCU_DCSR2_PCU_MASK (ANDES_BIT_MASK(31, 28)) ++#define PCU_DCSR2_PCU_OFFSET (28) ++#define PCU_DCSR2_PCU_DEFAULT (0x3) ++#define PCU_DCSR2_GPIO_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_DCSR2_GPIO_OFFSET (24) ++#define PCU_DCSR2_GPIO_DEFAULT (0x9) ++#define PCU_DCSR2_CFC_MASK (ANDES_BIT_MASK(23, 20)) ++#define PCU_DCSR2_CFC_OFFSET (20) ++#define PCU_DCSR2_CFC_DEFAULT (0xb) ++#define PCU_DCSR2_SD_MASK (ANDES_BIT_MASK(19, 16)) ++#define PCU_DCSR2_SD_OFFSET (16) ++#define PCU_DCSR2_SD_DEFAULT (0xb) ++#define PCU_DCSR2_SPI_MASK (ANDES_BIT_MASK(15, 12)) ++#define PCU_DCSR2_SPI_OFFSET (12) ++#define PCU_DCSR2_SPI_DEFAULT (0x9) ++#define PCU_DCSR2_AC97_MASK (ANDES_BIT_MASK(11, 8)) ++#define PCU_DCSR2_AC97_OFFSET (8) ++#define PCU_DCSR2_AC97_DEFAULT (0xb) ++#define PCU_DCSR2_UART2_MASK (ANDES_BIT_MASK(7, 4)) ++#define PCU_DCSR2_UART2_OFFSET (4) ++#define PCU_DCSR2_UART2_DEFAULT (0x9) ++#define PCU_DCSR2_UART1_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_DCSR2_UART1_OFFSET (0) ++#define PCU_DCSR2_UART1_DEFAULT (0x9) ++#define PCU_DCSR0_DEFAULT ((PCU_DCSR0_GPU_DEFAULT << PCU_DCSR0_GPU_OFFSET ) |\ ++ (PCU_DCSR0_GMAC_DEFAULT << PCU_DCSR0_GMAC_OFFSET ) |\ ++ (PCU_DCSR0_ULPI_DEFAULT << PCU_DCSR0_ULPI_OFFSET ) |\ ++ (PCU_DCSR0_LPC_DEFAULT << PCU_DCSR0_LPC_OFFSET ) |\ ++ (PCU_DCSR0_PCIAHB_DEFAULT << PCU_DCSR0_PCIAHB_OFFSET)) ++#define PCU_DCSR0_DFT_MASK ((PCU_DCSR0_GPU_MASK ) |\ ++ (PCU_DCSR0_GMAC_MASK ) |\ ++ (PCU_DCSR0_ULPI_MASK ) |\ ++ (PCU_DCSR0_LPC_MASK ) |\ ++ (PCU_DCSR0_PCIAHB_MASK)) ++ ++#define PCU_DCSR1_DEFAULT (PCU_DCSR1_I2C_DEFAULT << PCU_DCSR1_I2C_OFFSET ) ++#define PCU_DCSR1_DFT_MASK (PCU_DCSR1_I2C_MASK) ++ ++#define PCU_DCSR2_DEFAULT ((PCU_DCSR2_PCU_DEFAULT << PCU_DCSR2_PCU_OFFSET ) |\ ++ (PCU_DCSR2_GPIO_DEFAULT << PCU_DCSR2_GPIO_OFFSET ) |\ ++ (PCU_DCSR2_CFC_DEFAULT << PCU_DCSR2_CFC_OFFSET ) |\ ++ (PCU_DCSR2_SD_DEFAULT << PCU_DCSR2_SD_OFFSET ) |\ ++ (PCU_DCSR2_SPI_DEFAULT << PCU_DCSR2_SPI_OFFSET ) |\ ++ (PCU_DCSR2_AC97_DEFAULT << PCU_DCSR2_AC97_OFFSET ) |\ ++ (PCU_DCSR2_UART2_DEFAULT << PCU_DCSR2_UART2_OFFSET ) |\ ++ (PCU_DCSR2_UART1_DEFAULT << PCU_DCSR2_UART1_OFFSET )) ++#define PCU_DCSR2_DFT_MASK ((PCU_DCSR2_PCU_MASK ) |\ ++ (PCU_DCSR2_GPIO_MASK ) |\ ++ (PCU_DCSR2_CFC_MASK ) |\ ++ (PCU_DCSR2_SD_MASK ) |\ ++ (PCU_DCSR2_SPI_MASK ) |\ ++ (PCU_DCSR2_AC97_MASK ) |\ ++ (PCU_DCSR2_UART2_MASK) |\ ++ (PCU_DCSR2_UART1_MASK)) ++ ++//multi function port setting ++#define PCU_MFPS0_ENDIAN_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_MFPS0_ENDIAN_OFFSET (31) ++//#define PCU_MFPS0_ENDIAN_DEFAULT (0x) ++#define PCU_MFPS0_IVB_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_MFPS0_IVB_OFFSET (28) ++//#define PCU_MFPS0_IVB_DEFAULT (0x) ++#define PCU_MFPS0_AHBTARGET_MASK (ANDES_BIT_MASK(4, 4)) ++#define PCU_MFPS0_AHBTARGET_OFFSET (4) ++//#define PCU_MFPS0_AHBTARGET_DEFAULT (0x) ++#define PCU_MFPS0_AHBDBG_MASK (ANDES_BIT_MASK(3, 3)) ++#define PCU_MFPS0_AHBDBG_OFFSET (3) ++//#define PCU_MFPS0_AHBDBG_DEFAULT (0x) ++#define PCU_MFPS0_MINI_MASK (ANDES_BIT_MASK(2, 2)) ++#define PCU_MFPS0_MINI_OFFSET (2) ++//#define PCU_MFPS0_MINI_DEFAULT (0x) ++#define PCU_MFPS0_IDE_MASK (ANDES_BIT_MASK(1, 1)) ++#define PCU_MFPS0_IDE_OFFSET (1) ++//#define PCU_MFPS0_IDE_DEFAULT (0x) ++#define PCU_MFPS0_PCI_MASK (ANDES_BIT_MASK(0, 0)) ++#define PCU_MFPS0_PCI_OFFSET (0) ++//#define PCU_MFPS0_PCI_DEFAULT (0x) ++ ++#define PCU_MFPS1_EXT_INT_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_MFPS1_EXT_INT_OFFSET (31) ++#define PCU_MFPS1_EXT_INT_DEFAULT (0x0) ++#define PCU_MFPS1_AHB_FAST_REQ_MASK (ANDES_BIT_MASK(30, 30)) ++#define PCU_MFPS1_AHB_FAST_REQ_OFFSET (30) ++#define PCU_MFPS1_AHB_FAST_REQ_DEFAULT (0x1) ++#define PCU_MFPS1_HSMP_FAST_REQ_MASK (ANDES_BIT_MASK(29, 29)) ++#define PCU_MFPS1_HSMP_FAST_REQ_OFFSET (29) ++#define PCU_MFPS1_HSMP_FAST_REQ_DEFAULT (0x1) ++#define PCU_MFPS1_DVO_MASK (ANDES_BIT_MASK(28, 28)) ++#define PCU_MFPS1_DVO_OFFSET (28) ++#define PCU_MFPS1_DVO_DEFAULT (0x0) ++#define PCU_MFPS1_SD_GPIO_MASK (ANDES_BIT_MASK(10, 10)) ++#define PCU_MFPS1_SD_GPIO_OFFSET (10) ++#define PCU_MFPS1_SD_GPIO_DEFAULT (0x1) ++#define PCU_MFPS1_SPI_GPIO_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_MFPS1_SPI_GPIO_OFFSET (9) ++#define PCU_MFPS1_SPI_GPIO_DEFAULT (0x1) ++#define PCU_MFPS1_UART2_GPIO_MASK (ANDES_BIT_MASK(8, 8)) ++#define PCU_MFPS1_UART2_GPIO_OFFSET (8) ++#define PCU_MFPS1_UART2_GPIO_DEFAULT (0x1) ++#define PCU_MFPS1_UART1_GPIO_MASK (ANDES_BIT_MASK(7, 7)) ++#define PCU_MFPS1_UART1_GPIO_OFFSET (7) ++#define PCU_MFPS1_UART1_GPIO_DEFAULT (0x1) ++#define PCU_MFPS1_I2C_GPIO_MASK (ANDES_BIT_MASK(6, 6)) ++#define PCU_MFPS1_I2C_GPIO_OFFSET (6) ++#define PCU_MFPS1_I2C_GPIO_DEFAULT (0x1) ++#define PCU_MFPS1_PME_GPIO_MASK (ANDES_BIT_MASK(5, 5)) ++#define PCU_MFPS1_PME_GPIO_OFFSET (5) ++#define PCU_MFPS1_PME_GPIO_DEFAULT (0x1) ++#define PCU_MFPS1_PWEN_GPIO_MASK (ANDES_BIT_MASK(4, 4)) ++#define PCU_MFPS1_PWEN_GPIO_OFFSET (4) ++#define PCU_MFPS1_PWEN_GPIO_DEFAULT (0x1) ++#define PCU_MFPS1_AC97_GPIO_MASK (ANDES_BIT_MASK(3, 3)) ++#define PCU_MFPS1_AC97_GPIO_OFFSET (3) ++#define PCU_MFPS1_AC97_GPIO_DEFAULT (0x0) ++#define PCU_MFPS1_PWM1_GPIO_MASK (ANDES_BIT_MASK(2, 2)) ++#define PCU_MFPS1_PWM1_GPIO_OFFSET (2) ++#define PCU_MFPS1_PWM1_GPIO_DEFAULT (0x0) ++#define PCU_MFPS1_PWM0_GPIO_MASK (ANDES_BIT_MASK(1, 1)) ++#define PCU_MFPS1_PWM0_GPIO_OFFSET (1) ++#define PCU_MFPS1_PWM0_GPIO_DEFAULT (0x0) ++#define PCU_MFPS1_SUSPEND_GPIO_MASK (ANDES_BIT_MASK(0, 0)) ++#define PCU_MFPS1_SUSPEND_GPIO_OFFSET (0) ++#define PCU_MFPS1_SUSPEND_GPIO_DEFAULT (0x0) ++#define PCU_MFPS1_DEFAULT ((PCU_MFPS1_EXT_INT_DEFAULT << PCU_MFPS1_EXT_INT_OFFSET )|\ ++ (PCU_MFPS1_AHB_FAST_REQ_DEFAULT << PCU_MFPS1_AHB_FAST_REQ_OFFSET )|\ ++ (PCU_MFPS1_HSMP_FAST_REQ_DEFAULT << PCU_MFPS1_HSMP_FAST_REQ_OFFSET)|\ ++ (PCU_MFPS1_DVO_DEFAULT << PCU_MFPS1_DVO_OFFSET )|\ ++ (PCU_MFPS1_SD_GPIO_DEFAULT << PCU_MFPS1_SD_GPIO_OFFSET )|\ ++ (PCU_MFPS1_SPI_GPIO_DEFAULT << PCU_MFPS1_SPI_GPIO_OFFSET )|\ ++ (PCU_MFPS1_UART2_GPIO_DEFAULT << PCU_MFPS1_UART2_GPIO_OFFSET )|\ ++ (PCU_MFPS1_UART1_GPIO_DEFAULT << PCU_MFPS1_UART1_GPIO_OFFSET )|\ ++ (PCU_MFPS1_I2C_GPIO_DEFAULT << PCU_MFPS1_I2C_GPIO_OFFSET )|\ ++ (PCU_MFPS1_PME_GPIO_DEFAULT << PCU_MFPS1_PME_GPIO_OFFSET )|\ ++ (PCU_MFPS1_PWEN_GPIO_DEFAULT << PCU_MFPS1_PWEN_GPIO_OFFSET )|\ ++ (PCU_MFPS1_AC97_GPIO_DEFAULT << PCU_MFPS1_AC97_GPIO_OFFSET )|\ ++ (PCU_MFPS1_PWM1_GPIO_DEFAULT << PCU_MFPS1_PWM1_GPIO_OFFSET )|\ ++ (PCU_MFPS1_PWM0_GPIO_DEFAULT << PCU_MFPS1_PWM0_GPIO_OFFSET )|\ ++ (PCU_MFPS1_SUSPEND_GPIO_DEFAULT << PCU_MFPS1_SUSPEND_GPIO_OFFSET )) ++#define PCU_MFPS1_DFT_MASK ((PCU_MFPS1_EXT_INT_MASK )|\ ++ (PCU_MFPS1_AHB_FAST_REQ_MASK )|\ ++ (PCU_MFPS1_HSMP_FAST_REQ_MASK)|\ ++ (PCU_MFPS1_DVO_MASK )|\ ++ (PCU_MFPS1_SD_GPIO_MASK )|\ ++ (PCU_MFPS1_SPI_GPIO_MASK )|\ ++ (PCU_MFPS1_UART2_GPIO_MASK )|\ ++ (PCU_MFPS1_UART1_GPIO_MASK )|\ ++ (PCU_MFPS1_I2C_GPIO_MASK )|\ ++ (PCU_MFPS1_PME_GPIO_MASK )|\ ++ (PCU_MFPS1_PWEN_GPIO_MASK )|\ ++ (PCU_MFPS1_AC97_GPIO_MASK )|\ ++ (PCU_MFPS1_PWM1_GPIO_MASK )|\ ++ (PCU_MFPS1_PWM0_GPIO_MASK )|\ ++ (PCU_MFPS1_SUSPEND_GPIO_MASK )) ++ ++//DMA engine selection ++#define PCU_DMA_SEL_CFC_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_DMA_SEL_CFC_OFFSET (9) ++#define PCU_DMA_SEL_CFC_DEFAULT (0x0) ++#define PCU_DMA_SEL_SD_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_DMA_SEL_SD_OFFSET (9) ++#define PCU_DMA_SEL_SD_DEFAULT (0x0) ++#define PCU_DMA_SEL_UART2_TX_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_DMA_SEL_UART2_TX_OFFSET (9) ++#define PCU_DMA_SEL_UART2_TX_DEFAULT (0x0) ++#define PCU_DMA_SEL_UART2_RX_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_DMA_SEL_UART2_RX_OFFSET (9) ++#define PCU_DMA_SEL_UART2_RX_DEFAULT (0x0) ++#define PCU_DMA_SEL_UART1_TX_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_DMA_SEL_UART1_TX_OFFSET (9) ++#define PCU_DMA_SEL_UART1_TX_DEFAULT (0x0) ++#define PCU_DMA_SEL_UART1_RX_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_DMA_SEL_UART1_RX_OFFSET (9) ++#define PCU_DMA_SEL_UART1_RX_DEFAULT (0x0) ++#define PCU_DMA_SEL_AC97_TX_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_DMA_SEL_AC97_TX_OFFSET (9) ++#define PCU_DMA_SEL_AC97_TX_DEFAULT (0x0) ++#define PCU_DMA_SEL_AC97_RX_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_DMA_SEL_AC97_RX_OFFSET (9) ++#define PCU_DMA_SEL_AC97_RX_DEFAULT (0x0) ++#define PCU_DMA_SEL_DEFAULT ((PCU_DMA_SEL_CFC_DEFAULT << PCU_DMA_SEL_CFC_OFFSET ) |\ ++ (PCU_DMA_SEL_SD_DEFAULT << PCU_DMA_SEL_SD_OFFSET ) |\ ++ (PCU_DMA_SEL_UART2_TX_DEFAULT << PCU_DMA_SEL_UART2_TX_OFFSET) |\ ++ (PCU_DMA_SEL_UART2_RX_DEFAULT << PCU_DMA_SEL_UART2_RX_OFFSET) |\ ++ (PCU_DMA_SEL_UART1_TX_DEFAULT << PCU_DMA_SEL_UART1_TX_OFFSET) |\ ++ (PCU_DMA_SEL_UART1_RX_DEFAULT << PCU_DMA_SEL_UART1_RX_OFFSET) |\ ++ (PCU_DMA_SEL_AC97_TX_DEFAULT << PCU_DMA_SEL_AC97_TX_OFFSET ) |\ ++ (PCU_DMA_SEL_AC97_RX_DEFAULT << PCU_DMA_SEL_AC97_RX_OFFSET ) ) ++#define PCU_DMA_SEL_DFT_MASK ((PCU_DMA_SEL_CFC_MASK ) |\ ++ (PCU_DMA_SEL_SD_MASK ) |\ ++ (PCU_DMA_SEL_UART2_TX_MASK) |\ ++ (PCU_DMA_SEL_UART2_RX_MASK) |\ ++ (PCU_DMA_SEL_UART1_TX_MASK) |\ ++ (PCU_DMA_SEL_UART1_RX_MASK) |\ ++ (PCU_DMA_SEL_AC97_TX_MASK ) |\ ++ (PCU_DMA_SEL_AC97_RX_MASK ) ) ++ ++// OSC control ++#define PCU_OSC_CTRL_OSCH3RAN_MASK (ANDES_BIT_MASK(9, 8)) ++#define PCU_OSC_CTRL_OSCH3RAN_OFFSET (8) ++//#define PCU_OSC_CTRL_OSCH3RAN_DEFAULT (0x0) ++#define PCU_OSC_CTRL_OSCH2RAN_MASK (ANDES_BIT_MASK(7, 6)) ++#define PCU_OSC_CTRL_OSCH2RAN_OFFSET (6) ++#define PCU_OSC_CTRL_OSCH2RAN_DEFAULT (0x2) ++#define PCU_OSC_CTRL_OSCH1RAN_MASK (ANDES_BIT_MASK(5, 4)) ++#define PCU_OSC_CTRL_OSCH1RAN_OFFSET (4) ++//#define PCU_OSC_CTRL_OSCH1RAN_DEFAULT (0x0) ++#define PCU_OSC_CTRL_OSCHTRI_MASK (ANDES_BIT_MASK(2, 2)) ++#define PCU_OSC_CTRL_OSCHTRI_OFFSET (2) ++#define PCU_OSC_CTRL_OSCHTRI_DEFAULT (0x0) ++#define PCU_OSC_CTRL_OSCHSTABLE_MASK (ANDES_BIT_MASK(1, 1)) ++#define PCU_OSC_CTRL_OSCHSTABLE_OFFSET (1) ++//#define PCU_OSC_CTRL_OSCHSTABLE_DEFAULT (0x0) ++#define PCU_OSC_CTRL_OSCHOFF_MASK (ANDES_BIT_MASK(0, 0)) ++#define PCU_OSC_CTRL_OSCHOFF_OFFSET (0) ++//#define PCU_OSC_CTRL_OSCHOFF_DEFAULT (0x0) ++#define PCU_OSC_CTRL_DEFAULT (PCU_OSC_CTRL_OSCH2RAN_DEFAULT << PCU_OSC_CTRL_OSCH2RAN_OFFSET ) ++#define PCU_OSC_CTRL_DFT_MASK (PCU_OSC_CTRL_OSCH2RAN_MASK ) ++ ++// PWM divider ++#define PCU_PWM_DIV_DIV_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_PWM_DIV_DIV_OFFSET (0) ++#define PCU_PWM_DIV_DIV_DEFAULT (0x0) ++#define PCU_PWM_DIV_DEFAULT (PCU_PWM_DIV_DIV_DEFAULT<<PCU_PWM_DIV_DIV_OFFSET) ++#define PCU_PWM_DIV_DFT_MASK (PCU_PWM_DIV_DIV_MASK) ++ ++// MISC ++#define PCU_MISC_HW_RST_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_MISC_HW_RST_OFFSET (31) ++#define PCU_MISC_HW_RST_DEFAULT (0x0) ++#define PCU_MISC_WD_RST_MASK (ANDES_BIT_MASK(30, 30)) ++#define PCU_MISC_WD_RST_OFFSET (30) ++#define PCU_MISC_WD_RST_DEFAULT (0x0) ++#define PCU_MISC_CPUB_SRST_MASK (ANDES_BIT_MASK(29, 29)) ++#define PCU_MISC_CPUB_SRST_OFFSET (29) ++#define PCU_MISC_CPUB_SRST_DEFAULT (0x0) ++#define PCU_MISC_CPUA_SRST_MASK (ANDES_BIT_MASK(28, 28)) ++#define PCU_MISC_CPUA_SRST_OFFSET (28) ++#define PCU_MISC_CPUA_SRST_DEFAULT (0x0) ++#define PCU_MISC_PW_FAIL_MASK (ANDES_BIT_MASK(27, 27)) ++#define PCU_MISC_PW_FAIL_OFFSET (27) ++#define PCU_MISC_PW_FAIL_DEFAULT (0x0) ++#define PCU_MISC_PW_DAILY_MASK (ANDES_BIT_MASK(26, 26)) ++#define PCU_MISC_PW_DAILY_OFFSET (26) ++#define PCU_MISC_PW_DAILY_DEFAULT (0x0) ++#define PCU_MISC_PW_LPC_MASK (ANDES_BIT_MASK(25, 25)) ++#define PCU_MISC_PW_LPC_OFFSET (25) ++#define PCU_MISC_PW_LPC_DEFAULT (0x0) ++#define PCU_MISC_PW_PCI_MASK (ANDES_BIT_MASK(24, 24)) ++#define PCU_MISC_PW_PCI_OFFSET (24) ++#define PCU_MISC_PW_PCI_DEFAULT (0x0) ++#define PCU_MISC_PW_RTC_MASK (ANDES_BIT_MASK(23, 23)) ++#define PCU_MISC_PW_RTC_OFFSET (23) ++#define PCU_MISC_PW_RTC_DEFAULT (0x0) ++#define PCU_MISC_PW_WOL_MASK (ANDES_BIT_MASK(22, 22)) ++#define PCU_MISC_PW_WOL_OFFSET (2) ++#define PCU_MISC_PW_WOL_DEFAULT (0x0) ++#define PCU_MISC_PW_GPIO5_MASK (ANDES_BIT_MASK(21, 21)) ++#define PCU_MISC_PW_GPIO5_OFFSET (21) ++#define PCU_MISC_PW_GPIO5_DEFAULT (0x0) ++#define PCU_MISC_PW_GPIO4_MASK (ANDES_BIT_MASK(20, 20)) ++#define PCU_MISC_PW_GPIO4_OFFSET (20) ++#define PCU_MISC_PW_GPIO4_DEFAULT (0x0) ++#define PCU_MISC_PW_GPIO3_MASK (ANDES_BIT_MASK(19, 19)) ++#define PCU_MISC_PW_GPIO3_OFFSET (19) ++#define PCU_MISC_PW_GPIO3_DEFAULT (0x0) ++#define PCU_MISC_PW_GPIO2_MASK (ANDES_BIT_MASK(18, 18)) ++#define PCU_MISC_PW_GPIO2_OFFSET (18) ++#define PCU_MISC_PW_GPIO2_DEFAULT (0x0) ++#define PCU_MISC_PW_GPIO1_MASK (ANDES_BIT_MASK(17, 17)) ++#define PCU_MISC_PW_GPIO1_OFFSET (17) ++#define PCU_MISC_PW_GPIO1_DEFAULT (0x0) ++#define PCU_MISC_PW_GPIO0_MASK (ANDES_BIT_MASK(16, 16)) ++#define PCU_MISC_PW_GPIO0_OFFSET (16) ++#define PCU_MISC_PW_GPIO0_DEFAULT (0x0) ++#define PCU_MISC_EN_CPUB_MASK (ANDES_BIT_MASK(15, 15)) ++#define PCU_MISC_EN_CPUB_OFFSET (15) ++#define PCU_MISC_EN_CPUB_DEFAULT (0x0) ++#define PCU_MISC_EN_CPUA_MASK (ANDES_BIT_MASK(14, 14)) ++#define PCU_MISC_EN_CPUA_OFFSET (14) ++#define PCU_MISC_EN_CPUA_DEFAULT (0x1) ++#define PCU_MISC_DDR_DLL_TEST_MASK (ANDES_BIT_MASK(12, 12)) ++#define PCU_MISC_DDR_DLL_TEST_OFFSET (12) ++#define PCU_MISC_DDR_DLL_TEST_DEFAULT (0x0) ++#define PCU_MISC_DDR_DDQ_TEST_MASK (ANDES_BIT_MASK(11, 11)) ++#define PCU_MISC_DDR_DDQ_TEST_OFFSET (11) ++#define PCU_MISC_DDR_DDQ_TEST_DEFAULT (0x0) ++#define PCU_MISC_DDR_DLL_SRST_MASK (ANDES_BIT_MASK(10, 10)) ++#define PCU_MISC_DDR_DLL_SRST_OFFSET (10) ++#define PCU_MISC_DDR_DLL_SRST_DEFAULT (0x0) ++#define PCU_MISC_DDR_PLL_BYPASS_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_MISC_DDR_PLL_BYPASS_OFFSET (9) ++#define PCU_MISC_DDR_PLL_BYPASS_DEFAULT (0x0) ++#define PCU_MISC_400MHZ_SEL_MASK (ANDES_BIT_MASK(8, 8)) ++#define PCU_MISC_400MHZ_SEL_OFFSET (8) ++#define PCU_MISC_400MHZ_SEL_DEFAULT (0x0) ++#define PCU_MISC_EXLM_WAIT_B_MASK (ANDES_BIT_MASK(7, 6)) ++#define PCU_MISC_EXLM_WAIT_B_OFFSET (6) ++#define PCU_MISC_EXLM_WAIT_B_DEFAULT (0x0) ++#define PCU_MISC_EXLM_WAIT_A_MASK (ANDES_BIT_MASK(5, 4)) ++#define PCU_MISC_EXLM_WAIT_A_OFFSET (4) ++#define PCU_MISC_EXLM_WAIT_A_DEFAULT (0x0) ++#define PCU_MISC_USB_WAKE_MASK (ANDES_BIT_MASK(3, 3)) ++#define PCU_MISC_USB_WAKE_OFFSET (3) ++#define PCU_MISC_USB_WAKE_DEFAULT (0x0) ++#define PCU_MISC_RST_PCI_MASK (ANDES_BIT_MASK(2, 2)) ++#define PCU_MISC_RST_PCI_OFFSET (2) ++#define PCU_MISC_RST_PCI_DEFAULT (0x0) ++#define PCU_MISC_RST_CPUB_MASK (ANDES_BIT_MASK(1, 1)) ++#define PCU_MISC_RST_CPUB_OFFSET (1) ++#define PCU_MISC_RST_CPUB_DEFAULT (0x0) ++#define PCU_MISC_RST_CPUA_MASK (ANDES_BIT_MASK(0, 0)) ++#define PCU_MISC_RST_CPUA_OFFSET (0) ++#define PCU_MISC_RST_CPUA_DEFAULT (0x0) ++#define PCU_MISC_DEFAULT (/*(PCU_MISC_EN_CPUB_DEFAULT << PCU_MISC_EN_CPUB_OFFSET )|*/\ ++ (PCU_MISC_EN_CPUA_DEFAULT << PCU_MISC_EN_CPUA_OFFSET )|\ ++ (PCU_MISC_DDR_DLL_TEST_DEFAULT << PCU_MISC_DDR_DLL_TEST_OFFSET )|\ ++ (PCU_MISC_DDR_DDQ_TEST_DEFAULT << PCU_MISC_DDR_DDQ_TEST_OFFSET )|\ ++ (PCU_MISC_DDR_DLL_SRST_DEFAULT << PCU_MISC_DDR_DLL_SRST_OFFSET )|\ ++ (PCU_MISC_DDR_PLL_BYPASS_DEFAULT << PCU_MISC_DDR_PLL_BYPASS_OFFSET )|\ ++ (PCU_MISC_400MHZ_SEL_DEFAULT << PCU_MISC_400MHZ_SEL_OFFSET )|\ ++ (PCU_MISC_EXLM_WAIT_B_DEFAULT << PCU_MISC_EXLM_WAIT_B_OFFSET )|\ ++ (PCU_MISC_EXLM_WAIT_A_DEFAULT << PCU_MISC_EXLM_WAIT_A_OFFSET )|\ ++ (PCU_MISC_USB_WAKE_DEFAULT << PCU_MISC_USB_WAKE_OFFSET )|\ ++ (PCU_MISC_RST_PCI_DEFAULT << PCU_MISC_RST_PCI_OFFSET )|\ ++ (PCU_MISC_RST_CPUB_DEFAULT << PCU_MISC_RST_CPUB_OFFSET )|\ ++ (PCU_MISC_RST_CPUA_DEFAULT << PCU_MISC_RST_CPUA_OFFSET )) ++#define PCU_MISC_DFT_MASK (/*(PCU_MISC_EN_CPUB_MASK )|*/\ ++ (PCU_MISC_EN_CPUA_MASK )|\ ++ (PCU_MISC_DDR_DLL_TEST_MASK )|\ ++ (PCU_MISC_DDR_DDQ_TEST_MASK )|\ ++ (PCU_MISC_DDR_DLL_SRST_MASK )|\ ++ (PCU_MISC_DDR_PLL_BYPASS_MASK)|\ ++ (PCU_MISC_400MHZ_SEL_MASK )|\ ++ (PCU_MISC_EXLM_WAIT_B_MASK )|\ ++ (PCU_MISC_EXLM_WAIT_A_MASK )|\ ++ (PCU_MISC_USB_WAKE_MASK )|\ ++ (PCU_MISC_RST_PCI_MASK )|\ ++ (PCU_MISC_RST_CPUB_MASK )|\ ++ (PCU_MISC_RST_CPUA_MASK )) ++#define PCU_MISC_W1C_MASK ((PCU_MISC_HW_RST_MASK )|\ ++ (PCU_MISC_WD_RST_MASK )|\ ++ (PCU_MISC_CPUB_SRST_MASK)|\ ++ (PCU_MISC_CPUA_SRST_MASK)) ++ ++// BSM control and status ++#define PCU_BSM_CTRL_IE_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_BSM_CTRL_IE_OFFSET (31) ++#define PCU_BSM_CTRL_IE_DEFAULT (0x0) ++#define PCU_BSM_CTRL_CMD_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_BSM_CTRL_CMD_OFFSET (28) ++#define PCU_BSM_CTRL_CMD_DEFAULT (0x0) ++#define PCU_BSM_CTRL_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_BSM_CTRL_SYNC_OFFSET (24) ++#define PCU_BSM_CTRL_SYNC_DEFAULT (0x3) ++#define PCU_BSM_CTRL_LINK1_MASK (ANDES_BIT_MASK(7, 4)) ++#define PCU_BSM_CTRL_LINK1_OFFSET (4) ++#define PCU_BSM_CTRL_LINK1_DEFAULT (0x0) ++#define PCU_BSM_CTRL_LINK0_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_BSM_CTRL_LINK0_OFFSET (0) ++#define PCU_BSM_CTRL_LINK0_DEFAULT (0x0) ++#define PCU_BSM_CTRL_DEFAULT ((PCU_BSM_CTRL_IE_DEFAULT << PCU_BSM_CTRL_IE_OFFSET ) |\ ++ (PCU_BSM_CTRL_CMD_DEFAULT << PCU_BSM_CTRL_CMD_OFFSET ) |\ ++ (PCU_BSM_CTRL_SYNC_DEFAULT << PCU_BSM_CTRL_SYNC_OFFSET ) |\ ++ (PCU_BSM_CTRL_LINK1_DEFAULT << PCU_BSM_CTRL_LINK1_OFFSET) |\ ++ (PCU_BSM_CTRL_LINK0_DEFAULT << PCU_BSM_CTRL_LINK0_OFFSET)) ++ ++#define PCU_BSM_STATUS_STS_MASK (ANDES_BIT_MASK(31, 28)) ++#define PCU_BSM_STATUS_STS_OFFSET (28) ++#define PCU_BSM_STATUS_STS_DEFAULT (0x0) ++#define PCU_BSM_STATUS_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_BSM_STATUS_SYNC_OFFSET (24) ++#define PCU_BSM_STATUS_SYNC_DEFAULT (0x0) ++#define PCU_BSM_STATUS_CI1_MASK (ANDES_BIT_MASK(7, 4)) ++#define PCU_BSM_STATUS_CI1_OFFSET (4) ++#define PCU_BSM_STATUS_CI1_DEFAULT (0x0) ++#define PCU_BSM_STATUS_CI0_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_BSM_STATUS_CI0_OFFSET (0) ++#define PCU_BSM_STATUS_CI0_DEFAULT (0x0) ++#define PCU_BSM_STATUS_DEFAULT ((PCU_BSM_STATUS_STS_DEFAULT << PCU_BSM_STATUS_STS_OFFSET) |\ ++ (PCU_BSM_STATUS_CI1_DEFAULT << PCU_BSM_STATUS_CI1_OFFSET) |\ ++ (PCU_BSM_STATUS_CI0_DEFAULT << PCU_BSM_STATUS_CI0_OFFSET)) ++ ++//wakeup event sensitivity ++#define PCU_WAKEUP_SEN_POL15_MASK (ANDES_BIT_MASK(15, 15)) ++#define PCU_WAKEUP_SEN_POL15_OFFSET (15) ++#define PCU_WAKEUP_SEN_POL15_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL14_MASK (ANDES_BIT_MASK(14, 14)) ++#define PCU_WAKEUP_SEN_POL14_OFFSET (14) ++#define PCU_WAKEUP_SEN_POL14_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL13_MASK (ANDES_BIT_MASK(13, 13)) ++#define PCU_WAKEUP_SEN_POL13_OFFSET (13) ++#define PCU_WAKEUP_SEN_POL13_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL12_MASK (ANDES_BIT_MASK(12, 12)) ++#define PCU_WAKEUP_SEN_POL12_OFFSET (12) ++#define PCU_WAKEUP_SEN_POL12_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL11_MASK (ANDES_BIT_MASK(11, 11)) ++#define PCU_WAKEUP_SEN_POL11_OFFSET (11) ++#define PCU_WAKEUP_SEN_POL11_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL10_MASK (ANDES_BIT_MASK(10, 10)) ++#define PCU_WAKEUP_SEN_POL10_OFFSET (10) ++#define PCU_WAKEUP_SEN_POL10_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL9_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_WAKEUP_SEN_POL9_OFFSET (9) ++#define PCU_WAKEUP_SEN_POL9_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL8_MASK (ANDES_BIT_MASK(8, 8)) ++#define PCU_WAKEUP_SEN_POL8_OFFSET (8) ++#define PCU_WAKEUP_SEN_POL8_DEFAULT (0x1) ++#define PCU_WAKEUP_SEN_POL7_MASK (ANDES_BIT_MASK(7, 7)) ++#define PCU_WAKEUP_SEN_POL7_OFFSET (7) ++#define PCU_WAKEUP_SEN_POL7_DEFAULT (0x1) ++#define PCU_WAKEUP_SEN_POL6_MASK (ANDES_BIT_MASK(6, 6)) ++#define PCU_WAKEUP_SEN_POL6_OFFSET (6) ++#define PCU_WAKEUP_SEN_POL6_DEFAULT (0x1) ++#define PCU_WAKEUP_SEN_POL5_MASK (ANDES_BIT_MASK(5, 5)) ++#define PCU_WAKEUP_SEN_POL5_OFFSET (5) ++#define PCU_WAKEUP_SEN_POL5_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL4_MASK (ANDES_BIT_MASK(4, 4)) ++#define PCU_WAKEUP_SEN_POL4_OFFSET (4) ++#define PCU_WAKEUP_SEN_POL4_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL3_MASK (ANDES_BIT_MASK(3, 3)) ++#define PCU_WAKEUP_SEN_POL3_OFFSET (3) ++#define PCU_WAKEUP_SEN_POL3_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL2_MASK (ANDES_BIT_MASK(2, 2)) ++#define PCU_WAKEUP_SEN_POL2_OFFSET (2) ++#define PCU_WAKEUP_SEN_POL2_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL1_MASK (ANDES_BIT_MASK(1, 1)) ++#define PCU_WAKEUP_SEN_POL1_OFFSET (1) ++#define PCU_WAKEUP_SEN_POL1_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL0_MASK (ANDES_BIT_MASK(0, 0)) ++#define PCU_WAKEUP_SEN_POL0_OFFSET (0) ++#define PCU_WAKEUP_SEN_POL0_DEFAULT (0x0) ++#define PCU_WAKEUP_SEN_POL_MASK (ANDES_BIT_MASK(15, 0)) ++#define PCU_WAKEUP_SEN_POL_OFFSET (0) ++#define PCU_WAKEUP_SEN_POL_DEFAULT ((PCU_WAKEUP_SEN_POL15_DEFAULT << PCU_WAKEUP_SEN_POL15_OFFSET) |\ ++ (PCU_WAKEUP_SEN_POL14_DEFAULT << PCU_WAKEUP_SEN_POL14_OFFSET) |\ ++ (PCU_WAKEUP_SEN_POL13_DEFAULT << PCU_WAKEUP_SEN_POL13_OFFSET) |\ ++ (PCU_WAKEUP_SEN_POL12_DEFAULT << PCU_WAKEUP_SEN_POL12_OFFSET) |\ ++ (PCU_WAKEUP_SEN_POL11_DEFAULT << PCU_WAKEUP_SEN_POL11_OFFSET) |\ ++ (PCU_WAKEUP_SEN_POL10_DEFAULT << PCU_WAKEUP_SEN_POL10_OFFSET) |\ ++ (PCU_WAKEUP_SEN_POL9_DEFAULT << PCU_WAKEUP_SEN_POL9_OFFSET ) |\ ++ (PCU_WAKEUP_SEN_POL8_DEFAULT << PCU_WAKEUP_SEN_POL8_OFFSET ) |\ ++ (PCU_WAKEUP_SEN_POL7_DEFAULT << PCU_WAKEUP_SEN_POL7_OFFSET ) |\ ++ (PCU_WAKEUP_SEN_POL6_DEFAULT << PCU_WAKEUP_SEN_POL6_OFFSET ) |\ ++ (PCU_WAKEUP_SEN_POL5_DEFAULT << PCU_WAKEUP_SEN_POL5_OFFSET ) |\ ++ (PCU_WAKEUP_SEN_POL4_DEFAULT << PCU_WAKEUP_SEN_POL4_OFFSET ) |\ ++ (PCU_WAKEUP_SEN_POL3_DEFAULT << PCU_WAKEUP_SEN_POL3_OFFSET ) |\ ++ (PCU_WAKEUP_SEN_POL2_DEFAULT << PCU_WAKEUP_SEN_POL3_OFFSET ) |\ ++ (PCU_WAKEUP_SEN_POL1_DEFAULT << PCU_WAKEUP_SEN_POL2_OFFSET ) |\ ++ (PCU_WAKEUP_SEN_POL0_DEFAULT << PCU_WAKEUP_SEN_POL0_OFFSET ) ) ++#define PCU_WAKEUP_SEN_DEFAULT (PCU_WAKEUP_SEN_POL_DEFAULT) ++#define PCU_WAKEUP_SEN_DFT_MASK (PCU_WAKEUP_SEN_POL_MASK) ++ ++#define PCU_WAKEUP_SEN_GPIO0_POL_MASK PCU_WAKEUP_SEN_POL0_MASK ++#define PCU_WAKEUP_SEN_GPIO0_POL_OFFSET PCU_WAKEUP_SEN_POL0_OFFSET ++#define PCU_WAKEUP_SEN_GPIO0_POL_DEFAULT PCU_WAKEUP_SEN_POL0_DEFAULT ++#define PCU_WAKEUP_SEN_GPIO1_POL_MASK PCU_WAKEUP_SEN_POL1_MASK ++#define PCU_WAKEUP_SEN_GPIO1_POL_OFFSET PCU_WAKEUP_SEN_POL1_OFFSET ++#define PCU_WAKEUP_SEN_GPIO1_POL_DEFAULT PCU_WAKEUP_SEN_POL1_DEFAULT ++#define PCU_WAKEUP_SEN_GPIO2_POL_MASK PCU_WAKEUP_SEN_POL2_MASK ++#define PCU_WAKEUP_SEN_GPIO2_POL_OFFSET PCU_WAKEUP_SEN_POL2_OFFSET ++#define PCU_WAKEUP_SEN_GPIO2_POL_DEFAULT PCU_WAKEUP_SEN_POL2_DEFAULT ++#define PCU_WAKEUP_SEN_GPIO3_POL_MASK PCU_WAKEUP_SEN_POL3_MASK ++#define PCU_WAKEUP_SEN_GPIO3_POL_OFFSET PCU_WAKEUP_SEN_POL3_OFFSET ++#define PCU_WAKEUP_SEN_GPIO3_POL_DEFAULT PCU_WAKEUP_SEN_POL3_DEFAULT ++#define PCU_WAKEUP_SEN_GPIO4_POL_MASK PCU_WAKEUP_SEN_POL4_MASK ++#define PCU_WAKEUP_SEN_GPIO4_POL_OFFSET PCU_WAKEUP_SEN_POL4_OFFSET ++#define PCU_WAKEUP_SEN_GPIO4_POL_DEFAULT PCU_WAKEUP_SEN_POL4_DEFAULT ++#define PCU_WAKEUP_SEN_GPIO5_POL_MASK PCU_WAKEUP_SEN_POL5_MASK ++#define PCU_WAKEUP_SEN_GPIO5_POL_OFFSET PCU_WAKEUP_SEN_POL5_OFFSET ++#define PCU_WAKEUP_SEN_GPIO5_POL_DEFAULT PCU_WAKEUP_SEN_POL5_DEFAULT ++#define PCU_WAKEUP_SEN_WOL_POL_MASK PCU_WAKEUP_SEN_POL6_MASK ++#define PCU_WAKEUP_SEN_WOL_POL_OFFSET PCU_WAKEUP_SEN_POL6_OFFSET ++#define PCU_WAKEUP_SEN_WOL_POL_DEFAULT PCU_WAKEUP_SEN_POL6_DEFAULT ++#define PCU_WAKEUP_SEN_RTC_POL_MASK PCU_WAKEUP_SEN_POL7_MASK ++#define PCU_WAKEUP_SEN_RTC_POL_OFFSET PCU_WAKEUP_SEN_POL7_OFFSET ++#define PCU_WAKEUP_SEN_RTC_POL_DEFAULT PCU_WAKEUP_SEN_POL7_DEFAULT ++#define PCU_WAKEUP_SEN_DAY_POL_OFFSET PCU_WAKEUP_SEN_POL8_OFFSET ++#define PCU_WAKEUP_SEN_DAY_POL_DEFAULT PCU_WAKEUP_SEN_POL8_DEFAULT ++#define PCU_WAKEUP_SEN_DBG_POL_MASK PCU_WAKEUP_SEN_POL9_MASK ++#define PCU_WAKEUP_SEN_DBG_POL_OFFSET PCU_WAKEUP_SEN_POL9_OFFSET ++#define PCU_WAKEUP_SEN_DBG_POL_DEFAULT PCU_WAKEUP_SEN_POL9_DEFAULT ++#define PCU_WAKEUP_SEN_PCI_POL_MASK PCU_WAKEUP_SEN_POL10_MASK ++#define PCU_WAKEUP_SEN_PCI_POL_OFFSET PCU_WAKEUP_SEN_POL10_OFFSET ++#define PCU_WAKEUP_SEN_PCI_POL_DEFAULT PCU_WAKEUP_SEN_POL10_DEFAULT ++#define PCU_WAKEUP_SEN_LPC_POL_MASK PCU_WAKEUP_SEN_POL11_MASK ++#define PCU_WAKEUP_SEN_LPC_POL_OFFSET PCU_WAKEUP_SEN_POL11_OFFSET ++#define PCU_WAKEUP_SEN_LPC_POL_DEFAULT PCU_WAKEUP_SEN_POL11_DEFAULT ++ ++// wakeup event status register ++#define PCU_WAKEUP_STATUS_SIG_MASK (ANDES_BIT_MASK(15, 0)) ++#define PCU_WAKEUP_STATUS_SIG_OFFSET (0) ++#define PCU_WAKEUP_STATUS_SIG_DEFAULT (0x0) ++#define PCU_WAKEUP_STATUS_DEFAULT (PCU_WAKEUP_STATUS_SIG_DEFAULT << PCU_WAKEUP_STATUS_SIG_OFFSET) ++#define PCU_WAKEUP_STATUS_DFT_MASK (PCU_WAKEUP_STATUS_SIG_MASK) ++ ++//reset timing ++#define PCU_RESET_TIMER_RG3_MASK (ANDES_BIT_MASK(31, 24)) ++#define PCU_RESET_TIMER_RG3_OFFSET (24) ++#define PCU_RESET_TIMER_RG3_DEFAULT PCU_RESET_TIMER_RG3_CNT_DEFAULT // in rtl fast reset, this will be 0x2 ++#define PCU_RESET_TIMER_RG3_SRC_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_RESET_TIMER_RG3_SRC_OFFSET (31) ++#define PCU_RESET_TIMER_RG3_SRC_DEFAULT (0x0) ++#define PCU_RESET_TIMER_RG3_CNT_MASK (ANDES_BIT_MASK(30, 24)) ++#define PCU_RESET_TIMER_RG3_CNT_OFFSET (24) ++#define PCU_RESET_TIMER_RG3_CNT_DEFAULT (0x4) ++#define PCU_RESET_TIMER_RG2_MASK (ANDES_BIT_MASK(23, 16)) ++#define PCU_RESET_TIMER_RG2_OFFSET (16) ++#define PCU_RESET_TIMER_RG2_DEFAULT PCU_RESET_TIMER_RG2_CNT_DEFAULT // in rtl fast reset, this will be 0x2 ++#define PCU_RESET_TIMER_RG2_SRC_MASK (ANDES_BIT_MASK(23, 23)) ++#define PCU_RESET_TIMER_RG2_SRC_OFFSET (23) ++#define PCU_RESET_TIMER_RG2_SRC_DEFAULT (0x0) ++#define PCU_RESET_TIMER_RG2_CNT_MASK (ANDES_BIT_MASK(22, 16)) ++#define PCU_RESET_TIMER_RG2_CNT_OFFSET (16) ++#define PCU_RESET_TIMER_RG2_CNT_DEFAULT (0x4) ++#define PCU_RESET_TIMER_RG1_MASK (ANDES_BIT_MASK(15, 8)) ++#define PCU_RESET_TIMER_RG1_OFFSET (8) ++#define PCU_RESET_TIMER_RG1_DEFAULT PCU_RESET_TIMER_RG1_CNT_DEFAULT // in rtl fast reset, this will be 0x2 ++#define PCU_RESET_TIMER_RG1_SRC_MASK (ANDES_BIT_MASK(15, 15)) ++#define PCU_RESET_TIMER_RG1_SRC_OFFSET (15) ++#define PCU_RESET_TIMER_RG1_SRC_DEFAULT (0x0) ++#define PCU_RESET_TIMER_RG1_CNT_MASK (ANDES_BIT_MASK(14, 8)) ++#define PCU_RESET_TIMER_RG1_CNT_OFFSET (8) ++#define PCU_RESET_TIMER_RG1_CNT_DEFAULT (0x4) ++#define PCU_RESET_TIMER_RG0_MASK (ANDES_BIT_MASK(7, 0)) ++#define PCU_RESET_TIMER_RG0_OFFSET (0) ++#define PCU_RESET_TIMER_RG0_DEFAULT PCU_RESET_TIMER_RG0_CNT_DEFAULT // in rtl fast reset, this will be 0x2 ++#define PCU_RESET_TIMER_RG0_SRC_MASK (ANDES_BIT_MASK(7, 7)) ++#define PCU_RESET_TIMER_RG0_SRC_OFFSET (7) ++#define PCU_RESET_TIMER_RG0_SRC_DEFAULT (0x0) ++#define PCU_RESET_TIMER_RG0_CNT_MASK (ANDES_BIT_MASK(6, 0)) ++#define PCU_RESET_TIMER_RG0_CNT_OFFSET (0) ++#define PCU_RESET_TIMER_RG0_CNT_DEFAULT (0x4) ++ ++#define PCU_RESET_TIMER_DEFAULT 0x0 /*((PCU_RESET_TIMER_RG3_DEFAULT << PCU_RESET_TIMER_RG3_OFFSET)|\ ++ (PCU_RESET_TIMER_RG2_DEFAULT << PCU_RESET_TIMER_RG2_OFFSET)|\ ++ (PCU_RESET_TIMER_RG1_DEFAULT << PCU_RESET_TIMER_RG1_OFFSET)|\ ++ (PCU_RESET_TIMER_RG0_DEFAULT << PCU_RESET_TIMER_RG0_OFFSET))*/ ++#define PCU_RESET_TIMER_DFT_MASK 0x0 /*((PCU_RESET_TIMER_RG3_MASK)|\ ++ (PCU_RESET_TIMER_RG2_MASK)|\ ++ (PCU_RESET_TIMER_RG1_MASK)|\ ++ (PCU_RESET_TIMER_RG0_MASK))*/ ++#define PCU_RST_TIMER_SRC_500US (0x1) ++#define PCU_RST_TIMER_SRC_30US (0x0) ++ ++// interrupt ++#define PCU_INTR_GPIOSEC_MASK (ANDES_BIT_MASK(11, 11)) ++#define PCU_INTR_PWRLOW_MASK (ANDES_BIT_MASK(10, 10)) ++#define PCU_INTR_PCS9_MASK (ANDES_BIT_MASK(9, 9)) ++#define PCU_INTR_PCS9_OFFSET (9) ++#define PCU_INTR_PCS9_DEFAULT (0x0) ++#define PCU_INTR_PCS8_MASK (ANDES_BIT_MASK(8, 8)) ++#define PCU_INTR_PCS8_OFFSET (8) ++#define PCU_INTR_PCS8_DEFAULT (0x0) ++#define PCU_INTR_PCS7_MASK (ANDES_BIT_MASK(7, 7)) ++#define PCU_INTR_PCS7_OFFSET (7) ++#define PCU_INTR_PCS7_DEFAULT (0x0) ++#define PCU_INTR_PCS6_MASK (ANDES_BIT_MASK(6, 6)) ++#define PCU_INTR_PCS6_OFFSET (6) ++#define PCU_INTR_PCS6_DEFAULT (0x0) ++#define PCU_INTR_PCS5_MASK (ANDES_BIT_MASK(5, 5)) ++#define PCU_INTR_PCS5_OFFSET (5) ++#define PCU_INTR_PCS5_DEFAULT (0x0) ++#define PCU_INTR_PCS4_MASK (ANDES_BIT_MASK(4, 4)) ++#define PCU_INTR_PCS4_OFFSET (4) ++#define PCU_INTR_PCS4_DEFAULT (0x0) ++#define PCU_INTR_PCS3_MASK (ANDES_BIT_MASK(3, 3)) ++#define PCU_INTR_PCS3_OFFSET (3) ++#define PCU_INTR_PCS3_DEFAULT (0x0) ++#define PCU_INTR_PCS2_MASK (ANDES_BIT_MASK(2, 2)) ++#define PCU_INTR_PCS2_OFFSET (2) ++#define PCU_INTR_PCS2_DEFAULT (0x0) ++#define PCU_INTR_PCS1_MASK (ANDES_BIT_MASK(1, 1)) ++#define PCU_INTR_PCS1_OFFSET (1) ++#define PCU_INTR_PCS1_DEFAULT (0x0) ++#define PCU_INTR_BSM_MASK (ANDES_BIT_MASK(0, 0)) ++#define PCU_INTR_BSM_OFFSET (0) ++#define PCU_INTR_BSM_DEFAULT (0x0) ++#define PCU_INTR_DEFAULT (0x0) ++ ++// bits field for PCS1 registers ++#define PCU_PCS1_CFG_TYPE_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS1_CFG_TYPE_OFFSET (28) ++#define PCU_PCS1_CFG_TYPE_DEFAULT (0x1) ++#define PCU_PCS1_CFG_WR_MASK (ANDES_BIT_MASK(27, 27)) ++#define PCU_PCS1_CFG_WR_OFFSET (27) ++#define PCU_PCS1_CFG_WR_DEFAULT (0x0) ++#define PCU_PCS1_CFG_SR_MASK (ANDES_BIT_MASK(26, 26)) ++#define PCU_PCS1_CFG_SR_OFFSET (0) ++#define PCU_PCS1_CFG_SR_DEFAULT (0x0) ++#define PCU_PCS1_CFG_LS_MASK (ANDES_BIT_MASK(23, 20)) ++#define PCU_PCS1_CFG_LS_OFFSET (20) ++#define PCU_PCS1_CFG_LS_DEFAULT (0x0) ++#define PCU_PCS1_CFG_LW_MASK (ANDES_BIT_MASK(19, 16)) ++#define PCU_PCS1_CFG_LW_OFFSET (16) ++#define PCU_PCS1_CFG_LW_DEFAULT (0x0) ++#define PCU_PCS1_CFG_WKEN_MASK (ANDES_BIT_MASK(15, 0)) ++#define PCU_PCS1_CFG_WKEN_OFFSET (0) ++#define PCU_PCS1_CFG_WKEN_DEFAULT (0x0) ++#define PCU_PCS1_CFG_DEFAULT ((PCU_PCS1_CFG_TYPE_DEFAULT << PCU_PCS1_CFG_TYPE_OFFSET)|\ ++ (PCU_PCS1_CFG_WR_DEFAULT << PCU_PCS1_CFG_WR_OFFSET )|\ ++ (PCU_PCS1_CFG_SR_DEFAULT << PCU_PCS1_CFG_SR_OFFSET )|\ ++ (PCU_PCS1_CFG_LS_DEFAULT << PCU_PCS1_CFG_LS_OFFSET )|\ ++ (PCU_PCS1_CFG_LW_DEFAULT << PCU_PCS1_CFG_LW_OFFSET )|\ ++ (PCU_PCS1_CFG_WKEN_DEFAULT << PCU_PCS1_CFG_WKEN_OFFSET)) ++ ++#define PCU_PCS1_PARA_IE_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_PCS1_PARA_IE_OFFSET (31) ++#define PCU_PCS1_PARA_IE_DEFAULT (0x0) ++#define PCU_PCS1_PARA_CMD_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS1_PARA_CMD_OFFSET (28) ++#define PCU_PCS1_PARA_CMD_DEFAULT (0x0) ++#define PCU_PCS1_PARA_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS1_PARA_SYNC_OFFSET (24) ++#define PCU_PCS1_PARA_SYNC_DEFAULT (0x3) ++#define PCU_PCS1_PARA_NXTPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS1_PARA_NXTPAR_OFFSET (0) ++#define PCU_PCS1_PARA_NXTPAR_DEFAULT (0x1) ++#define PCU_PCS1_PARA_DIV_MASK (ANDES_BIT_MASK(5, 4)) ++#define PCU_PCS1_PARA_DIV_OFFSET (4) ++//#define PCU_PCS1_PARA_DIV_DEFAULT (0x0) //jumper setting ++#define PCU_PCS1_PARA_RATIO_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_PCS1_PARA_RATIO_OFFSET (0) ++//#define PCU_PCS1_PARA_RATIO_DEFAULT (0x0) //jumper setting ++#define PCU_PCS1_PARA_DEFAULT ((PCU_PCS1_PARA_IE_DEFAULT << PCU_PCS1_PARA_IE_OFFSET )|\ ++ (PCU_PCS1_PARA_CMD_DEFAULT << PCU_PCS1_PARA_CMD_OFFSET )|\ ++ (PCU_PCS1_PARA_SYNC_DEFAULT << PCU_PCS1_PARA_SYNC_OFFSET)) ++#define PCU_PCS1_PARA_DFT_MASK ((PCU_PCS1_PARA_IE_MASK )|\ ++ (PCU_PCS1_PARA_CMD_MASK )|\ ++ (PCU_PCS1_PARA_SYNC_MASK)) ++ ++#define PCU_PCS1_ST1_STS_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS1_ST1_STS_OFFSET (28) ++#define PCU_PCS1_ST1_STS_DEFAULT (0x0) ++#define PCU_PCS1_ST1_ERR_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_PCS1_ST1_ERR_OFFSET (0) ++#define PCU_PCS1_ST1_ERR_DEFAULT (0x0) ++#define PCU_PCS1_ST1_DEFAULT ((PCU_PCS1_ST1_STS_DEFAULT << PCU_PCS1_ST1_STS_OFFSET )|\ ++ (PCU_PCS1_ST1_ERR_DEFAULT << PCU_PCS1_ST1_ERR_OFFSET )) ++ ++#define PCU_PCS1_ST2_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS1_ST2_SYNC_OFFSET (24) ++#define PCU_PCS1_ST2_SYNC_DEFAULT (0x0) ++#define PCU_PCS1_ST2_CURPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS1_ST2_CURPAR_OFFSET (0) ++//#define PCU_PCS1_ST2_CURPAR_DEFAULT (0x0) ++#define PCU_PCS1_ST2_DIV_MASK (ANDES_BIT_MASK(5, 4)) ++#define PCU_PCS1_ST2_DIV_OFFSET (4) ++//#define PCU_PCS1_ST2_DIV_DEFAULT (0x0) //jumper setting ++#define PCU_PCS1_ST2_RATIO_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_PCS1_ST2_RATIO_OFFSET (0) ++//#define PCU_PCS1_ST2_RATIO_DEFAULT (0x0) //jumper setting ++#define PCU_PCS1_ST2_DEFAULT (PCU_PCS1_ST2_SYNC_DEFAULT << PCU_PCS1_ST2_SYNC_OFFSET) ++#define PCU_PCS1_ST2_DFT_MASK (PCU_PCS1_ST2_SYNC_MASK) ++ ++ ++// bits field for PCS2 registers ++#define PCU_PCS2_CFG_TYPE_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS2_CFG_TYPE_OFFSET (28) ++#define PCU_PCS2_CFG_TYPE_DEFAULT (0x2) ++#define PCU_PCS2_CFG_WR_MASK (ANDES_BIT_MASK(27, 27)) ++#define PCU_PCS2_CFG_WR_OFFSET (27) ++#define PCU_PCS2_CFG_WR_DEFAULT (0x0) ++#define PCU_PCS2_CFG_SR_MASK (ANDES_BIT_MASK(26, 26)) ++#define PCU_PCS2_CFG_SR_OFFSET (0) ++#define PCU_PCS2_CFG_SR_DEFAULT (0x0) ++#define PCU_PCS2_CFG_LS_MASK (ANDES_BIT_MASK(23, 20)) ++#define PCU_PCS2_CFG_LS_OFFSET (20) ++#define PCU_PCS2_CFG_LS_DEFAULT (0x0) ++#define PCU_PCS2_CFG_LW_MASK (ANDES_BIT_MASK(19, 16)) ++#define PCU_PCS2_CFG_LW_OFFSET (16) ++#define PCU_PCS2_CFG_LW_DEFAULT (0x0) ++#define PCU_PCS2_CFG_WKEN_MASK (ANDES_BIT_MASK(15, 0)) ++#define PCU_PCS2_CFG_WKEN_OFFSET (0) ++#define PCU_PCS2_CFG_WKEN_DEFAULT (0x0) ++#define PCU_PCS2_CFG_DEFAULT ((PCU_PCS2_CFG_TYPE_DEFAULT << PCU_PCS2_CFG_TYPE_OFFSET)|\ ++ (PCU_PCS2_CFG_WR_DEFAULT << PCU_PCS2_CFG_WR_OFFSET )|\ ++ (PCU_PCS2_CFG_SR_DEFAULT << PCU_PCS2_CFG_SR_OFFSET )|\ ++ (PCU_PCS2_CFG_LS_DEFAULT << PCU_PCS2_CFG_LS_OFFSET )|\ ++ (PCU_PCS2_CFG_LW_DEFAULT << PCU_PCS2_CFG_LW_OFFSET )|\ ++ (PCU_PCS2_CFG_WKEN_DEFAULT << PCU_PCS2_CFG_WKEN_OFFSET)) ++ ++#define PCU_PCS2_PARA_IE_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_PCS2_PARA_IE_OFFSET (31) ++#define PCU_PCS2_PARA_IE_DEFAULT (0x0) ++#define PCU_PCS2_PARA_CMD_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS2_PARA_CMD_OFFSET (28) ++#define PCU_PCS2_PARA_CMD_DEFAULT (0x0) ++#define PCU_PCS2_PARA_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS2_PARA_SYNC_OFFSET (24) ++#define PCU_PCS2_PARA_SYNC_DEFAULT (0x3) ++#define PCU_PCS2_PARA_NXTPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS2_PARA_NXTPAR_OFFSET (0) ++#define PCU_PCS2_PARA_NXTPAR_DEFAULT (0x0) ++#define PCU_PCS2_PARA_DEFAULT ((PCU_PCS2_PARA_IE_DEFAULT << PCU_PCS2_PARA_IE_OFFSET )|\ ++ (PCU_PCS2_PARA_CMD_DEFAULT << PCU_PCS2_PARA_CMD_OFFSET )|\ ++ (PCU_PCS2_PARA_SYNC_DEFAULT << PCU_PCS2_PARA_SYNC_OFFSET )|\ ++ (PCU_PCS2_PARA_NXTPAR_DEFAULT << PCU_PCS2_PARA_NXTPAR_OFFSET)) ++#define PCU_PCS2_PARA_DFT_MASK ((PCU_PCS2_PARA_IE_MASK )|\ ++ (PCU_PCS2_PARA_CMD_MASK )|\ ++ (PCU_PCS2_PARA_SYNC_MASK )|\ ++ (PCU_PCS2_PARA_NXTPAR_MASK)) ++ ++#define PCU_PCS2_ST1_STS_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS2_ST1_STS_OFFSET (28) ++#define PCU_PCS2_ST1_STS_DEFAULT (0x0) ++#define PCU_PCS2_ST1_ERR_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_PCS2_ST1_ERR_OFFSET (0) ++#define PCU_PCS2_ST1_ERR_DEFAULT (0x0) ++#define PCU_PCS2_ST1_DEFAULT ((PCU_PCS2_ST1_STS_DEFAULT << PCU_PCS2_ST1_STS_OFFSET )|\ ++ (PCU_PCS2_ST1_ERR_DEFAULT << PCU_PCS2_ST1_ERR_OFFSET )) ++ ++#define PCU_PCS2_ST2_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS2_ST2_SYNC_OFFSET (24) ++#define PCU_PCS2_ST2_SYNC_DEFAULT (0x0) ++#define PCU_PCS2_ST2_CURPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS2_ST2_CURPAR_OFFSET (0) ++#define PCU_PCS2_ST2_CURPAR_DEFAULT (0x0) ++#define PCU_PCS2_ST2_DEFAULT ((PCU_PCS2_ST2_SYNC_DEFAULT << PCU_PCS2_ST2_SYNC_OFFSET )|\ ++ (PCU_PCS2_ST2_CURPAR_DEFAULT << PCU_PCS2_ST2_CURPAR_OFFSET)) ++#define PCU_PCS2_ST2_DFT_MASK ((PCU_PCS2_ST2_SYNC_MASK )|\ ++ (PCU_PCS2_ST2_CURPAR_MASK)) ++ ++// bits field for PCS3 registers ++#define PCU_PCS3_CFG_TYPE_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS3_CFG_TYPE_OFFSET (28) ++#define PCU_PCS3_CFG_TYPE_DEFAULT (0x2) ++#define PCU_PCS3_CFG_WR_MASK (ANDES_BIT_MASK(27, 27)) ++#define PCU_PCS3_CFG_WR_OFFSET (27) ++#define PCU_PCS3_CFG_WR_DEFAULT (0x0) ++#define PCU_PCS3_CFG_SR_MASK (ANDES_BIT_MASK(26, 26)) ++#define PCU_PCS3_CFG_SR_OFFSET (0) ++#define PCU_PCS3_CFG_SR_DEFAULT (0x0) ++#define PCU_PCS3_CFG_LS_MASK (ANDES_BIT_MASK(23, 20)) ++#define PCU_PCS3_CFG_LS_OFFSET (20) ++#define PCU_PCS3_CFG_LS_DEFAULT (0x0) ++#define PCU_PCS3_CFG_LW_MASK (ANDES_BIT_MASK(19, 16)) ++#define PCU_PCS3_CFG_LW_OFFSET (16) ++#define PCU_PCS3_CFG_LW_DEFAULT (0x0) ++#define PCU_PCS3_CFG_WKEN_MASK (ANDES_BIT_MASK(15, 0)) ++#define PCU_PCS3_CFG_WKEN_OFFSET (0) ++#define PCU_PCS3_CFG_WKEN_DEFAULT (0x0) ++#define PCU_PCS3_CFG_DEFAULT ((PCU_PCS3_CFG_TYPE_DEFAULT << PCU_PCS3_CFG_TYPE_OFFSET)|\ ++ (PCU_PCS3_CFG_WR_DEFAULT << PCU_PCS3_CFG_WR_OFFSET )|\ ++ (PCU_PCS3_CFG_SR_DEFAULT << PCU_PCS3_CFG_SR_OFFSET )|\ ++ (PCU_PCS3_CFG_LS_DEFAULT << PCU_PCS3_CFG_LS_OFFSET )|\ ++ (PCU_PCS3_CFG_LW_DEFAULT << PCU_PCS3_CFG_LW_OFFSET )|\ ++ (PCU_PCS3_CFG_WKEN_DEFAULT << PCU_PCS3_CFG_WKEN_OFFSET)) ++ ++#define PCU_PCS3_PARA_IE_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_PCS3_PARA_IE_OFFSET (31) ++#define PCU_PCS3_PARA_IE_DEFAULT (0x0) ++#define PCU_PCS3_PARA_CMD_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS3_PARA_CMD_OFFSET (28) ++#define PCU_PCS3_PARA_CMD_DEFAULT (0x0) ++#define PCU_PCS3_PARA_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS3_PARA_SYNC_OFFSET (24) ++#define PCU_PCS3_PARA_SYNC_DEFAULT (0x3) ++#define PCU_PCS3_PARA_NXTPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS3_PARA_NXTPAR_OFFSET (0) ++#define PCU_PCS3_PARA_NXTPAR_DEFAULT (0x0) ++#define PCU_PCS3_PARA_DEFAULT ((PCU_PCS3_PARA_IE_DEFAULT << PCU_PCS3_PARA_IE_OFFSET )|\ ++ (PCU_PCS3_PARA_CMD_DEFAULT << PCU_PCS3_PARA_CMD_OFFSET )|\ ++ (PCU_PCS3_PARA_SYNC_DEFAULT << PCU_PCS3_PARA_SYNC_OFFSET )|\ ++ (PCU_PCS3_PARA_NXTPAR_DEFAULT << PCU_PCS3_PARA_NXTPAR_OFFSET)) ++#define PCU_PCS3_PARA_DFT_MASK ((PCU_PCS3_PARA_IE_MASK )|\ ++ (PCU_PCS3_PARA_CMD_MASK )|\ ++ (PCU_PCS3_PARA_SYNC_MASK )|\ ++ (PCU_PCS3_PARA_NXTPAR_MASK)) ++ ++#define PCU_PCS3_ST1_STS_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS3_ST1_STS_OFFSET (28) ++#define PCU_PCS3_ST1_STS_DEFAULT (0x0) ++#define PCU_PCS3_ST1_ERR_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_PCS3_ST1_ERR_OFFSET (0) ++#define PCU_PCS3_ST1_ERR_DEFAULT (0x0) ++#define PCU_PCS3_ST1_DEFAULT ((PCU_PCS3_ST1_STS_DEFAULT << PCU_PCS3_ST1_STS_OFFSET )|\ ++ (PCU_PCS3_ST1_ERR_DEFAULT << PCU_PCS3_ST1_ERR_OFFSET )) ++ ++#define PCU_PCS3_ST2_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS3_ST2_SYNC_OFFSET (24) ++#define PCU_PCS3_ST2_SYNC_DEFAULT (0x0) ++#define PCU_PCS3_ST2_CURPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS3_ST2_CURPAR_OFFSET (0) ++#define PCU_PCS3_ST2_CURPAR_DEFAULT (0x0) ++#define PCU_PCS3_ST2_DEFAULT ((PCU_PCS3_ST2_SYNC_DEFAULT << PCU_PCS3_ST2_SYNC_OFFSET )|\ ++ (PCU_PCS3_ST2_CURPAR_DEFAULT << PCU_PCS3_ST2_CURPAR_OFFSET)) ++#define PCU_PCS3_ST2_DFT_MASK ((PCU_PCS3_ST2_SYNC_MASK )|\ ++ (PCU_PCS3_ST2_CURPAR_MASK)) ++ ++// bits field for PCS4 registers ++#define PCU_PCS4_CFG_TYPE_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS4_CFG_TYPE_OFFSET (28) ++#define PCU_PCS4_CFG_TYPE_DEFAULT (0x0) ++#define PCU_PCS4_CFG_WR_MASK (ANDES_BIT_MASK(27, 27)) ++#define PCU_PCS4_CFG_WR_OFFSET (27) ++#define PCU_PCS4_CFG_WR_DEFAULT (0x0) ++#define PCU_PCS4_CFG_SR_MASK (ANDES_BIT_MASK(26, 26)) ++#define PCU_PCS4_CFG_SR_OFFSET (0) ++#define PCU_PCS4_CFG_SR_DEFAULT (0x0) ++#define PCU_PCS4_CFG_LS_MASK (ANDES_BIT_MASK(23, 20)) ++#define PCU_PCS4_CFG_LS_OFFSET (20) ++#define PCU_PCS4_CFG_LS_DEFAULT (0x0) ++#define PCU_PCS4_CFG_LW_MASK (ANDES_BIT_MASK(19, 16)) ++#define PCU_PCS4_CFG_LW_OFFSET (16) ++#define PCU_PCS4_CFG_LW_DEFAULT (0x0) ++#define PCU_PCS4_CFG_WKEN_MASK (ANDES_BIT_MASK(15, 0)) ++#define PCU_PCS4_CFG_WKEN_OFFSET (0) ++#define PCU_PCS4_CFG_WKEN_DEFAULT (0x0) ++#define PCU_PCS4_CFG_DEFAULT ((PCU_PCS4_CFG_TYPE_DEFAULT << PCU_PCS4_CFG_TYPE_OFFSET)|\ ++ (PCU_PCS4_CFG_WR_DEFAULT << PCU_PCS4_CFG_WR_OFFSET )|\ ++ (PCU_PCS4_CFG_SR_DEFAULT << PCU_PCS4_CFG_SR_OFFSET )|\ ++ (PCU_PCS4_CFG_LS_DEFAULT << PCU_PCS4_CFG_LS_OFFSET )|\ ++ (PCU_PCS4_CFG_LW_DEFAULT << PCU_PCS4_CFG_LW_OFFSET )|\ ++ (PCU_PCS4_CFG_WKEN_DEFAULT << PCU_PCS4_CFG_WKEN_OFFSET)) ++ ++#define PCU_PCS4_PARA_IE_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_PCS4_PARA_IE_OFFSET (31) ++#define PCU_PCS4_PARA_IE_DEFAULT (0x0) ++#define PCU_PCS4_PARA_CMD_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS4_PARA_CMD_OFFSET (28) ++#define PCU_PCS4_PARA_CMD_DEFAULT (0x0) ++#define PCU_PCS4_PARA_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS4_PARA_SYNC_OFFSET (24) ++#define PCU_PCS4_PARA_SYNC_DEFAULT (0x3) ++#define PCU_PCS4_PARA_NXTPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS4_PARA_NXTPAR_OFFSET (0) ++#define PCU_PCS4_PARA_NXTPAR_DEFAULT (0x4) ++#define PCU_PCS4_PARA_PWDN_MASK (ANDES_BIT_MASK(23, 23)) ++#define PCU_PCS4_PARA_PWDN_OFFSET (23) ++#define PCU_PCS4_PARA_PWDN_DEFAULT (0x0) ++#define PCU_PCS4_PARA_RANGE_MASK (ANDES_BIT_MASK(17, 16)) ++#define PCU_PCS4_PARA_RANGE_OFFSET (16) ++#define PCU_PCS4_PARA_RANGE_DEFAULT (0x0) ++#define PCU_PCS4_PARA_N_FACTOR_MASK (ANDES_BIT_MASK(7, 0)) ++#define PCU_PCS4_PARA_N_FACTOR_OFFSET (0) ++#define PCU_PCS4_PARA_N_FACTOR_DEFAULT (0x4) ++#define PCU_PCS4_PARA_DEFAULT ((PCU_PCS4_PARA_IE_DEFAULT << PCU_PCS4_PARA_IE_OFFSET )|\ ++ (PCU_PCS4_PARA_CMD_DEFAULT << PCU_PCS4_PARA_CMD_OFFSET )|\ ++ (PCU_PCS4_PARA_SYNC_DEFAULT << PCU_PCS4_PARA_SYNC_OFFSET)|\ ++ (PCU_PCS4_PARA_PWDN_DEFAULT << PCU_PCS4_PARA_PWDN_OFFSET)) ++#define PCU_PCS4_PARA_DFT_MASK ((PCU_PCS4_PARA_IE_MASK )|\ ++ (PCU_PCS4_PARA_CMD_MASK )|\ ++ (PCU_PCS4_PARA_SYNC_MASK)|\ ++ (PCU_PCS4_PARA_PWDN_MASK)) ++ ++#define PCU_PCS4_ST1_STS_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS4_ST1_STS_OFFSET (28) ++#define PCU_PCS4_ST1_STS_DEFAULT (0x0) ++#define PCU_PCS4_ST1_ERR_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_PCS4_ST1_ERR_OFFSET (0) ++#define PCU_PCS4_ST1_ERR_DEFAULT (0x0) ++#define PCU_PCS4_ST1_DEFAULT ((PCU_PCS4_ST1_STS_DEFAULT << PCU_PCS4_ST1_STS_OFFSET )|\ ++ (PCU_PCS4_ST1_ERR_DEFAULT << PCU_PCS4_ST1_ERR_OFFSET )) ++ ++#define PCU_PCS4_ST2_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS4_ST2_SYNC_OFFSET (24) ++#define PCU_PCS4_ST2_SYNC_DEFAULT (0x0) ++#define PCU_PCS4_ST2_CURPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS4_ST2_CURPAR_OFFSET (0) ++//#define PCU_PCS4_ST2_CURPAR_DEFAULT (0x0) ++#define PCU_PCS4_ST2_PWDN_MASK PCU_PCS4_PARA_PWDN_MASK ++#define PCU_PCS4_ST2_PWDN_OFFSET PCU_PCS4_PARA_PWDN_OFFSET ++#define PCU_PCS4_ST2_PWDN_DEFAULT PCU_PCS4_PARA_PWDN_DEFAULT ++#define PCU_PCS4_ST2_RANGE_MASK PCU_PCS4_PARA_RANGE_MASK ++#define PCU_PCS4_ST2_RANGE_OFFSET PCU_PCS4_PARA_RANGE_OFFSET ++//#define PCU_PCS4_ST2_RANGE_DEFAULT PCU_PCS4_PARA_RANGE_DEFAULT ++#define PCU_PCS4_ST2_N_FACTOR_MASK PCU_PCS4_PARA_N_FACTOR_MASK ++#define PCU_PCS4_ST2_N_FACTOR_OFFSET PCU_PCS4_PARA_N_FACTOR_OFFSET ++//#define PCU_PCS4_ST2_N_FACTOR_DEFAULT PCU_PCS4_PARA_N_FACTOR_DEFAULT ++#define PCU_PCS4_ST2_DEFAULT ((PCU_PCS4_ST2_SYNC_DEFAULT << PCU_PCS4_ST2_SYNC_OFFSET)|\ ++ (PCU_PCS4_ST2_PWDN_DEFAULT << PCU_PCS4_ST2_PWDN_OFFSET)) ++#define PCU_PCS4_ST2_DFT_MASK ((PCU_PCS4_ST2_SYNC_MASK)|\ ++ (PCU_PCS4_ST2_PWDN_MASK)) ++ ++// bits field for PCS5 registers ++#define PCU_PCS5_CFG_TYPE_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS5_CFG_TYPE_OFFSET (28) ++#define PCU_PCS5_CFG_TYPE_DEFAULT (0x0) ++#define PCU_PCS5_CFG_WR_MASK (ANDES_BIT_MASK(27, 27)) ++#define PCU_PCS5_CFG_WR_OFFSET (27) ++#define PCU_PCS5_CFG_WR_DEFAULT (0x0) ++#define PCU_PCS5_CFG_SR_MASK (ANDES_BIT_MASK(26, 26)) ++#define PCU_PCS5_CFG_SR_OFFSET (0) ++#define PCU_PCS5_CFG_SR_DEFAULT (0x0) ++#define PCU_PCS5_CFG_LS_MASK (ANDES_BIT_MASK(23, 20)) ++#define PCU_PCS5_CFG_LS_OFFSET (20) ++#define PCU_PCS5_CFG_LS_DEFAULT (0x0) ++#define PCU_PCS5_CFG_LW_MASK (ANDES_BIT_MASK(19, 16)) ++#define PCU_PCS5_CFG_LW_OFFSET (16) ++#define PCU_PCS5_CFG_LW_DEFAULT (0x0) ++#define PCU_PCS5_CFG_WKEN_MASK (ANDES_BIT_MASK(15, 0)) ++#define PCU_PCS5_CFG_WKEN_OFFSET (0) ++#define PCU_PCS5_CFG_WKEN_DEFAULT (0x0) ++#define PCU_PCS5_CFG_DEFAULT ((PCU_PCS5_CFG_TYPE_DEFAULT << PCU_PCS5_CFG_TYPE_OFFSET)|\ ++ (PCU_PCS5_CFG_WR_DEFAULT << PCU_PCS5_CFG_WR_OFFSET )|\ ++ (PCU_PCS5_CFG_SR_DEFAULT << PCU_PCS5_CFG_SR_OFFSET )|\ ++ (PCU_PCS5_CFG_LS_DEFAULT << PCU_PCS5_CFG_LS_OFFSET )|\ ++ (PCU_PCS5_CFG_LW_DEFAULT << PCU_PCS5_CFG_LW_OFFSET )|\ ++ (PCU_PCS5_CFG_WKEN_DEFAULT << PCU_PCS5_CFG_WKEN_OFFSET)) ++ ++#define PCU_PCS5_PARA_IE_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_PCS5_PARA_IE_OFFSET (31) ++#define PCU_PCS5_PARA_IE_DEFAULT (0x0) ++#define PCU_PCS5_PARA_CMD_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS5_PARA_CMD_OFFSET (28) ++#define PCU_PCS5_PARA_CMD_DEFAULT (0x0) ++#define PCU_PCS5_PARA_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS5_PARA_SYNC_OFFSET (24) ++#define PCU_PCS5_PARA_SYNC_DEFAULT (0x3) ++#define PCU_PCS5_PARA_NXTPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS5_PARA_NXTPAR_OFFSET (0) ++#define PCU_PCS5_PARA_NXTPAR_DEFAULT (0x0) ++#define PCU_PCS5_PARA_DLL_PWDN_MASK (ANDES_BIT_MASK(23, 23)) ++#define PCU_PCS5_PARA_DLL_PWDN_OFFSET (23) ++#define PCU_PCS5_PARA_DLL_PWDN_DEFAULT (0x0) ++#define PCU_PCS5_PARA_PLL_PWDN_MASK (ANDES_BIT_MASK(22, 22)) ++#define PCU_PCS5_PARA_PLL_PWDN_OFFSET (22) ++#define PCU_PCS5_PARA_PLL_PWDN_DEFAULT (0x0) ++#define PCU_PCS5_PARA_DLL_BYPASS_MASK (ANDES_BIT_MASK(16, 16)) ++#define PCU_PCS5_PARA_DLL_BYPASS_OFFSET (16) ++#define PCU_PCS5_PARA_DLL_BYPASS_DEFAULT (0x0) ++#define PCU_PCS5_PARA_DLL_DELAY_MASK (ANDES_BIT_MASK(15, 12)) ++#define PCU_PCS5_PARA_DLL_DELAY_OFFSET (12) ++#define PCU_PCS5_PARA_DLL_DELAY_DEFAULT (0x0) ++#define PCU_PCS5_PARA_66MHZ_MASK (ANDES_BIT_MASK(11, 11)) ++#define PCU_PCS5_PARA_66MHZ_OFFSET (11) ++//#define PCU_PCS5_PARA_66MHZ_DEFAULT (0x0) /dumper setting ++#define PCU_PCS5_PARA_DEFAULT ((PCU_PCS5_PARA_IE_DEFAULT << PCU_PCS5_PARA_IE_OFFSET )|\ ++ (PCU_PCS5_PARA_CMD_DEFAULT << PCU_PCS5_PARA_CMD_OFFSET )|\ ++ (PCU_PCS5_PARA_SYNC_DEFAULT << PCU_PCS5_PARA_SYNC_OFFSET )|\ ++ (PCU_PCS5_PARA_PLL_PWDN_DEFAULT << PCU_PCS5_PARA_PLL_PWDN_OFFSET )|\ ++ (PCU_PCS5_PARA_DLL_DELAY_DEFAULT << PCU_PCS5_PARA_DLL_DELAY_OFFSET )) ++#define PCU_PCS5_PARA_DFT_MASK ((PCU_PCS5_PARA_IE_MASK )|\ ++ (PCU_PCS5_PARA_CMD_MASK )|\ ++ (PCU_PCS5_PARA_SYNC_MASK )|\ ++ (PCU_PCS5_PARA_PLL_PWDN_MASK )|\ ++ (PCU_PCS5_PARA_DLL_DELAY_MASK )) ++ ++#define PCU_PCS5_ST1_STS_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS5_ST1_STS_OFFSET (28) ++#define PCU_PCS5_ST1_STS_DEFAULT (0x0) ++#define PCU_PCS5_ST1_ERR_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_PCS5_ST1_ERR_OFFSET (0) ++#define PCU_PCS5_ST1_ERR_DEFAULT (0x0) ++#define PCU_PCS5_ST1_DEFAULT ((PCU_PCS5_ST1_STS_DEFAULT << PCU_PCS5_ST1_STS_OFFSET )|\ ++ (PCU_PCS5_ST1_ERR_DEFAULT << PCU_PCS5_ST1_ERR_OFFSET )) ++ ++#define PCU_PCS5_ST2_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS5_ST2_SYNC_OFFSET (24) ++#define PCU_PCS5_ST2_SYNC_DEFAULT (0x0) ++#define PCU_PCS5_ST2_CURPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS5_ST2_CURPAR_OFFSET (0) ++//#define PCU_PCS5_ST2_CURPAR_DEFAULT (0x0) //no default ++#define PCU_PCS5_ST2_DLL_PWDN_MASK PCU_PCS5_PARA_DLL_PWDN_MASK ++#define PCU_PCS5_ST2_DLL_PWDN_OFFSET PCU_PCS5_PARA_DLL_PWDN_OFFSET ++#define PCU_PCS5_ST2_DLL_PWDN_DEFAULT PCU_PCS5_PARA_DLL_PWDN_DEFAULT ++#define PCU_PCS5_ST2_PLL_PWDN_MASK PCU_PCS5_PARA_PLL_PWDN_MASK ++#define PCU_PCS5_ST2_PLL_PWDN_OFFSET PCU_PCS5_PARA_PLL_PWDN_OFFSET ++#define PCU_PCS5_ST2_PLL_PWDN_DEFAULT PCU_PCS5_PARA_PLL_PWDN_DEFAULT ++#define PCU_PCS5_ST2_DLL_BYPASS_MASK PCU_PCS5_PARA_DLL_BYPASS_MASK ++#define PCU_PCS5_ST2_DLL_BYPASS_OFFSET PCU_PCS5_PARA_DLL_BYPASS_OFFSET ++#define PCU_PCS5_ST2_DLL_BYPASS_DEFAULT PCU_PCS5_PARA_DLL_BYPASS_DEFAULT ++#define PCU_PCS5_ST2_DLL_DELAY_MASK PCU_PCS5_PARA_DLL_DELAY_MASK ++#define PCU_PCS5_ST2_DLL_DELAY_OFFSET PCU_PCS5_PARA_DLL_DELAY_OFFSET ++#define PCU_PCS5_ST2_DLL_DELAY_DEFAULT PCU_PCS5_PARA_DLL_DELAY_DEFAULT ++#define PCU_PCS5_ST2_DEFAULT ((PCU_PCS5_ST2_SYNC_DEFAULT << PCU_PCS5_ST2_SYNC_OFFSET )|\ ++ (PCU_PCS5_ST2_PLL_PWDN_DEFAULT << PCU_PCS5_ST2_PLL_PWDN_OFFSET )|\ ++ (PCU_PCS5_ST2_DLL_DELAY_DEFAULT << PCU_PCS5_ST2_DLL_DELAY_OFFSET )) ++#define PCU_PCS5_ST2_DFT_MASK ((PCU_PCS5_ST2_SYNC_MASK )|\ ++ (PCU_PCS5_ST2_PLL_PWDN_MASK )|\ ++ (PCU_PCS5_ST2_DLL_DELAY_MASK )) ++ ++// bits field for PCS6 registers ++#define PCU_PCS6_CFG_TYPE_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS6_CFG_TYPE_OFFSET (28) ++#define PCU_PCS6_CFG_TYPE_DEFAULT (0x0) ++#define PCU_PCS6_CFG_WR_MASK (ANDES_BIT_MASK(27, 27)) ++#define PCU_PCS6_CFG_WR_OFFSET (27) ++#define PCU_PCS6_CFG_WR_DEFAULT (0x0) ++#define PCU_PCS6_CFG_SR_MASK (ANDES_BIT_MASK(26, 26)) ++#define PCU_PCS6_CFG_SR_OFFSET (0) ++#define PCU_PCS6_CFG_SR_DEFAULT (0x0) ++#define PCU_PCS6_CFG_LS_MASK (ANDES_BIT_MASK(23, 20)) ++#define PCU_PCS6_CFG_LS_OFFSET (20) ++#define PCU_PCS6_CFG_LS_DEFAULT (0x0) ++#define PCU_PCS6_CFG_LW_MASK (ANDES_BIT_MASK(19, 16)) ++#define PCU_PCS6_CFG_LW_OFFSET (16) ++#define PCU_PCS6_CFG_LW_DEFAULT (0x0) ++#define PCU_PCS6_CFG_WKEN_MASK (ANDES_BIT_MASK(15, 0)) ++#define PCU_PCS6_CFG_WKEN_OFFSET (0) ++#define PCU_PCS6_CFG_WKEN_DEFAULT (0x0) ++#define PCU_PCS6_CFG_DEFAULT ((PCU_PCS6_CFG_TYPE_DEFAULT << PCU_PCS6_CFG_TYPE_OFFSET)|\ ++ (PCU_PCS6_CFG_WR_DEFAULT << PCU_PCS6_CFG_WR_OFFSET )|\ ++ (PCU_PCS6_CFG_SR_DEFAULT << PCU_PCS6_CFG_SR_OFFSET )|\ ++ (PCU_PCS6_CFG_LS_DEFAULT << PCU_PCS6_CFG_LS_OFFSET )|\ ++ (PCU_PCS6_CFG_LW_DEFAULT << PCU_PCS6_CFG_LW_OFFSET )|\ ++ (PCU_PCS6_CFG_WKEN_DEFAULT << PCU_PCS6_CFG_WKEN_OFFSET)) ++ ++#define PCU_PCS6_PARA_IE_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_PCS6_PARA_IE_OFFSET (31) ++#define PCU_PCS6_PARA_IE_DEFAULT (0x0) ++#define PCU_PCS6_PARA_CMD_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS6_PARA_CMD_OFFSET (28) ++#define PCU_PCS6_PARA_CMD_DEFAULT (0x0) ++#define PCU_PCS6_PARA_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS6_PARA_SYNC_OFFSET (24) ++#define PCU_PCS6_PARA_SYNC_DEFAULT (0x3) ++#define PCU_PCS6_PARA_NXTPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS6_PARA_NXTPAR_OFFSET (0) ++#define PCU_PCS6_PARA_NXTPAR_DEFAULT (0x0) ++#define PCU_PCS6_PARA_PWDN_MASK (ANDES_BIT_MASK(23, 23)) ++#define PCU_PCS6_PARA_PWDN_OFFSET (23) ++#define PCU_PCS6_PARA_PWDN_DEFAULT (0x0) ++#define PCU_PCS6_PARA_DEFAULT ((PCU_PCS6_PARA_IE_DEFAULT << PCU_PCS6_PARA_IE_OFFSET )|\ ++ (PCU_PCS6_PARA_CMD_DEFAULT << PCU_PCS6_PARA_CMD_OFFSET )|\ ++ (PCU_PCS6_PARA_SYNC_DEFAULT << PCU_PCS6_PARA_SYNC_OFFSET)|\ ++ (PCU_PCS6_PARA_PWDN_DEFAULT << PCU_PCS6_PARA_PWDN_OFFSET)) ++#define PCU_PCS6_PARA_DFT_MASK ((PCU_PCS6_PARA_IE_MASK )|\ ++ (PCU_PCS6_PARA_CMD_MASK )|\ ++ (PCU_PCS6_PARA_SYNC_MASK)|\ ++ (PCU_PCS6_PARA_PWDN_MASK)) ++ ++#define PCU_PCS6_ST1_STS_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS6_ST1_STS_OFFSET (28) ++#define PCU_PCS6_ST1_STS_DEFAULT (0x0) ++#define PCU_PCS6_ST1_ERR_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_PCS6_ST1_ERR_OFFSET (0) ++#define PCU_PCS6_ST1_ERR_DEFAULT (0x0) ++#define PCU_PCS6_ST1_DEFAULT ((PCU_PCS6_ST1_STS_DEFAULT << PCU_PCS6_ST1_STS_OFFSET )|\ ++ (PCU_PCS6_ST1_ERR_DEFAULT << PCU_PCS6_ST1_ERR_OFFSET )) ++ ++#define PCU_PCS6_ST2_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS6_ST2_SYNC_OFFSET (24) ++#define PCU_PCS6_ST2_SYNC_DEFAULT (0x0) ++#define PCU_PCS6_ST2_CURPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS6_ST2_CURPAR_OFFSET (0) ++//#define PCU_PCS6_ST2_CURPAR_DEFAULT (0x0) //no default ++#define PCU_PCS6_ST2_PWDN_MASK PCU_PCS6_PARA_PWDN_MASK ++#define PCU_PCS6_ST2_PWDN_OFFSET PCU_PCS6_PARA_PWDN_OFFSET ++#define PCU_PCS6_ST2_PWDN_DEFAULT PCU_PCS6_PARA_PWDN_DEFAULT ++#define PCU_PCS6_ST2_DEFAULT ((PCU_PCS6_ST2_SYNC_DEFAULT << PCU_PCS6_ST2_SYNC_OFFSET)|\ ++ (PCU_PCS6_ST2_PWDN_DEFAULT << PCU_PCS6_ST2_PWDN_OFFSET)) ++#define PCU_PCS6_ST2_DFT_MASK ((PCU_PCS6_ST2_SYNC_MASK)|\ ++ (PCU_PCS6_ST2_PWDN_MASK)) ++ ++// bits field for PCS7 registers ++#define PCU_PCS7_CFG_TYPE_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS7_CFG_TYPE_OFFSET (28) ++#define PCU_PCS7_CFG_TYPE_DEFAULT (0x0) ++#define PCU_PCS7_CFG_WR_MASK (ANDES_BIT_MASK(27, 27)) ++#define PCU_PCS7_CFG_WR_OFFSET (27) ++#define PCU_PCS7_CFG_WR_DEFAULT (0x0) ++#define PCU_PCS7_CFG_SR_MASK (ANDES_BIT_MASK(26, 26)) ++#define PCU_PCS7_CFG_SR_OFFSET (0) ++#define PCU_PCS7_CFG_SR_DEFAULT (0x0) ++#define PCU_PCS7_CFG_LS_MASK (ANDES_BIT_MASK(23, 20)) ++#define PCU_PCS7_CFG_LS_OFFSET (20) ++#define PCU_PCS7_CFG_LS_DEFAULT (0x0) ++#define PCU_PCS7_CFG_LW_MASK (ANDES_BIT_MASK(19, 16)) ++#define PCU_PCS7_CFG_LW_OFFSET (16) ++#define PCU_PCS7_CFG_LW_DEFAULT (0x0) ++#define PCU_PCS7_CFG_WKEN_MASK (ANDES_BIT_MASK(15, 0)) ++#define PCU_PCS7_CFG_WKEN_OFFSET (0) ++#define PCU_PCS7_CFG_WKEN_DEFAULT (0x0) ++#define PCU_PCS7_CFG_DEFAULT ((PCU_PCS7_CFG_TYPE_DEFAULT << PCU_PCS7_CFG_TYPE_OFFSET)|\ ++ (PCU_PCS7_CFG_WR_DEFAULT << PCU_PCS7_CFG_WR_OFFSET )|\ ++ (PCU_PCS7_CFG_SR_DEFAULT << PCU_PCS7_CFG_SR_OFFSET )|\ ++ (PCU_PCS7_CFG_LS_DEFAULT << PCU_PCS7_CFG_LS_OFFSET )|\ ++ (PCU_PCS7_CFG_LW_DEFAULT << PCU_PCS7_CFG_LW_OFFSET )|\ ++ (PCU_PCS7_CFG_WKEN_DEFAULT << PCU_PCS7_CFG_WKEN_OFFSET)) ++ ++#define PCU_PCS7_PARA_IE_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_PCS7_PARA_IE_OFFSET (31) ++#define PCU_PCS7_PARA_IE_DEFAULT (0x0) ++#define PCU_PCS7_PARA_CMD_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS7_PARA_CMD_OFFSET (28) ++#define PCU_PCS7_PARA_CMD_DEFAULT (0x0) ++#define PCU_PCS7_PARA_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS7_PARA_SYNC_OFFSET (24) ++#define PCU_PCS7_PARA_SYNC_DEFAULT (0x3) ++#define PCU_PCS7_PARA_NXTPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS7_PARA_NXTPAR_OFFSET (0) ++#define PCU_PCS7_PARA_NXTPAR_DEFAULT (0x0) ++#define PCU_PCS7_PARA_PWDN_MASK (ANDES_BIT_MASK(23, 23)) ++#define PCU_PCS7_PARA_PWDN_OFFSET (23) ++#define PCU_PCS7_PARA_PWDN_DEFAULT (0x0) ++#define PCU_PCS7_PARA_DEFAULT ((PCU_PCS7_PARA_IE_DEFAULT << PCU_PCS7_PARA_IE_OFFSET )|\ ++ (PCU_PCS7_PARA_CMD_DEFAULT << PCU_PCS7_PARA_CMD_OFFSET )|\ ++ (PCU_PCS7_PARA_SYNC_DEFAULT << PCU_PCS7_PARA_SYNC_OFFSET)|\ ++ (PCU_PCS7_PARA_PWDN_DEFAULT << PCU_PCS7_PARA_PWDN_OFFSET)) ++#define PCU_PCS7_PARA_DFT_MASK ((PCU_PCS7_PARA_IE_MASK )|\ ++ (PCU_PCS7_PARA_CMD_MASK )|\ ++ (PCU_PCS7_PARA_SYNC_MASK)|\ ++ (PCU_PCS7_PARA_PWDN_MASK)) ++ ++#define PCU_PCS7_ST1_STS_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS7_ST1_STS_OFFSET (28) ++#define PCU_PCS7_ST1_STS_DEFAULT (0x0) ++#define PCU_PCS7_ST1_ERR_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_PCS7_ST1_ERR_OFFSET (0) ++#define PCU_PCS7_ST1_ERR_DEFAULT (0x0) ++#define PCU_PCS7_ST1_DEFAULT ((PCU_PCS7_ST1_STS_DEFAULT << PCU_PCS7_ST1_STS_OFFSET )|\ ++ (PCU_PCS7_ST1_ERR_DEFAULT << PCU_PCS7_ST1_ERR_OFFSET )) ++ ++#define PCU_PCS7_ST2_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS7_ST2_SYNC_OFFSET (24) ++#define PCU_PCS7_ST2_SYNC_DEFAULT (0x0) ++#define PCU_PCS7_ST2_CURPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS7_ST2_CURPAR_OFFSET (0) ++//#define PCU_PCS7_ST2_CURPAR_DEFAULT (0x0) //no default ++#define PCU_PCS7_ST2_PWDN_MASK PCU_PCS7_PARA_PWDN_MASK ++#define PCU_PCS7_ST2_PWDN_OFFSET PCU_PCS7_PARA_PWDN_OFFSET ++#define PCU_PCS7_ST2_PWDN_DEFAULT PCU_PCS7_PARA_PWDN_DEFAULT ++#define PCU_PCS7_ST2_DEFAULT ((PCU_PCS7_ST2_SYNC_DEFAULT << PCU_PCS7_ST2_SYNC_OFFSET)|\ ++ (PCU_PCS7_ST2_PWDN_DEFAULT << PCU_PCS7_ST2_PWDN_OFFSET)) ++#define PCU_PCS7_ST2_DFT_MASK ((PCU_PCS7_ST2_SYNC_MASK)|\ ++ (PCU_PCS7_ST2_PWDN_MASK)) ++ ++// bits field for PCS8 registers ++#define PCU_PCS8_CFG_TYPE_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS8_CFG_TYPE_OFFSET (28) ++#define PCU_PCS8_CFG_TYPE_DEFAULT (0x4) ++#define PCU_PCS8_CFG_WR_MASK (ANDES_BIT_MASK(27, 27)) ++#define PCU_PCS8_CFG_WR_OFFSET (27) ++#define PCU_PCS8_CFG_WR_DEFAULT (0x0) ++#define PCU_PCS8_CFG_SR_MASK (ANDES_BIT_MASK(26, 26)) ++#define PCU_PCS8_CFG_SR_OFFSET (0) ++#define PCU_PCS8_CFG_SR_DEFAULT (0x0) ++#define PCU_PCS8_CFG_LS_MASK (ANDES_BIT_MASK(23, 20)) ++#define PCU_PCS8_CFG_LS_OFFSET (20) ++#define PCU_PCS8_CFG_LS_DEFAULT (0x0) ++#define PCU_PCS8_CFG_LW_MASK (ANDES_BIT_MASK(19, 16)) ++#define PCU_PCS8_CFG_LW_OFFSET (16) ++#define PCU_PCS8_CFG_LW_DEFAULT (0x0) ++#define PCU_PCS8_CFG_WKEN_MASK (ANDES_BIT_MASK(15, 0)) ++#define PCU_PCS8_CFG_WKEN_OFFSET (0) ++#define PCU_PCS8_CFG_WKEN_DEFAULT (0x0) ++#define PCU_PCS8_CFG_DEFAULT ((PCU_PCS8_CFG_TYPE_DEFAULT << PCU_PCS8_CFG_TYPE_OFFSET)|\ ++ (PCU_PCS8_CFG_WR_DEFAULT << PCU_PCS8_CFG_WR_OFFSET )|\ ++ (PCU_PCS8_CFG_SR_DEFAULT << PCU_PCS8_CFG_SR_OFFSET )|\ ++ (PCU_PCS8_CFG_LS_DEFAULT << PCU_PCS8_CFG_LS_OFFSET )|\ ++ (PCU_PCS8_CFG_LW_DEFAULT << PCU_PCS8_CFG_LW_OFFSET )|\ ++ (PCU_PCS8_CFG_WKEN_DEFAULT << PCU_PCS8_CFG_WKEN_OFFSET)) ++ ++#define PCU_PCS8_PARA_IE_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_PCS8_PARA_IE_OFFSET (31) ++#define PCU_PCS8_PARA_IE_DEFAULT (0x0) ++#define PCU_PCS8_PARA_CMD_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS8_PARA_CMD_OFFSET (28) ++#define PCU_PCS8_PARA_CMD_DEFAULT (0x0) ++#define PCU_PCS8_PARA_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS8_PARA_SYNC_OFFSET (24) ++#define PCU_PCS8_PARA_SYNC_DEFAULT (0x3) ++#define PCU_PCS8_PARA_NXTPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS8_PARA_NXTPAR_OFFSET (0) ++#define PCU_PCS8_PARA_NXTPAR_DEFAULT (0x0) ++#define PCU_PCS8_PARA_STOP_MASK (ANDES_BIT_MASK(13, 13)) ++#define PCU_PCS8_PARA_STOP_OFFSET (13) ++#define PCU_PCS8_PARA_STOP_DEFAULT (0x0) ++#define PCU_PCS8_PARA_START_MASK (ANDES_BIT_MASK(12, 12)) ++#define PCU_PCS8_PARA_START_OFFSET (12) ++#define PCU_PCS8_PARA_START_DEFAULT (0x0) ++#define PCU_PCS8_PARA_BYTES_MASK (ANDES_BIT_MASK(10, 8)) ++#define PCU_PCS8_PARA_BYTES_OFFSET (8) ++#define PCU_PCS8_PARA_BYTES_DEFAULT (0x0) ++#define PCU_PCS8_PARA_ADDR_MASK (ANDES_BIT_MASK(7, 1)) ++#define PCU_PCS8_PARA_ADDR_OFFSET (1) ++#define PCU_PCS8_PARA_ADDR_DEFAULT (0x0) ++#define PCU_PCS8_PARA_READ_MASK (ANDES_BIT_MASK(0, 0)) ++#define PCU_PCS8_PARA_READ_OFFSET (0) ++#define PCU_PCS8_PARA_READ_DEFAULT (0x0) ++#define PCU_PCS8_PARA_DEFAULT ((PCU_PCS8_PARA_IE_DEFAULT << PCU_PCS8_PARA_IE_OFFSET )|\ ++ (PCU_PCS8_PARA_CMD_DEFAULT << PCU_PCS8_PARA_CMD_OFFSET )|\ ++ (PCU_PCS8_PARA_SYNC_DEFAULT << PCU_PCS8_PARA_SYNC_OFFSET )|\ ++ (PCU_PCS8_PARA_NXTPAR_DEFAULT << PCU_PCS8_PARA_NXTPAR_OFFSET)) ++ ++ ++#define PCU_PCS8_ST1_STS_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS8_ST1_STS_OFFSET (28) ++#define PCU_PCS8_ST1_STS_DEFAULT (0x0) ++#define PCU_PCS8_ST1_ERR_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_PCS8_ST1_ERR_OFFSET (0) ++#define PCU_PCS8_ST1_ERR_DEFAULT (0x0) ++#define PCU_PCS8_ST1_DEFAULT ((PCU_PCS8_ST1_STS_DEFAULT << PCU_PCS8_ST1_STS_OFFSET )|\ ++ (PCU_PCS8_ST1_ERR_DEFAULT << PCU_PCS8_ST1_ERR_OFFSET )) ++ ++#define PCU_PCS8_ST2_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS8_ST2_SYNC_OFFSET (24) ++#define PCU_PCS8_ST2_SYNC_DEFAULT (0x0) ++#define PCU_PCS8_ST2_CURPAR_MASK PCU_PCS8_PARA_NXTPAR_MASK ++#define PCU_PCS8_ST2_CURPAR_OFFSET PCU_PCS8_PARA_NXTPAR_OFFSET ++#define PCU_PCS8_ST2_CURPAR_DEFAULT PCU_PCS8_PARA_NXTPAR_DEFAULT ++#define PCU_PCS8_ST2_DEFAULT ((PCU_PCS8_ST2_SYNC_DEFAULT << PCU_PCS8_ST2_SYNC_OFFSET )|\ ++ (PCU_PCS8_ST2_CURPAR_DEFAULT << PCU_PCS8_ST2_CURPAR_OFFSET)) ++ ++ ++#define PCU_PCS8_PDD_4TH_BYTE_MASK (ANDES_BIT_MASK(31, 24)) ++#define PCU_PCS8_PDD_4TH_BYTE_OFFSET (24) ++#define PCU_PCS8_PDD_4TH_BYTE_DEFAULT (0x0) ++#define PCU_PCS8_PDD_3RD_BYTE_MASK (ANDES_BIT_MASK(23, 16)) ++#define PCU_PCS8_PDD_3RD_BYTE_OFFSET (16) ++#define PCU_PCS8_PDD_3RD_BYTE_DEFAULT (0x0) ++#define PCU_PCS8_PDD_2ND_BYTE_MASK (ANDES_BIT_MASK(15, 8)) ++#define PCU_PCS8_PDD_2ND_BYTE_OFFSET (8) ++#define PCU_PCS8_PDD_2ND_BYTE_DEFAULT (0x0) ++#define PCU_PCS8_PDD_1ST_BYTE_MASK (ANDES_BIT_MASK(7, 0)) ++#define PCU_PCS8_PDD_1ST_BYTE_OFFSET (0) ++#define PCU_PCS8_PDD_1ST_BYTE_DEFAULT (0x0) ++#define PCU_PCS8_PDD_DEFAULT ((PCU_PCS8_PDD_4TH_BYTE_DEFAULT << PCU_PCS8_PDD_4TH_BYTE_OFFSET)|\ ++ (PCU_PCS8_PDD_3RD_BYTE_DEFAULT << PCU_PCS8_PDD_3RD_BYTE_OFFSET)|\ ++ (PCU_PCS8_PDD_2ND_BYTE_DEFAULT << PCU_PCS8_PDD_2ND_BYTE_OFFSET)|\ ++ (PCU_PCS8_PDD_1ST_BYTE_DEFAULT << PCU_PCS8_PDD_1ST_BYTE_OFFSET)) ++ ++// bits field for PCS9 registers ++#define PCU_PCS9_CFG_TYPE_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS9_CFG_TYPE_OFFSET (28) ++#define PCU_PCS9_CFG_TYPE_DEFAULT (0x6) ++#define PCU_PCS9_CFG_WR_MASK (ANDES_BIT_MASK(27, 27)) ++#define PCU_PCS9_CFG_WR_OFFSET (27) ++#define PCU_PCS9_CFG_WR_DEFAULT (0x0) ++#define PCU_PCS9_CFG_SR_MASK (ANDES_BIT_MASK(26, 26)) ++#define PCU_PCS9_CFG_SR_OFFSET (0) ++#define PCU_PCS9_CFG_SR_DEFAULT (0x0) ++#define PCU_PCS9_CFG_LS_MASK (ANDES_BIT_MASK(23, 20)) ++#define PCU_PCS9_CFG_LS_OFFSET (20) ++#define PCU_PCS9_CFG_LS_DEFAULT (0x0) ++#define PCU_PCS9_CFG_LW_MASK (ANDES_BIT_MASK(19, 16)) ++#define PCU_PCS9_CFG_LW_OFFSET (16) ++#define PCU_PCS9_CFG_LW_DEFAULT (0x0) ++#define PCU_PCS9_CFG_WKEN_MASK (ANDES_BIT_MASK(15, 0)) ++#define PCU_PCS9_CFG_WKEN_OFFSET (0) ++#define PCU_PCS9_CFG_WKEN_DEFAULT (0x0) ++#define PCU_PCS9_CFG_DEFAULT ((PCU_PCS9_CFG_TYPE_DEFAULT << PCU_PCS9_CFG_TYPE_OFFSET)|\ ++ (PCU_PCS9_CFG_WR_DEFAULT << PCU_PCS9_CFG_WR_OFFSET )|\ ++ (PCU_PCS9_CFG_SR_DEFAULT << PCU_PCS9_CFG_SR_OFFSET )|\ ++ (PCU_PCS9_CFG_LS_DEFAULT << PCU_PCS9_CFG_LS_OFFSET )|\ ++ (PCU_PCS9_CFG_LW_DEFAULT << PCU_PCS9_CFG_LW_OFFSET )|\ ++ (PCU_PCS9_CFG_WKEN_DEFAULT << PCU_PCS9_CFG_WKEN_OFFSET)) ++ ++#define PCU_PCS9_PARA_IE_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_PCS9_PARA_IE_OFFSET (31) ++#define PCU_PCS9_PARA_IE_DEFAULT (0x0) ++#define PCU_PCS9_PARA_CMD_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS9_PARA_CMD_OFFSET (28) ++#define PCU_PCS9_PARA_CMD_DEFAULT (0x0) ++#define PCU_PCS9_PARA_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS9_PARA_SYNC_OFFSET (24) ++#define PCU_PCS9_PARA_SYNC_DEFAULT (0x3) ++#define PCU_PCS9_PARA_NXTPAR_MASK (ANDES_BIT_MASK(23, 0)) ++#define PCU_PCS9_PARA_NXTPAR_OFFSET (0) ++#define PCU_PCS9_PARA_NXTPAR_DEFAULT (0x0) ++#define PCU_PCS9_PARA_TEST_MASK (PCS_POWER_GPU_AND_DAC |\ ++ PCS_POWER_CPUB ) ++ ++#define PCU_PCS9_PARA_TEST PCU_PCS9_PARA_TEST_MASK ++ ++#define PCU_PCS9_PARA_DEFAULT ((PCU_PCS9_PARA_IE_DEFAULT << PCU_PCS9_PARA_IE_OFFSET )|\ ++ (PCU_PCS9_PARA_CMD_DEFAULT << PCU_PCS9_PARA_CMD_OFFSET )|\ ++ (PCU_PCS9_PARA_SYNC_DEFAULT << PCU_PCS9_PARA_SYNC_OFFSET )|\ ++ (PCU_PCS9_PARA_NXTPAR_DEFAULT << PCU_PCS9_PARA_NXTPAR_OFFSET)) ++ ++#define PCU_PCS9_ST1_STS_MASK (ANDES_BIT_MASK(30, 28)) ++#define PCU_PCS9_ST1_STS_OFFSET (28) ++#define PCU_PCS9_ST1_STS_DEFAULT (0x0) ++#define PCU_PCS9_ST1_ERR_MASK (ANDES_BIT_MASK(3, 0)) ++#define PCU_PCS9_ST1_ERR_OFFSET (0) ++#define PCU_PCS9_ST1_ERR_DEFAULT (0x0) ++#define PCU_PCS9_ST1_DEFAULT ((PCU_PCS9_ST1_STS_DEFAULT << PCU_PCS9_ST1_STS_OFFSET )|\ ++ (PCU_PCS9_ST1_ERR_DEFAULT << PCU_PCS9_ST1_ERR_OFFSET )) ++ ++#define PCU_PCS9_ST2_SYNC_MASK (ANDES_BIT_MASK(27, 24)) ++#define PCU_PCS9_ST2_SYNC_OFFSET (24) ++#define PCU_PCS9_ST2_SYNC_DEFAULT (0x0) ++#define PCU_PCS9_ST2_CURPAR_MASK PCU_PCS9_PARA_NXTPAR_MASK ++#define PCU_PCS9_ST2_CURPAR_OFFSET PCU_PCS9_PARA_NXTPAR_OFFSET ++#define PCU_PCS9_ST2_CURPAR_DEFAULT (0x1f) ++#define PCU_PCS9_ST2_DEFAULT ((PCU_PCS9_ST2_SYNC_DEFAULT << PCU_PCS9_ST2_SYNC_OFFSET )|\ ++ (PCU_PCS9_ST2_CURPAR_DEFAULT << PCU_PCS9_ST2_CURPAR_OFFSET)) ++ ++#define PCU_PCS9_PDD_CLR_PWOFF_FLAG_MASK (ANDES_BIT_MASK(31, 31)) ++#define PCU_PCS9_PDD_CLR_PWOFF_FLAG_OFFSET (31) ++#define PCU_PCS9_PDD_CLR_PWOFF_FLAG_DEFAULT (0x0) ++#define PCU_PCS9_PDD_SUSP2RAM_MASK (ANDES_BIT_MASK(30, 30)) ++#define PCU_PCS9_PDD_SUSP2RAM_OFFSET (30) ++#define PCU_PCS9_PDD_SUSP2RAM_DEFAULT (0x0) ++#define PCU_PCS9_PDD_PWR_OFF_TIME_MASK (ANDES_BIT_MASK(29, 28)) ++#define PCU_PCS9_PDD_PWR_OFF_TIME_OFFSET (28) ++#define PCU_PCS9_PDD_PWR_OFF_TIME_DEFAULT (0x3) ++#define PCU_PCS9_PDD_TICK_MASK (ANDES_BIT_MASK(24, 24)) ++#define PCU_PCS9_PDD_TICK_OFFSET (24) ++#define PCU_PCS9_PDD_TICK_DEFAULT (0x1) ++#define PCU_PCS9_PDD_TIMER4_MASK (ANDES_BIT_MASK(23, 18)) ++#define PCU_PCS9_PDD_TIMER4_OFFSET (18) ++#define PCU_PCS9_PDD_TIMER4_DEFAULT (0x20) ++#define PCU_PCS9_PDD_TIMER3_MASK (ANDES_BIT_MASK(17, 12)) ++#define PCU_PCS9_PDD_TIMER3_OFFSET (12) ++#define PCU_PCS9_PDD_TIMER3_DEFAULT (0x20) ++#define PCU_PCS9_PDD_TIMER2_MASK (ANDES_BIT_MASK(11, 6)) ++#define PCU_PCS9_PDD_TIMER2_OFFSET (6) ++#define PCU_PCS9_PDD_TIMER2_DEFAULT (0x20) ++#define PCU_PCS9_PDD_TIMER1_MASK (ANDES_BIT_MASK(5, 0)) ++#define PCU_PCS9_PDD_TIMER1_OFFSET (0) ++#define PCU_PCS9_PDD_TIMER1_DEFAULT (0x20) ++ ++#define PCU_PCS9_PDD_DEFAULT ((PCU_PCS9_PDD_CLR_PWOFF_FLAG_DEFAULT << PCU_PCS9_PDD_CLR_PWOFF_FLAG_OFFSET)|\ ++ (PCU_PCS9_PDD_SUSP2RAM_DEFAULT << PCU_PCS9_PDD_SUSP2RAM_OFFSET )|\ ++ (PCU_PCS9_PDD_PWR_OFF_TIME_DEFAULT << PCU_PCS9_PDD_PWR_OFF_TIME_OFFSET )|\ ++ (PCU_PCS9_PDD_TICK_DEFAULT << PCU_PCS9_PDD_TICK_OFFSET )|\ ++ (PCU_PCS9_PDD_TIMER4_DEFAULT << PCU_PCS9_PDD_TIMER4_OFFSET )|\ ++ (PCU_PCS9_PDD_TIMER3_DEFAULT << PCU_PCS9_PDD_TIMER3_OFFSET )|\ ++ (PCU_PCS9_PDD_TIMER2_DEFAULT << PCU_PCS9_PDD_TIMER2_OFFSET )|\ ++ (PCU_PCS9_PDD_TIMER1_DEFAULT << PCU_PCS9_PDD_TIMER1_OFFSET )) ++ ++// ====================================================== ++// PCU definitaion macro ++// ====================================================== ++#define PCS_TYPE_PLL 0 ++#define PCS_TYPE_DIVIDER 1 ++#define PCS_TYPE_CLK_GATING 2 ++#define PCS_TYPE_I2C 4 ++#define PCS_TYPE_PMBUS 5 ++ ++#define PCS_WKEN0 (0x1<<0) ++#define PCS_WKEN1 (0x1<<1) ++#define PCS_WKEN2 (0x1<<2) ++#define PCS_WKEN3 (0x1<<3) ++#define PCS_WKEN4 (0x1<<4) ++#define PCS_WKEN5 (0x1<<5) ++#define PCS_WKEN6 (0x1<<6) ++#define PCS_WKEN7 (0x1<<7) ++#define PCS_WKEN8 (0x1<<8) ++#define PCS_WKEN9 (0x1<<9) ++#define PCS_WKEN10 (0x1<<10) ++#define PCS_WKEN11 (0x1<<11) ++#define PCS_WKEN12 (0x1<<12) ++#define PCS_WKEN13 (0x1<<13) ++#define PCS_WKEN14 (0x1<<14) ++#define PCS_WKEN15 (0x1<<15) ++ ++#define PCS_WKEN_GPIO0 PCS_WKEN0 ++#define PCS_WKEN_GPIO1 PCS_WKEN1 ++#define PCS_WKEN_GPIO2 PCS_WKEN2 ++#define PCS_WKEN_GPIO3 PCS_WKEN3 ++#define PCS_WKEN_GPIO4 PCS_WKEN4 ++#define PCS_WKEN_GPIO5 PCS_WKEN5 ++#define PCS_WKEN_WOL PCS_WKEN6 ++#define PCS_WKEN_RTC PCS_WKEN7 ++#define PCS_WKEN_DAY PCS_WKEN8 ++#define PCS_WKEN_DBG PCS_WKEN9 ++#define PCS_WKEN_PCI PCS_WKEN10 ++#define PCS_WKEN_LPC PCS_WKEN11 ++#define PCS_WKEN_SRC_CNT 12 // wakeup source number ++#define PCS_WKEN_SRC_MASK ((1<<PCS_WKEN_SRC_CNT)-1) ++ ++#define PCS_CMD_NOP 0x0 ++#define PCS_CMD_SCALING 0x1 ++#define PCS_CMD_PW_DOWN 0x2 ++#define PCS_CMD_DRAM_SF 0x4 // DRAM self-refresh ++ ++#define PCS_SYNC_CPUA_STBY 0x1 ++#define PCS_SYNC_CPUB_STBY 0x2 ++ ++#if ((!defined(CORE0_IDLE)) && (!defined(CORE1_IDLE))) ++ #define PCS_SYNC_SRC PCS_SYNC_CPUA_STBY ++#elif (!defined(CORE0_IDLE)) ++ #define PCS_SYNC_SRC PCS_SYNC_CPUA_STBY ++#else //(!defined(CORE1_IDLE)) ++ #define PCS_SYNC_SRC PCS_SYNC_CPUB_STBY ++#endif ++ ++#define PCS_PLL_DIVIDE1 0 ++#define PCS_PLL_DIVIDE2 1 ++#define PCS_PLL_DIVIDE4 2 ++#define PCS_PLL_DIVIDE8 3 ++ ++#define PCS_RATIO_44221H 0 // h(alf): stands for 0.5, ++#define PCS_RATIO_4422HQ 1 // q(uarter) stands for 0.25, ++#define PCS_RATIO_42221H 2 // f(ixed) stands for fixed 400Mhz ++#define PCS_RATIO_4222HQ 3 ++#define PCS_RATIO_41121H 4 ++#define PCS_RATIO_4112HQ 5 ++#define PCS_RATIO_44421H 6 ++#define PCS_RATIO_4442HQ 7 ++#define PCS_RATIO_442F1H 8 ++#define PCS_RATIO_442FHQ 9 ++#define PCS_RATIO_422F1H 10 ++#define PCS_RATIO_422FHQ 11 ++#define PCS_RATIO_411F1H 12 ++#define PCS_RATIO_411FHQ 13 ++#define PCS_RATIO_111111e 14 // enable pll ++#define PCS_RATIO_111111d 15 // disable pll ++#define PCS_RATIO_MAX PCS_RATIO_111111d ++#define PCS_RATIO_CNT (PCS_RATIO_MAX+1) ++ ++#define PCS_GATING_DDR2_HCLK (0x1<<2 ) ++#define PCS_GATING_AHB2AHB_HCLK (0x1<<3 ) ++#define PCS_GATING_DMAC_HCLK (0x1<<4 ) ++#define PCS_GATING_L2CC_HCLK (0x1<<5 ) ++#define PCS_GATING_LPC_HCLK (0x1<<6 ) ++#define PCS_GATING_I2C_HCLK (0x1<<7 ) ++#define PCS_GATING_IDE_HCLK (0x1<<8 ) ++#define PCS_GATING_GPU_HCLK (0x1<<9) ++#define PCS_GATING_GMAC_HCLK (0x1<<10) ++#define PCS_GATING_USB_HCLK (0x1<<11) ++#define PCS_GATING_PCI_HCLK (0x1<<12) ++#define PCS_GATING_HCLK_CNT (16) ++#define PCS_GATING_HCLK_VALID (PCS_GATING_DDR2_HCLK |\ ++ PCS_GATING_AHB2AHB_HCLK|\ ++ PCS_GATING_DMAC_HCLK |\ ++ PCS_GATING_L2CC_HCLK |\ ++ PCS_GATING_LPC_HCLK |\ ++ PCS_GATING_I2C_HCLK |\ ++ PCS_GATING_IDE_HCLK |\ ++ PCS_GATING_GPU_HCLK |\ ++ PCS_GATING_GMAC_HCLK |\ ++ PCS_GATING_USB_HCLK |\ ++ PCS_GATING_PCI_HCLK ) ++ ++#define PCS_GATING_NO_PCLK (0x0) ++#define PCS_GATING_SPI_PCLK (0x1<<0 ) ++#define PCS_GATING_CFC_PCLK (0x1<<1 ) ++#define PCS_GATING_SDC_PCLK (0x1<<2 ) ++#define PCS_GATING_WDT_PCLK (0x1<<3 ) ++#define PCS_GATING_TMR_PCLK (0x1<<4 ) ++#define PCS_GATING_GPIO_PCLK (0x1<<5 ) ++#define PCS_GATING_PWM_PCLK (0x1<<6 ) ++#define PCS_GATING_I2C_PCLK (0x1<<7 ) ++#define PCS_GATING_AC97I2S_PCLK (0x1<<8) ++#define PCS_GATING_UART1_PCLK (0x1<<9) ++#define PCS_GATING_UART2_PCLK (0x1<<10) ++#define PCS_GATING_PCLK_CNT (16) ++ ++#define PCS_MAIN_PLL_FREF (33) // reference frequency in MHz ++#define PCS_MAIN_PLL_M_FACTOR (1) // fixed M factor of Main PLL ++#define PCS_MAIN_PLL_50MHZ_H (66) ++#define PCS_MAIN_PLL_125MHZ_L (99) ++#define PCS_MAIN_PLL_125MHZ_H (132) ++#define PCS_MAIN_PLL_250MHZ_L (231) ++#define PCS_MAIN_PLL_250MHZ_H (264) ++#define PCS_MAIN_PLL_500MHZ_L (495) ++#define PCS_MAIN_PLL_500MHZ_H (528) ++#define PCS_MAIN_PLL_830MHZ_L (825) ++//#define PCS_MAIN_PLL_800MHZ_H () ++//#define PCS_MAIN_PLL_1000MHZ_L () ++//#define PCS_MAIN_PLL_1000MHZ_H () ++#define PCS_MAIN_PLL_CNT (4) ++#define PCS_PLL_50to125MHZ (0x0) ++#define PCS_PLL_125to250MHZ (0x1) ++#define PCS_PLL_250to500MHZ (0x2) ++#define PCS_PLL_500to1000MHZ (0x3) ++ ++#define PCU_PLL_N_FACTOR(seed, F_ref, M_factor, F_low, F_high) \ ++ (((seed)%( 1+ (F_high)*(M_factor)/(F_ref) - (F_low)*(M_factor)/(F_ref))) + ((F_low)*(M_factor)/(F_ref))) ++#define PCS_MAIN_PLL_N_FACTOR(seed, F_low, F_high) \ ++ PCU_PLL_N_FACTOR(seed, PCS_MAIN_PLL_FREF, PCS_MAIN_PLL_M_FACTOR, F_low, F_high) ++#define PCS_MAIN_PLL_CLOCK(n_factor) ((n_factor/PCS_MAIN_PLL_M_FACTOR)*PCS_MAIN_PLL_FREF) ++ ++#define PCS_POWER_GPU_AND_DAC (0x1<<1) ++#define PCS_POWER_CPUB (0x1<<2) ++#define PCS_POWER_CNT (5) ++ ++#define PCS_TICK_OSCH 0x0 ++#define PCS_TICK_OSCL 0x1 ++ ++// ++#define PCS_STS_NORMAL 0x0 ++#define PCS_STS_READY 0x1 ++#define PCS_STS_SEQUENCE 0x2 ++#define PCS_STS_DONE 0x4 ++#define PCS_STS_WAKEN 0x6 ++ ++#define PCS_ERR_NONE 0x0 ++#define PCS_ERR_ILLEGAL 0x1 ++#define PCS_ERR_SYNC_TIMEOUT 0x2 ++#define PCS_ERR_UPDATE_TIMEOUT 0x3 ++ ++// ++#define PCS_BSM_IDLE 0x0 ++#define PCS_BSM_SCALING 0x1 ++#define PCS_BSM_DONE 0x3 ++#define PCS_BSM_PWDN 0x4 ++#define PCS_BSM_ERROR 0x7 ++#define PCS_BSM_WAKEN 0x8 ++ ++#define PCS_BSM_VALID_NO_MAX 9 ++ ++// ++#define PCS_SCALING_WITH_WAIT_DOWN 0 ++#define PCS_SCALING_WITH_WAKE_GRANT 1 ++#define PCS_PW_DOWN_WITH_WAIT_DOWN 2 ++#define PCS_PW_DOWN_WAKE_GRANT 3 ++ ++#define PCS_WAKE_WITH_SCALING_CNT (PCS_SCALING_WITH_WAKE_GRANT+1) ++#define PCS_WAKE_WITH_PWDnSCL_CNT (PCS_PW_DOWN_WAKE_GRANT+1) ++ ++// standby mode define macro ++#define PCU_STBY_NO_WAKE_GRANT 0 ++#define PCU_STBY_WAKE_GRANT 1 ++#define PCU_STBY_WAIT_DONE 2 ++ ++ ++// PCU interrupt service routine signal ++#define PCU_ISR_SIG_NONE 0x0 ++#define PCU_ISR_SIG_BSM PCU_INTR_BSM_MASK ++#define PCU_ISR_SIG_PCS1 PCU_INTR_PCS1_MASK ++#define PCU_ISR_SIG_PCS2 PCU_INTR_PCS2_MASK ++#define PCU_ISR_SIG_PCS3 PCU_INTR_PCS3_MASK ++#define PCU_ISR_SIG_PCS4 PCU_INTR_PCS4_MASK ++#define PCU_ISR_SIG_PCS5 PCU_INTR_PCS5_MASK ++#define PCU_ISR_SIG_PCS6 PCU_INTR_PCS6_MASK ++#define PCU_ISR_SIG_PCS7 PCU_INTR_PCS7_MASK ++#define PCU_ISR_SIG_PCS8 PCU_INTR_PCS8_MASK ++#define PCU_ISR_SIG_PCS9 PCU_INTR_PCS9_MASK ++ ++// ====================================================== ++// PCU access macro ++// ====================================================== ++#define PCU_SET_FIELD(reg, field, value) SET_FIELD(PCU_REG_##reg, PCU_##reg##_##field##_##MASK, PCU_##reg##_##field##_##OFFSET, value) ++#define PCU_GET_FIELD(reg, field) GET_FIELD(PCU_REG_##reg, PCU_##reg##_##field##_##MASK, PCU_##reg##_##field##_##OFFSET) ++#define PCU_TEST_FIELD(reg, field) TEST_FIELD(PCU_REG_##reg, PCU_##reg##_##field##_##MASK) ++ ++#define PCU_SET_REG(reg, value) SET_REG(PCU_REG_##reg, value) ++#define PCU_GET_REG(reg) GET_REG(PCU_REG_##reg) ++#define PCU_TEST_BIT(reg, field, value) VAR_TEST_BIT(value, PCU_##reg##_##field##_##MASK) ++ ++#define PCU_CHECK(reg, field, value) CHECK_FIELD (value, PCU_##reg##_##field##_##MASK) ++#define PCU_EXTRACT(reg, field, value) EXTRACT_FIELD(value, PCU_##reg##_##field##_##MASK, PCU_##reg##_##field##_##OFFSET ) ++#define PCU_PREPARE(reg, field, value) PREPARE_FIELD(value, PCU_##reg##_##field##_##MASK, PCU_##reg##_##field##_##OFFSET ) ++ ++#define PCU_DEFAULT(reg, field) ( PCU_##reg##_##field##_##DEFAULT ) ++ ++#define PCU_TEST_SIG(var, sig) VAR_TEST_BIT(var, PCU_ISR_SIG_##sig) ++#define PCU_SET_SIG(var, sig) VAR_SET_BIT(var, PCU_ISR_SIG_##sig) ++#define PCU_CLR_SIG(var, sig) VAR_CLR_BIT(var, PCU_ISR_SIG_##sig) ++ ++// ====================================================== ++// PCU access function prototype ++// ====================================================== ++#if __STDC__ || defined(__cplusplus) ++#define PROTO_PARAMS(s) s ++#else ++#define PROTO_PARAMS(s) () ++#endif ++ ++#endif //__PCU_H +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag102/pm.c linux-3.4.110/arch/nds32/platforms/ag102/pm.c +--- linux-3.4.110.orig/arch/nds32/platforms/ag102/pm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag102/pm.c 2016-04-07 10:20:51.002083345 +0200 +@@ -0,0 +1,1614 @@ ++/* ++ * AG101 Power Management Routines ++ * ++ * Copyright (c) 2010 Gavin Guo <gavinguo@andestech.com> ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License. ++ * ++ * Abstract: ++ * ++ * This program is for AG102 power management routines. ++ * ++ * Revision History: ++ * ++ * Jul.19.2010 Initial code by Gavin. ++ */ ++#include <linux/init.h> ++#include <linux/suspend.h> ++#include <linux/errno.h> ++#include <linux/time.h> ++#include <linux/delay.h> ++/* ++ * the following include file is for testing device node ++ */ ++#include <linux/device.h> ++#include <linux/fs.h> ++#include <asm/uaccess.h> ++/*************************/ ++#include <asm/hardware.h> ++#include <asm/memory.h> ++#include <asm/system.h> ++#include <asm/mach/time.h> ++#include <asm/cacheflush.h> ++#include <asm/timer.h> ++#include <asm/io.h> ++#include <asm/amic.h> ++ ++#include "pcu.h" ++#include "gmac.h" ++ ++#ifdef CONFIG_PLAT_AG102 ++#include <asm/spec-ag102.h> ++#endif ++ ++#define ANDES_PCU_STRING "andes_pcu" ++static int andes_pcu_major; ++static struct class *andes_pcu_class; ++extern void ag102_cpu_sleep(void); ++extern void ag102_cpu_resume(void); ++extern void ag102_cpu_resume2(void); ++extern void __SELF_REFRESH_LOCK_START(); ++extern void __SELF_REFRESH_LOCK_END(); ++extern void ftpci_postinit(void /**sysdata*/ ); ++UINT32 mac_dah, mac_dal; ++ ++// ADD by river 2010.12.07 for WOL ++ ++UINT32 eth_phy_reg_read(UINT32 phy_addr, UINT32 phy_page, UINT32 phy_reg, ++ UINT32 * phy_data) ++{ ++ UINT32 cycthr = GMAC_GET_FIELD(PHYCR, MDC_CYCTHR); ++ UINT32 wdata; ++ UINT32 rdata; ++ //TIMER_P timer; ++ ++ printk(">>>>> GMAC : Calling eth_phy_reg_read()...\n"); ++ ++ wdata = GMAC_PREPARE(PHYCR, MIIRD, 0x1) | ++ GMAC_PREPARE(PHYCR, PHYAD, phy_addr) | ++ GMAC_PREPARE(PHYCR, REGAD, phy_reg) | cycthr; ++ ++ printk(">>>>> GMAC : wdata = [0x%08x]\n", wdata); ++ ++ GMAC_SET_REG(PHYCR, wdata); ++ ++ // wait phy data read ++ //TIMER_INIT(timer, 10000); // trigger timer & wait until finish of data read ++ //while ( (!TIMER_IS_TIMEOUT(timer)) && (GMAC_GET_FIELD(PHYCR, MIIRD))) { ++ // TIMER_TICK(timer); ++ //} ++ ++ while (GMAC_GET_FIELD(PHYCR, MIIRD)) { ++ mdelay(50); ++ } ++ ++ if (GMAC_GET_FIELD(PHYCR, MIIRD)) { ++ printk("ERR: GPHY read reg[%x] timeout!\n", phy_reg); ++ return 1; ++ } else { ++ rdata = GMAC_GET_FIELD(PHYDATA, MIIRDATA); ++ *phy_data = rdata; ++ printk("GPHY read [%x] \n", rdata); ++ return 0; ++ } ++} ++ ++UINT32 eth_phy_reg_write(UINT32 phy_addr, UINT32 phy_page, UINT32 phy_reg, ++ UINT32 phy_data) ++{ ++ UINT32 wdata; ++ //TIMER_P timer; ++ ++ printk(">>>>> GMAC : Calling eth_phy_reg_write()...\n"); ++ ++ GMAC_SET_FIELD(PHYDATA, MIIWDATA, phy_data); ++ wdata = GMAC_PREPARE(PHYCR, MIIWR, 0x1) | GMAC_PREPARE(PHYCR, PHYAD, phy_addr) | GMAC_PREPARE(PHYCR, REGAD, phy_reg) | 0x34; //cycthr; ++ GMAC_SET_REG(PHYCR, wdata); ++ ++ // wait phy data write ++ //TIMER_INIT(timer, 10000); // trigger timer & wait until finish of data write ++ //while ( (!TIMER_IS_TIMEOUT(timer)) && (GMAC_GET_FIELD(PHYCR, MIIWR))) { ++ // TIMER_TICK(timer); ++ //} ++ ++ while (GMAC_GET_FIELD(PHYCR, MIIWR)) { ++ mdelay(50); ++ } ++ ++ if (GMAC_GET_FIELD(PHYCR, MIIWR)) { ++ printk("ERR: GPHY write reg[%x] = %x timeout!\n", phy_reg, ++ phy_data); ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ ++INT32 eth_phy_detect(UINT32 * phy_addr, UINT32 * phy_id) ++{ ++ UINT32 i, find, data1, data2; ++ ++ printk(">>>>> GMAC : Calling eth_phy_detect()...\n"); ++ ++ for (i = 0, find = 0; i <= 0x1f; i++) { ++ eth_phy_reg_read(i, 0, 2, &data1); ++ if ((data1 != 0) && (data1 != 0xffff)) { ++ find = 1; ++ break; ++ } ++ } ++ ++ if (find == 0) { ++ printk("Err: no valid phy found!\n"); ++ *phy_id = 0; ++ return (-1); ++ } ++ ++ eth_phy_reg_read(i, 0, 2, &data1); ++ eth_phy_reg_read(i, 0, 3, &data2); ++ *phy_id = (data1 << 16) | (data2 & 0xffff); ++ *phy_addr = i; ++ printk("Info: phy id = 0x%08x!\n", *phy_id); ++ return 0; ++} ++ ++void eth_phy_init(UINT32 phy_addr) ++{ ++ UINT32 data, i; ++ //TIMER_P timer; ++ //phy_addr = DVC_PHY_ADDR; ++ ++ printk(">>>>> GMAC : Calling eth_phy_init()...\n"); ++ // GPHY SW reset ++ eth_phy_reg_read(phy_addr, 0, DVC_PHY_REG_CTL, &data); ++ data |= ++ DVC_PHY_REG_CTL_SW_RST | DVC_PHY_REG_CTL_AN_EN | ++ DVC_PHY_REG_CTL_AN_RST; ++ eth_phy_reg_write(phy_addr, 0, DVC_PHY_REG_CTL, data); ++ for (i = 0; i < 10000; i++) { // must delay enough for phy to get ready ++ //eth_mdelay(2000); ++ mdelay(2); ++ eth_phy_reg_read(phy_addr, 0, DVC_PHY_REG_CTL, &data); ++ if ((data & 0x8000) == 0) ++ break; ++ } ++ if ((data & 0x8000) != 0) { ++ printk("Err: phy sw reset timeout!!!\n"); ++ } ++ eth_phy_reg_read(phy_addr, 0, DVC_PHY_REG_CTL, &data); ++ printk("phy control = 0x%x\n", data); ++ eth_phy_reg_read(phy_addr, 0, DVC_PHY_REG_STS, &data); ++ printk("phy status = 0x%x\n", data); ++ ++ return; ++} ++ ++// initialize MAC setting ++void eth_mac_init(ETH_PHY_STAT * phy_stat) ++{ ++ UINT32 i, wdata, rdata; ++ UINT32 duplex, speed, gmac; ++ //UINT32 mac_dah, mac_dal; ++ printk(">>>>> GMAC : Calling eth_mac_init()...\n"); ++ ++ wdata = GMAC_PREPARE(MACCR, SW_RST, 0x1); ++ GMAC_SET_REG(MACCR, wdata); ++ for (i = 0; i < 1000; i++) { // must delay enough for phy to get ready ++ //eth_mdelay(8000); // delay should be enough ++ mdelay(8); ++ rdata = GMAC_GET_REG(FEAR); ++ if ((rdata >> 31) == 0) ++ break; ++ } ++ if ((rdata >> 31) != 0) { ++ printk("Err: mac sw reset timeout!!!\n"); ++ } ++ if (phy_stat->speed == 2) { //giga ++ gmac = 0x1; ++ speed = 0x1; ++ } else if (phy_stat->speed == 1) { //100 Mbps ++ gmac = 0x0; ++ speed = 0x1; ++ } else { //10 Mbps ++ gmac = 0x0; ++ speed = 0x0; ++ } ++ duplex = phy_stat->duplex; ++ GMAC_SET_REG(ISR, 0xffff); // Interrupt Status, write 1 to clear ++ GMAC_SET_REG(IME, 0xffff); // Interrupt Enable, enabling all interrupts ++ GMAC_SET_REG(MAC_MADR, mac_dah); ++ GMAC_SET_REG(MAC_LADR, mac_dal); ++ rdata = GMAC_GET_REG(FEAR); ++ GMAC_SET_FIELD(TPAFCR, TFIFO_SIZE, ++ GMAC_EXTRACT(FEAR, TFIFO_RSIZE, rdata)); ++ GMAC_SET_FIELD(TPAFCR, RFIFO_SIZE, ++ GMAC_EXTRACT(FEAR, RFIFO_RSIZE, rdata)); ++ ++ wdata = GMAC_PREPARE(MACCR, RX_MULTIPKT_EN, 0x1) | ++ GMAC_PREPARE(MACCR, BROADPKT_EN, 0x1) | ++ GMAC_PREPARE(MACCR, RX_ALLADR, 0x1) | ++ GMAC_PREPARE(MACCR, CRC_APD, 0x1) | ++ GMAC_PREPARE(MACCR, FULLDUP, duplex) | ++ GMAC_PREPARE(MACCR, RX_RUNT, 0x1) | ++ GMAC_PREPARE(MACCR, SPEED, speed) | ++ GMAC_PREPARE(MACCR, GMAC_MODE, gmac) | ++ GMAC_PREPARE(MACCR, RXMAC_EN, 0x1) | ++ GMAC_PREPARE(MACCR, TXMAC_EN, 0x1) | ++ GMAC_PREPARE(MACCR, RXDMA_EN, 0x1) | ++ GMAC_PREPARE(MACCR, TXDMA_EN, 0x1); ++ GMAC_SET_REG(MACCR, wdata); ++ ++#ifdef AHBC_NO_REMAP ++ GMAC_SET_REG(NPTXR_BADR, FTGMAC100_TXR_BASE | 0x40000000); ++ GMAC_SET_REG(RXR_BADR, FTGMAC100_RXR_BASE | 0x40000000); ++#else ++ GMAC_SET_REG(NPTXR_BADR, FTGMAC100_TXR_BASE); ++ GMAC_SET_REG(RXR_BADR, FTGMAC100_RXR_BASE); ++#endif ++ return; ++} ++ ++UINT32 eth_phy_stat(UINT32 phy_addr, ETH_PHY_STAT * phy_stat) ++{ ++ ++ phy_stat->speed = 0x1; ++ phy_stat->duplex = 0x1; ++ ++ return 0; ++} ++ ++void gmac_set_wol() ++{ ++ UINT32 wdata; ++ ++ // Set Rx Wake-up Frame ++ // write 1 clear register before enable power saving mode ++ GMAC_SET_REG(WOLSR, 0xffffffff); // clear wol status ++ ++ // set wakeup_sel and power saving mode enable ++ wdata = GMAC_PREPARE(WOLCR, MAGICPKT_EN, 0x1) | ++ GMAC_PREPARE(WOLCR, PWRSAV, 0x1); ++ ++ GMAC_SET_REG(WOLCR, wdata); ++ ++ return; ++} ++ ++// End ADD by river 2010.12.07 for WOL ++ ++//////////////////////////////// LPC wake up /////////////////////////////////////////////////// ++#define CPE_LPCIO_BASE LPC_IO_VA_BASE //VA Base ++#define CPE_LPCREG_BASE LPC_REG_VA_BASE //VA Base ++#define CPE_IC_BASE AMIC_VA_BASE ++ ++#define ITE_ADDR 0x2e ++#define ITE_DATA 0x2f ++ ++#define KBC_CMD 0x64 ++#define KBC_STATUS KBC_CMD ++#define KBC_DATA 0x60 ++ ++#define BIT_OBF 0x01 ++#define BIT_IBF 0x02 ++ ++#define LPC_REG_SCR 0x10 ++#define LPC_REG_SIR 0x14 ++#define LPC_REG_SIMR 0x18 ++ ++#define SIRQ_KB 1 ++#define SIRQ_MS 12 ++ ++//#define outlpc(addr, data) outb(data, CPE_LPCIO_BASE + 4 * addr) ++//#define inlpc(addr) inb(CPE_LPCIO_BASE + 4 * addr) ++#define inlpc(addr) REG32(CPE_LPCIO_BASE + 4 * addr) ++ ++#define IRQ_LPC 29 ++#define LEVEL 0 ++#define H_ACTIVE 0 ++#define L_ACTIVE 1 ++#define IRQ_MASK 0x80 ++#define IRQ_MODE 0x20 ++#define IRQ_LEVEL 0x24 ++ ++UINT32 IRQSources = 0; //define the current irq source for debug ++ ++static inline void outlpc(unsigned long addr, unsigned long data) ++{ ++ REG32(CPE_LPCIO_BASE + 4 * addr) = data; ++} ++ ++static void kbc_cmd(UINT8 cmd) ++{ ++ int loop_limit = 1000; ++ int i; ++ UINT8 tmpc; ++ ++ // wait until the input buffer is empty ++ for (i = 0; i < loop_limit; i++) { ++ tmpc = inlpc(KBC_STATUS); ++ if ((tmpc & BIT_IBF) == 0) ++ break; ++ } ++ ++ outlpc(KBC_CMD, cmd); ++} ++ ++static void kbc_wdata(UINT8 wdata) ++{ ++ int loop_limit = 1000; ++ int i; ++ UINT8 tmpc; ++ ++ // wait until the input buffer is empty ++ for (i = 0; i < loop_limit; i++) { ++ tmpc = inlpc(KBC_STATUS); ++ if ((tmpc & BIT_IBF) == 0) ++ break; ++ } ++ ++ outlpc(KBC_DATA, wdata); ++} ++ ++static UINT8 kbc_rdata(void) ++{ ++ int loop_limit = 1000; ++ int i; ++ UINT8 rdata; ++ UINT8 tmpc; ++ ++ // wait until the output buffer is not empty ++ for (i = 0; i < loop_limit; i++) { ++ tmpc = inlpc(KBC_STATUS); ++ if (tmpc & BIT_OBF) ++ break; ++ } ++ ++ rdata = inlpc(KBC_DATA); ++ return (rdata); ++} ++ ++static void delay_loop(int max_no) ++{ ++ int i; ++ ++ for (i = 0; i < max_no; i++) ; ++} ++ ++static UINT8 get_response(void) ++{ ++ UINT8 tmpc; ++ ++ delay_loop(200000); ++ tmpc = kbc_rdata(); ++ return (tmpc); ++} ++ ++int it8718f_init(void) ++{ ++ static int initialized = 0; ++ UINT8 tmpc; ++ unsigned int chip_id; ++ ++ if (initialized == 1) ++ return (0); ++ ++ // Enter the configuration mode ++ outlpc(ITE_ADDR, 0x87); ++ outlpc(ITE_ADDR, 0x01); ++ outlpc(ITE_ADDR, 0x55); ++ outlpc(ITE_ADDR, 0x55); ++ ++ // Check the chip ID ++ printk("Check IT8718F chip ID => "); ++ outlpc(ITE_ADDR, 0x20); ++ tmpc = inlpc(ITE_DATA); ++ chip_id = (tmpc & 0xff) << 8; ++ outlpc(ITE_ADDR, 0x21); ++ tmpc = inlpc(ITE_DATA); ++ chip_id |= tmpc & 0xff; ++ ++ if (chip_id != 0x8718) { ++ printk("FAILED with chip ID = 0x%C%C.\n", (chip_id >> 8) & 0xff, ++ chip_id & 0xff); ++ return (1); ++ } else ++ printk("PASSED\n"); ++ ++ // KBC Self Test ++ printk("KBC self-test => "); ++ kbc_cmd(0xaa); ++ tmpc = kbc_rdata(); ++ if (tmpc != 0x55) { ++ printk("FAILED with code = 0x%C\n", tmpc & 0xff); ++ return (2); ++ } else ++ printk("PASSED\n"); ++ ++ // KBC Interface Test ++ printk("KBC interface test => "); ++ kbc_cmd(0xab); ++ tmpc = kbc_rdata(); ++ switch (tmpc) { ++ case 0: ++ printk("PASSED\n"); ++ break; ++ ++ case 1: ++ printk("FAILED as the clock is stuck low\n"); ++ return (3); ++ ++ case 2: ++ printk("FAILED as the clock is stuck high\n"); ++ return (3); ++ ++ case 3: ++ printk("FAILED as the data is stuck low\n"); ++ return (3); ++ ++ case 4: ++ printk("FAILED as the data is stuck high\n"); ++ return (3); ++ ++ default: ++ printk("FAILED with unknown error\n"); ++ return (3); ++ break; ++ } ++ ++ // Read the KBC mode ++ kbc_cmd(0xca); ++ tmpc = kbc_rdata(); ++ ++ // Set KBC to the PS/2 mode ++ tmpc |= 0x01; ++ kbc_cmd(0xcb); ++ kbc_wdata(tmpc); ++ ++ // Enable keyboard ++ kbc_wdata(0xf4); ++ tmpc = get_response(); ++ printk("@@@@@ : Response of enabling keyboard = 0x%x\n", tmpc & 0xff); ++ ++ // Enable mouse ++ kbc_cmd(0xd4); ++ kbc_wdata(0xf4); ++ tmpc = get_response(); ++ //outmsg("Response of enabling mouse = 0x%C\n", tmpc & 0xff); ++ ++ // bit 6: translate ++ // bit 5: mouse enable ++ // bit 4: keyboard enable ++ // bit 3: ignore keyboard lock ++ // bit 2: system flag ++ // bit 1: mouse interrupt enable ++ // bit 0: Keyboard interrupt enable ++ kbc_cmd(0x60); ++ kbc_wdata(0x47); ++ ++ // Set repeat rate and delay ++ kbc_wdata(0xf3); ++ kbc_wdata(0x00); ++ tmpc = get_response(); ++ ++ // Set LDN = 5 (Keyboard) ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x05); ++ ++ // KBC clock = 8MHz, Key lock enabled, interrupt type can be changed ++ outlpc(ITE_ADDR, 0xf0); ++ outlpc(ITE_DATA, 0x4e); ++ ++ // Low-level triggered interrupt ++ outlpc(ITE_ADDR, 0x71); ++ outlpc(ITE_DATA, 0x01); ++ ++ // Set LDN = 6 (Mouse) ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x06); ++ ++ // Enable mouse ++ outlpc(ITE_ADDR, 0x30); ++ outlpc(ITE_DATA, 0x01); ++ ++ // Interrupt type can be changed ++ outlpc(ITE_ADDR, 0xf0); ++ outlpc(ITE_DATA, 0x01); ++ ++ // Low-level triggered interrupt ++ outlpc(ITE_ADDR, 0x71); ++ outlpc(ITE_DATA, 0x01); ++ ++ // Exit the configuration mode ++ outlpc(ITE_ADDR, 0x02); ++ outlpc(ITE_DATA, 0x02); ++ ++ initialized = 1; ++ return (0); ++} ++ ++//INT for lpc ++/* Turn the interrupt source on. */ ++void UnmaskIRQ(UINT32 IRQ) ++{ ++ volatile UINT32 *IRQBase; ++ ++ IRQBase = (UINT32 *) CPE_IC_BASE; ++ ++ IRQBase[(IRQ_MASK / sizeof(UINT32))] |= (1 << IRQ); ++} ++ ++void EnableIRQ() ++{ ++ ++ __asm__ volatile ("setgie.d\n\t" ++ "isb\n\t" ++ "mfsr $r1, $INT_MASK\n\t" ++ "ori $r1, $r1, #0x3f\n\t" ++ "mtsr $r1, $INT_MASK\n\t" ++ "setgie.e\n\t" "isb\n\t"); ++ ++} ++ ++void SetIRQmode(UINT32 IRQ, UINT32 edge) ++{ ++ volatile UINT32 *IRQBase; ++ ++ IRQBase = (UINT32 *) CPE_IC_BASE; ++ ++ if (edge) ++ IRQBase[(IRQ_MODE / sizeof(UINT32))] |= (1 << IRQ); ++ else ++ IRQBase[(IRQ_MODE / sizeof(UINT32))] &= ~(1 << IRQ); ++} ++ ++void SetIRQlevel(UINT32 IRQ, UINT32 low) ++{ ++ volatile UINT32 *IRQBase; ++ ++ IRQBase = (UINT32 *) CPE_IC_BASE; ++ ++ if (low) ++ IRQBase[(IRQ_LEVEL / sizeof(UINT32))] |= (1 << IRQ); ++ else ++ IRQBase[(IRQ_LEVEL / sizeof(UINT32))] &= ~(1 << IRQ); ++} ++ ++BOOL SetIntTrig(UINT32 intNum, int intMode, int intLevel) ++{ ++ if (intNum >= 32) { ++ printk("ERROR: The interrupt number %d is incorrect\n", intNum); ++ return FALSE; ++ } else { ++ SetIRQmode(intNum, intMode); ++ SetIRQlevel(intNum, intLevel); ++ return TRUE; ++ } ++} ++ ++BOOL EnableInt(UINT32 intNum) ++{ ++ ++ if (intNum >= 32) { ++ printk("ERROR: The interrupt number %d is incorrect\n", intNum); ++ return FALSE; ++ } else { ++ IRQSources |= 1 << intNum; ++ UnmaskIRQ(intNum); ++ EnableIRQ(); ++ return TRUE; ++ } ++} ++ ++//End INT for lpc ++ ++void enable_sirq(void) ++{ ++ UINT32 data; ++ ++ // Unmask SERIRQs of Keyboard and Mouse ++ data = inw(CPE_LPCREG_BASE + LPC_REG_SIMR); ++ data &= ~((1 << SIRQ_KB) | (1 << SIRQ_MS)); ++ outw(CPE_LPCREG_BASE + LPC_REG_SIMR, data); ++ ++ // Enable SERIRQ ++ data = inw(CPE_LPCREG_BASE + LPC_REG_SCR); ++ data |= 0x1; ++ outw(CPE_LPCREG_BASE + LPC_REG_SCR, data); ++} ++ ++void ite_set_pme() ++{ ++ ++ UINT8 tmpc; ++ unsigned int chip_id; ++ // Enter the configuration mode ++ outlpc(ITE_ADDR, 0x87); ++ outlpc(ITE_ADDR, 0x01); ++ outlpc(ITE_ADDR, 0x55); ++ outlpc(ITE_ADDR, 0x55); ++ ++ // Check the chip ID ++ printk("@@@@@ : Check IT8718F chip ID in get_lpc_value => \n"); ++ outlpc(ITE_ADDR, 0x20); ++ tmpc = inlpc(ITE_DATA); ++ chip_id = (tmpc & 0xff) << 8; ++ outlpc(ITE_ADDR, 0x21); ++ tmpc = inlpc(ITE_DATA); ++ chip_id |= tmpc & 0xff; ++ ++ printk("@@@@@ : chip_id = 0x%08x\n", chip_id); ++ if (chip_id != 0x8718) { ++ printk("FAILED with chip ID = 0x%C%C.\n", (chip_id >> 8) & 0xff, ++ chip_id & 0xff); ++ return (1); ++ } else ++ printk("@@@@@ : PASSED\n"); ++ ++ // Set LDN = 5 ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x05); ++ ++ //Read index 30 ++ outlpc(ITE_ADDR, 0x30); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x30] = 0x%x\n", tmpc); ++ //Set index 30 bit0 = 0; ++ outlpc(ITE_ADDR, 0x30); ++ outlpc(ITE_DATA, tmpc & 0xFE); ++ ++ // Set LDN = 6 ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x06); ++ ++ //Read index 30 ++ outlpc(ITE_ADDR, 0x30); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x30] = 0x%x\n", tmpc); ++ //Set index 30 bit0 = 0; ++ outlpc(ITE_ADDR, 0x30); ++ outlpc(ITE_DATA, tmpc & 0xFE); ++ ++ // Set LDN = 4 for PME ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x04); ++ ++ //Read index F0 ++ outlpc(ITE_ADDR, 0xF0); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xF0] = 0x%x\n", tmpc); ++ //Set index F0 BIT[4:3]=1; ++ outlpc(ITE_ADDR, 0xF0); ++ outlpc(ITE_DATA, tmpc | 0x18); ++ ++ //PME output enable ++ //Read index F2 ++ outlpc(ITE_ADDR, 0xF2); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xF2] = 0x%x\n", tmpc); ++ //Set index F2 bit6=0; ++ outlpc(ITE_ADDR, 0xF2); ++ outlpc(ITE_DATA, tmpc & 0xBF); ++ ++ // Exit the configuration mode ++ outlpc(ITE_ADDR, 0x02); ++ outlpc(ITE_DATA, 0x02); ++} ++ ++void get_keyboard_status() ++{ ++ ++ printk("Getting keyboard status....\n"); ++ ++ UINT8 tmpc; ++ unsigned int chip_id; ++ ++ // Enter the configuration mode ++ outlpc(ITE_ADDR, 0x87); ++ outlpc(ITE_ADDR, 0x01); ++ outlpc(ITE_ADDR, 0x55); ++ outlpc(ITE_ADDR, 0x55); ++ ++ // Check the chip ID ++ //printk("@@@@@ : Check IT8718F chip ID in get_lpc_value => \n"); ++ outlpc(ITE_ADDR, 0x20); ++ tmpc = inlpc(ITE_DATA); ++ chip_id = (tmpc & 0xff) << 8; ++ outlpc(ITE_ADDR, 0x21); ++ tmpc = inlpc(ITE_DATA); ++ chip_id |= tmpc & 0xff; ++ ++ //printk("@@@@@ : chip_id = 0x%08x\n", chip_id); ++ if (chip_id != 0x8718) { ++ printk("FAILED with chip ID = 0x%C%C.\n", (chip_id >> 8) & 0xff, ++ chip_id & 0xff); ++ return (1); ++ } ++ // Set LDN = 4 for PME ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x04); ++ ++ ///////// Dump configuration register ++ outlpc(ITE_ADDR, 0xf1); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xf1] = 0x%x\n", tmpc); ++ ++ ///////// Dump configuration register ++ outlpc(ITE_ADDR, 0xf0); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xf0] = 0x%x\n", tmpc); ++ ++} ++ ++void get_lpc_value() ++{ ++ UINT8 tmpc; ++ unsigned int chip_id; ++ ++ // Enter the configuration mode ++ outlpc(ITE_ADDR, 0x87); ++ outlpc(ITE_ADDR, 0x01); ++ outlpc(ITE_ADDR, 0x55); ++ outlpc(ITE_ADDR, 0x55); ++ ++ // Check the chip ID ++ printk("@@@@@ : Check IT8718F chip ID in get_lpc_value => \n"); ++ outlpc(ITE_ADDR, 0x20); ++ tmpc = inlpc(ITE_DATA); ++ chip_id = (tmpc & 0xff) << 8; ++ outlpc(ITE_ADDR, 0x21); ++ tmpc = inlpc(ITE_DATA); ++ chip_id |= tmpc & 0xff; ++ ++ printk("@@@@@ : chip_id = 0x%08x\n", chip_id); ++ if (chip_id != 0x8718) { ++ printk("FAILED with chip ID = 0x%C%C.\n", (chip_id >> 8) & 0xff, ++ chip_id & 0xff); ++ return (1); ++ } else ++ printk("@@@@@ : PASSED\n"); ++ ++ printk("=================== Get Values ==================\n"); ++ //////////// Environment Controller configuration register ++ printk("@@@@@ : Environment Controller configuration register\n"); ++ // Set LDN = 4 for PME ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x04); ++ ++ printk("@@@@@ : LDN = 4\n"); ++ ++ ///////// Dump configuration register ++ outlpc(ITE_ADDR, 0x30); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x30] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x60); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x60] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x61); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x61] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x62); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x62] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x63); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x63] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x70); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x70] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xf0); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xf0] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xf1); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xf1] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xf2); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xf2] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xf3); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xf3] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xf4); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xf4] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xf5); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xf5] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xf6); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xf6] = 0x%x\n", tmpc); ++ ++ //////////// Keyboard configuration register ++ printk("@@@@@ : Keyboard configuration register\n"); ++ // Set LDN = 5 ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x05); ++ ++ printk("@@@@@ : LDN = 5\n"); ++ ++ outlpc(ITE_ADDR, 0x30); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x30] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x60); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x60] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x61); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x61] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x62); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x62] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x63); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x63] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x70); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x70] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x71); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x71] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xf0); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xf0] = 0x%x\n", tmpc); ++ ++ //////////// GPIO configuration register ++ printk("@@@@@ : GPIO configuration register\n"); ++ // Set LDN = 7 for GPIO ++ outlpc(ITE_ADDR, 0x07); ++ outlpc(ITE_DATA, 0x07); ++ ++ printk("@@@@@ : LDN = 7\n"); ++ ++ outlpc(ITE_ADDR, 0x60); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x60] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x62); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x62] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x63); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x63] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x64); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x64] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x65); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x65] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x70); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x70] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x71); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x71] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x72); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x72] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x73); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x73] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0x74); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0x74] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xB0); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xB0] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xB1); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xB1] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xB2); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xB2] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xB3); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xB3] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xB4); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xB4] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xB5); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xB5] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xB8); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xB8] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xBA); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xBA] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xBB); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xBB] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xBC); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xBC] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xBD); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xBD] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xC0); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xC0] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xC1); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xC1] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xC2); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xC2] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xC3); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xC3] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xC4); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xC4] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xC5); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xC5] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xC8); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xC8] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xC9); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xC9] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xCA); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xCA] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xCB); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xCB] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xCC); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xCC] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xCD); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xCD] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xE0); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xE0] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xE1); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xE1] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xE2); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xE2] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xE3); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xE3] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xE4); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xE4] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xE5); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xE5] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xE6); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xE6] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xF0); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xF0] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xF1); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xF1] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xF2); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xF2] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xF3); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xF3] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xF4); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xF4] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xF5); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xF5] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xF6); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xF6] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xF7); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xF7] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xF8); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xF8] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xF9); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xF9] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xFA); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xFA] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xFB); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xFB] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xFC); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xFC] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xFD); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xFD] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xFE); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xFE] = 0x%x\n", tmpc); ++ ++ outlpc(ITE_ADDR, 0xFF); ++ tmpc = inlpc(ITE_DATA); ++ printk("[0xFF] = 0x%x\n", tmpc); ++ ++ printk("=================== End Get Values ==================\n"); ++ ++} ++ ++/////////////////////////////// End LPC wake up /////////////////////////////////////////////// ++ ++/* ++ * AG102 PMU sleep mode handler. ++ */ ++void andes_suspend_to_ram() ++{ ++ int i, k, l, checksum, checksuma; ++ unsigned int addr, reg; ++ static int irq_saves[3]; ++ unsigned int tmp; ++ pgd_t *pgdv; ++ pud_t *pudv; ++ pmd_t *pmdv; ++ pte_t *ptev; ++ unsigned int resume_addr /*, resume_temp */ ; ++ //unsigned int *resume_tempaddr; ++ __asm__ volatile ("mfsr %0, $ir14\n\t":"=&r" (tmp)); ++ //printk("\nag102_cpu_resume:0x%x\n", ag102_cpu_resume); ++ //printk( KERN_WARNING "\nag102_cpu_resume2:0x%x\n", ag102_cpu_resume2); ++ pgdv = ++ (pgd_t *) __va((GET_L1_PPTB() & L1_PPTB_mskBASE)) + ++ pgd_index((unsigned int)ag102_cpu_resume); ++ pudv = pud_offset(pgdv, (unsigned int)ag102_cpu_resume); ++ pmdv = pmd_offset(pudv, (unsigned int)ag102_cpu_resume); ++ ptev = pte_offset_map(pmdv, (unsigned int)ag102_cpu_resume); ++ //printk("ag102_cpu_resume pte:0x%x\n", ptev); ++ resume_addr = ++ ((*ptev) & TLB_DATA_mskPPN) | ((unsigned int)ag102_cpu_resume & ++ 0x00000fff); ++ printk("resume_addr using Page Table :0x%08x\n", resume_addr); ++ ++ //ADD by river 2010.09.23 ++ printk("@@@@@ resume_addr(VA):0x%08x\n", ag102_cpu_resume); ++ printk("@@@@@ resume_addr2(VA):0x%08x\n", ag102_cpu_resume2); ++ printk("@@@@@ resume_addr(PA) using virt_to_phys :0x%08x\n", ++ virt_to_phys(ag102_cpu_resume)); ++ printk("@@@@@ resume_addr2(PA):0x%08x\n", ++ virt_to_phys(ag102_cpu_resume2)); ++ printk("@@@@@ AHB Controller for ROM :0x%08x\n", ++ REG32(AHB_ATFAHBC020S_0_VA_BASE + 0x10)); ++ printk("@@@@@ AHB Controller for RAM :0x%08x\n", ++ REG32(AHB_ATFAHBC020S_0_VA_BASE + 0x18)); ++ //End ADD by river 2010.09.23 ++ ++ /* trigger mode regs */ ++ irq_saves[0] = REG32(AMIC_VA_BASE + 0x20); ++ /* trigger level regs */ ++ irq_saves[1] = REG32(AMIC_VA_BASE + 0x24); ++ /* interrupt enable regs */ ++ irq_saves[2] = REG32(AMIC_VA_BASE + 0x80); ++ /* save SDRAM settings */ ++ ++ /* set resume return address */ ++ //REG32(PCU_VA_BASE + 0x400) = (resume_addr); ++ REG32(PCU_VA_BASE + 0x400) = (resume_addr) | 0x80000000; ++ REG32(PCU_VA_BASE + 0x404) = (u32) ag102_cpu_resume2; ++ REG32(PCU_VA_BASE + 0x410) = GET_L1_PPTB(); ++ //ADD by river 2010.12.02 for reserve kernel remap ++ REG32(PCU_VA_BASE + 0x418) = REG32(AHB_ATFAHBC020S_0_VA_BASE + 0x10); ++ REG32(PCU_VA_BASE + 0x41C) = REG32(AHB_ATFAHBC020S_0_VA_BASE + 0x18); ++ //End ADD by river 2010.12.02 for reserve kernel remap ++ printk("L1_PPTB (PA) =0x%08x\n", GET_L1_PPTB()); ++ printk("L1_PPTB (VA) in virtual address =0x%08x\n", ++ phys_to_virt(GET_L1_PPTB())); ++ ++ //ADD by river 2010.12.07 ++ UINT32 phy_id, phy_addr; ++ ETH_PHY_STAT phy_stat; ++ ++ if (eth_phy_detect(&phy_addr, &phy_id) != 0) { ++ printk("ERR: fail to detect known PHY!!!\n"); ++ return; ++ } ++ //TEST by river 2010.12.10 ++ eth_phy_init(phy_addr); ++ eth_phy_stat(phy_addr, &phy_stat); ++ eth_mac_init(&phy_stat); ++ //End TEST by river 2010.12.10 ++ gmac_set_wol(); ++ //End ADD by river 2010.12.07 ++ ++ /////////// ADD by river 2010.12.20 for LPC wakeup ///////////////////////////// ++ if (it8718f_init() != 0) ++ return; ++ ++ //INTC setup ++ SetIntTrig(IRQ_LPC, LEVEL, H_ACTIVE); ++ EnableInt(IRQ_LPC); // including INT_MASK and GIE in Core ++ ++ enable_sirq(); ++ ++ //__asm__ volatile ("1:\n\t"); ++ //__asm__ volatile ("b 1b\n\t"); ++ ++ printk("Calling ite_set_pme() YAYAYA....\n"); ++ ite_set_pme(); ++ ++ printk("Get Value..... YAYAYA....1\n"); ++ get_lpc_value(); ++ ++ /////////// End ADD by river 2010.12.20 for LPC wakeup ///////////////////////////// ++ ++ //set GPIO[2] as suspend2dram power control pin ++ PCU_SET_FIELD(MFPS1, SUSPEND_GPIO, 0x1); ++ PCU_SET_FIELD(PCS9_PDD, SUSP2RAM, 0x1); ++ //ADD by river 2010.12.07 ++ PCU_SET_REG(PCS9_CFG, PCU_PREPARE(PCS9_CFG, WKEN, PCS_WKEN_WOL | PCS_WKEN_LPC | PCS_WKEN_RTC)); // use only gpio0 and wol ++ //PCU_SET_REG(PCS9_CFG, PCU_PREPARE(PCS9_CFG, WKEN, PCS_WKEN_LPC)); // use lpc ++ ++ //End ADD by river 2010.12.07 ++ ++ /* set pwoer status */ ++ //int par = PCS_POWER_GPU_AND_DAC|PCS_POWER_CPUB; ++ int reg_tmp = PCU_PREPARE(PCS9_PARA, IE, 0x1) | ++ PCU_PREPARE(PCS9_PARA, CMD, ++ PCS_CMD_PW_DOWN /*PCS_CMD_SCALING|PCS_CMD_DRAM_SF */ ) | ++ PCU_PREPARE(PCS9_PARA, SYNC, PCS_SYNC_SRC) | PCU_PREPARE(PCS9_PARA, NXTPAR, 0 /*par */ ); // change power status ++ PCU_SET_REG(PCS9_PARA, reg_tmp); ++ ++ //PCU_SET_FIELD(MFPS1, SUSPEND_GPIO, 0x1); ++ /* setup wakeup sources */ ++ /* ++ k = PCU_PREPARE(WAKEUP_SEN, GPIO0_POL, 0x1) | ++ PCU_PREPARE(WAKEUP_SEN, GPIO1_POL, 0x1) | ++ PCU_PREPARE(WAKEUP_SEN, GPIO2_POL, 0x1) | ++ PCU_PREPARE(WAKEUP_SEN, GPIO3_POL, 0x1) | ++ PCU_PREPARE(WAKEUP_SEN, GPIO4_POL, 0x1) | ++ PCU_PREPARE(WAKEUP_SEN, GPIO5_POL, 0x1) | ++ PCU_PREPARE(WAKEUP_SEN, WOL_POL, 0x1) | ++ PCU_PREPARE(WAKEUP_SEN, LPC_POL, 0x1); ++ l = ~k; //set polarity ++ //l = 0x1c0; ++ PCU_SET_REG(WAKEUP_SEN, l); ++ PCU_SET_REG(PCS9_CFG, PCU_PREPARE(PCS9_CFG, WKEN, k)); ++ */ ++ /* Set PDD register and set suspend_to_ram */ ++ //PCU_SET_FIELD(PCS9_PDD, SUSP2RAM, 0x1); ++ ++ cpu_dcache_wbinval_all(); ++ cpu_icache_inval_all(); ++ SET_CACHE_CTL(GET_CACHE_CTL() & ~CACHE_CTL_mskDC_EN); ++ ++ /* lock self-refresh code to L1 cache */ ++ ++ addr = (unsigned int)__SELF_REFRESH_LOCK_START; ++ reg = (((unsigned int)__SELF_REFRESH_LOCK_END - (unsigned int)__SELF_REFRESH_LOCK_START) >> 5) + 1; // ++ ++ for (i = 0; i < reg; i++) { ++ __asm__ volatile ("li $p0, 0x0\n\t" ++ "add $p0, $p0, %0\n\t" ++ "cctl $p0, L1I_VA_FILLCK\n\t" ++ "isb\n\t"::"r" (addr)); ++ ++ addr += 32; ++ } ++ ++ unsigned char *ptr; ++ //ADD by river 2010.11.19 ++ printk("The resume address's content is :\n"); ++ ptr = (unsigned char *)ag102_cpu_resume; ++ for (i = 0; i < 20; i++) { ++ printk("0x%02x - ", *ptr++); ++ } ++ ++ printk("Get Value..... YAYAYA....2\n"); ++ get_lpc_value(); ++ ++ //End ADD by river 2010.11.19 ++ ag102_cpu_sleep(); ++ printk("return success-1..........\n"); ++ /* wakeup and ckeck */ ++ /* ++ reg_tmp = PCU_GET_REG(PCS9_ST2);// check Status-2 ++ if (PCU_EXTRACT(PCS9_ST2, CURPAR, reg_tmp) != par) ++ printk("Parameter setup is not the same!\n"); ++ ++ reg_tmp = PCU_GET_REG(PCS9_ST1); // check Status-1 ++ if (PCU_EXTRACT(PCS9_ST1, STS, reg_tmp) != PCS_STS_DONE) ++ printk("The work is not done?!\n"); ++ if (PCU_EXTRACT(PCS9_ST1, ERR, reg_tmp) != PCS_ERR_NONE) ++ printk("Some error happened!!\n"); ++ PCU_SET_REG(PCS9_ST1, 0x0); //clear status ++ ++ */ ++ ftpci_postinit(); ++ SET_CACHE_CTL(GET_CACHE_CTL() | CACHE_CTL_mskDC_EN); ++ /* trigger mode regs */ ++ REG32(AMIC_VA_BASE + 0x20) = irq_saves[0]; ++ /* trigger level regs */ ++ REG32(AMIC_VA_BASE + 0x24) = irq_saves[1]; ++ /* interrupt enable regs */ ++ REG32(AMIC_VA_BASE + 0x80) = irq_saves[2]; ++ __asm__ volatile ("mtsr %0, $ir14\n\t"::"r" (tmp)); ++ ++ printk("return success-2..........\n"); ++ dump_stack(); ++ ++} ++ ++static int ag102_pm_valid(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_ON: ++ case PM_SUSPEND_STANDBY: ++ case PM_SUSPEND_MEM: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++ ++static int ag102_pm_begin(suspend_state_t state) ++{ ++ /* TBD if we need it */ ++ return 0; ++} ++ ++static void andes_suspend_cpu(void) ++{ ++ unsigned int irq_save; ++ /* setup GPIO interrupt enable regs to enable GPIO0 */ ++ REG32(GPIO_VA_BASE + 0x20) = 1; ++ /* save interrupt enable regs */ ++ irq_save = REG32(AMIC_VA_BASE + 0x80); ++ /* accept all interrupts to wake up except timer interrupt */ ++ REG32(AMIC_VA_BASE + 0x80) &= ~(1 << 19); ++ /* enable UART0 interrupt */ ++ REG32(AMIC_VA_BASE + 0x80) |= 1 << 13; ++ ++ /* ++ * for more IRQ info, please refer to ++ * arch/nds32/include/asm/spec.h&spec-ag102.h ++ */ ++ ++ __asm__ volatile ("standby no_wake_grant\n\t"); ++ /* clear GPIO interrupt */ ++ REG32(GPIO_VA_BASE + 0x30) = 1; ++ /* disable GPIO interrupt */ ++ REG32(GPIO_VA_BASE + 0x20) = 0; ++ /* restore GPIO enable regs */ ++ REG32(AMIC_VA_BASE + 0x80) = irq_save; ++} ++ ++static int ag102_pm_enter(suspend_state_t state) ++{ ++ switch (state) { ++ case PM_SUSPEND_STANDBY: ++ andes_suspend_cpu(); ++ return 0; ++ case PM_SUSPEND_MEM: ++ printk("@@@@@@@@@@ : ag102_pm_enter()... from gavin.......\n"); ++ andes_suspend_to_ram(); ++ return 0; ++ default: ++ return -EINVAL; ++ } ++} ++ ++/* ++ * Called after processes are frozen, but before we shutdown devices. ++ */ ++static int ag102_pm_prepare(void) ++{ ++ /* TBD if we need it */ ++ return 0; ++} ++ ++/* ++ * Called after devices are wakeuped, but before processes are thawed. ++ */ ++static void ag102_pm_finish(void) ++{ ++ /* TBD if we need it */ ++} ++ ++static void ag102_pm_end(void) ++{ ++ /* TBD if we need it */ ++#if 0 ++ class_destroy(andes_pcu_class); ++ unregister_chrdev(andes_pcu_major, ANDES_PCU_STRING); ++#endif ++ printk("pm_exit\n"); ++} ++ ++static int andes_pcu_ioctl(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ return 0; ++} ++ ++static int andes_pcu_open(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++static ssize_t andes_pcu_write(struct file *filp, const char *buff, ++ size_t count, loff_t * ppos) ++{ ++ char data; ++ get_user(data, buff); ++ switch (data) { ++ case 's': ++ printk("Just suspend cpu\n"); ++ andes_suspend_cpu(); ++ break; ++ case 'm': ++ printk("Suspend to ram\n"); ++ andes_suspend_to_ram(); ++ break; ++ } ++ return 0; ++} ++ ++static int andes_pcu_release(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++static struct file_operations andes_pcu_fops = { ++ .owner = THIS_MODULE, ++ .ioctl = andes_pcu_ioctl, ++ .open = andes_pcu_open, ++ .write = andes_pcu_write, ++ .release = andes_pcu_release, ++}; ++ ++static struct platform_suspend_ops ag102_pm_ops = { ++ .valid = ag102_pm_valid, ++ .begin = ag102_pm_begin, ++ .prepare = ag102_pm_prepare, ++ .enter = ag102_pm_enter, ++ .finish = ag102_pm_finish, ++ .end = ag102_pm_end, ++}; ++ ++//PCU power-off workaround { ++#undef IRQ_LEVEL ++#include <linux/interrupt.h> ++#include <linux/irq.h> ++ ++//#define PM_DEBUG ++#ifdef PM_DEBUG ++#define PRINTK printk ++#else ++#define PRINTK(...) ++#endif ++ ++static volatile int pcuirq = 0; ++ ++static inline void poweroff_pcu(void) ++{ ++ PRINTK(KERN_INFO "[kernel] poweroff_pcu()"); ++ REG32(PCU_VA_BASE + 0x1a4) = (2 << 28) | (1 << 24) | (6 << 0); //power-down, sync CPUA, domain GPU+CPUB ++ __asm__ volatile ("standby wait_done\n"); ++ REG32(PCU_VA_BASE + 0x1a8) = 0x0; //PCS9 status normal, no error ++} ++ ++static inline void clear_pcu_status(void) ++{ ++ PRINTK(KERN_INFO "[kernel] clear_pcu_status()"); ++ REG32(PCU_VA_BASE + 0x1b0) |= (1 << 31); //clear poweroff flag ++ asm("msync store\nisb"); ++} ++ ++static irqreturn_t gpio0_isr(int irq, void *dev_id) ++{ ++ PRINTK(KERN_INFO "[kernel] gpio0_isr(irq=%d)\n", irq); ++ ++ // is GPIO0 IRQ ++ if (REG32(GPIO_VA_BASE + 0x28) & (1 << 0)) { ++ PRINTK(KERN_INFO "GPIO#0 ASSERT!\n"); ++ ++ pcuirq = 0; ++ ++ //disable GPIO0 IRQ ++ REG32(GPIO_VA_BASE + 0x2c) |= (1 << 0); //GPIO0 IRQ mask, level mode AMIC.GPIO#0 also cleared ++ ++// REG32(AMIC_VA_BASE + 0x84) = (1<<13); //AMIC clear GPIO interrupt ++ ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++#define GPIO_SEC (1<<11) ++static irqreturn_t pcu_isr(int irq, void *dev_id) ++{ ++ UINT32 status = REG32(PCU_VA_BASE + 0x94); ++ PRINTK(KERN_INFO "[kernel] pcu_isr(irq=%d) status=0x%08x\n", irq, ++ status); ++ if (0 == (GPIO_SEC & status)) ++ return IRQ_NONE; ++ ++ PRINTK(KERN_INFO "[kernel] GPIO_SEC\n"); ++ clear_pcu_status(); //clear PCS9 IRQ (level mode => AMIC.PCU also cleared) ++ pcuirq++; ++ if (1 == pcuirq) { ++ //enable GPIO0 IRQ ++ REG32(GPIO_VA_BASE + 0x30) = (1 << 0); //GPIO0 IRQ cleared ++// REG32(AMIC_VA_BASE + 0x84) = (1 << 13); //AMIC clear GPIO interrupt ++// enable_irq(GPIO_FTGPIO010_IRQ); ++ REG32(AMIC_VA_BASE + 0x80) |= (1 << 13); //AMIC enable GPIO IRQ ++ REG32(GPIO_VA_BASE + 0x2c) &= ~(1 << 0); //GPIO0 IRQ unmask ++ } else if (5 == pcuirq) { ++ poweroff_pcu(); ++ } ++// REG32(AMIC_VA_BASE + 0x84) = (1 << 8); //PCU IRQ clear ++ ++ return IRQ_HANDLED; ++} ++ ++//PCU power-off workaround } ++ ++static int __init ag102_pm_init(void) ++{ ++ int ret = 0; ++ struct device *temp_class; ++ printk("PM driver init\n"); ++ suspend_set_ops(&ag102_pm_ops); ++ ++ andes_pcu_major = register_chrdev(0, ANDES_PCU_STRING, &andes_pcu_fops); ++ ++ printk("@@@@@ : andes_pcu_major = 0x%08x\n", andes_pcu_major); ++ if (andes_pcu_major < 0) { ++ printk("Unable to get a major for andes pcu driver!\n"); ++ return andes_pcu_major; ++ } ++ ++ andes_pcu_class = class_create(THIS_MODULE, ANDES_PCU_STRING); ++ ++ if (IS_ERR(andes_pcu_class)) { ++ printk(KERN_ERR "Error creating andes pcu class.\n"); ++ ret = PTR_ERR(andes_pcu_class); ++ goto err_out1; ++ } ++ ++ temp_class = device_create(andes_pcu_class, NULL, ++ MKDEV(andes_pcu_major, 0), ++ NULL, ANDES_PCU_STRING); ++ ++ if (IS_ERR(temp_class)) { ++ printk(KERN_ERR "Error creating andes pcu class device.\n"); ++ ret = PTR_ERR(temp_class); ++ goto err_out2; ++ } ++ ++ mac_dah = GMAC_GET_REG(MAC_MADR); ++ mac_dal = GMAC_GET_REG(MAC_LADR); ++ ++ //poweroff workaround ++ { ++ if (request_irq ++ (PCU_IRQ, pcu_isr, IRQF_SHARED, "PCU_POWEROFF", pcu_isr)) { ++ printk("Failed to request PCU interrupt.\n"); ++ } ++ ++ if (request_irq ++ (GPIO_FTGPIO010_IRQ, gpio0_isr, IRQF_SHARED, ++ "GPIO0_FOR_PCU", gpio0_isr)) { ++ printk("Failed to request GPIO0 interrupt.\n"); ++ } ++ ++ REG32(PCU_VA_BASE + 0x1b0) |= (3 << 28); //poweroff in 5s ++ ++ //AMIC setup ++ // PCU IRQ default edge trigger, rising edge ++ // GPIO_FTGPIO010_IRQ default edge trigger, rising edge ++// REG32(AMIC_VA_BASE + 0x20) &= ~(1 << 8); //PCU IRQ level trigger ++// REG32(AMIC_VA_BASE + 0x24) &= ~(1 << 8); //PCU IRQ active-high ++// REG32(AMIC_VA_BASE + 0x20) &= ~(1 << 13); //GPIO IRQ level trigger ++ ++ //GPIO #0 setup ++ REG32(GPIO_VA_BASE + 0x08) &= ~(1 << 0); //GPIO0 input ++ REG32(GPIO_VA_BASE + 0x18) &= ~(1 << 0); //GPIO0 not pulled (external pull-high) ++ REG32(GPIO_VA_BASE + 0x2c) |= (1 << 0); //GPIO0 IRQ masked ++ REG32(GPIO_VA_BASE + 0x34) |= (1 << 0); //GPIO0 IRQ level trigger ++// REG32(GPIO_VA_BASE + 0x38) &= ~(1<<0); //GPIO0 IRQ single edge ++ REG32(GPIO_VA_BASE + 0x3c) &= ~(1 << 0); //GPIO0 IRQ high-active ++ REG32(GPIO_VA_BASE + 0x40) |= (1 << 0); //GPIO0 enable bounce ++ REG32(GPIO_VA_BASE + 0x40) = 0xffff; //GPIO bounce time = x/PCLK ++// REG32(GPIO_VA_BASE + 0x30) = (1<<0); //GPIO0 IRQ cleared ++ REG32(GPIO_VA_BASE + 0x20) |= (1 << 0); //GPIO0 IRQ enable ++ ++// enable_irq(PCU_IRQ); ++ REG32(AMIC_VA_BASE + 0x80) |= (1 << 8); //IRQ enabled ++ } ++ ++ printk("pm_init\n"); ++ return 0; ++err_out2: ++ class_destroy(andes_pcu_class); ++err_out1: ++ unregister_chrdev(andes_pcu_major, ANDES_PCU_STRING); ++ return 1; ++} ++ ++//static void resume_to_ccode(void) ++//{ ++// printk("Resume to C code successfully....\n"); ++//} ++ ++late_initcall(ag102_pm_init); +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ag102/sleep.S linux-3.4.110/arch/nds32/platforms/ag102/sleep.S +--- linux-3.4.110.orig/arch/nds32/platforms/ag102/sleep.S 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ag102/sleep.S 2016-04-07 10:20:51.002083345 +0200 +@@ -0,0 +1,465 @@ ++#include <asm/spec-ag102.h> ++.text ++ ++.globl ag102_cpu_sleep ++.globl ag102_cpu_resume ++.globl ag102_cpu_resume2 ++.globl __SELF_REFRESH_LOCK_START ++.globl __SELF_REFRESH_LOCK_END ++ ++#! 0x94200000; keep r0, r1, r2 ++ .macro putch ch ++ li $r0, #0x94200000 ++ move $r2, \ch ++88: ++ lwi $r1, [$r0+#0x14] ++ srli $r1, $r1, #5 ++ andi $r1, $r1, #0x1 ++ beqz $r1, 88b ++ swi $r2, [$r0] ++ .endm ++#! 0x94200000; keep r3, r4 ++ .macro hex2asc val ++ addi \val, \val, -10 ++ bltz \val, 1f ++ addi \val, \val, 0x41 ++ j 2f ++1: ++ addi \val, \val, 0x3a ++2: ++ .endm ++ ++ .macro print_hex mhex ++ move $r3, \mhex ++ ++ srli $r4, $r3, #28 ++ andi $r4, $r4, 0xf ++ hex2asc $r4 ++ putch $r4 ++ srli $r4, $r3, #24 ++ andi $r4, $r4, 0xf ++ hex2asc $r4 ++ putch $r4 ++ srli $r4, $r3, #20 ++ andi $r4, $r4, 0xf ++ hex2asc $r4 ++ putch $r4 ++ srli $r4, $r3, #16 ++ andi $r4, $r4, 0xf ++ hex2asc $r4 ++ putch $r4 ++ srli $r4, $r3, #12 ++ andi $r4, $r4, 0xf ++ hex2asc $r4 ++ putch $r4 ++ srli $r4, $r3, #8 ++ andi $r4, $r4, 0xf ++ hex2asc $r4 ++ putch $r4 ++ srli $r4, $r3, #4 ++ andi $r4, $r4, 0xf ++ hex2asc $r4 ++ putch $r4 ++ move $r4, $r3 ++ andi $r4, $r4, 0xf ++ hex2asc $r4 ++ putch $r4 ++ .endm ++ ++ag102_cpu_resume2: ++/*1: ++b 1b*/ ++ //MOD by river 2010.10.13 ++ popm $r0, $r19 ++ mtusr $r0, $d0.lo ! $d0 lo byte ++ mtusr $r1, $d0.hi ! $d0 hi byte ++ mtusr $r2, $d1.lo ! $d1 lo byte ++ mtusr $r3, $d1.hi ! $d1 hi byte ++ mtsr $r4, $mr0 ++ mtsr $r5, $mr1 ++ mtsr $r6, $mr4 ++ mtsr $r7, $mr6 ++ mtsr $r8, $mr7 ++ mtsr $r9, $mr8 ++ mtsr $r10, $ir0 ++ mtsr $r11, $ir1 ++ mtsr $r12, $ir2 ++ mtsr $r13, $ir3 ++ mtsr $r14, $ir9 ++ mtsr $r15, $ir10 ++ mtsr $r16, $ir12 ++ mtsr $r17, $ir13 ++ mtsr $r18, $ir14 ++ mtsr $r19, $ir15 ++ //End MOD by river 2010.10.13 ++ popm $r0, $r30 ++ ret ++ ++ag102_cpu_sleep: ++ ++ pushm $r0, $r30 ++ //MOD by river 2010.10.13 ++ mfusr $r0, $d0.lo ! $d0 lo byte ++ mfusr $r1, $d0.hi ! $d0 hi byte ++ mfusr $r2, $d1.lo ! $d1 lo byte ++ mfusr $r3, $d1.hi ! $d1 hi byte ++ mfsr $r4, $mr0 ++ mfsr $r5, $mr1 ++ mfsr $r6, $mr4 ++ mfsr $r7, $mr6 ++ mfsr $r8, $mr7 ++ mfsr $r9, $mr8 ++ mfsr $r10, $ir0 ++ mfsr $r11, $ir1 ++ mfsr $r12, $ir2 ++ mfsr $r13, $ir3 ++ mfsr $r14, $ir9 ++ mfsr $r15, $ir10 ++ mfsr $r16, $ir12 ++ mfsr $r17, $ir13 ++ mfsr $r18, $ir14 ++ mfsr $r19, $ir15 ++ pushm $r0, $r19 ++ //End MOD by river 2010.10.13 ++ ++ /* store $sp to 0x408 scratch pad */ ++ sethi $r0, hi20(PCU_VA_BASE + 0x408) ++ ori $r2, $r0, lo12(PCU_VA_BASE + 0x408) ++ swi $r31, [$r2] ++ ++ /* set signaure "SUSP" to 0x40c */ ++ li $r0, (PCU_VA_BASE + 0x40c) ++ li $r1, 0x53555350 ! set signature "SUSP" to scratch pad register offset 0x40c ++ swi $r1, [$r0] ++ ++ /* ++ * store 8 bytes from 16mb to pcu scratch pad resgister ++ * due to data training process will destroy it ++ */ ++ li $r0, 0x10000 ++ li $r2, (PCU_VA_BASE + 0x414) ++ lwi $r1, [$r0] ++ swi $r1, [$r2] ++ lwi $r1, [$r0 + 0x4] ++ swi $r1, [$r2 + 0x4] ++ ++ /* ADD by river 2010.09.23 */ ++ /* Save PSW in PCU_VA_BASE + 0x420 */ ++ li $r0, (PCU_VA_BASE + 0x420) ++ mfsr $r1, $ir0 ++ swi $r1, [$r0] ++ /* Save $mr0 in PCU_VA_BASE + 0x424 */ ++ li $r0, (PCU_VA_BASE + 0x424) ++ mfsr $r1, $mr0 ++ swi $r1, [$r0] ++ /* Save $mr1 in PCU_VA_BASE + 0x428 */ ++ li $r0, (PCU_VA_BASE + 0x428) ++ mfsr $r1, $mr1 ++ swi $r1, [$r0] ++ /* Save $mr2 in PCU_VA_BASE + 0x42c */ ++ li $r0, (PCU_VA_BASE + 0x42c) ++ mfsr $r1, $mr2 ++ swi $r1, [$r0] ++ /* Save $mr3 in PCU_VA_BASE + 0x430 */ ++ li $r0, (PCU_VA_BASE + 0x430) ++ mfsr $r1, $mr3 ++ swi $r1, [$r0] ++ /* Save $mr4 in PCU_VA_BASE + 0x434 */ ++ li $r0, (PCU_VA_BASE + 0x434) ++ mfsr $r1, $mr4 ++ swi $r1, [$r0] ++ /* Save $mr5 in PCU_VA_BASE + 0x438 */ ++ //li $r0, (PCU_VA_BASE + 0x438) ++ //mfsr $r1, $mr5 ++ //swi $r1, [$r0] ++ /* Save $mr6 in PCU_VA_BASE + 0x43c */ ++ li $r0, (PCU_VA_BASE + 0x43c) ++ mfsr $r1, $mr6 ++ swi $r1, [$r0] ++ /* Save $mr7 in PCU_VA_BASE + 0x440 */ ++ li $r0, (PCU_VA_BASE + 0x440) ++ mfsr $r1, $mr7 ++ swi $r1, [$r0] ++ /* Save $mr8 in PCU_VA_BASE + 0x444 */ ++ li $r0, (PCU_VA_BASE + 0x444) ++ mfsr $r1, $mr8 ++ swi $r1, [$r0] ++ ++ /* Save $ir3 in PCU_VA_BASE + 0x450 */ ++ li $r0, (PCU_VA_BASE + 0x450) ++ mfsr $r1, $ir3 ++ swi $r1, [$r0] ++ ++ /* Save $ir14 in PCU_VA_BASE + 0x454 */ ++ li $r0, (PCU_VA_BASE + 0x454) ++ mfsr $r1, $ir14 ++ swi $r1, [$r0] ++ ++ /* Save $ir15 in PCU_VA_BASE + 0x458 */ ++ li $r0, (PCU_VA_BASE + 0x458) ++ mfsr $r1, $ir15 ++ swi $r1, [$r0] ++ ++ tlbop FlushAll ++ isb ++ /* End ADD by river 2010.09.23 */ ++ ++ //Trace by river 2010.12.01 ++ /*1: ++ b 1b*/ ++ //End Trace by river 2010.12.01 ++.p2align 5 ++__SELF_REFRESH_LOCK_START: ++ /*sethi $r0, hi20(0x900005cc) ++ ori $r0, $r0, lo12(0x900005cc) ++ sethi $r1, hi20(DDR2C_VA_BASE) ++ swi $r0, [$r1+0x4] ++ ++ msync ++ isb ++ ++ standby wake_grant ++ .p2align 5*/ ++ sethi $r0, hi20(DDR2C_VA_BASE) ++ lwi $r1, [$r0+0x4] ++ li $r2, 0x07ffefff ++ and $r1, $r2, $r1 ++ li $r2, 0x90001000 ++ or $r1, $r2, $r1 ++ swi $r1, [$r0+0x4] ++ ++ msync ++ isb ++ ++ standby wake_grant ++ .p2align ++ ++__SELF_REFRESH_LOCK_END: ++ ++ag102_cpu_resume: ++ /* TRACE by river 2010.12.02 */ ++ /*1: ++ b 1b*/ ++ /* End TRACE by river 2010.12.02 */ ++ mfsr $r2, $mr0 ++ ori $r2, $r2, #0x6 ++#ifdef CONFIG_ANDES_PAGE_SIZE_8KB ++ ori $r2, $r2, #0x1 ++#endif ++ mtsr $r2, $mr0 ++ ++ /* ADD by river 2010.09.23 */ ++ li $r3, 'C ++ putch $r3 ++ li $r3, '\r ++ putch $r3 ++ li $r3, '\n ++ putch $r3 ++ li $r3, 'P ++ putch $r3 ++ li $r3, '\r ++ putch $r3 ++ li $r3, '\n ++ putch $r3 ++ li $r3, 'U ++ putch $r3 ++ li $r3, '\r ++ putch $r3 ++ li $r3, '\n ++ putch $r3 ++ li $r3, 'R ++ putch $r3 ++ li $r3, '\r ++ putch $r3 ++ li $r3, '\n ++ putch $r3 ++ li $r3, 'E ++ putch $r3 ++ li $r3, '\r ++ putch $r3 ++ li $r3, '\n ++ putch $r3 ++ li $r3, 'S ++ putch $r3 ++ li $r3, '\r ++ putch $r3 ++ li $r3, '\n ++ putch $r3 ++ li $r3, 'U ++ putch $r3 ++ li $r3, '\r ++ putch $r3 ++ li $r3, '\n ++ putch $r3 ++ li $r3, 'M ++ putch $r3 ++ li $r3, '\r ++ putch $r3 ++ li $r3, '\n ++ putch $r3 ++ li $r3, 'E ++ putch $r3 ++ li $r3, '\r ++ putch $r3 ++ li $r3, '\n ++ putch $r3 ++ /* ADD by river 2010.09.23 */ ++ ++ /*tlbop FlushAll*/ ! invalidate TLB\n" ++ ++ /* ADD by river 2010.09.23 */ ++ /* restore PSW */ ++ //sethi $r2, hi20(PCU_PA_BASE + 0x420) ++ //ori $r2, $r2, lo12(PCU_PA_BASE + 0x420) ++ //lwi $r3, [$r2] ++ //mtsr $r3, $ir0 ++ //move $p1, $r3 ++ /* restore $mr0 */ ++ sethi $r2, hi20(PCU_PA_BASE + 0x424) ++ ori $r2, $r2, lo12(PCU_PA_BASE + 0x424) ++ lwi $r3, [$r2] ++ mtsr $r3, $mr0 ++ /* restore $mr1 */ ++ sethi $r2, hi20(PCU_PA_BASE + 0x428) ++ ori $r2, $r2, lo12(PCU_PA_BASE + 0x428) ++ lwi $r3, [$r2] ++ mtsr $r3, $mr1 ++ ++ /* restore $mr2 */ ++ //sethi $r2, hi20(PCU_PA_BASE + 0x42c) ++ //ori $r2, $r2, lo12(PCU_PA_BASE + 0x42c) ++ //lwi $r3, [$r2] ++ //mtsr $r3, $mr2 ++ /* restore $mr3 */ ++ //sethi $r2, hi20(PCU_PA_BASE + 0x430) ++ //ori $r2, $r2, lo12(PCU_PA_BASE + 0x430) ++ //lwi $r3, [$r2] ++ //mtsr $r3, $mr3 ++ /* restore $mr4 */ ++ sethi $r2, hi20(PCU_PA_BASE + 0x434) ++ ori $r2, $r2, lo12(PCU_PA_BASE + 0x434) ++ lwi $r3, [$r2] ++ mtsr $r3, $mr4 ++ /* restore $mr5 */ ++ //sethi $r2, hi20(PCU_PA_BASE + 0x438) ++ //ori $r2, $r2, lo12(PCU_PA_BASE + 0x438) ++ //lwi $r3, [$r2] ++ //mtsr $r3, $mr5 ++ /* restore $mr6 */ ++ sethi $r2, hi20(PCU_PA_BASE + 0x43c) ++ ori $r2, $r2, lo12(PCU_PA_BASE + 0x43c) ++ lwi $r3, [$r2] ++ mtsr $r3, $mr6 ++ /* restore $mr7 */ ++ sethi $r2, hi20(PCU_PA_BASE + 0x440) ++ ori $r2, $r2, lo12(PCU_PA_BASE + 0x440) ++ lwi $r3, [$r2] ++ mtsr $r3, $mr7 ++ /* restore $mr8 */ ++ sethi $r2, hi20(PCU_PA_BASE + 0x444) ++ ori $r2, $r2, lo12(PCU_PA_BASE + 0x444) ++ lwi $r3, [$r2] ++ /* ADD by river 2010.12.02 for ICache Enable */ ++ ori $r3, $r3, #0x1 ++ /* End ADD by river 2010.12.02 for ICache Enable */ ++ mtsr $r3, $mr8 ++ ++ /* restore $ir3 */ ++ sethi $r2, hi20(PCU_PA_BASE + 0x450) ++ ori $r2, $r2, lo12(PCU_PA_BASE + 0x450) ++ lwi $r3, [$r2] ++ mtsr $r3, $ir3 ++ ++ move $p1, $r3 ++ li $r3, '\r ++ putch $r3 ++ li $r3, '\n ++ putch $r3 ++ print_hex $p1 ++ li $r3, '\r ++ putch $r3 ++ li $r3, '\n ++ putch $r3 ++ ++ ++ /* restore $ir14 */ ++ sethi $r2, hi20(PCU_PA_BASE + 0x454) ++ ori $r2, $r2, lo12(PCU_PA_BASE + 0x454) ++ lwi $r3, [$r2] ++ mtsr $r3, $ir14 ++ ++ /* restore $ir15 */ ++ sethi $r2, hi20(PCU_PA_BASE + 0x458) ++ ori $r2, $r2, lo12(PCU_PA_BASE + 0x458) ++ lwi $r3, [$r2] ++ mtsr $r3, $ir15 ++ ++ li $r3, '\r ++ putch $r3 ++ li $r3, '\n ++ putch $r3 ++ move $p1, $r3 ++ print_hex $p1 ++ ++ /* End ADD by river 2010.09.23 */ ++ ++ /* in this buggy version(ram locate at 1G) TC01 we don't need to do remap. ++ * ebios set memory locate at 1G & size = 1G, for more detail info, please ++ * refer to ebios boot.S. ++ * ++ * sethi $r2, hi20(0x90c00000 + 0x88) ++ * ori $r2, $r2, lo12(0x90c00000 + 0x88) ++ * movi $r3, #0x1 ++ * swi $r3, [$r2] ++ **/ ++ ++ /* restore 8 bytes from pcu scratch pad resgister to 16mb */ ++ li $r0, 0x10000 ++ li $r2, (PCU_PA_BASE + 0x414) ++ lwi $r1, [$r2] ++ swi $r1, [$r0] ++ lwi $r1, [$r2 + 0x4] ++ swi $r1, [$r0 + 0x4] ++ ++ .p2align 5 ++ resume_lock_start: ++ /* ADD by river 2010.12.02 for ag102_cpu_resume2 for jral.ton $r4, $r4 */ ++ sethi $r2, hi20(PCU_PA_BASE + 0x404) ++ ori $r2, $r2, lo12(PCU_PA_BASE + 0x404) ++ lwi $r4, [$r2] ++ /* End ADD by river 2010.12.02 for ag102_cpu_resume2 */ ++ ++ /* ADD by river 2010.12.02 for restore kernel ROM map */ ++ sethi $r0, hi20(0x40080000) ++ ori $r0, $r0, lo12(0x40080000) ++ sethi $r1, hi20(AHB_ATFAHBC020S_0_PA_BASE + 0x10) ++ ori $r1, $r1, lo12(AHB_ATFAHBC020S_0_PA_BASE + 0x10) ++ swi $r0, [$r1] ++ ++ /* ADD by river 2010.12.02 for restore kernel RAM map */ ++ sethi $r0, hi20(0x000A0000) ++ ori $r0, $r0, lo12(0x000A0000) ++ sethi $r1, hi20(AHB_ATFAHBC020S_0_PA_BASE + 0x18) ++ ori $r1, $r1, lo12(AHB_ATFAHBC020S_0_PA_BASE + 0x18) ++ swi $r0, [$r1] ++ ++ /******************* Gavin version ***************************/ ++ //MOD by river 2010.10.13 ++ /*sethi $r2, hi20(PCU_PA_BASE + 0x404) ++ ori $r2, $r2, lo12(PCU_PA_BASE + 0x404) ++ lwi $r4, [$r2] ++ mtsr $r4, $IPC ++ li $r1, 0xcb ++ mtsr $r1, $IPSW ++ iret*/ ++ //End MOD by river 2010.10.13 ++ //End Gavin version//////////////////////////////////////////////////////////// ++ ++ /* End ADD by river 2010.09.23 */ ++ //MOD by river 2010.10.13 ++ //////// jral.ton version //////////////////////////////////////////////////// ++ ++ jral.ton $r4, $r4 ++ .p2align ++ resume_lock_end: ++ //End MOD by river 2010.10.13 +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/amic.c linux-3.4.110/arch/nds32/platforms/amic.c +--- linux-3.4.110.orig/arch/nds32/platforms/amic.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/amic.c 2016-04-07 10:20:51.002083345 +0200 +@@ -0,0 +1,203 @@ ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <linux/delay.h> ++ ++#include <asm/io.h> ++#include <asm/amic.h> ++ ++#define DEBUG(enabled, tagged, ...) \ ++ do { \ ++ if (enabled) { \ ++ if (tagged) \ ++ printk("[ %30s() ] ", __func__); \ ++ printk(__VA_ARGS__); \ ++ } \ ++ } while (0) ++ ++static DEFINE_SPINLOCK(amic_irq_lock); ++ ++static void amic_ack_irq(unsigned int irq) ++{ ++ unsigned int data; ++ ++ spin_lock(&amic_irq_lock); ++ writel(1 << irq, AMIC_BASE + INTSTA); ++ data = readl(AMIC_BASE + INTSTA); ++ spin_unlock(&amic_irq_lock); ++} ++ ++static void amic_mask_irq(unsigned int irq) ++{ ++ unsigned int data; ++ ++ spin_lock(&amic_irq_lock); ++ data = readl(AMIC_BASE + INTEN); ++ data &= ~(1 << irq); ++ writel(data, AMIC_BASE + INTEN); ++ data = readl(AMIC_BASE + INTEN); ++ spin_unlock(&amic_irq_lock); ++} ++ ++static int amic_set_type(unsigned int irq, unsigned int flow_type) ++{ ++ unsigned int data; ++ ++ spin_lock(&amic_irq_lock); ++ if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { ++ data = readl(AMIC_BASE + INTTRG); ++ data |= 1 << irq; ++ writel(data, AMIC_BASE + INTTRG); ++ } ++ ++ if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { ++ data = readl(AMIC_BASE + INTTRG); ++ data &= ~(1 << irq); ++ writel(data, AMIC_BASE + INTTRG); ++ } ++ ++ if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) { ++ data = readl(AMIC_BASE + INTLVL); ++ data |= 1 << irq; ++ writel(data, AMIC_BASE + INTLVL); ++ } ++ ++ if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING)) { ++ data = readl(AMIC_BASE + INTLVL); ++ data &= ~(1 << irq); ++ writel(data, AMIC_BASE + INTLVL); ++ } ++ spin_unlock(&amic_irq_lock); ++ return 0; ++} ++ ++static void amic_unmask_irq(unsigned int irq) ++{ ++ unsigned int data; ++ ++ spin_lock(&amic_irq_lock); ++ data = readl(AMIC_BASE + INTEN); ++ data |= 1 << irq; ++ writel(data, AMIC_BASE + INTEN); ++ data = readl(AMIC_BASE + INTEN); ++ spin_unlock(&amic_irq_lock); ++} ++ ++static int amic_set_affinity(unsigned int irq, const struct cpumask *dest) ++{ ++ int cnt = 0; ++ int cpu; ++ volatile unsigned int data; ++ volatile unsigned int dc, amic_irq; ++ ++ if (num_online_cpus() > 2) ++ return 0; ++ ++ spin_lock(&amic_irq_lock); ++ /* remap irq number for real controller */ ++ /* this may be needed in future */ ++ /* amic_irq = irq_remap(irq); */ ++ amic_irq = irq; ++ ++ /* change owner */ ++ data = readl(AMIC_BASE + CPUID0 + ((amic_irq >> 4) << 2)); ++ for_each_online_cpu(cpu) { ++ if (cpumask_test_cpu(cpu, dest)) { ++ data &= ~(0x3 << ((amic_irq & ~0x10) * 2)); ++ data |= cpu << ((amic_irq & ~0x10) * 2); ++ cnt++; ++ } ++ } ++ writel(data, AMIC_BASE + CPUID0 + ((amic_irq >> 4) << 2)); ++ ++ dc = readl(AMIC_BASE + CPUDC); ++ if (cnt == 2) /* set bit */ ++ writel((dc | (1 << amic_irq)), (AMIC_BASE + CPUDC)); ++ else /* clear bit */ ++ writel((dc & ~(1 << amic_irq)), (AMIC_BASE + CPUDC)); ++ ++ spin_unlock(&amic_irq_lock); ++ ++ DEBUG(0, 1, "en=%08x,status=%08x\n", readl(AMIC_BASE + INTEN), ++ readl(AMIC_BASE + INTSTA)); ++ ++ return 0; ++} ++ ++static struct irq_chip amic_chip = { ++ .name = "AMIC", ++ .ack = amic_ack_irq, ++ .mask = amic_mask_irq, ++ .unmask = amic_unmask_irq, ++ .set_affinity = amic_set_affinity, ++ .set_type = amic_set_type, ++}; ++ ++void __init amic_init(void) ++{ ++ int i, edge; ++ unsigned int temp = smp_processor_id(); ++ temp |= temp << 2; ++ temp |= temp << 4; ++ temp |= temp << 8; ++ temp |= temp << 16; ++ ++ writel(0x0, AMIC_BASE + INTEN); ++ writel(0x0, AMIC_BASE + CPUDC); ++ writel(temp, AMIC_BASE + CPUID0); ++ writel(temp, AMIC_BASE + CPUID1); ++ writel(0xffff, AMIC_BASE + IPISTA); ++ writel(0xffffffff, AMIC_BASE + INTSTA); ++ writel(0x11111111, AMIC_BASE + PRITY0); ++ writel(0x11111111, AMIC_BASE + PRITY1); ++ writel(0x11111111, AMIC_BASE + PRITY2); ++ writel(0x11111111, AMIC_BASE + PRITY3); ++ writel(DEFAULT_MODE, AMIC_BASE + INTTRG); ++ writel(~DEFAULT_LEVEL, AMIC_BASE + INTLVL); ++ printk("AMIC config %x %x\n", temp, readl(AMIC_BASE + CONFIG)); ++ ++ for (i = IRQ_BASE, edge = 1; i < IRQ_BASE + IRQ_TOTAL; i++, edge <<= 1) { ++ set_irq_chip(i, &amic_chip); ++ if (DEFAULT_MODE & edge) ++ set_irq_handler(i, handle_edge_irq); ++ else ++ set_irq_handler(i, handle_level_irq); ++ } ++ ++} ++ ++unsigned int get_IntSrc(void) ++{ ++ unsigned int irqsta, irq = 31; ++ ++ spin_lock(&amic_irq_lock); ++ irqsta = readl(AMIC_BASE + IPISTA); ++ if (irqsta != 0) ++ irqsta = 0; ++ else ++ irqsta = readl(AMIC_BASE + INTSTA); ++ spin_unlock(&amic_irq_lock); ++ ++ if (irqsta == 0) ++ return 32; ++ if (irqsta & 0x0000ffff) { ++ irq -= 16; ++ irqsta <<= 16; ++ } ++ if (irqsta & 0x00ff0000) { ++ irq -= 8; ++ irqsta <<= 8; ++ } ++ if (irqsta & 0x0f000000) { ++ irq -= 4; ++ irqsta <<= 4; ++ } ++ if (irqsta & 0x30000000) { ++ irq -= 2; ++ irqsta <<= 2; ++ } ++ if (irqsta & 0x40000000) { ++ irq -= 1; ++ } ++ return irq; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/dmad.c linux-3.4.110/arch/nds32/platforms/dmad.c +--- linux-3.4.110.orig/arch/nds32/platforms/dmad.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/dmad.c 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,3601 @@ ++/***************************************************************************** ++ * ++ * Copyright Andes Technology Corporation 2007-2008 ++ * All Rights Reserved. ++ * ++ * Revision History: ++ * ++ * Aug.21.2007 Created. ++ * Feb.23.2009 Porting to Linux 2.6. ++*****************************************************************************/ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/spinlock.h> ++#include <linux/completion.h> ++#include <linux/errno.h> ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <asm/sizes.h> ++#include <asm/types.h> ++#include <asm/io.h> ++#include <asm/dmad.h> ++#include <linux/irq.h> ++ ++#if (defined(CONFIG_PLATFORM_AHBDMA) || defined(CONFIG_PLATFORM_APBDMA)) ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++#define DMAD_AHB_MAX_CHANNELS DMAC_MAX_CHANNELS ++#else ++#define DMAD_AHB_MAX_CHANNELS 0 ++#endif /* CONFIG_PLATFORM_AHBDMA */ ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++#define DMAD_APB_MAX_CHANNELS APBBR_DMA_MAX_CHANNELS ++#else ++#define DMAD_APB_MAX_CHANNELS 0 ++#endif /* CONFIG_PLATFORM_APBDMA */ ++ ++#define DMAD_DRB_POOL_SIZE 32 /* 128 */ ++ ++/* reg/io supplementals */ ++static inline void setbl(addr_t bit, addr_t reg) ++{ ++ outl(inl(reg) | (addr_t) ((addr_t) 1 << bit), reg); ++} ++ ++static inline void clrbl(addr_t bit, addr_t reg) ++{ ++ outl(inl(reg) & (~((addr_t) ((addr_t) 1 << bit))), reg); ++} ++ ++static inline addr_t getbl(addr_t bit, addr_t reg) ++{ ++ return inl(reg) & (addr_t) ((addr_t) 1 << bit); ++} ++ ++/******************************************************************************/ ++ ++enum DMAD_DRQ_FLAGS { ++ DMAD_DRQ_STATE_READY = 0x00000001, /* channel allocation status */ ++ DMAD_DRQ_STATE_ABORT = 0x00000002, /* abort drb alloc block-wait */ ++ DMAD_DRQ_DIR_A1_TO_A0 = 0x00000004, /* Transfer direction */ ++}; ++ ++#define DMAD_DRQ_DIR_MASK DMAD_DRQ_DIR_A1_TO_A0 ++ ++/* DMA request queue, one instance per channel */ ++typedef struct dmad_drq { ++ u32 state; /* enum DMAD_DRQ_STATE */ ++ ++ addr_t channel_base; /* register base address */ ++ addr_t enable_port; /* enable register */ ++ addr_t src_port; /* source address register */ ++ addr_t dst_port; /* dest address register */ ++ addr_t cyc_port; /* size(cycle) register */ ++ ++ u32 flags; /* enum DMAD_CHREQ_FLAGS */ ++ ++ spinlock_t drb_pool_lock; ++ dmad_drb *drb_pool; /* drb pool */ ++ ++ u32 fre_head; /* free list head */ ++ u32 fre_tail; /* free list tail */ ++ ++ u32 rdy_head; /* ready list head */ ++ u32 rdy_tail; /* ready list tail */ ++ ++ u32 sbt_head; /* submitted list head */ ++ u32 sbt_tail; /* submitted list tail */ ++ ++ u32 data_width; /* dma transfer data width */ ++ ++ struct completion drb_alloc_sync; ++ ++ /* client supplied callback function, executed in interrupt context ++ * client private data to be passed to data argument of completion_cb(). ++ */ ++ void (*completion_cb) (int channel, u16 status, void *data); ++ void *completion_data; ++ ++ /* ring-mode fields are valid for DMAD_FLAGS_RING_MODE */ ++ dma_addr_t ring_base; /* ring buffer base address */ ++ dma_addr_t ring_size; /* size (of data width) */ ++ addr_t ring_port; /* for setup/fetch hw_ptr */ ++ dmad_drb *ring_drb; ++ ++ addr_t dev_addr; /* device data port */ ++ ++ int periods; /* interrupts periods */ ++ dma_addr_t period_size; /* of dma data with */ ++ dma_addr_t period_bytes; /* Period size, in bytes */ ++ ++ /* ring_size - period_size * periods */ ++ dma_addr_t remnant_size; ++ ++ dma_addr_t sw_ptr; /* sw pointer */ ++ int sw_p_idx; /* current ring_ptr */ ++ dma_addr_t sw_p_off; /* offset to period base */ ++ ++} dmad_drq; ++ ++/* To shrink code size and improve performance, common channel registers ++ * are preload in drq struct at channel allocation time. One of the key ++ * dependency is the enable bit of both DMAC and APBDMA channel command ++ * registers. Please make sure hw design them at bit 0 of the command register ++ * in future evolvement. ++ */ ++#if (DMAC_CSR_CH_EN_BIT != APBBR_DMA_CHEN_BIT) ++#error "DMAC_CSR_CH_EN_BIT != APBBR_DMA_CHEN_BIT" ++#endif ++ ++#define DMAD_PORT_ENABLE_BIT APBBR_DMA_CHEN_BIT ++ ++static inline void dmad_enable_channel(dmad_drq * drq) ++{ ++ setbl(DMAD_PORT_ENABLE_BIT, drq->enable_port); ++} ++ ++static inline void dmad_disable_channel(dmad_drq * drq) ++{ ++ clrbl(DMAD_PORT_ENABLE_BIT, drq->enable_port); ++} ++ ++static inline addr_t dmad_is_channel_enabled(dmad_drq * drq) ++{ ++ return (addr_t) getbl(DMAD_PORT_ENABLE_BIT, drq->enable_port); ++} ++ ++/* AHB DMAC channel re-route table structure */ ++typedef struct _DMAD_AHB_CH_ROUTE { ++ u32 dev_reqn; /* device req/gnt number */ ++ addr_t clear_cr; /* routing control register address */ ++ addr_t route_cr; /* routing control register address */ ++} DMAD_AHB_CH_ROUTE; ++ ++#ifdef CONFIG_PLAT_AG102 ++#if 0 ++/* AHB DMAC channel re-route table. Indexed by AHB DMAC req/ack number. */ ++static DMAD_AHB_CH_ROUTE ahb_ch_route_table[] __attribute__ ((__unused__)) = { ++ /* all todo ... */ ++ ++ { ++ 0x00, DMAC_REQN_IDERX, DMAC_REQN_IDERX}, { ++ 0x01, DMAC_REQN_IDETX, DMAC_REQN_IDETX}, { ++ 0x02, DMAC_REQN_I2SAC97RX, DMAC_REQN_I2SAC97RX}, { ++ 0x03, DMAC_REQN_I2SAC97TX, DMAC_REQN_I2SAC97TX}, { ++ 0x04, DMAC_REQN_UART2RX, DMAC_REQN_UART2RX}, { ++ 0x05, DMAC_REQN_UART2TX, DMAC_REQN_UART2TX}, { ++ 0x06, DMAC_REQN_UART1RX, DMAC_REQN_UART1RX}, { ++ 0x07, DMAC_REQN_UART1TX, DMAC_REQN_UART1TX}, { ++ 0x08, DMAC_REQN_SDC, DMAC_REQN_SDC}, { ++ 0x09, DMAC_REQN_CFC, DMAC_REQN_CFC}, { ++ 0x0a, DMAC_REQN_LPCREQ0, DMAC_REQN_LPCREQ0}, { ++ 0x0b, DMAC_REQN_LPCREQ1, DMAC_REQN_LPCREQ1}, { ++ 0x0c, DMAC_REQN_LPCREQ2, DMAC_REQN_LPCREQ2}, { ++ 0x0d, DMAC_REQN_LPCREQ3, DMAC_REQN_LPCREQ3}, { ++ 0x0e, 0, 0}, { ++0x0f, DMAC_REQN_LPCREQ5, DMAC_REQN_LPCREQ5},}; ++#endif ++#else /* CONFIG_PLAT_AG102 */ ++ ++/* AHB DMAC channel re-route table. Indexed by AHB DMAC req/ack number. */ ++static DMAD_AHB_CH_ROUTE ahb_ch_route_table[] = { ++ {0x00, 0, 0}, ++ {0x01, PMU_CFC_REQACK_CFG, PMU_CFC_REQACK_CFG}, ++ {0x02, PMU_SSP1_REQACK_CFG, PMU_SSP1_REQACK_CFG}, ++ {0x03, PMU_UART1RX_REQACK_CFG, PMU_UART1TX_REQACK_CFG}, ++ {0x04, PMU_UART1TX_REQACK_CFG, PMU_UART1RX_REQACK_CFG}, ++ {0x05, PMU_UART2RX_REQACK_CFG, PMU_UART2TX_REQACK_CFG}, ++ {0x06, PMU_UART2TX_REQACK_CFG, PMU_UART2RX_REQACK_CFG}, ++ {0x07, PMU_SDC_REQACK_CFG, PMU_SDC_REQACK_CFG}, ++ {0x08, PMU_I2SAC97RX_REQACK_CFG, PMU_I2SAC97TX_REQACK_CFG}, ++ {0x09, 0, 0}, ++ {0x0a, PMU_I2SAC97TX_REQACK_CFG, PMU_I2SAC97RX_REQACK_CFG}, ++ {0x0b, PMU_USB_REQACK_CFG, PMU_USB_REQACK_CFG}, ++ {0x0c, 0, 0}, ++ {0x0d, 0, 0}, ++ {0x0e, PMU_EXT0_REQACK_CFG, PMU_EXT0_REQACK_CFG}, ++ {0x0f, PMU_EXT1_REQACK_CFG, PMU_EXT1_REQACK_CFG}, ++}; ++ ++#endif /* CONFIG_PLAT_AG102 */ ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ ++/* system irq number (per channel, ahb) */ ++static const unsigned int ahb_irqs[DMAD_AHB_MAX_CHANNELS] = { ++ DMAC_FTDMAC020_0_IRQ0, ++ DMAC_FTDMAC020_0_IRQ1, ++ DMAC_FTDMAC020_0_IRQ2, ++ DMAC_FTDMAC020_0_IRQ3, ++ DMAC_FTDMAC020_0_IRQ4, ++ DMAC_FTDMAC020_0_IRQ5, ++ DMAC_FTDMAC020_0_IRQ6, ++ DMAC_FTDMAC020_0_IRQ7, ++}; ++ ++#endif /* CONFIG_PLATFORM_AHBDMA */ ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++ ++/* APB Bridge DMA request number re-route table */ ++typedef struct _DMAD_APB_REQN_ROUTE { ++ u32 apb_reqn; /* APB device req/gnt number */ ++ u32 ahb_reqn_tx; /* AHB DMAC req/ack number (tx) */ ++ u32 ahb_reqn_rx; /* AHB DMAC req/ack number (rx) */ ++ u32 bus_sel; /* APBBR_ADDRSEL_APB(0) or APBBR_ADDRSEL_AHB(1) */ ++} DMAD_APB_REQN_ROUTE; ++ ++#ifdef CONFIG_PLAT_AG102 ++ ++/* APB Bridge DMA request number re-route table. Indexed by APB DMA req/gnt ++ * number. */ ++static DMAD_APB_REQN_ROUTE apb_reqn_route_table[] = { ++ {0x00, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x01, DMAC_REQN_CFC, DMAC_REQN_CFC, APBBR_ADDRSEL_APB}, ++ {0x02, 0x00, 0x00, APBBR_ADDRSEL_APB}, ++ {0x03, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x04, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ //MOD by river 2010.10.20 ++ {0x05, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ //End MOD by river 2010.10.20 ++ {0x06, DMAC_REQN_I2SAC97TX, DMAC_REQN_I2SAC97RX, APBBR_ADDRSEL_APB}, ++ {0x07, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ //MOD by river 2010.10.20 ++ {0x08, DMAC_REQN_SDC, DMAC_REQN_SDC, APBBR_ADDRSEL_APB}, ++ //End MOD by river 2010.10.20 ++ {0x09, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x0a, DMAC_REQN_UART2TX, DMAC_REQN_UART2RX, APBBR_ADDRSEL_APB}, ++ {0x0b, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x0c, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x0d, DMAC_REQN_I2SAC97TX, DMAC_REQN_I2SAC97RX, APBBR_ADDRSEL_APB}, ++ {0x0e, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x0f, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++}; ++ ++#else /* CONFIG_PLAT_AG102 */ ++ ++/* APB Bridge DMA request number re-route table. Indexed by APB DMA req/gnt ++ * number. */ ++static DMAD_APB_REQN_ROUTE apb_reqn_route_table[] = { ++ {0x00, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x01, DMAC_REQN_CFC, DMAC_REQN_CFC, APBBR_ADDRSEL_APB}, ++ {0x02, DMAC_REQN_SSP, DMAC_REQN_SSP, APBBR_ADDRSEL_APB}, ++ {0x03, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x04, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x05, DMAC_REQN_SDC, DMAC_REQN_SDC, APBBR_ADDRSEL_APB}, ++ {0x06, DMAC_REQN_I2SAC97TX, DMAC_REQN_I2SAC97RX, APBBR_ADDRSEL_APB}, ++/* for amerald ++ { 0x07, 0x00, 0x00, APBBR_ADDRSEL_AHB },*/ ++ {0x07, APBBR_REQN_SDC_AMERALD, APBBR_REQN_SDC_AMERALD, ++ APBBR_ADDRSEL_AHB}, ++/* for amerald ac97 ++ { 0x08, 0x00, 0x00, APBBR_ADDRSEL_AHB }, */ ++ {0x08, APBBR_REQN_I2SAC97TX_AMERALD, APBBR_REQN_I2SAC97TX_AMERALD, ++ APBBR_ADDRSEL_APB}, ++ {0x09, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x0a, DMAC_REQN_UART2TX, DMAC_REQN_UART2RX, APBBR_ADDRSEL_APB}, ++ {0x0b, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x0c, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x0d, DMAC_REQN_I2SAC97TX, DMAC_REQN_I2SAC97RX, APBBR_ADDRSEL_APB}, ++ {0x0e, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++ {0x0f, 0x00, 0x00, APBBR_ADDRSEL_AHB}, ++}; ++ ++#endif /* CONFIG_PLAT_AG102 */ ++ ++/* system irq number (per channel, apb) */ ++static const unsigned int apb_irqs[DMAD_APB_MAX_CHANNELS] = { ++ APBBRG_FTAPBBRG020S_0_IRQ0, ++ APBBRG_FTAPBBRG020S_0_IRQ1, ++ APBBRG_FTAPBBRG020S_0_IRQ2, ++ APBBRG_FTAPBBRG020S_0_IRQ3, ++}; ++ ++#endif ++ ++/* Driver data structure, one instance per system */ ++typedef struct DMAD_DATA_STRUCT { ++ /* Driver data initialization flag */ ++ ++ /* DMA queue pool access control object */ ++ spinlock_t drq_pool_lock; ++ ++ /* DMA queue base address, to ease alloc/free flow */ ++ dmad_drq *drq_pool; ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ /* DMA queue for AHB DMA channels */ ++ dmad_drq *ahb_drq_pool; ++#endif ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++ /* DMA queue for APB DMA channels */ ++ dmad_drq *apb_drq_pool; ++#endif ++ ++} DMAD_DATA; ++ ++/* Driver data structure instance, one instance per system */ ++static DMAD_DATA dmad __attribute__ ((aligned(4))) = { ++ .drq_pool_lock = __SPIN_LOCK_UNLOCKED(dmad.drq_pool_lock), ++// .drq_pool_lock = SPIN_LOCK_UNLOCKED, ++ .drq_pool = 0, ++#ifdef CONFIG_PLATFORM_AHBDMA ++ .ahb_drq_pool = 0, ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ .apb_drq_pool = 0, ++#endif ++}; ++ ++/** ++ * dmad_next_drb - static function ++ * @drb_pool : [in] The raw DRB pool of a DMA channel ++ * @node : [in] The node number to lookup its next node ++ * @drb : [out] The drb next to the "node" node number ++ * ++ * Lookup next DRB of the specified node number. "drb" is null if reaches end ++ * of the list. ++ */ ++static inline void dmad_next_drb(dmad_drb * drb_pool, u32 node, dmad_drb ** drb) ++{ ++ if (likely(drb_pool[node].next != 0)) ++ *drb = &drb_pool[drb_pool[node].next]; ++ else ++ *drb = 0; ++} ++ ++/** ++ * dmad_prev_drb - static function ++ * @drb_pool : [in] The raw DRB pool of a DMA channel ++ * @node : [in] The node number to lookup its previous node ++ * @drb : [out] The drb previous to the "node" node number ++ * ++ * Lookup previous DRB of the specified node number. "drb" is null if reaches ++ * head-end of the list. ++ */ ++static inline void dmad_prev_drb(dmad_drb * drb_pool, u32 node, dmad_drb ** drb) ++{ ++ if (unlikely(drb_pool[node].prev != 0)) ++ *drb = &drb_pool[drb_pool[node].prev]; ++ else ++ *drb = 0; ++} ++ ++/** ++ * dmad_detach_node - static function ++ * @drb_pool : [in] The raw DRB pool of a DMA channel ++ * @head : [in/out] Reference to the head node number ++ * @tail : [in/out] Reference to the tail node number ++ * @node : [in] The node to be dettached from the queue ++ * ++ * Detached a DRB specified by the node number from the queue. The head and ++ * tail records will be updated accordingly. ++ */ ++static inline void dmad_detach_node(dmad_drb * drb_pool, ++ u32 * head, u32 * tail, u32 node) ++{ ++ if (likely(drb_pool[node].prev != 0)) { ++ /* prev->next = this->next (= 0, if this is a tail) */ ++ drb_pool[drb_pool[node].prev].next = drb_pool[node].next; ++ } else { ++ /* this node is head, move head to next node ++ * (= 0, if this is the only one node) */ ++ *head = drb_pool[node].next; ++ } ++ ++ if (unlikely(drb_pool[node].next != 0)) { ++ /* next->prev = this->prev (= 0, if this is a head) */ ++ drb_pool[drb_pool[node].next].prev = drb_pool[node].prev; ++ } else { ++ /* this node is tail, move tail to previous node ++ * (= 0, if this is the only one node) */ ++ *tail = drb_pool[node].prev; ++ } ++ ++ drb_pool[node].prev = drb_pool[node].next = 0; ++} ++ ++/** ++ * dmad_detach_head - static function ++ * @drb_pool : [in] The raw DRB pool of a DMA channel ++ * @head : [in/out] Reference to the head node number ++ * @tail : [in/out] Reference to the tail node number ++ * @drb : [out] The detached head node; null if the queue is empty ++ * ++ * Detached a DRB from the head of the queue. The head and tail records will ++ * be updated accordingly. ++ */ ++static inline void dmad_detach_head(dmad_drb * drb_pool, ++ u32 * head, u32 * tail, dmad_drb ** drb) ++{ ++ if (unlikely(*head == 0)) { ++ *drb = NULL; ++ return; ++ } ++ ++ *drb = &drb_pool[*head]; ++ ++ if (likely((*drb)->next != 0)) { ++ /* next->prev = this->prev (= 0, if this is a head) */ ++ drb_pool[(*drb)->next].prev = 0; ++ ++ /* prev->next = this->next (do nothing, if this is a head) */ ++ ++ /* head = this->next */ ++ *head = (*drb)->next; ++ } else { ++ /* head = tail = 0 */ ++ *head = 0; ++ *tail = 0; ++ } ++ ++ /* this->prev = this->next = 0 (do nothing, if save code size) */ ++ (*drb)->prev = (*drb)->next = 0; ++} ++ ++/** ++ * dmad_get_head - static function ++ * @drb_pool : [in] The raw DRB pool of a DMA channel ++ * @head : [in/out] Reference to the head node number ++ * @tail : [in/out] Reference to the tail node number ++ * @drb : [out] The head node; null if the queue is empty ++ * ++ * Get a DRB from the head of the queue. The head and tail records remain ++ * unchanged. ++ */ ++static inline void dmad_get_head(dmad_drb * drb_pool, const u32 * head, ++ const u32 * tail, dmad_drb ** drb) ++{ ++ if (unlikely(*head == 0)) { ++ *drb = NULL; ++ return; ++ } ++ ++ *drb = &drb_pool[*head]; ++} ++ ++/** ++ * dmad_detach_tail - static function ++ * @drb_pool : [in] The raw DRB pool of a DMA channel ++ * @head : [in/out] Reference to the head node number ++ * @tail : [in/out] Reference to the tail node number ++ * @drb : [out] The tail node; null if the queue is empty ++ * ++ * Detached a DRB from the head of the queue. The head and tail records will ++ * be updated accordingly. ++ */ ++static inline void dmad_detach_tail(dmad_drb * drb_pool, ++ u32 * head, u32 * tail, dmad_drb ** drb) ++{ ++ if (unlikely(*tail == 0)) { ++ *drb = NULL; ++ return; ++ } ++ ++ *drb = &drb_pool[*tail]; ++ ++ if (likely((*drb)->prev != 0)) { ++ /* prev->next = this->next (= 0, if this is a tail) */ ++ drb_pool[(*drb)->prev].next = 0; ++ ++ /* next->prev = this->prev (do nothing, if this is a tail) */ ++ ++ /* tail = this->prev */ ++ *tail = (*drb)->prev; ++ } else { ++ /* head = tail = 0 */ ++ *head = 0; ++ *tail = 0; ++ } ++ ++ /* this->next = this->prev = 0 (do nothing, if save code size) */ ++ (*drb)->prev = (*drb)->next = 0; ++} ++ ++/** ++ * dmad_get_tail - static function ++ * @drb_pool : [in] The raw DRB pool of a DMA channel ++ * @head : [in/out] Reference to the head node number ++ * @tail : [in/out] Reference to the tail node number ++ * @drb : [out] The tail node; null if the queue is empty ++ * ++ * Get a DRB from the tail of the queue. The head and tail records remain ++ * unchanged. ++ */ ++static inline void dmad_get_tail(dmad_drb * drb_pool, ++ u32 * head, u32 * tail, dmad_drb ** drb) ++{ ++ if (unlikely(*tail == 0)) { ++ *drb = NULL; ++ return; ++ } ++ ++ *drb = &drb_pool[*tail]; ++} ++ ++/** ++ * dmad_attach_head - static function ++ * @drb_pool : [in] The raw DRB pool of a DMA channel ++ * @head : [in/out] Reference to the head node number ++ * @tail : [in/out] Reference to the tail node number ++ * @node : [in] The node to be attached ++ * ++ * Attach a DRB node to the head of the queue. The head and tail records will ++ * be updated accordingly. ++ */ ++static inline void dmad_attach_head(dmad_drb * drb_pool, ++ u32 * head, u32 * tail, u32 node) ++{ ++ if (likely(*head != 0)) { ++ /* head->prev = this */ ++ drb_pool[*head].prev = node; ++ ++ /* this->next = head */ ++ drb_pool[node].next = *head; ++ /* this->prev = 0 */ ++ drb_pool[node].prev = 0; ++ ++ /* head = node */ ++ *head = node; ++ } else { ++ /* head = tail = node */ ++ *head = *tail = node; ++ drb_pool[node].prev = drb_pool[node].next = 0; ++ } ++} ++ ++/** ++ * dmad_attach_head - static function ++ * @drb_pool : [in] The raw DRB pool of a DMA channel ++ * @head : [in/out] Reference to the head node number ++ * @tail : [in/out] Reference to the tail node number ++ * @node : [in] The node to be attached ++ * ++ * Attach a DRB node to the tail of the queue. The head and tail records will ++ * be updated accordingly. ++ */ ++static inline void dmad_attach_tail(dmad_drb * drb_pool, ++ u32 * head, u32 * tail, u32 node) ++{ ++ if (likely(*tail != 0)) { ++ /* tail->next = this */ ++ drb_pool[*tail].next = node; ++ ++ /* this->prev = tail */ ++ drb_pool[node].prev = *tail; ++ /* this->next = 0 */ ++ drb_pool[node].next = 0; ++ ++ /* tail = node */ ++ *tail = node; ++ } else { ++ /* head = tail = node */ ++ *head = *tail = node; ++ drb_pool[node].prev = drb_pool[node].next = 0; ++ } ++} ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ ++/** ++ * dmad_ahb_isr - AHB DMA interrupt service routine ++ * ++ * @irq : [in] The irq number ++ * @dev_id : [in] The identifier to identify the asserted channel ++ * ++ * This is the ISR that services all AHB DMA channels. ++ */ ++static irqreturn_t dmad_ahb_isr(int irq, void *dev_id) ++{ ++ dmad_drq *drq; ++ dmad_drb *drb, *drb_iter; ++ u32 channel = ((u32) dev_id) - 1; ++ u8 tc_int = 0; ++ u8 err_int = 0; ++ u8 abt_int = 0; ++ u8 cpl_events = 1; ++ ++ dmad_dbg("%s() >> channel(%d)\n", __func__, channel); ++ ++ if (channel >= DMAD_AHB_MAX_CHANNELS) { ++ dmad_err("%s() invlaid channel number: %d!\n", ++ __func__, channel); ++ return IRQ_HANDLED; ++ } ++ ++ /* Fetch channel's DRQ struct (DMA Request Queue) */ ++ drq = (dmad_drq *) & dmad.ahb_drq_pool[channel]; ++ ++ /* Check DMA status register to get channel number */ ++ if (likely(getbl(channel, DMAC_INT_TC))) { ++ ++ /* Mark as TC int */ ++ tc_int = 1; ++ ++ /* DMAC INT TC status clear */ ++ setbl(channel, DMAC_INT_TC_CLR); ++ ++ } else if (getbl(channel + DMAC_INT_ERR_SHIFT, DMAC_INT_ERRABT)) { ++ ++ /* Mark as ERR int */ ++ err_int = 1; ++ ++ /* DMAC INT ERR status clear */ ++ setbl(channel + DMAC_INT_ERR_CLR_SHIFT, DMAC_INT_ERRABT_CLR); ++ ++ } else if (getbl(channel + DMAC_INT_ABT_SHIFT, DMAC_INT_ERRABT)) { ++ ++ /* Mark as ABT int */ ++ abt_int = 1; ++ ++ /* DMAC INT ABT status clear */ ++ setbl(channel + DMAC_INT_ABT_CLR_SHIFT, DMAC_INT_ERRABT_CLR); ++ ++ } else { ++ ++ dmad_err("%s() possible false-fired ahb dma int," ++ "channel %d status-reg: tc(0x%08x) arrabt(0x%08x)\n", ++ __func__, channel, ++ inl(DMAC_INT_TC), inl(DMAC_INT_ERRABT_CLR)); ++ ++ /* Stop DMA channel (make sure the channel will be stopped) */ ++ clrbl(DMAC_CSR_CH_EN_BIT, drq->channel_base + DMAC_CSR_OFFSET); ++ ++ return IRQ_HANDLED; ++ } ++ ++ /* DMAC ++ * Stop DMA channel temporarily */ ++ dmad_disable_channel(drq); ++ ++ spin_lock(&drq->drb_pool_lock); ++ ++ /* Lookup/detach latest submitted DRB (DMA Request Block) from ++ * the DRQ (DMA Request Queue), so ISR could kick off next DRB */ ++ dmad_detach_head(drq->drb_pool, &drq->sbt_head, &drq->sbt_tail, &drb); ++ if (drb == NULL) { ++ spin_unlock(&drq->drb_pool_lock); ++ /* submitted list could be empty if client cancel all requests ++ * of the channel. */ ++ return IRQ_HANDLED; ++ } ++ ++ /* release blocking of drb-allocation, if any ... */ ++ if (unlikely((drq->fre_head == 0) && ++ (drq->flags & DMAD_FLAGS_SLEEP_BLOCK))) { ++ complete_all(&drq->drb_alloc_sync); ++ } ++ ++ /* Process DRBs according to interrupt reason */ ++ if (tc_int) { ++ ++ dmad_dbg("dma finish\n"); ++ ++ dmad_dbg("finish drb(%d 0x%08x) addr0(0x%08x) " ++ "addr1(0x%08x) size(0x%08x)\n", ++ drb->node, (u32) drb, drb->src_addr, ++ drb->dst_addr, drb->req_cycle); ++ ++ if (drb->req_cycle == 0) ++ cpl_events = 0; ++ ++ // Mark DRB state as completed ++ drb->state = DMAD_DRB_STATE_COMPLETED; ++ if (cpl_events && drb->sync) ++ complete_all(drb->sync); ++ ++ dmad_attach_tail(drq->drb_pool, &drq->fre_head, ++ &drq->fre_tail, drb->node); ++ ++ // Check whether there are pending requests in the DRQ ++ if (drq->sbt_head != 0) { ++ ++ // Lookup next DRB (DMA Request Block) ++ drb_iter = &drq->drb_pool[drq->sbt_head]; ++ ++ dmad_dbg("exec drb(%d 0x%08x) addr0(0x%08x) " ++ "addr1(0x%08x) size(0x%08x)\n", ++ drb_iter->node, (u32) drb_iter, ++ drb_iter->src_addr, drb_iter->dst_addr, ++ drb_iter->req_cycle); ++ ++ // Kick-off DMA for next DRB ++ // - Source and destination address ++ if (drq->flags & DMAD_DRQ_DIR_A1_TO_A0) { ++ outl(drb_iter->addr1, drq->src_port); ++ outl(drb_iter->addr0, drq->dst_port); ++ } else { ++ outl(drb_iter->addr0, drq->src_port); ++ outl(drb_iter->addr1, drq->dst_port); ++ } ++ ++ /* - Transfer size (in units of source width) */ ++ outl(drb_iter->req_cycle, drq->cyc_port); ++ ++ /* Kick off next request */ ++ dmad_enable_channel(drq); ++ ++ drb_iter->state = DMAD_DRB_STATE_EXECUTED; ++ ++ } else { ++ /* No pending requests, keep the DMA channel stopped */ ++ } ++ ++ } else { ++ ++ dmad_err("%s() ahb dma channel %d error!\n", __func__, channel); ++ ++ /* Zero out src, dst, and size */ ++ outl(0, drq->src_port); ++ outl(0, drq->dst_port); ++ outl(0, drq->cyc_port); ++ ++ /* Remove all pending requests in the queue */ ++ drb_iter = drb; ++ while (drb_iter) { ++ ++ dmad_err("abort drb(%d 0x%08x) addr0(0x%08x) " ++ "addr1(0x%08x) size(0x%08x)\n", ++ drb_iter->node, (u32) drb_iter, ++ drb_iter->src_addr, drb_iter->dst_addr, ++ drb_iter->req_cycle); ++ ++ if (drb_iter->req_cycle == 0) ++ cpl_events = 0; ++ ++ /* Mark DRB state as abort */ ++ drb_iter->state = DMAD_DRB_STATE_ABORT; ++ ++ if (cpl_events && drb_iter->sync) ++ complete_all(drb_iter->sync); ++ ++ dmad_attach_tail(drq->drb_pool, &drq->fre_head, ++ &drq->fre_tail, drb_iter->node); ++ ++ /* Detach next submitted DRB (DMA Request Block) ++ * from the DRQ (DMA Request Queue) */ ++ dmad_detach_head(drq->drb_pool, &drq->sbt_head, ++ &drq->sbt_tail, &drb_iter); ++ } ++ } ++ ++ spin_unlock(&drq->drb_pool_lock); ++ ++ /* dispatch interrupt-context level callbacks */ ++ if (cpl_events && drq->completion_cb) { ++ /* signal DMA driver that new node is available */ ++ drq->completion_cb(channel, tc_int, drq->completion_data); ++ } ++ ++ dmad_dbg("%s() <<\n", __func__); ++ ++ return IRQ_HANDLED; ++} ++ ++/** ++ * dmad_ahb_config_dir - prepare command reg according to tx direction ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @channel_cmds : [out] Reference to array of command words to be prepared with ++ * @return : none ++ * ++ * Prepare command registers according to transfer direction ... ++ * channel_cmd[0] DMAC_CSR ++ * channel_cmd[1] DMAC_CFG ++ * ++ * This function only serves as local helper. No protection wrappers. ++ */ ++static void dmad_ahb_config_dir(dmad_chreq * ch_req, addr_t * channel_cmds) ++{ ++ dmad_drq *drq = (dmad_drq *) ch_req->drq; ++ dmad_ahb_chreq *ahb_req = (dmad_ahb_chreq *) (&ch_req->ahb_req); ++/* for amerald */ ++ u32 reqn0, reqn1; ++ dmad_dbg("%s() channel_cmds(0x%08x, 0x%08x)\n", ++ __func__, channel_cmds[0], channel_cmds[1]); ++/* for amerald */ ++ if ((inl(PMU_BASE) & AMERALD_MASK) == AMERALD_PRODUCT_ID) { ++ reqn0 = ahb_req->addr0_reqn; ++ reqn1 = ahb_req->addr1_reqn; ++ } else { ++ reqn0 = ch_req->channel; ++ reqn1 = ch_req->channel; ++ } ++ channel_cmds[0] &= ~(addr_t) ++ (DMAC_CSR_SRC_WIDTH_MASK | DMAC_CSR_SRCAD_CTL_MASK | ++ DMAC_CSR_DST_WIDTH_MASK | DMAC_CSR_DSTAD_CTL_MASK | ++ DMAC_CSR_MODE_MASK); ++ channel_cmds[1] &= ~(addr_t) ++ (DMAC_CFG_INT_SRC_RS_MASK | DMAC_CFG_INT_SRC_HE_MASK | ++ DMAC_CFG_INT_DST_RS_MASK | DMAC_CFG_INT_DST_HE_MASK); ++ ++ /* 0 - addr0 to addr1; 1 - addr1 to addr0 */ ++ if (ahb_req->tx_dir == 0) { ++ ++ dmad_dbg("%s() addr0 --> addr1\n", __func__); ++ ++ /* - Channel CSR ++ * DST_SEL : 0 (Master 0) ++ * SRC_SEL : 0 (Master 0) ++ * DSTAD_CTL : ahb_req->dst_ctrl ++ * SRCAD_CTL : ahb_req->src_ctrl ++ * MODE : 0 (normal) ++ * DST_WIDTH : ahb_req->dst_width ++ * SRC_WIDTH : ahb_req->src_width ++ * SRC_SIZE : 0 (burst size = 1 byte) ++ */ ++ channel_cmds[0] |= ++ (((ahb_req->addr0_width << DMAC_CSR_SRC_WIDTH_SHIFT) & ++ DMAC_CSR_SRC_WIDTH_MASK) | ++ ((ahb_req->addr0_ctrl << DMAC_CSR_SRCAD_CTL_SHIFT) & ++ DMAC_CSR_SRCAD_CTL_MASK) | ++ ((ahb_req->addr1_width << DMAC_CSR_DST_WIDTH_SHIFT) & ++ DMAC_CSR_DST_WIDTH_MASK) | ++ ((ahb_req->addr1_ctrl << DMAC_CSR_DSTAD_CTL_SHIFT) & ++ DMAC_CSR_DSTAD_CTL_MASK)); ++ ++ /* - Channel CFG ++ * SRC_RS : channel number (not reqn) ++ * SRC_HE : 0 if memory, 1 if device ++ * DST_RS : channel number (not reqn) ++ * DST_HE : 0 if memory, 1 if device ++ */ ++ if (likely(ahb_req->hw_handshake != 0)) { ++ /* Channel CSR - Enable HW-handshake mode */ ++ channel_cmds[0] |= DMAC_CSR_MODE_MASK; ++ ++ /* Channel CFG - Device REQN and HW-handshake mode */ ++#ifdef CONFIG_PLAT_AG102 ++ /* AG102 fixes this bug */ ++ if (ahb_req->addr0_reqn != DMAC_REQN_NONE) { ++ channel_cmds[1] |= (DMAC_CFG_INT_SRC_HE_MASK | ++ ((ahb_req->addr0_reqn << ++ DMAC_CFG_INT_SRC_RS_SHIFT) ++ & ++ DMAC_CFG_INT_SRC_RS_MASK)); ++ } ++ ++ if (ahb_req->addr1_reqn != DMAC_REQN_NONE) { ++ channel_cmds[1] |= (DMAC_CFG_INT_DST_HE_MASK | ++ ((ahb_req->addr1_reqn << ++ DMAC_CFG_INT_DST_RS_SHIFT) ++ & ++ DMAC_CFG_INT_DST_RS_MASK)); ++ } ++#else ++ /* AG101/XC5 bug */ ++/* for amerald */ ++ if (ahb_req->addr0_reqn != DMAC_REQN_NONE) { ++ channel_cmds[1] |= (DMAC_CFG_INT_SRC_HE_MASK | ++ ((reqn0 << ++ DMAC_CFG_INT_SRC_RS_SHIFT) ++ & ++ DMAC_CFG_INT_SRC_RS_MASK)); ++ } ++ ++ if (ahb_req->addr1_reqn != DMAC_REQN_NONE) { ++ channel_cmds[1] |= (DMAC_CFG_INT_DST_HE_MASK | ++ ((reqn1 << ++ DMAC_CFG_INT_DST_RS_SHIFT) ++ & ++ DMAC_CFG_INT_DST_RS_MASK)); ++ } ++#endif ++ } ++ ++ /* update source data width for faster cycle/byte size conversion */ ++ drq->data_width = ahb_req->addr0_width; ++ ++ /* remember channel transfer direction */ ++ drq->flags &= ~(addr_t) DMAD_DRQ_DIR_A1_TO_A0; ++ ++ } else { ++ ++ dmad_dbg("%s() addr0 <-- addr1\n", __func__); ++ ++ /* - Channel CSR ++ * DST_SEL : 0 (Master 0) ++ * SRC_SEL : 0 (Master 0) ++ * DSTAD_CTL : ahb_req->dst_ctrl ++ * SRCAD_CTL : ahb_req->src_ctrl ++ * MODE : 0 (normal) ++ * DST_WIDTH : ahb_req->dst_width ++ * SRC_WIDTH : ahb_req->src_width ++ * SRC_SIZE : 0 (burst size = 1 byte) ++ */ ++ channel_cmds[0] |= ++ (((ahb_req->addr1_width << DMAC_CSR_SRC_WIDTH_SHIFT) & ++ DMAC_CSR_SRC_WIDTH_MASK) | ++ ((ahb_req->addr1_ctrl << DMAC_CSR_SRCAD_CTL_SHIFT) & ++ DMAC_CSR_SRCAD_CTL_MASK) | ++ ((ahb_req->addr0_width << DMAC_CSR_DST_WIDTH_SHIFT) & ++ DMAC_CSR_DST_WIDTH_MASK) | ++ ((ahb_req->addr0_ctrl << DMAC_CSR_DSTAD_CTL_SHIFT) & ++ DMAC_CSR_DSTAD_CTL_MASK)); ++ ++ /* - Channel CFG ++ * SRC_RS : channel number (not reqn) ++ * SRC_HE : 0 if memory, 1 if device ++ * DST_RS : channel number (not reqn) ++ * DST_HE : 0 if memory, 1 if device ++ */ ++ if (likely(ahb_req->hw_handshake != 0)) { ++ /* Channel CSR - Enable HW-handshake mode */ ++ channel_cmds[0] |= DMAC_CSR_MODE_MASK; ++ ++ /* Channel CFG - Device REQN and HW-handshake mode */ ++#ifdef CONFIG_PLAT_AG102 ++ /* AG102 fixes this bug */ ++ if (ahb_req->addr1_reqn != DMAC_REQN_NONE) { ++ channel_cmds[1] |= (DMAC_CFG_INT_SRC_HE_MASK | ++ ((ahb_req->addr1_reqn << ++ DMAC_CFG_INT_SRC_RS_SHIFT) ++ & ++ DMAC_CFG_INT_SRC_RS_MASK)); ++ } ++ ++ if (ahb_req->addr0_reqn != DMAC_REQN_NONE) { ++ channel_cmds[1] |= (DMAC_CFG_INT_DST_HE_MASK | ++ ((ahb_req->addr0_reqn << ++ DMAC_CFG_INT_DST_RS_SHIFT) ++ & ++ DMAC_CFG_INT_DST_RS_MASK)); ++ } ++#else ++ /* AG101/XC5 bug */ ++/* for amerald */ ++ if (ahb_req->addr1_reqn != DMAC_REQN_NONE) { ++ channel_cmds[1] |= (DMAC_CFG_INT_SRC_HE_MASK | ++ ((reqn1 << ++ DMAC_CFG_INT_SRC_RS_SHIFT) ++ & ++ DMAC_CFG_INT_SRC_RS_MASK)); ++ } ++ ++ if (ahb_req->addr0_reqn != DMAC_REQN_NONE) { ++ channel_cmds[1] |= (DMAC_CFG_INT_DST_HE_MASK | ++ ((reqn0 << ++ DMAC_CFG_INT_DST_RS_SHIFT) ++ & ++ DMAC_CFG_INT_DST_RS_MASK)); ++ } ++#endif ++ } ++ ++ /* source data width */ ++ drq->data_width = ahb_req->addr1_width; ++ ++ /* remember channel transfer direction */ ++ drq->flags |= (addr_t) DMAD_DRQ_DIR_A1_TO_A0; ++ } ++ ++ dmad_dbg("%s() channel_cmds(0x%08x, 0x%08x)\n", ++ __func__, channel_cmds[0], channel_cmds[1]); ++} ++ ++/** ++ * dmad_ahb_init - initialize a ahb dma channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @return : 0 if success, non-zero if any error ++ * ++ * Register AHB DMA ISR and performs hw initialization for the given DMA ++ * channel. ++ */ ++static int dmad_ahb_init(dmad_chreq * ch_req) ++{ ++ int err = 0; ++ dmad_drq *drq = (dmad_drq *) ch_req->drq; ++ dmad_ahb_chreq *ahb_req = (dmad_ahb_chreq *) (&ch_req->ahb_req); ++ u32 channel = (u32) ch_req->channel; ++ addr_t channel_base = drq->channel_base; ++ addr_t channel_cmds[2]; // [0] DMAC_CSR; [1] DMAC_CFG ++ unsigned long lock_flags; ++ ++ dmad_dbg("%s()\n", __func__); ++ ++ /* register interrupt handler */ ++ err = request_irq(ahb_irqs[channel], dmad_ahb_isr, 0, ++ "AHB_DMA", (void *)(channel + 1)); ++ if (unlikely(err != 0)) { ++ dmad_err("unable to request IRQ %d for AHB DMA " ++ "(error %d)\n", ahb_irqs[channel], err); ++ free_irq(ahb_irqs[channel], (void *)(channel + 1)); ++ return err; ++ } ++ ++ spin_lock_irqsave(&dmad.drq_pool_lock, lock_flags); ++ ++ /********************************************************** ++ * Following code require _safe_exit return path ++ */ ++ ++#ifdef CONFIG_PLAT_AG102 ++ /* PCU ++ * ++ * Add by Dennis 2011.03.09 ++ * set 0 to dma selection register to using AHB ++ * DMA. ++ */ ++ if (ahb_req->dst_reqn == ahb_req->src_reqn) { ++ dmad_err ++ ("[dmad] invalid source reqn(%d) or destination reqn(%d)\n", ++ ahb_req->src_reqn, ahb_req->dst_reqn); ++ err = -EBADR; ++ goto _safe_exit; ++ } ++ outl(0, PCU_DMA_SEL); ++#else /* CONFIG_PLAT_AG102 */ ++ ++ /* PMU ++ * ++ * Route APB device DMA to an AHB DMAC channel and specify the channel ++ * number. (connection status could be read back from PMU_AHBDMA_REQACK ++ * register) ++ * ++ * Note: Only one device is routed per AHB DMA channel, the other target ++ * should be either (1) the same device (same reqn), or (2) the AHB ++ * device (reqn = 0). ++ */ ++ ++ if (ahb_req->dst_reqn != DMAC_REQN_NONE) { ++ // DMA transfer to device ++ if ((ahb_req->dst_reqn > DMAC_REQN_MAX) || ++ (ahb_ch_route_table[ahb_req->dst_reqn].route_cr == 0)) { ++ dmad_err("Invalid destination reqn(%d) " ++ "or route_cr(0x%08x)\n", ahb_req->dst_reqn, ++ (u32) ahb_ch_route_table[ahb_req->dst_reqn]. ++ route_cr); ++ err = -EBADR; ++ goto _safe_exit; ++ } ++ ++ outl(0, ahb_ch_route_table[ahb_req->dst_reqn].clear_cr); ++ outl(PMU_DMACUSED_MASK | ((channel << PMU_CHANNEL_SHIFT) & ++ PMU_CHANNEL_MASK), ++ ahb_ch_route_table[ahb_req->dst_reqn].route_cr); ++ ++ } else if (ahb_req->src_reqn != DMAC_REQN_NONE) { ++ ++ // DMA transfer from device ++ if ((ahb_req->src_reqn > DMAC_REQN_MAX) || ++ (ahb_ch_route_table[ahb_req->src_reqn].route_cr == 0)) { ++ dmad_err("Invalid source reqn(%d) or " ++ "route_cr(0x%08x)\n", ahb_req->src_reqn, ++ (u32) ahb_ch_route_table[ahb_req->src_reqn]. ++ route_cr); ++ err = -EBADR; ++ goto _safe_exit; ++ } ++ ++ outl(0, ahb_ch_route_table[ahb_req->src_reqn].clear_cr); ++ outl(PMU_DMACUSED_MASK | ((channel << PMU_CHANNEL_SHIFT) & ++ PMU_CHANNEL_MASK), ++ ahb_ch_route_table[ahb_req->src_reqn].route_cr); ++ } ++#endif /* CONFIG_PLAT_AG102 */ ++ ++ /* DMAC (Controller Setting) */ ++ ++ /* - INT TC/ERR/ABT status clear */ ++ setbl(channel, DMAC_INT_TC_CLR); ++ setbl(channel + DMAC_INT_ERR_CLR_SHIFT, DMAC_INT_ERRABT_CLR); ++ setbl(channel + DMAC_INT_ABT_CLR_SHIFT, DMAC_INT_ERRABT_CLR); ++ ++ // - CSR (enable DMAC, set M0 & M1 default to little endian) ++ outl(DMAC_DMACEN_MASK | ++ ((DMAC_ENDIAN_LITTLE << DMAC_M0ENDIAN_BIT) & DMAC_M0ENDIAN_MASK) | ++ ((DMAC_ENDIAN_LITTLE << DMAC_M1ENDIAN_BIT) & DMAC_M1ENDIAN_MASK), ++ DMAC_CSR); ++ ++ /* DMAC (Channel-Specific Setting) */ ++ /* - SYNC */ ++ if (ahb_req->sync) ++ setbl(channel, DMAC_SYNC); ++ else ++ clrbl(channel, DMAC_SYNC); ++ ++ /* - Channel CSR ++ * CH_EN : 0 (disable) ++ * DST_SEL : 0 (Master 0) ++ * SRC_SEL : 0 (Master 0) ++ * DSTAD_CTL : ahb_req->dst_ctrl ++ * SRCAD_CTL : ahb_req->src_ctrl ++ * MODE : 0 (normal) ++ * DST_WIDTH : ahb_req->dst_width ++ * SRC_WIDTH : ahb_req->src_width ++ * ABT : 0 (not abort) ++ * SRC_SIZE : 0 (burst size = 1 byte) ++ * PROT1 : 0 (user mode) ++ * PROT2 : 0 (bot bufferable) ++ * PROT3 : 0 (not cacheable) ++ * CHPRI : ahb_req->priority ++ * DMA_FF_TH : 0 (FIA320 only, threshold = 1) ++ * TC_MSK : 0 (TC counter status enable) ++ */ ++ channel_cmds[0] = (ahb_req->priority << DMAC_CSR_CHPRI_SHIFT) & ++ DMAC_CSR_CHPRI_MASK; ++ channel_cmds[0] |= (ahb_req->burst_size << DMAC_CSR_SRC_SIZE_SHIFT) & ++ DMAC_CSR_SRC_SIZE_MASK; ++ ++ // - Channel CFG ++ // INT_TC_MSK : 0 (enable TC int) ++ // INT_ERR_MSK : 0 (enable ERR int) ++ // INT_ABT_MSK : 0 (enable ABT int) ++ // SRC_RS : 0 ++ // SRC_HE : 0 ++ // BUSY : r/o ++ // DST_RS : 0 ++ // DST_HE : 0 ++ // LLP_CNT : r/o ++ channel_cmds[1] = 0; ++ ++ if (0 == ++ (ch_req->flags & (DMAD_FLAGS_RING_MODE | DMAD_FLAGS_BIDIRECTION))) ++ ahb_req->tx_dir = 0; ++ ++ dmad_ahb_config_dir(ch_req, channel_cmds); ++ ++ outl(channel_cmds[0], channel_base + DMAC_CSR_OFFSET); ++ outl(channel_cmds[1], channel_base + DMAC_CFG_OFFSET); ++ ++ /* SRCADR and DESADR */ ++ outl(0, (addr_t) drq->src_port); ++ outl(0, (addr_t) drq->dst_port); ++ ++ /* CYC (transfer size) */ ++ outl(0, (addr_t) drq->cyc_port); ++ ++ /* LLP */ ++ outl(0, channel_base + DMAC_LLP_OFFSET); ++ ++ /* TOT_SIZE - not now */ ++ ++_safe_exit: ++ ++ spin_unlock_irqrestore(&dmad.drq_pool_lock, lock_flags); ++ ++ return err; ++} ++ ++#endif /* CONFIG_PLATFORM_AHBDMA */ ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++ ++/** ++ * dmad_apb_isr - APB DMA interrupt service routine ++ * ++ * @irq : [in] The irq number ++ * @dev_id : [in] The identifier to identify the asserted channel ++ * ++ * This is the ISR that services all APB DMA channels. ++ */ ++static irqreturn_t dmad_apb_isr(int irq, void *dev_id) ++{ ++ dmad_drq *drq; ++ dmad_drb *drb, *drb_iter; ++ u32 channel = ((u32) dev_id) - 1; ++ u32 status; ++ u8 finish_int = 0; ++ u8 err_int = 0; ++ u8 cpl_events = 1; ++ ++ dmad_dbg("%s() >> channel(%d)\n", __func__, channel); ++ ++ if (channel >= DMAD_APB_MAX_CHANNELS) { ++ dmad_err("%s() invlaid channel number: %d!\n", ++ __func__, channel); ++ return IRQ_HANDLED; ++ } ++ ++ /* Lookup channel's DRQ (DMA Request Queue) */ ++ drq = (dmad_drq *) & dmad.apb_drq_pool[channel]; ++ ++ /* - Check DMA status register to get channel number */ ++ status = inl((addr_t) drq->channel_base + APBBR_DMA_CMD_OFFSET); ++ ++ if (likely(status & APBBR_DMA_FINTST_MASK)) { ++ ++ /*dmad_dbg("apb dma int status: finish (0x%08x)\n", status); */ ++ finish_int = 1; ++ ++ /* APB DMA finish int status clear */ ++ clrbl(APBBR_DMA_FINTST_BIT, ++ (addr_t) drq->channel_base + APBBR_DMA_CMD_OFFSET); ++ ++ } else if (status & APBBR_DMA_ERRINTST_MASK) { ++ ++ /* Perform DMA error checking if no valid channel was found ++ * who assert the finish signal. */ ++ dmad_err("apb dma int status: err (0x%08x)\n", status); ++ ++ /* Mark as error int */ ++ err_int = 1; ++ ++ /* APB DMA error int status clear */ ++ clrbl(APBBR_DMA_ERRINTST_BIT, ++ (addr_t) drq->channel_base + APBBR_DMA_CMD_OFFSET); ++ ++ } else { ++ ++ dmad_err("%s() possible false-fired apb dma int," ++ " channel %d status-reg: 0x%08x\n", ++ __func__, channel, status); ++ ++ /* Stop DMA channel (make sure the channel will be stopped) */ ++ clrbl(APBBR_DMA_CHEN_BIT, ++ (addr_t) drq->channel_base + APBBR_DMA_CMD_OFFSET); ++ ++ return IRQ_HANDLED; ++ } ++ ++ /* Stop DMA channel (make sure the channel will be stopped) */ ++ dmad_disable_channel(drq); ++ ++ spin_lock(&drq->drb_pool_lock); ++ ++ /* Lookup/detach latest submitted DRB (DMA Request Block) from */ ++ /* the DRQ (DMA Request Queue), so ISR could kick off next DRB */ ++ dmad_detach_head(drq->drb_pool, &drq->sbt_head, &drq->sbt_tail, &drb); ++ ++ if (unlikely(drb == NULL)) { ++ spin_unlock(&drq->drb_pool_lock); ++ return IRQ_HANDLED; ++ } ++ ++ /* release blocking of drb-allocation, if any ... */ ++ if (unlikely((drq->fre_head == 0) && ++ (drq->flags & DMAD_FLAGS_SLEEP_BLOCK))) { ++ complete_all(&drq->drb_alloc_sync); ++ } ++ ++ /* Process DRBs according to the cause of this interrupt */ ++ if (likely(finish_int)) { ++ ++ if (drb->req_cycle == 0) ++ cpl_events = 0; ++ ++ /* Mark DRB state as completed */ ++ drb->state = DMAD_DRB_STATE_COMPLETED; ++ if (cpl_events && drb->sync) ++ complete_all(drb->sync); ++ ++ dmad_attach_tail(drq->drb_pool, &drq->fre_head, ++ &drq->fre_tail, drb->node); ++ ++ /* Check whether there are pending requests in the DRQ */ ++ if (drq->sbt_head != 0) { ++ ++ /* Lookup next DRB (DMA Request Block) */ ++ drb_iter = &drq->drb_pool[drq->sbt_head]; ++ ++ dmad_dbg("exec drb(%d 0x%08x) addr0(0x%08x) " ++ "addr1(0x%08x) size(0x%08x)\n", ++ drb_iter->node, (u32) drb_iter, ++ drb_iter->src_addr, drb_iter->dst_addr, ++ drb_iter->req_cycle); ++ ++ /* Kick-off DMA for next DRB */ ++ /* - Source and destination address */ ++ if (drq->flags & DMAD_DRQ_DIR_A1_TO_A0) { ++ outl(drb_iter->addr1, drq->src_port); ++ outl(drb_iter->addr0, drq->dst_port); ++ } else { ++ outl(drb_iter->addr0, drq->src_port); ++ outl(drb_iter->addr1, drq->dst_port); ++ } ++ ++ /* - Transfer size (in units of source width) */ ++ outl(drb_iter->req_cycle, drq->cyc_port); ++ ++ /* Kick off next request */ ++ dmad_enable_channel(drq); ++ ++ drb_iter->state = DMAD_DRB_STATE_EXECUTED; ++ ++ } else { ++ /* No pending requests, keep the DMA channel stopped */ ++ } ++ ++ } else if (err_int) { ++ ++ dmad_err("%s() apb dma channel %d error!\n", __func__, channel); ++ ++ /* Zero out src, dst, and size */ ++ outl(0, drq->src_port); ++ outl(0, drq->dst_port); ++ outl(0, drq->cyc_port); ++ ++ /* Remove all pending requests in the queue */ ++ drb_iter = drb; ++ while (drb_iter) { ++ ++ dmad_err("abort drb(%d 0x%08x) addr0(0x%08x) " ++ "addr1(0x%08x) size(0x%08x)\n", ++ drb_iter->node, (u32) drb_iter, ++ drb_iter->src_addr, drb_iter->dst_addr, ++ drb_iter->req_cycle); ++ ++ if (drb_iter->req_cycle == 0) ++ cpl_events = 0; ++ ++ /* Mark DRB state as abort */ ++ drb_iter->state = DMAD_DRB_STATE_ABORT; ++ ++ if (cpl_events && drb_iter->sync) ++ complete_all(drb_iter->sync); ++ ++ dmad_attach_tail(drq->drb_pool, &drq->fre_head, ++ &drq->fre_tail, drb_iter->node); ++ ++ dmad_detach_head(drq->drb_pool, &drq->sbt_head, ++ &drq->sbt_tail, &drb_iter); ++ } ++ } ++ ++ spin_unlock(&drq->drb_pool_lock); ++ ++ /* dispatch interrupt-context level callbacks */ ++ if (cpl_events && drq->completion_cb) { ++ /* signal DMA driver that new node is available */ ++ drq->completion_cb(channel, status, drq->completion_data); ++ } ++ ++ dmad_dbg("%s() <<\n", __func__); ++ ++ return IRQ_HANDLED; ++} ++ ++/** ++ * dmad_apb_config_dir - prepare command reg according to tx direction ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @channel_cmds : [out] Reference to array of command words to be prepared with ++ * @return : none ++ * ++ * Prepare command registers according to transfer direction ... ++ * channel_cmd[0] APBBR_DMA_CMD ++ * ++ * This function only serves as local helper. No protection wrappers. ++ */ ++static void dmad_apb_config_dir(dmad_chreq * ch_req, addr_t * channel_cmds) ++{ ++ dmad_drq *drq = (dmad_drq *) ch_req->drq; ++ dmad_apb_chreq *apb_req = (dmad_apb_chreq *) (&ch_req->apb_req); ++ ++ dmad_dbg("%s() channel_cmd(0x%08x)\n", __func__, channel_cmds[0]); ++ ++ *channel_cmds &= ~(addr_t) ++ (APBBR_DMA_SRCADDRINC_MASK | APBBR_DMA_DSTADDRINC_MASK | ++ APBBR_DMA_DSTADDRSEL_MASK | APBBR_DMA_DREQSEL_MASK | ++ APBBR_DMA_SRCADDRSEL_MASK | APBBR_DMA_SREQSEL_MASK); ++ ++ /* 0 - addr0 to addr1; 1 - addr1 to addr0 */ ++ if (apb_req->tx_dir == 0) { ++ ++ dmad_dbg("%s() addr0 --> addr1\n", __func__); ++ ++ /* APB Bridge DMA (Channel Setting) ++ * - CMD ++ * SRCADR : apb_req->src_ctrl ++ * DESADR : apb_req->dst_ctrl ++ */ ++ *channel_cmds |= ++ (((apb_req->addr0_ctrl << APBBR_DMA_SRCADDRINC_SHIFT) & ++ APBBR_DMA_SRCADDRINC_MASK) | ++ ((apb_req->addr1_ctrl << APBBR_DMA_DSTADDRINC_SHIFT) & ++ APBBR_DMA_DSTADDRINC_MASK)); ++ ++ /* - CMD ++ * DESADRSEL : AHB/APB, driver auto-conf ++ * DREQSEL ++ */ ++ *channel_cmds |= ++ ((addr_t) (APBBR_DMA_DSTADDRSEL_MASK & ++ (apb_reqn_route_table[apb_req->addr1_reqn]. ++ bus_sel << APBBR_DMA_DSTADDRSEL_BIT)) | ++ (((addr_t) apb_req-> ++ addr1_reqn << APBBR_DMA_DREQSEL_SHIFT) & ++ APBBR_DMA_DREQSEL_MASK)); ++ ++ /* - CMD ++ * SRCADRSEL : AHB/APB, driver auto-conf ++ * SREQSEL ++ */ ++ *channel_cmds |= ++ ((addr_t) (APBBR_DMA_SRCADDRSEL_MASK & ++ (apb_reqn_route_table[apb_req->addr0_reqn]. ++ bus_sel << APBBR_DMA_SRCADDRSEL_BIT)) | ++ (((addr_t) apb_req-> ++ addr0_reqn << APBBR_DMA_SREQSEL_SHIFT) & ++ APBBR_DMA_SREQSEL_MASK)); ++ ++ drq->flags &= ~(addr_t) DMAD_DRQ_DIR_A1_TO_A0; ++ ++ } else { ++ ++ dmad_dbg("%s() addr0 <-- addr1\n", __func__); ++ ++ /* APB Bridge DMA (Channel Setting) ++ * - CMD ++ * SRCADR : apb_req->src_ctrl ++ * DESADR : apb_req->dst_ctrl ++ */ ++ *channel_cmds |= ++ (((apb_req->addr1_ctrl << APBBR_DMA_SRCADDRINC_SHIFT) & ++ APBBR_DMA_SRCADDRINC_MASK) | ++ ((apb_req->addr0_ctrl << APBBR_DMA_DSTADDRINC_SHIFT) & ++ APBBR_DMA_DSTADDRINC_MASK)); ++ ++ /* - CMD ++ * DESADRSEL : AHB/APB, driver auto-conf ++ * DREQSEL ++ */ ++ *channel_cmds |= ((addr_t) (APBBR_DMA_DSTADDRSEL_MASK & ++ (apb_reqn_route_table ++ [apb_req->addr0_reqn]. ++ bus_sel << ++ APBBR_DMA_DSTADDRSEL_BIT)) | ++ (((addr_t) apb_req-> ++ addr0_reqn << APBBR_DMA_DREQSEL_SHIFT) & ++ APBBR_DMA_DREQSEL_MASK)); ++ ++ /* - CMD ++ * SRCADRSEL : AHB/APB, driver auto-conf ++ * SREQSEL ++ */ ++ *channel_cmds |= ((addr_t) (APBBR_DMA_SRCADDRSEL_MASK & ++ (apb_reqn_route_table ++ [apb_req->addr1_reqn]. ++ bus_sel << ++ APBBR_DMA_SRCADDRSEL_BIT)) | ++ (((addr_t) apb_req-> ++ addr1_reqn << APBBR_DMA_SREQSEL_SHIFT) & ++ APBBR_DMA_SREQSEL_MASK)); ++ ++ drq->flags |= (addr_t) DMAD_DRQ_DIR_A1_TO_A0; ++ } ++ ++ dmad_dbg("%s() channel_cmd(0x%08x)\n", __func__, channel_cmds[0]); ++} ++ ++/** ++ * dmad_apb_init - initialize a apb dma channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @return : 0 if success, non-zero if any error ++ * ++ * Register APB DMA ISR and performs hw initialization for the given DMA ++ * channel. ++ */ ++static int dmad_apb_init(dmad_chreq * ch_req) ++{ ++ int err = 0; ++ dmad_drq *drq = (dmad_drq *) ch_req->drq; ++ dmad_apb_chreq *apb_req = (dmad_apb_chreq *) (&ch_req->apb_req); ++ u32 channel = (u32) ch_req->channel; ++ addr_t channel_cmd = 0; ++ unsigned long lock_flags; ++ ++ dmad_dbg("%s()\n", __func__); ++ ++ /* register interrupt handler */ ++ err = request_irq(apb_irqs[channel], dmad_apb_isr, 0, ++ "APB_DMA", (void *)(channel + 1)); ++ if (unlikely(err != 0)) { ++ dmad_err("unable to request IRQ %d for APB DMA (error %d)\n", ++ apb_irqs[channel], err); ++ free_irq(apb_irqs[channel], (void *)(channel + 1)); ++ return err; ++ } ++ ++ spin_lock_irqsave(&dmad.drq_pool_lock, lock_flags); ++ ++ /********************************************************** ++ * Following code require _safe_exit return path ++ */ ++ ++#ifdef CONFIG_PLAT_AG102 ++ ++ /* PCU ++ * ++ */ ++ //ADD by river 2010.10.20 ++ if (unlikely((apb_req->src_reqn > APBBR_REQN_MAX) || ++ (apb_req->dst_reqn > APBBR_REQN_MAX))) { ++ dmad_err("Invalid source reqn(%d) or destination reqn(%d)\n", ++ apb_req->src_reqn, apb_req->dst_reqn); ++ err = -EBADR; ++ goto _safe_exit; ++ } ++ ++ if (apb_req->src_reqn != APBBR_REQN_NONE) { ++ u32 ahb_reqn; ++ ++ if (apb_req->tx_dir == DMAD_DIR_A0_TO_A1) ++ ahb_reqn = ++ apb_reqn_route_table[apb_req->src_reqn].ahb_reqn_tx; ++ else ++ ahb_reqn = ++ apb_reqn_route_table[apb_req->src_reqn].ahb_reqn_rx; ++ ++ } ++ ++ if (apb_req->dst_reqn != APBBR_REQN_NONE) { ++ u32 ahb_reqn; ++ ++ if (apb_req->tx_dir == DMAD_DIR_A0_TO_A1) ++ ahb_reqn = ++ apb_reqn_route_table[apb_req->dst_reqn].ahb_reqn_tx; ++ else ++ ahb_reqn = ++ apb_reqn_route_table[apb_req->dst_reqn].ahb_reqn_rx; ++ ++ } ++ //End ADD by river 2010.10.20 ++ ++#else /* CONFIG_PLAT_AG102 */ ++ ++ /* PMU ++ * - Undo APB device DMA to AHB DMAC channel routing. (connection status ++ * is obtained from reading back the PMU_AHBDMA_REQACK register) ++ */ ++ if (unlikely((apb_req->src_reqn > APBBR_REQN_MAX) || ++ (apb_req->dst_reqn > APBBR_REQN_MAX))) { ++ dmad_err("Invalid source reqn(%d) or destination reqn(%d)\n", ++ apb_req->src_reqn, apb_req->dst_reqn); ++ err = -EBADR; ++ goto _safe_exit; ++ } ++ ++ if (apb_req->src_reqn != APBBR_REQN_NONE) { ++ u32 ahb_reqn; ++ ++ if (apb_req->tx_dir == DMAD_DIR_A0_TO_A1) ++ ahb_reqn = ++ apb_reqn_route_table[apb_req->src_reqn].ahb_reqn_tx; ++ else ++ ahb_reqn = ++ apb_reqn_route_table[apb_req->src_reqn].ahb_reqn_rx; ++ ++ outl(0, ahb_ch_route_table[ahb_reqn].clear_cr); ++ outl(0, ahb_ch_route_table[ahb_reqn].route_cr); ++ outl(0, ahb_ch_route_table[ahb_reqn].clear_cr); ++ outl(0, ahb_ch_route_table[ahb_reqn].route_cr); ++ } ++ ++ if (apb_req->dst_reqn != APBBR_REQN_NONE) { ++ u32 ahb_reqn; ++ ++ if (apb_req->tx_dir == DMAD_DIR_A0_TO_A1) ++ ahb_reqn = ++ apb_reqn_route_table[apb_req->dst_reqn].ahb_reqn_tx; ++ else ++ ahb_reqn = ++ apb_reqn_route_table[apb_req->dst_reqn].ahb_reqn_rx; ++ ++ outl(0, ahb_ch_route_table[ahb_reqn].clear_cr); ++ outl(0, ahb_ch_route_table[ahb_reqn].route_cr); ++ outl(0, ahb_ch_route_table[ahb_reqn].clear_cr); ++ outl(0, ahb_ch_route_table[ahb_reqn].route_cr); ++ } ++#endif /* CONFIG_PLAT_AG102 */ ++ ++ /* APB Bridge DMA (Channel Setting) ++ * - CMD ++ * ENBDIS : 0 (disable for now) ++ * FININTSTS : 0 (clear finishing interrupt status) ++ * FININTENB : 1 (enable finishing interrupt) ++ * BURMOD : apb_req->burst_mode ++ * ERRINTSTS : 0 (clear error interrupt status) ++ * ERRINTENB : 1 (enable error interrupt) ++ * SRCADRSEL : AHB/APB, driver auto-conf ++ * DESADRSEL : AHB/APB, driver auto-conf ++ * SRCADR : apb_req->src_ctrl ++ * DESADR : apb_req->dst_ctrl ++ * REQSEL : apb_req->src_reqn ++ * DATAWIDTH : apb_req->data_width ++ */ ++ ++ /* - CMD ++ * ENBDIS ++ * FININTSTS ++ * FININTENB ++ * BURMOD ++ * ERRINTSTS ++ * ERRINTENB ++ * DATAWIDTH ++ */ ++ channel_cmd = ++ ((addr_t) APBBR_DMA_FINTEN_MASK | APBBR_DMA_ERRINTEN_MASK | ++ ((apb_req-> ++ burst_mode << APBBR_DMA_BURST_BIT) & APBBR_DMA_BURST_MASK) | ++ ((apb_req-> ++ data_width << APBBR_DMA_DATAWIDTH_SHIFT) & ++ APBBR_DMA_DATAWIDTH_MASK)); ++ ++ /* - CMD ++ * SRCADRSEL ++ * DESADRSEL ++ * SRCADR ++ * DESADR ++ * REQSEL ++ */ ++ if (0 == ++ (ch_req->flags & (DMAD_FLAGS_RING_MODE | DMAD_FLAGS_BIDIRECTION))) ++ apb_req->tx_dir = 0; ++ dmad_apb_config_dir(ch_req, &channel_cmd); ++ ++ /* - CMD outport */ ++ outl(channel_cmd, (addr_t) drq->channel_base + APBBR_DMA_CMD_OFFSET); ++ ++ /* SRCADR and DESADR */ ++ outl(0, (addr_t) drq->src_port); ++ outl(0, (addr_t) drq->dst_port); ++ ++ /* CYC (transfer size) */ ++ outl(0, (addr_t) drq->cyc_port); ++ ++ /* keep channel data width for faster cycle/byte size conversion */ ++ drq->data_width = apb_req->data_width; ++ ++_safe_exit: ++ ++ spin_unlock_irqrestore(&dmad.drq_pool_lock, lock_flags); ++ ++ return err; ++} ++ ++#endif /* CONFIG_PLATFORM_APBDMA */ ++ ++/** ++ * dmad_channel_init - initialize given dma channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @return : 0 if success, non-zero if any error ++ * ++ * This function serves as the abstraction layer of dmad_ahb_init() ++ * and dmad_apb_init() functions. ++ */ ++static int dmad_channel_init(dmad_chreq * ch_req) ++{ ++ int err = 0; ++ ++ dmad_dbg("%s()\n", __func__); ++ ++ if (unlikely(ch_req == NULL)) ++ return -EFAULT; ++ ++ if (unlikely(ch_req->drq == NULL)) ++ return -EBADR; ++ ++ /* Initialize DMA controller */ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (ch_req->controller == DMAD_DMAC_AHB_CORE) ++ err = dmad_ahb_init(ch_req); ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ if (ch_req->controller == DMAD_DMAC_APB_CORE) ++ err = dmad_apb_init(ch_req); ++#endif ++ ++ return err; ++} ++ ++static inline void dmad_reset_channel(dmad_drq * drq) ++{ ++ /* disable dma controller */ ++ dmad_disable_channel(drq); ++ ++ /* Source and destination address */ ++ outl(0, drq->src_port); ++ outl(0, drq->dst_port); ++ ++ /* Transfer size (in units of source width) */ ++ outl(0, drq->cyc_port); ++} ++ ++/** ++ * dmad_channel_reset - reset given dma channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @return : 0 if success, non-zero if any error ++ * ++ * This function serves as the abstraction layer of dmad_ahb_reset() ++ * and dmad_apb_reset() functions. ++ */ ++static int dmad_channel_reset(dmad_chreq * ch_req) ++{ ++ u32 channel = (u32) ch_req->channel; ++ unsigned long lock_flags; ++ int err = 0; ++ ++ dmad_dbg("%s()\n", __func__); ++ ++ if (unlikely(ch_req == NULL)) ++ return -EFAULT; ++ ++ if (unlikely(ch_req->drq == NULL)) ++ return -EBADR; ++ ++ spin_lock_irqsave(&((dmad_drq *) ch_req->drq)->drb_pool_lock, ++ lock_flags); ++ ++ /* stop DMA channel */ ++ dmad_reset_channel((dmad_drq *) ch_req->drq); ++ ++ spin_unlock_irqrestore(&((dmad_drq *) ch_req->drq)->drb_pool_lock, ++ lock_flags); ++ ++ /* unregister interrupt handler */ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (ch_req->controller == DMAD_DMAC_AHB_CORE) ++ free_irq(ahb_irqs[channel], (void *)(channel + 1)); ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ if (ch_req->controller == DMAD_DMAC_APB_CORE) ++ free_irq(apb_irqs[channel], (void *)(channel + 1)); ++#endif ++ ++ return err; ++} ++ ++/** ++ * dmad_channel_alloc - allocates and initialize a dma channel ++ * @ch_req : [in/out] Reference to the DMA request descriptor structure ++ * @return : 0 if success, non-zero if any error ++ * ++ * This function allocates a DMA channel according to client's request ++ * parameters. ISR and HW state will also be initialized accordingly. ++ */ ++int dmad_channel_alloc(dmad_chreq * ch_req) ++{ ++ dmad_drq *drq_iter = NULL; ++ dmad_drb *drb_iter; ++ int err = 0; ++ u32 i = 0; ++ ++ dmad_dbg("%s()\n", __func__); ++ ++ if (ch_req == NULL) { ++ printk(KERN_ERR "%s() invalid argument!\n", __func__); ++ return -EFAULT; ++ } ++ ++ spin_lock(&dmad.drq_pool_lock); ++ ++ /* locate an available DMA channel */ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (ch_req->controller == DMAD_DMAC_AHB_CORE) { ++ ++ drq_iter = dmad.ahb_drq_pool; ++ ++ if ((ch_req->ahb_req.src_reqn != DMAC_REQN_NONE) || ++ (ch_req->ahb_req.dst_reqn != DMAC_REQN_NONE)) { ++ /* [2007-12-03] It looks current board have problem to ++ * do dma traffic for APB devices on DMAC channel 0/1. ++ * Redirect all APB devices to start from channel 2. ++ */ ++ ++ /* [todo] include USB controller ? */ ++ drq_iter = &dmad.ahb_drq_pool[2]; ++ for (i = 2; i < DMAD_AHB_MAX_CHANNELS; ++i, ++drq_iter) { ++ if (!(drq_iter->state & DMAD_DRQ_STATE_READY)) ++ break; ++ } ++ } else { ++ /* channel for other devices is free to allocate */ ++ for (i = 0; i < DMAD_AHB_MAX_CHANNELS; ++i, ++drq_iter) { ++ if (!(drq_iter->state & DMAD_DRQ_STATE_READY)) ++ break; ++ } ++ } ++ ++ if (unlikely(i == DMAD_AHB_MAX_CHANNELS)) { ++ spin_unlock(&dmad.drq_pool_lock); ++ dmad_err("out of available channels (AHB DMAC)!\n"); ++ return -ENOSPC; ++ } ++ ++ dmad_dbg("allocated channel: %d (AHB DMAC)\n", i); ++ ++ } ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ if (ch_req->controller == DMAD_DMAC_APB_CORE) { ++ ++ drq_iter = dmad.apb_drq_pool; ++ ++ for (i = 0; i < DMAD_APB_MAX_CHANNELS; ++i, ++drq_iter) { ++ if ((drq_iter->state & DMAD_DRQ_STATE_READY) == 0) ++ break; ++ } ++ ++ if (unlikely(i == DMAD_APB_MAX_CHANNELS)) { ++ spin_unlock(&dmad.drq_pool_lock); ++ dmad_err("out of available channels (APB DMAC)!\n"); ++ return -ENOSPC; ++ } ++ ++ dmad_dbg("allocated channel: %d (APB DMAC)\n", i); ++ } ++#endif ++ if (drq_iter == NULL) { ++ spin_unlock(&dmad.drq_pool_lock); ++ printk(KERN_ERR "%s() invalid argument!\n", __func__); ++ return -EFAULT; ++ } ++ ++ spin_unlock(&dmad.drq_pool_lock); ++ memset(drq_iter, 0, sizeof(dmad_drq)); ++ ++ /* Initialize DMA channel's DRB pool as list of free DRBs */ ++ drq_iter->drb_pool = ++ kmalloc(DMAD_DRB_POOL_SIZE * sizeof(dmad_drb), GFP_ATOMIC); ++ ++ if (drq_iter->drb_pool == NULL) { ++ printk(KERN_ERR "%s() failed to allocate drb pool!\n", ++ __func__); ++ return -ENOMEM; ++ } ++ ++ /* Allocate the DMA channel */ ++ drq_iter->state = DMAD_DRQ_STATE_READY; ++ drq_iter->flags = ch_req->flags; ++ ++ /* Initialize synchronization object for DMA queue access control */ ++ spin_lock_init(&drq_iter->drb_pool_lock); ++ ++ /* Initialize synchronization object for free drb notification */ ++ init_completion(&drq_iter->drb_alloc_sync); ++ ++ /* Record the channel number in client's struct */ ++ ch_req->channel = i; ++ ++ /* Record the channel's queue handle in client's struct */ ++ ch_req->drq = drq_iter; ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (ch_req->controller == DMAD_DMAC_AHB_CORE) { ++ drq_iter->channel_base = (addr_t) DMAC_BASE_CH(i); ++ drq_iter->enable_port = ++ (addr_t) drq_iter->channel_base + DMAC_CSR_OFFSET; ++ drq_iter->src_port = ++ (addr_t) drq_iter->channel_base + DMAC_SRC_ADDR_OFFSET; ++ drq_iter->dst_port = ++ (addr_t) drq_iter->channel_base + DMAC_DST_ADDR_OFFSET; ++ drq_iter->cyc_port = ++ (addr_t) drq_iter->channel_base + DMAC_SIZE_OFFSET; ++ } ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ if (ch_req->controller == DMAD_DMAC_APB_CORE) { ++ drq_iter->channel_base = (addr_t) APBBR_DMA_BASE_CH(i); ++ drq_iter->enable_port = ++ (addr_t) drq_iter->channel_base + APBBR_DMA_CMD_OFFSET; ++ drq_iter->src_port = ++ (addr_t) drq_iter->channel_base + APBBR_DMA_SAD_OFFSET; ++ drq_iter->dst_port = ++ (addr_t) drq_iter->channel_base + APBBR_DMA_DAD_OFFSET; ++ drq_iter->cyc_port = ++ (addr_t) drq_iter->channel_base + APBBR_DMA_CYC_OFFSET; ++ } ++#endif ++ /* drb-0 is an invalid node - for node validation */ ++ drb_iter = &drq_iter->drb_pool[0]; ++ drb_iter->prev = 0; ++ drb_iter->next = 0; ++ drb_iter->node = 0; ++ ++drb_iter; ++ ++ /* init other drbs - link in order */ ++ for (i = 1; i < DMAD_DRB_POOL_SIZE; ++i, ++drb_iter) { ++ drb_iter->prev = i - 1; ++ drb_iter->next = i + 1; ++ drb_iter->node = i; ++ } ++ drq_iter->drb_pool[DMAD_DRB_POOL_SIZE - 1].next = 0; ++ ++ /* Initialize channel's DRB free-list, ready-list, and submitted-list */ ++ drq_iter->fre_head = 1; ++ drq_iter->fre_tail = DMAD_DRB_POOL_SIZE - 1; ++ drq_iter->rdy_head = drq_iter->rdy_tail = 0; ++ drq_iter->sbt_head = drq_iter->sbt_tail = 0; ++ ++ /* initialize ring buffer mode resources */ ++ if (ch_req->flags & DMAD_FLAGS_RING_MODE) { ++ ++ int remnant = (int)ch_req->ring_size - ++ (int)ch_req->periods * (int)ch_req->period_size; ++ if (remnant == 0) { ++ drq_iter->periods = ch_req->periods; ++ } else if (remnant > 0) { ++ drq_iter->periods = ch_req->periods; // + 1; ++ } else { ++ dmad_err("%s() Error - buffer_size < " ++ "periods * period_size!\n", __func__); ++ err = -EFAULT; ++ goto _err_exit; ++ } ++ ++ drq_iter->ring_size = ch_req->ring_size; ++ drq_iter->period_size = ch_req->period_size; ++ drq_iter->remnant_size = (dma_addr_t) remnant; ++ ++ drq_iter->ring_base = (dma_addr_t) ch_req->ring_base; ++ drq_iter->dev_addr = (dma_addr_t) ch_req->dev_addr; ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (ch_req->controller == DMAD_DMAC_AHB_CORE) { ++ if ((ch_req->ahb_req.ring_ctrl == DMAC_CSR_AD_DEC) || ++ (ch_req->ahb_req.dev_ctrl == DMAC_CSR_AD_DEC)) { ++ dmad_err("%s() Error - decremental" ++ " addressing DMA is not supported in" ++ " ring mode currently!\n", __func__); ++ err = -EFAULT; ++ goto _err_exit; ++ } ++ ++ if (ch_req->ahb_req.ring_ctrl == DMAC_CSR_AD_FIX) { ++ dmad_err("%s() Error - ring address control is " ++ "fixed in ring DMA mode!\n", __func__); ++ err = -EFAULT; ++ goto _err_exit; ++ } ++ ++ drq_iter->period_bytes = ++ DMAC_CYCLE_TO_BYTES(ch_req->period_size, ++ ch_req->ahb_req.ring_width); ++ ++ /* 0 - addr0 to addr1; 1 - addr1 to addr0 */ ++ if (ch_req->ahb_req.tx_dir == 0) ++ drq_iter->ring_port = ++ (addr_t) drq_iter->src_port; ++ else ++ drq_iter->ring_port = ++ (addr_t) drq_iter->dst_port; ++ ++ } ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ if (ch_req->controller == DMAD_DMAC_APB_CORE) { ++ ++ if ((ch_req->apb_req.ring_ctrl >= APBBR_ADDRINC_D1) || ++ (ch_req->apb_req.dev_ctrl >= APBBR_ADDRINC_D1)) { ++ dmad_err("%s() Error - decremental" ++ " addressing DMA is not supported in" ++ " ring mode currently!\n", __func__); ++ err = -EFAULT; ++ goto _err_exit; ++ } ++ ++ if (ch_req->apb_req.ring_ctrl == APBBR_ADDRINC_FIXED) { ++ dmad_err("%s() Error - ring address control is " ++ "fixed in ring DMA mode!\n", __func__); ++ err = -EFAULT; ++ goto _err_exit; ++ } ++ ++ drq_iter->period_bytes = ++ APBBR_DMA_CYCLE_TO_BYTES(ch_req->period_size, ++ ch_req->apb_req. ++ data_width); ++ ++ /* 0 - addr0 to addr1; 1 - addr1 to addr0 */ ++ if (ch_req->apb_req.tx_dir == 0) ++ drq_iter->ring_port = ++ (addr_t) drq_iter->src_port; ++ else ++ drq_iter->ring_port = ++ (addr_t) drq_iter->dst_port; ++ } ++#endif ++ dmad_dbg("%s() ring: base(0x%08x) port(0x%08x) periods(0x%08x)" ++ " period_size(0x%08x) period_bytes(0x%08x)" ++ " remnant_size(0x%08x)\n", ++ __func__, drq_iter->ring_base, drq_iter->ring_port, ++ drq_iter->periods, drq_iter->period_size, ++ drq_iter->period_bytes, drq_iter->remnant_size); ++ } ++ ++ drq_iter->completion_cb = ch_req->completion_cb; ++ drq_iter->completion_data = ch_req->completion_data; ++ ++ /* Initialize the channel && register isr */ ++ err = dmad_channel_init(ch_req); ++ ++_err_exit: ++ ++ if (err != 0) { ++ spin_lock(&dmad.drq_pool_lock); ++ ++ kfree(drq_iter->drb_pool); ++ memset(drq_iter, 0, sizeof(dmad_drq)); ++ ++ ch_req->channel = -1; ++ ch_req->drq = (void *)0; ++ ++ spin_unlock(&dmad.drq_pool_lock); ++ ++ dmad_err("Failed to initialize APB DMA! " ++ "Channel allocation aborted!\n"); ++ } ++ ++ return err; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_channel_alloc); ++ ++/** ++ * dmad_channel_free - release a dma channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @return : 0 if success, non-zero if any error ++ * ++ * This function releases a DMA channel. The channel is available for future ++ * allocation after the invokation. ++ */ ++int dmad_channel_free(dmad_chreq * ch_req) ++{ ++ dmad_drq *drq; ++ ++ dmad_dbg("%s()\n", __func__); ++ ++ if (unlikely(ch_req == NULL)) { ++ dmad_err("null ch_req!\n"); ++ return -EFAULT; ++ } ++ ++ drq = (dmad_drq *) ch_req->drq; ++ ++ if (unlikely(drq == NULL)) { ++ dmad_err("null ch_req->drq!\n"); ++ return -EBADR; ++ } ++ if (unlikely((ch_req->channel < 0) || ++ ((drq->state & DMAD_DRQ_STATE_READY) == 0))) { ++ dmad_err("try to free a free channel!\n"); ++ return -EBADR; ++ } ++ ++ /* Stop/abort channel I/O ++ * (forced to shutdown and should be protected against isr) ++ */ ++ dmad_drain_requests(ch_req, 1); ++ dmad_channel_reset(ch_req); ++ ++ dmad_dbg("freed channel: %d\n", ch_req->channel); ++ ++ spin_lock(&dmad.drq_pool_lock); ++ ++ kfree(drq->drb_pool); ++ memset(drq, 0, sizeof(dmad_drq)); ++ ++ ch_req->drq = 0; ++ ch_req->channel = (u32) - 1; ++ ++ spin_unlock(&dmad.drq_pool_lock); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_channel_free); ++ ++/** ++ * dmad_channel_enable - enable/disable a dma channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @enable : [in] 1 to enable the channel, 0 to disable ++ * @return : 0 if success, non-zero if any error ++ * ++ * Enable or disable the given DMA channel. ++ */ ++int dmad_channel_enable(const dmad_chreq * ch_req, u8 enable) ++{ ++ dmad_drq *drq; ++ unsigned long lock_flags; ++ ++ dmad_dbg("%s()\n", __func__); ++ ++ if (unlikely(ch_req == NULL)) ++ return -EFAULT; ++ ++ drq = (dmad_drq *) ch_req->drq; ++ ++ if (unlikely(drq == NULL)) ++ return -EBADR; ++ ++ spin_lock_irqsave(&drq->drb_pool_lock, lock_flags); ++ ++ /* Enable/disable DMA channel */ ++ if (enable) ++ dmad_enable_channel(drq); ++ else ++ dmad_disable_channel(drq); ++ ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_channel_enable); ++ ++/** ++ * dmad_config_channel_dir - config dma channel transfer direction ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @dir : [in] DMAD_DRQ_DIR_A0_TO_A1 or DMAD_DRQ_DIR_A1_TO_A0 ++ * @return : 0 if success, non-zero if any error ++ * ++ * Reconfigure the channel transfer direction. This function works only if ++ * the channel was allocated with the DMAD_FLAGS_BIDIRECTION flags. Note ++ * that bi-direction mode and ring mode are mutual-exclusive from user's ++ * perspective. ++ */ ++int dmad_config_channel_dir(dmad_chreq * ch_req, u8 dir) ++{ ++ dmad_drq *drq; ++ addr_t channel_cmds[2]; ++ unsigned long lock_flags; ++ u8 cur_dir; ++ ++ if (unlikely(ch_req == NULL)) ++ return -EFAULT; ++ ++ drq = (dmad_drq *) ch_req->drq; ++ ++ if (unlikely(drq == NULL)) ++ return -EBADR; ++ ++ if (unlikely(!(ch_req->flags & DMAD_FLAGS_BIDIRECTION))) { ++ dmad_err("%s() Channel is not configured as" ++ " bidirectional!\n", __func__); ++ return -EFAULT; ++ } ++ ++ cur_dir = drq->flags & DMAD_DRQ_DIR_MASK; ++ if (dir == cur_dir) { ++ dmad_dbg("%s() cur_dir(%d) == dir(%d) skip reprogramming hw.\n", ++ __func__, cur_dir, dir); ++ return 0; ++ } ++ ++ spin_lock_irqsave(&drq->drb_pool_lock, lock_flags); ++ ++ if (unlikely((drq->sbt_head != 0) /*||dmad_is_channel_enabled(drq) */ )) { ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ dmad_err("%s() Cannot change direction while the " ++ "channel has pending requests!\n", __func__); ++ return -EFAULT; ++ } ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (ch_req->controller == DMAD_DMAC_AHB_CORE) { ++ ++ channel_cmds[0] = ++ inl((addr_t) drq->channel_base + DMAC_CSR_OFFSET); ++ channel_cmds[1] = ++ inl((addr_t) drq->channel_base + DMAC_CFG_OFFSET); ++ ++ ch_req->ahb_req.tx_dir = dir; ++ dmad_ahb_config_dir(ch_req, channel_cmds); ++ ++ outl(channel_cmds[1], ++ (addr_t) drq->channel_base + DMAC_CFG_OFFSET); ++ outl(channel_cmds[0], ++ (addr_t) drq->channel_base + DMAC_CSR_OFFSET); ++ ++ } ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ if (ch_req->controller == DMAD_DMAC_APB_CORE) { ++ ++ channel_cmds[0] = ++ inl((addr_t) drq->channel_base + APBBR_DMA_CMD_OFFSET); ++ ++ ch_req->apb_req.tx_dir = dir; ++ dmad_apb_config_dir(ch_req, channel_cmds); ++ ++ outl(channel_cmds[0], ++ (addr_t) drq->channel_base + APBBR_DMA_CMD_OFFSET); ++ } ++#endif ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_config_channel_dir); ++ ++/** ++ * dmad_max_size_per_drb - return maximum transfer size per drb ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @return : The maximum transfer size per drb, in bytes. ++ * ++ * Calculate the maximum transfer size per drb according to the setting of ++ * data width during channel initialization. ++ * ++ * Return size is aligned to 4-byte boundary; this ensures the alignment ++ * requirement of dma starting address if the function was used in a loop to ++ * separate a large size dma transfer. ++ */ ++u32 dmad_max_size_per_drb(dmad_chreq * ch_req) ++{ ++ addr_t size = 0; ++ addr_t data_width = (addr_t) ((dmad_drq *) ch_req->drq)->data_width; ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (ch_req->controller == DMAD_DMAC_AHB_CORE) { ++ size = DMAC_CYCLE_TO_BYTES(DMAC_TOT_SIZE_MASK & ((addr_t) ~ 3), ++ data_width); ++ } ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ if (ch_req->controller == DMAD_DMAC_APB_CORE) { ++ size = ++ APBBR_DMA_CYCLE_TO_BYTES(APBBR_DMA_CYC_MASK & ++ ((addr_t) ~ 3), data_width); ++ } ++#endif ++ dmad_dbg("%s() - 0x%08x bytes\n", __func__, size); ++ ++ return size; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_max_size_per_drb); ++ ++/** ++ * dmad_bytes_to_cycles - calculate drb transfer size, in cycles ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @byte_size : [in] The DMA transfer size to be converted, in bytes ++ * @return : The drb transfer size, in cycles. ++ * ++ * Calculate the drb transfer cycle according to the setting of channel data ++ * width and burst setting. ++ * ++ * AHB DMA : unit is number of "data width". ++ * APB DMA : unit is number of "data width * burst size" ++ * ++ * APB Note: According to specification, decrement addressing seems to regard ++ * the burst size setting. For code efficiency, ++ * dmad_make_req_cycles() does not take care of this case and might ++ * produce wrong result. ++ */ ++u32 dmad_bytes_to_cycles(dmad_chreq * ch_req, u32 byte_size) ++{ ++ addr_t cycle = 0; ++ addr_t data_width = (addr_t) ((dmad_drq *) ch_req->drq)->data_width; ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (ch_req->controller == DMAD_DMAC_AHB_CORE) { ++ cycle = DMAC_BYTES_TO_CYCLE(byte_size, data_width); ++ } ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ if (ch_req->controller == DMAD_DMAC_APB_CORE) { ++ cycle = APBBR_DMA_BYTES_TO_CYCLE(byte_size, data_width); ++ if (ch_req->apb_req.burst_mode) ++ cycle = cycle >> 2; ++ } ++#endif ++ ++ dmad_dbg("%s() - 0x%08x bytes --> 0x%08x cycles\n", ++ __func__, byte_size, cycle); ++ ++ return cycle; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_bytes_to_cycles); ++ ++/** ++ * dmad_alloc_drb_internal - allocate a dma-request-block of a dma channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @drb : [out] Reference to a drb pointer to receive the allocated drb ++ * @return : 0 if success, non-zero if any error ++ * ++ * Allocates a DRB (DMA request block) of the given DMA channel. DRB is a ++ * single dma request which will be pushed into the submission queue of the ++ * given DMA channel. This is a lightweight internal version of ++ * dmad_alloc_drb() majorly for use in ring mode. Critical access to the ++ * drb pool should be protected before entering this function. ++ */ ++static inline int dmad_alloc_drb_internal(dmad_drq * drq, dmad_drb ** drb) ++{ ++ /* Initialize drb ptr in case of fail allocation */ ++ *drb = NULL; ++ ++ if (unlikely(drq->fre_head == 0)) { ++ return -EAGAIN; ++ } ++ ++ dmad_detach_head(drq->drb_pool, &drq->fre_head, &drq->fre_tail, drb); ++ ++ dmad_attach_tail(drq->drb_pool, ++ &drq->rdy_head, &drq->rdy_tail, (*drb)->node); ++ ++ (*drb)->state = DMAD_DRB_STATE_READY; ++ (*drb)->sync = 0; ++ ++ dmad_dbg("%s() drb(%d 0x%08x)\n", __func__, (*drb)->node, (u32) (*drb)); ++ ++ return 0; ++} ++ ++/** ++ * dmad_alloc_drb - allocate a dma-request-block of a dma channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @drb : [out] Reference to a drb pointer to receive the allocated drb ++ * @return : 0 if success, non-zero if any error ++ * ++ * Allocates a DRB (DMA request block) of the given DMA channel. DRB is a ++ * single dma request which will be pushed into the submission queue of the ++ * given DMA channel. ++ */ ++int dmad_alloc_drb(dmad_chreq * ch_req, dmad_drb ** drb) ++{ ++ dmad_drq *drq; ++ unsigned long lock_flags; ++ ++ dmad_dbg("%s()\n", __func__); ++ ++ if (unlikely(ch_req == NULL)) { ++ dmad_err("null ch_req!\n"); ++ return -EFAULT; ++ } ++ ++ drq = (dmad_drq *) ch_req->drq; ++ ++ if (likely(drq == NULL)) { ++ dmad_err("null ch_req->drq!\n"); ++ return -EBADR; ++ } ++ ++ spin_lock_irqsave(&drq->drb_pool_lock, lock_flags); ++ ++ /* Initialize drb ptr in case of fail allocation */ ++ *drb = NULL; ++ ++ if (unlikely(drq->fre_head == 0)) { ++ ++ drq->state &= (u32) ~ DMAD_DRQ_STATE_ABORT; ++ ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ ++_wait_for_free_drbs: ++ ++ /* Wait for free urbs */ ++ if (drq->flags & DMAD_FLAGS_SLEEP_BLOCK) { ++ ++ int timeout = ++ wait_for_completion_interruptible_timeout(&drq-> ++ drb_alloc_sync, ++ msecs_to_jiffies ++ (6000)); ++ ++ /* reset sync object */ ++ INIT_COMPLETION(drq->drb_alloc_sync); ++ ++ if (timeout < 0) { ++ dmad_err("%s() wait for" ++ " completion error! (%d)\n", ++ __func__, timeout); ++ return timeout; ++ } ++ ++ } else if (drq->flags & DMAD_FLAGS_SPIN_BLOCK) { ++ ++ u32 timeout = 0x00ffffff; ++ ++ while ((drq->fre_head == 0) && (--timeout != 0)) { ++ } ++ if (timeout == 0) { ++ dmad_err("%s() polling wait for " ++ "completion timeout!\n", __func__); ++ return -EAGAIN; ++ } ++ ++ } else { ++ return -EAGAIN; ++ } ++ ++ spin_lock_irqsave(&drq->drb_pool_lock, lock_flags); ++ ++ /* check whether all the requests of the channel has been ++ * abandoned or not */ ++ if (unlikely(drq->state & DMAD_DRQ_STATE_ABORT)) { ++ dmad_dbg("%s() drb-allocation aborted due" ++ " to cancel-request ...\n", __func__); ++ drq->state &= (u32) ~ DMAD_DRQ_STATE_ABORT; ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ return -ECANCELED; ++ } ++ ++ /* check again to avoid non-atomic operation between above ++ * two calls */ ++ if (unlikely(drq->fre_head == 0)) { ++ dmad_dbg("%s() lost free drbs ... " ++ "continue waiting ...\n", __func__); ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ goto _wait_for_free_drbs; ++ } ++ } ++ ++ dmad_detach_head(drq->drb_pool, &drq->fre_head, &drq->fre_tail, drb); ++ ++ dmad_attach_tail(drq->drb_pool, ++ &drq->rdy_head, &drq->rdy_tail, (*drb)->node); ++ ++ (*drb)->state = DMAD_DRB_STATE_READY; ++ (*drb)->sync = 0; ++ ++ dmad_dbg("%s() drb(%d 0x%08x)\n", __func__, (*drb)->node, (u32) (*drb)); ++ ++ drq->state &= (u32) ~ DMAD_DRQ_STATE_ABORT; ++ ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_alloc_drb); ++ ++/** ++ * dmad_free_drb - free a dma-request-block of a dma channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @drb : [in] Reference to a drb to be freed ++ * @return : 0 if success, non-zero if any error ++ * ++ * Frees a DRB (DMA request block) of the given DMA channel. DRB is a ++ * single dma request which will be pushed into the submission queue of the ++ * given DMA channel. ++ */ ++int dmad_free_drb(dmad_chreq * ch_req, dmad_drb * drb) ++{ ++ dmad_drq *drq; ++ unsigned long lock_flags; ++ ++ dmad_dbg("%s()\n", __func__); ++ ++ if (unlikely(ch_req == NULL)) { ++ dmad_err("null ch_req!\n"); ++ return -EFAULT; ++ } ++ ++ drq = (dmad_drq *) ch_req->drq; ++ ++ if (unlikely(drq == NULL)) { ++ dmad_err("null ch_req->drq!\n"); ++ return -EBADR; ++ } ++ ++ spin_lock_irqsave(&drq->drb_pool_lock, lock_flags); ++ ++ /**************************************************** ++ * Following code requires _safe_exit return path ++ */ ++ ++ if (unlikely((drq->rdy_head == 0) || (drb->node == 0) || ++ (drb->state != DMAD_DRB_STATE_READY) || ++ (drb->node >= DMAD_DRB_POOL_SIZE))) { ++ dmad_err("Ready-queue is empty or invalid node!\n"); ++ ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ return -EBADR; ++ } ++ ++ dmad_detach_node(drq->drb_pool, ++ &drq->rdy_head, &drq->rdy_tail, drb->node); ++ dmad_attach_tail(drq->drb_pool, ++ &drq->fre_head, &drq->fre_tail, drb->node); ++ ++ drb->state = DMAD_DRB_STATE_FREE; ++ drb->sync = 0; ++ ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_free_drb); ++ ++/** ++ * dmad_submit_request_internal - submit a dma-request-block to the dma channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @drb : [in] Reference to a drb to be submitted ++ * @keep_fired : [in] non-zero to kickoff dma even the channel has stopped due ++ * to finishing its previous request ++ * @return : 0 if success, non-zero if any error ++ * ++ * Submit a DRB (DMA request block) of the given DMA channel to submission ++ * queue. DRB is a single dma request which will be pushed into the ++ * submission queue of the given DMA channel. This is a lightweight internal ++ * version of dmad_alloc_drb() majorly for use in ring mode. Critical access to ++ * the drb pool should be protected before entering this function. ++ */ ++static inline int dmad_submit_request_internal(dmad_drq * drq, dmad_drb * drb) ++{ ++ if (drb->state == DMAD_DRB_STATE_READY) { ++ /* Detach user node from ready list */ ++ dmad_detach_node(drq->drb_pool, ++ &drq->rdy_head, &drq->rdy_tail, drb->node); ++ ++ dmad_attach_tail(drq->drb_pool, ++ &drq->sbt_head, &drq->sbt_tail, drb->node); ++ ++ drb->state = DMAD_DRB_STATE_SUBMITTED; ++ ++ dmad_dbg("%s() submit drb(%d 0x%08x) addr0(0x%08x) " ++ "addr1(0x%08x) size(0x%08x) state(%d)\n", __func__, ++ drb->node, (u32) drb, drb->src_addr, drb->dst_addr, ++ drb->req_cycle, drb->state); ++ } else { ++ dmad_dbg("%s() skip drb(%d 0x%08x) addr0(0x%08x) addr1(0x%08x)" ++ " size(0x%08x) state(%d)\n", __func__, ++ drb->node, (u32) drb, drb->src_addr, drb->dst_addr, ++ drb->req_cycle, drb->state); ++ } ++ ++ return 0; ++} ++ ++/** ++ * dmad_submit_request - submit a dma-request-block to the dma channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @drb : [in] Reference to a drb to be submitted ++ * @keep_fired : [in] non-zero to kickoff dma even the channel has stopped due ++ * to finishing its previous request ++ * @return : 0 if success, non-zero if any error ++ * ++ * Submit a DRB (DMA request block) of the given DMA channel to submission ++ * queue. DRB is a single dma request which will be pushed into the ++ * submission queue of the given DMA channel. ++ */ ++int dmad_submit_request(dmad_chreq * ch_req, dmad_drb * drb, u8 keep_fired) ++{ ++ dmad_drq *drq; ++ unsigned long lock_flags; ++ ++ dmad_dbg("%s()\n", __func__); ++ ++ if (unlikely(ch_req == NULL)) { ++ dmad_err("null ch_req!\n"); ++ return -EFAULT; ++ } ++ ++ drq = (dmad_drq *) ch_req->drq; ++ ++ if (unlikely(drq == NULL)) { ++ dmad_err("null ch_req->drq!\n"); ++ return -EBADR; ++ } ++ ++ spin_lock_irqsave(&drq->drb_pool_lock, lock_flags); ++ ++ /****************************************************** ++ * Following code require _safe_exit return path ++ */ ++ ++ if (unlikely((drq->rdy_head == 0) || (drb->node == 0) || ++ (drb->node >= DMAD_DRB_POOL_SIZE))) { ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ return -EBADR; ++ } ++ ++ /* Detach user node from ready list */ ++ dmad_detach_node(drq->drb_pool, &drq->rdy_head, &drq->rdy_tail, ++ drb->node); ++ ++ /* Queue DRB to the end of the submitted list */ ++ dmad_dbg("submit drb(%d 0x%08x) addr0(0x%08x) addr1(0x%08x) " ++ "size(0x%08x) sync(0x%08x) fire(%d)\n", ++ drb->node, (u32) drb, drb->src_addr, drb->dst_addr, ++ drb->req_cycle, (u32) drb->sync, keep_fired); ++ ++ /* Check if submission is performed to an empty queue */ ++ if (unlikely(keep_fired && (drq->sbt_head == 0))) { ++ /* DMA is not running, so kick off transmission */ ++ dmad_dbg("kickoff dma engine.\n"); ++ ++ dmad_attach_tail(drq->drb_pool, ++ &drq->sbt_head, &drq->sbt_tail, drb->node); ++ ++ /* Source and destination address */ ++ if (drq->flags & DMAD_DRQ_DIR_A1_TO_A0) { ++ outl(drb->addr1, (addr_t) drq->src_port); ++ outl(drb->addr0, (addr_t) drq->dst_port); ++ } else { ++ outl(drb->addr0, (addr_t) drq->src_port); ++ outl(drb->addr1, (addr_t) drq->dst_port); ++ } ++ ++ /* Transfer size (in units of source width) */ ++ outl(drb->req_cycle, (addr_t) drq->cyc_port); ++ ++ /* Enable DMA channel (Kick off transmission when client ++ * enable it's transfer state) */ ++ dmad_enable_channel(drq); ++ ++ drb->state = DMAD_DRB_STATE_EXECUTED; ++ ++ } else { ++ /* DMA is already running, so only queue DRB to the end of the ++ * list */ ++ dmad_attach_tail(drq->drb_pool, ++ &drq->sbt_head, &drq->sbt_tail, drb->node); ++ drb->state = DMAD_DRB_STATE_SUBMITTED; ++ } ++ ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_submit_request); ++ ++/** ++ * dmad_withdraw_request - cancel a submitted dma-request-block ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @drb : [in] Reference to a drb to be submitted ++ * @keep_fired : [in] non-zero to kickoff dma even the channel has stopped due ++ * to finishing its previous request ++ * @return : 0 if success, non-zero if any error ++ * ++ * Cancel a submitted DRB (DMA request block) of the given DMA channel in its ++ * submission queue. DRB is a single dma request which will be pushed into the ++ * submission queue of the given DMA channel. Cancellation fails if the DRB has ++ * already been kicked off. ++ */ ++int dmad_withdraw_request(dmad_chreq * ch_req, dmad_drb * drb) ++{ ++ dmad_drq *drq = 0; ++ unsigned long lock_flags; ++ ++ dmad_dbg("%s()\n", __func__); ++ ++ if (unlikely(ch_req == NULL)) { ++ dmad_err("null ch_req!\n"); ++ return -EFAULT; ++ } ++ ++ drq = (dmad_drq *) ch_req->drq; ++ ++ if (unlikely(drq == NULL)) { ++ dmad_err("null ch_req->drq!\n"); ++ return -EBADR; ++ } ++ ++ if (unlikely(drq->sbt_head == 0)) ++ return -EBADR; ++ ++ if (unlikely((drb->node == 0) || (drb->node >= DMAD_DRB_POOL_SIZE))) ++ return -EBADR; ++ ++ spin_lock_irqsave(&drq->drb_pool_lock, lock_flags); ++ ++ if (unlikely((drq->sbt_head == 0) || (drb->node == 0) || ++ (drb->state != DMAD_DRB_STATE_SUBMITTED) || ++ (drb->node >= DMAD_DRB_POOL_SIZE))) { ++ dmad_err("Submitted-queue is empty or invalid node!\n"); ++ ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ return -EBADR; ++ } ++ ++ dmad_dbg("cancel drb(%d 0x%08x) addr0(0x%08x) addr1(0x%08x) " ++ "size(0x%08x) state(%d)\n", ++ drb->node, (u32) drb, drb->src_addr, drb->dst_addr, ++ drb->req_cycle, drb->state); ++ ++ if (unlikely(drb->state == DMAD_DRB_STATE_EXECUTED)) { ++ dmad_dbg("Already running drb cannot be stopped currently!\n"); ++ ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ return 0;/*-EBADR; */ ++ } ++ ++ dmad_detach_node(drq->drb_pool, ++ &drq->rdy_head, &drq->rdy_tail, drb->node); ++ dmad_attach_tail(drq->drb_pool, ++ &drq->fre_head, &drq->fre_tail, drb->node); ++ ++ drb->state = DMAD_DRB_STATE_FREE; ++ ++ if (drb->sync) ++ complete_all(drb->sync); ++ drb->sync = 0; ++ ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_withdraw_request); ++ ++/** ++ * dmad_kickoff_requests_internal - kickoff hw DMA transmission ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @return : 0 if success, non-zero if any error ++ * ++ * Kickoff hw DMA transmission of the given DMA channel. This function is ++ * valid for both ring & non-ring mode. This is a lightweight internal version ++ * of dmad_kickoff_requests() majorly for use in ring mode. Critical access to ++ * the drb pool should be protected before entering this function. ++ */ ++static inline int dmad_kickoff_requests_internal(dmad_drq * drq) ++{ ++ dmad_drb *drb; ++ ++ dmad_get_head(drq->drb_pool, &drq->sbt_head, &drq->sbt_tail, &drb); ++ ++ if (!drb) { ++ dmad_err("%s() null drb!\n", __func__); ++ return -EBADR; ++ } ++ ++ dmad_dbg("%s() drb(%d 0x%08x) addr0(0x%08x) addr1(0x%08x) " ++ "size(0x%08x) state(%d)\n", __func__, ++ drb->node, (u32) drb, drb->src_addr, drb->dst_addr, ++ drb->req_cycle, drb->state); ++ ++ if (drb->state == DMAD_DRB_STATE_SUBMITTED) { ++ /* Transfer size (in units of source width) */ ++ outl(drb->req_cycle, (addr_t) drq->cyc_port); ++ ++ /* Source and destination address */ ++ if (drq->flags & DMAD_DRQ_DIR_A1_TO_A0) { ++ outl(drb->addr1, (addr_t) drq->src_port); ++ outl(drb->addr0, (addr_t) drq->dst_port); ++ } else { ++ outl(drb->addr0, (addr_t) drq->src_port); ++ outl(drb->addr1, (addr_t) drq->dst_port); ++ } ++ ++ drb->state = DMAD_DRB_STATE_EXECUTED; ++ } ++ ++ /* Enable DMA channel */ ++ if (!dmad_is_channel_enabled(drq)) { ++ dmad_enable_channel(drq); ++ } ++ ++ return 0; ++} ++ ++/** ++ * dmad_kickoff_requests - kickoff hw DMA transmission of the given DMA channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @return : 0 if success, non-zero if any error ++ * ++ * Kickoff hw DMA transmission of the given DMA channel. This function is ++ * valid for both ring & non-ring mode. ++ */ ++int dmad_kickoff_requests(dmad_chreq * ch_req) ++{ ++ dmad_drq *drq = 0; ++ dmad_drb *drb = 0; ++ unsigned long lock_flags; ++ dma_addr_t req_cycle; ++ ++ dmad_dbg("%s()\n", __func__); ++ ++ if (unlikely(ch_req == NULL)) { ++ dmad_err("null ch_req!\n"); ++ return -EFAULT; ++ } ++ ++ drq = (dmad_drq *) ch_req->drq; ++ ++ if (unlikely(drq == NULL)) { ++ dmad_err("null ch_req->drq!\n"); ++ return -EBADR; ++ } ++ ++ spin_lock_irqsave(&drq->drb_pool_lock, lock_flags); ++ ++ dmad_get_head(drq->drb_pool, &drq->sbt_head, &drq->sbt_tail, &drb); ++ ++ dmad_dbg("drq(0x%08x) channel_base(0x%08x)\n", ++ (u32) drq, drq->channel_base); ++ dmad_dbg("kick off drb(%d 0x%08x) addr0(0x%08x) addr1(0x%08x) " ++ "size(0x%08x) state(%d) a1_to_a0(%d)\n", ++ (u32) drb->node, (u32) drb, drb->addr0, drb->addr1, ++ drb->req_cycle, drb->state, ++ drq->flags & DMAD_DRQ_DIR_A1_TO_A0); ++ ++ /* do nothing if no drbs are in the submission queue */ ++ if (unlikely((drb == 0) || (drb->state != DMAD_DRB_STATE_SUBMITTED))) { ++ dmad_dbg("%s() invalid drb(%d 0x%08x) or drb-state(%d)!\n", ++ __func__, ++ drb->node, (u32) drb, drb ? drb->state : 0xffffffff); ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ return 0; ++ } ++ ++ req_cycle = drb->req_cycle; ++ ++ if (unlikely(req_cycle == 0)) { ++ dmad_dbg("%s() zero transfer size!\n", __func__); ++ goto _safe_exit; ++ } ++ ++ /* Transfer size (in units of source width) */ ++ outl(req_cycle, (addr_t) drq->cyc_port); ++ ++ /* Source and destination address */ ++ if (drq->flags & DMAD_DRQ_DIR_A1_TO_A0) { ++ outl(drb->addr1, (addr_t) drq->src_port); ++ outl(drb->addr0, (addr_t) drq->dst_port); ++ } else { ++ outl(drb->addr0, (addr_t) drq->src_port); ++ outl(drb->addr1, (addr_t) drq->dst_port); ++ } ++ ++ drb->state = DMAD_DRB_STATE_EXECUTED; ++ ++ /* Enable DMA channel */ ++ dmad_enable_channel(drq); ++ ++_safe_exit: ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_kickoff_requests); ++ ++/** ++ * dmad_probe_hw_ptr_src - probe DMA source hw-address of the given channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @return : physical address of current HW source pointer ++ * ++ * Probe DMA source hw-address of the given channel. ++ */ ++dma_addr_t dmad_probe_hw_ptr_src(dmad_chreq * ch_req) ++{ ++ return (dma_addr_t) inl(((dmad_drq *) ch_req->drq)->src_port); ++} ++ ++EXPORT_SYMBOL_GPL(dmad_probe_hw_ptr_src); ++ ++/** ++ * dmad_probe_hw_ptr_dst - probe DMA destination hw-address of the given channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @return : physical address of current HW destination pointer ++ * ++ * Probe DMA destination hw-address of the given channel. ++ */ ++dma_addr_t dmad_probe_hw_ptr_dst(dmad_chreq * ch_req) ++{ ++ return (dma_addr_t) inl(((dmad_drq *) ch_req->drq)->dst_port); ++} ++ ++EXPORT_SYMBOL_GPL(dmad_probe_hw_ptr_dst); ++ ++/** ++ * dmad_update_ring - update DMA ring buffer base && size of the given channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @size : [in] The new ring buffer size, in unit of data width (cycles) ++ * @return : 0 if success, non-zero if any error ++ * ++ * Update DMA ring buffer size of the given channel. This function is valid ++ * only if the channel is initialized as ring buffer mode. ++ */ ++int dmad_update_ring(dmad_chreq * ch_req) ++{ ++ unsigned long lock_flags; ++ dmad_drq *drq = (dmad_drq *) ch_req->drq; ++ int remnant; ++ ++ if (unlikely(dmad_is_channel_enabled(drq))) { ++ dmad_err("%s() Error - dma channel should be " ++ "disabled before updating ring size!\n", __func__); ++ return -EFAULT; ++ } ++ ++ spin_lock_irqsave(&drq->drb_pool_lock, lock_flags); ++ ++ /* todo: range checking */ ++ ++ remnant = (int)ch_req->ring_size - ++ (int)ch_req->periods * (int)ch_req->period_size; ++ if (remnant == 0) { ++ drq->periods = ch_req->periods; ++ } else if (remnant > 0) { ++ drq->periods = ch_req->periods; // + 1; ++ } else { ++ dmad_err("%s() Error - buffer_size < " ++ "periods * period_size!\n", __func__); ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ return -EFAULT; ++ } ++ ++ drq->ring_base = ch_req->ring_base; ++ drq->ring_size = ch_req->ring_size; ++ drq->period_size = ch_req->period_size; ++ drq->remnant_size = (dma_addr_t) remnant; ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (ch_req->controller == DMAD_DMAC_AHB_CORE) { ++ drq->period_bytes = ++ DMAC_CYCLE_TO_BYTES(drq->period_size, drq->data_width); ++ } ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ if (ch_req->controller == DMAD_DMAC_APB_CORE) { ++ drq->period_bytes = ++ APBBR_DMA_CYCLE_TO_BYTES(drq->period_size, drq->data_width); ++ } ++#endif ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ ++ dmad_dbg("%s() ring: base(0x%08x) port(0x%08x) periods(0x%08x) " ++ "period_size(0x%08x) period_bytes(0x%08x) " ++ "remnant_size(0x%08x)\n", ++ __func__, drq->ring_base, drq->ring_port, ++ drq->periods, drq->period_size, drq->period_bytes, ++ drq->remnant_size); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_update_ring); ++ ++/** ++ * dmad_update_ring_sw_ptr - update DMA ring buffer sw-pointer ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @sw_ptr : [in] The new sw-pointer for the hw-pointer to chase of ++ * @keep_fired : [in] non-zero to kickoff dma even the channel has stopped due ++ * to finishing its previous request ++ * @return : 0 if success, non-zero if any error ++ * ++ * Update DMA ring buffer sw-pointer of the given channel on the fly. This ++ * function is valid only if the channel is initialized as ring buffer mode. ++ * Uint of sw_ptr is in number of dma data width. ++ */ ++int dmad_update_ring_sw_ptr(dmad_chreq * ch_req, ++ dma_addr_t sw_ptr, u8 keep_fired) ++{ ++ dmad_drq *drq; ++ unsigned long lock_flags; ++ dma_addr_t hw_off = 0, ring_ptr; ++ dma_addr_t sw_p_off, ring_p_off, period_size, period_bytes; ++ dma_addr_t remnant_size; ++ int sw_p_idx, ring_p_idx, period, periods; ++ dmad_drb *drb = NULL; ++ ++ /*if (ch_req == NULL) { */ ++ /* dmad_dbg("%s() null ch_req!\n", __func__); */ ++ /* return -EFAULT; */ ++ /*} */ ++ ++ drq = (dmad_drq *) ch_req->drq; ++ ++ /*if (drq == NULL) { */ ++ /* dmad_dbg("%s() null ch_req->drq!\n", __func__); */ ++ /* return -EBADR; */ ++ /*} */ ++ ++ if (unlikely(sw_ptr > drq->ring_size)) { ++ dmad_err("%s() Invalid ring buffer sw-pointer " ++ "range (0x%08x)! ring_size(0x%08x)\n", ++ __func__, sw_ptr, drq->ring_size); ++ return -EBADR; ++ } ++ ++ spin_lock_irqsave(&drq->drb_pool_lock, lock_flags); ++ ++ periods = drq->periods; ++ period_size = drq->period_size; ++ period_bytes = drq->period_bytes; ++ remnant_size = drq->remnant_size; ++ ++ ring_ptr = drq->sw_ptr; ++ ring_p_idx = drq->sw_p_idx; ++ ring_p_off = drq->sw_p_off; ++ ++ sw_p_idx = (int)(sw_ptr / period_size); ++ sw_p_off = sw_ptr % period_size; ++ ++ if (remnant_size && (sw_p_idx == periods)) { ++ --sw_p_idx; ++ sw_p_off += period_size; ++ } ++ ++ dmad_dbg("%s() ring_ptr(0x%08x) ring_p_idx(0x%08x) " ++ "ring_p_off(0x%08x)\n", ++ __func__, ring_ptr, ring_p_idx, ring_p_off); ++ dmad_dbg("%s() sw_ptr(0x%08x) sw_p_idx(0x%08x) sw_p_off(0x%08x)\n", ++ __func__, sw_ptr, sw_p_idx, sw_p_off); ++ ++ if (drq->ring_drb && ++ (drq->ring_drb->state & (DMAD_DRB_STATE_READY | ++ DMAD_DRB_STATE_SUBMITTED | ++ DMAD_DRB_STATE_EXECUTED))) { ++ drb = drq->ring_drb; ++ } else { ++ /* alloc new drb if there is none yet at ring_ptr */ ++ if (0 != dmad_alloc_drb_internal(drq, &drb)) { ++ dmad_err("%s() drb allocation failed!\n", __func__); ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ return -ENOSPC; ++ } ++ drb->addr0 = ((dma_addr_t) ring_p_idx * period_bytes) + ++ drq->ring_base; ++ drb->addr1 = drq->dev_addr; ++ drb->req_cycle = 0; // redundent, though, no harm to performance ++ ++ dmad_dbg("init_drb(%d 0x%08x) addr0(0x%08x) addr1(0x%08x) " ++ "size(0x%08x) state(%d)\n", ++ (u32) drb->node, (u32) drb, drb->src_addr, ++ drb->dst_addr, drb->req_cycle, drb->state); ++ ++ drq->ring_drb = drb; ++ } ++ ++ /* Following code-path has been optimized. The design flow is expanded ++ * below for reference. ++ * ++ * if (sw_ptr >= ring_ptr) ++ * if (sw_p_idx == ring_p_idx) ++ * ring_drb::req_cycle <- sw_p_off ++ * if (ring_drb::state == executed) ++ * hw_cycle <- sw_p_idx ++ * fi ++ * else ++ * ring_drb::req_cycle <- period_size ++ * if (ring_drb::state == executed) ++ * hw_cycle <- period_size ++ * fi ++ * for (i = ring_p_idx+1 ~ sw_p_idx-1) ++ * new_drb::ring_addr <- i * period_bytes + ring_base ++ * new_drb::req_cycle <- period_size ++ * rof ++ * sw_drb::ring_addr <- sw_p_idx * period_bytes + ring_base ++ * sw_drb::req_cycle <- sw_p_off ++ * else ++ * // sw_ptr < ring_ptr ++ * ring_drb::req_cycle <- period_size ++ * if (ring_drb::state == executed) ++ * hw_cycle <- period_size ++ * fi ++ * for (i = ring_p_idx+1 ~ idx_max) ++ * new_drb::ring_addr <- i * period_bytes + ring_base ++ * new_drb::req_cycle <- period_size ++ * rof ++ * for (i = 0 ~ sw_p_idx-1) ++ * new_drb::ring_addr <- i * period_bytes + ring_base ++ * new_drb::req_cycle <- period_size ++ * rof ++ * sw_drb::ring_addr <- sw_p_idx * period_bytes + ring_base ++ * sw_drb::req_cycle <- sw_p_off ++ * fi ++ */ ++ if ((sw_ptr >= ring_ptr) && (sw_p_idx == ring_p_idx) && (sw_p_off != 0)) { ++ ++ dmad_dbg("update ring drb\n"); ++ ++ /* update drb size at ring_ptr */ ++ drb->req_cycle = sw_p_off; ++ ++ dmad_dbg("ring_drb(%d 0x%08x) addr0(0x%08x) addr1(0x%08x) " ++ "size(0x%08x) state(%d)\n", ++ (u32) drb->node, (u32) drb, drb->addr0, drb->addr1, ++ drb->req_cycle, drb->state); ++ ++ /* update hw dma size of this drb if it has been sent to the ++ * controller */ ++ if (drb->state == DMAD_DRB_STATE_EXECUTED) { ++ dmad_disable_channel(drq); ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (ch_req->controller == DMAD_DMAC_AHB_CORE) ++ hw_off = DMAC_BYTES_TO_CYCLE((addr_t) ++ inl((addr_t) drq-> ++ ring_port) - ++ (addr_t) drb-> ++ addr0, ++ drq->data_width); ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ if (ch_req->controller == DMAD_DMAC_APB_CORE) ++ hw_off = APBBR_DMA_BYTES_TO_CYCLE((addr_t) ++ inl((addr_t) ++ drq-> ++ ring_port) ++ - ++ (addr_t) drb-> ++ addr0, ++ drq-> ++ data_width); ++#endif ++ dmad_dbg("hw_off(0x%08x) sw_p_off(0x%08x)\n", ++ (u32) hw_off, (u32) sw_p_off); ++ ++ if (sw_p_off < hw_off) ++ dmad_err("%s() underrun! sw_p_off(0x%08x) <" ++ " hw_off(0x%08x)\n", __func__, ++ (u32) sw_p_off, (u32) hw_off); ++ else ++ outl(sw_p_off - hw_off, drq->cyc_port); ++ ++ dmad_enable_channel(drq); ++ ++ } else { ++ dmad_submit_request_internal(drq, drb); ++ } ++ ++ } else { ++ ++ dmad_dbg("fulfill ring drb - sw_ptr(0x%08x) ring_ptr(0x%08x)\n", ++ (u32) sw_ptr, (u32) ring_ptr); ++ ++ /* fulfill last drb at ring_ptr */ ++ if (ring_p_idx == (periods - 1)) ++ drb->req_cycle = period_size + remnant_size; ++ else ++ drb->req_cycle = period_size; ++ ++ dmad_dbg("ring_drb(%d 0x%08x) addr0(0x%08x) addr1(0x%08x) " ++ "size(0x%08x) state(%d)\n", ++ (u32) drb->node, (u32) drb, drb->addr0, drb->addr1, ++ drb->req_cycle, drb->state); ++ ++ if (drb->state == DMAD_DRB_STATE_EXECUTED) { ++ dmad_disable_channel(drq); ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (ch_req->controller == DMAD_DMAC_AHB_CORE) ++ hw_off = DMAC_BYTES_TO_CYCLE((addr_t) ++ inl((addr_t) drq-> ++ ring_port) - ++ (addr_t) drb-> ++ addr0, ++ drq->data_width); ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ if (ch_req->controller == DMAD_DMAC_APB_CORE) ++ hw_off = APBBR_DMA_BYTES_TO_CYCLE((addr_t) ++ inl((addr_t) ++ drq-> ++ ring_port) ++ - ++ (addr_t) drb-> ++ addr0, ++ drq-> ++ data_width); ++#endif ++ dmad_dbg("hw_off(0x%08x) period_size(0x%08x)\n", ++ (u32) hw_off, (u32) period_size); ++ ++ if (ring_p_idx == (periods - 1)) { ++ if (period_size < hw_off) ++ dmad_err("%s() illegal! " ++ "period_size(0x%08x) + " ++ "remnant_size(0x%08x) < " ++ "hw_off(0x%08x)\n", __func__, ++ (u32) period_size, ++ (u32) remnant_size, ++ (u32) hw_off); ++ else ++ outl(period_size + remnant_size - ++ hw_off, drq->cyc_port); ++ } else { ++ if (period_size < hw_off) ++ dmad_err("%s() illegal! " ++ "period_size(0x%08x) < " ++ "hw_off(0x%08x)\n", __func__, ++ (u32) period_size, ++ (u32) hw_off); ++ else ++ outl(period_size - hw_off, ++ drq->cyc_port); ++ } ++ ++ dmad_enable_channel(drq); ++ ++ } else { ++ dmad_submit_request_internal(drq, drb); ++ } ++ ++ ++ring_p_idx; ++ ++ /* adjust sw_ptr period index ahead by one ring cycle */ ++ //if (sw_ptr < ring_ptr) { ++ if (sw_p_idx < ring_p_idx) { ++ sw_p_idx += periods; ++ } ++ ++ /* allocate in-between (ring_ptr+1 to sw_ptr-1) ++ * full-cycle drbs */ ++ for (period = ring_p_idx; period < sw_p_idx; ++period) { ++ if (0 != dmad_alloc_drb_internal(drq, &drb)) { ++ dmad_err("%s() drb allocation failed!\n", ++ __func__); ++ spin_unlock_irqrestore(&drq->drb_pool_lock, ++ lock_flags); ++ return -ENOSPC; ++ } ++ ++ drb->addr0 = (dma_addr_t) (period % periods) * ++ period_bytes + drq->ring_base; ++ drb->addr1 = drq->dev_addr; ++ ++ if (period == (periods - 1)) { ++ drb->req_cycle = period_size + remnant_size; ++ } else { ++ drb->req_cycle = period_size; ++ } ++ ++ dmad_dbg("inbtw_drb(%d 0x%08x) addr0(0x%08x) " ++ "addr1(0x%08x) size(0x%08x) state(%d)\n", ++ (u32) drb->node, (u32) drb, drb->addr0, ++ drb->addr1, drb->req_cycle, drb->state); ++ ++ dmad_submit_request_internal(drq, drb); ++ } ++ ++ /* allocate drb right at sw_ptr */ ++ if (0 != dmad_alloc_drb_internal(drq, &drb)) { ++ dmad_err("%s() drb allocation failed!\n", __func__); ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ return -ENOSPC; ++ } ++ drb->addr0 = (dma_addr_t) (sw_p_idx % periods) * ++ period_bytes + drq->ring_base; ++ drb->addr1 = drq->dev_addr; ++ drb->req_cycle = sw_p_off; ++ ++ dmad_dbg("swptr_drb(%d 0x%08x) addr0(0x%08x) addr1(0x%08x) " ++ "size(0x%08x) state(%d)\n", ++ (u32) drb->node, (u32) drb, drb->addr0, drb->addr1, ++ drb->req_cycle, drb->state); ++ ++ drq->ring_drb = drb; ++ ++ if (sw_p_off > 0) ++ dmad_submit_request_internal(drq, drb); ++ } ++ ++ drq->sw_ptr = sw_ptr % drq->ring_size; ++ drq->sw_p_idx = sw_p_idx % periods; ++ drq->sw_p_off = sw_p_off; ++ ++ if (likely(keep_fired)) { ++ dmad_kickoff_requests_internal(drq); ++ } ++ ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_update_ring_sw_ptr); ++ ++/** ++ * dmad_probe_ring_hw_ptr - probe DMA ring buffer position of the given channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @return : Ring buffer position of current HW ring buffer pointer ++ * ++ * Probe DMA ring buffer position of the given channel. The position is ++ * relative to the ring buffer base. This function is valid only if the ++ * channel is initialized as ring buffer mode. ++ */ ++dma_addr_t dmad_probe_ring_hw_ptr(dmad_chreq * ch_req) ++{ ++ dmad_drq *drq = (dmad_drq *) ch_req->drq; ++ dma_addr_t cycles = ++ (dma_addr_t) inl(drq->ring_port) - (dma_addr_t) drq->ring_base; ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (ch_req->controller == DMAD_DMAC_AHB_CORE) ++ cycles = DMAC_BYTES_TO_CYCLE(cycles, drq->data_width); ++#endif ++#ifdef CONFIG_PLATFORM_APBDMA ++ if (ch_req->controller == DMAD_DMAC_APB_CORE) ++ cycles = APBBR_DMA_BYTES_TO_CYCLE(cycles, drq->data_width); ++#endif ++ return cycles; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_probe_ring_hw_ptr); ++ ++/** ++ * dmad_channel_drain - cancel DMA transmission of the given DMA channel ++ * @controller : [in] One of the enum value of DMAD_DMAC_CORE ++ * @drq : [in] Reference to the DMA queue structure (dmad_drq) ++ * @shutdown : [in] Non-zero to force a immediate channel shutdown ++ * @return : 0 if success, non-zero if any error ++ * ++ * Stop the DMA transmission and cancel all submitted requests of the given ++ * DMA channel. This function drains a single channel and is the internal ++ * implementation of the interface routine dmad_drain_requests() and the ++ * module_exit function. ++ */ ++static int dmad_channel_drain(u32 controller, dmad_drq * drq, u8 shutdown) ++{ ++ dmad_drb *drb = 0; ++ unsigned long lock_flags; ++ ++ if (unlikely(drq == NULL)) { ++ dmad_err("null ch_req->drq!\n"); ++ return -EBADR; ++ } ++ ++ spin_lock_irqsave(&drq->drb_pool_lock, lock_flags); ++ ++ /* Stop DMA channel if forced to shutdown immediately */ ++ if (shutdown) { ++ /* disable dma controller */ ++ dmad_reset_channel(drq); ++ ++ /* todo: more settings to stop DMA controller ?? */ ++ ++ /*if (drb->state == DMAD_DRB_STATE_EXECUTED) { */ ++ /*} */ ++ } ++ ++ /* Detach DRBs in submit queue */ ++ dmad_detach_head(drq->drb_pool, &drq->sbt_head, &drq->sbt_tail, &drb); ++ ++ while (drb) { ++ dmad_dbg("cancel sbt drb(%d 0x%08x) addr0(0x%08x) " ++ "addr1(0x%08x) size(0x%08x) state(%d)\n", ++ drb->node, (u32) drb, drb->src_addr, drb->dst_addr, ++ drb->req_cycle, (u32) drb->state); ++ ++ /* Mark DRB state as abort */ ++ drb->state = DMAD_DRB_STATE_ABORT; ++ ++ if (drb->sync) ++ complete_all(drb->sync); ++ ++ dmad_attach_tail(drq->drb_pool, &drq->fre_head, &drq->fre_tail, ++ drb->node); ++ ++ dmad_detach_head(drq->drb_pool, &drq->sbt_head, &drq->sbt_tail, ++ &drb); ++ } ++ ++ /* Detach DRBs in ready queue */ ++ dmad_detach_head(drq->drb_pool, &drq->rdy_head, &drq->rdy_tail, &drb); ++ ++ while (drb) { ++ dmad_dbg("cancel rdy drb(%d 0x%08x) addr0(0x%08x) " ++ "addr1(0x%08x) size(0x%08x) state(%d)\n", ++ drb->node, (u32) drb, drb->src_addr, drb->dst_addr, ++ drb->req_cycle, (u32) drb->state); ++ ++ /* Mark DRB state as abort */ ++ drb->state = DMAD_DRB_STATE_ABORT; ++ ++ dmad_attach_tail(drq->drb_pool, &drq->fre_head, &drq->fre_tail, ++ drb->node); ++ ++ /* Detach next submitted DRB (DMA Request Block) from the ++ * DRQ (DMA Request Queue) */ ++ dmad_detach_head(drq->drb_pool, &drq->rdy_head, &drq->rdy_tail, ++ &drb); ++ } ++ ++ drq->state |= DMAD_DRQ_STATE_ABORT; ++ ++ drq->ring_drb = NULL; ++ drq->sw_ptr = 0; ++ drq->sw_p_idx = 0; ++ drq->sw_p_off = 0; ++ ++ spin_unlock_irqrestore(&drq->drb_pool_lock, lock_flags); ++ ++ if ( /*(drq->fre_head == 0) && */ (drq->flags & DMAD_FLAGS_SLEEP_BLOCK)) { ++ complete_all(&drq->drb_alloc_sync); ++ } ++ ++ return 0; ++} ++ ++/** ++ * dmad_cancel_requests - cancel DMA transmission of the given DMA channel ++ * @ch_req : [in] Reference to the DMA request descriptor structure ++ * @shutdown : [in] Non-zero to force a immediate channel shutdown ++ * @return : 0 if success, non-zero if any error ++ * ++ * Stop the DMA transmission and cancel all submitted requests of the given ++ * DMA channel. ++ */ ++int dmad_drain_requests(dmad_chreq * ch_req, u8 shutdown) ++{ ++ dmad_dbg("%s()\n", __func__); ++ ++ if (ch_req == NULL) { ++ dmad_err("null ch_req!\n"); ++ return -EFAULT; ++ } ++ ++ return dmad_channel_drain(ch_req->controller, ch_req->drq, shutdown); ++} ++ ++EXPORT_SYMBOL_GPL(dmad_drain_requests); ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ ++/** ++ * dmad_probe_irq_source - probe DMA channel who asserts the shared sw-irq line ++ * @return : The channel number which asserts the shared sw-irq line ++ * ++ * Probe DMA channel who asserts the shared sw-irq line. ++ */ ++int dmad_probe_irq_source_ahb(void) ++{ ++ int channel; /* interrupt channel number */ ++ ++ /* todo: spin_lock */ ++ ++ /* - Check DMA status register to get channel number */ ++ for (channel = 0; channel < DMAD_AHB_MAX_CHANNELS; ++channel) { ++ if (getbl(channel, DMAC_INT_TC)) ++ return channel; ++ } ++ ++ /* Perform DMA error checking if no valid channel was found who ++ * assert the finish signal. */ ++ for (channel = 0; channel < DMAD_AHB_MAX_CHANNELS; ++channel) { ++ if (getbl(channel, DMAC_INT_ERRABT)) ++ return channel; ++ if (getbl(channel << DMAC_INT_ABT_SHIFT, DMAC_INT_ERRABT)) ++ return channel; ++ } ++ ++ /* todo: spin_unlock */ ++ ++ return -EFAULT; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_probe_irq_source_ahb); ++ ++#endif /* CONFIG_PLATFORM_AHBDMA */ ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++ ++int dmad_probe_irq_source_apb(void) ++{ ++ int channel; /* interrupt channel number */ ++ ++ /* todo: spin_lock */ ++ ++ /* Check DMA status register to get channel number */ ++ for (channel = 0; channel < DMAD_APB_MAX_CHANNELS; ++channel) { ++ if (getbl(APBBR_DMA_FINTST_BIT, APBBR_DMA_BASE_CH(channel) + ++ APBBR_DMA_CMD_OFFSET)) ++ return channel; ++ } ++ ++ /* Perform DMA error checking if no valid channel was found who ++ * assert the finish signal. */ ++ for (channel = 0; channel < DMAD_APB_MAX_CHANNELS; ++channel) { ++ if (getbl(APBBR_DMA_ERRINTST_BIT, APBBR_DMA_BASE_CH(channel) + ++ APBBR_DMA_CMD_OFFSET)) ++ return channel; ++ } ++ ++ /* todo: spin_unlock */ ++ ++ return -EFAULT; ++} ++ ++EXPORT_SYMBOL_GPL(dmad_probe_irq_source_apb); ++ ++#endif /* CONFIG_PLATFORM_APBDMA */ ++ ++/** ++ * dmad_module_init - dma module-init function ++ * @return : 0 if success, non-zero if any error ++ */ ++int __init dmad_module_init(void) ++{ ++ int err = 0; ++ dmad_dbg("%s() >>\n", __func__); ++ ++ /* clear device struct since the module may be load/unload many times */ ++ memset(&dmad, 0, sizeof(dmad)); ++ ++ dmad.drq_pool = ++ kmalloc((DMAD_AHB_MAX_CHANNELS + ++ DMAD_APB_MAX_CHANNELS) * sizeof(dmad_drq), GFP_KERNEL); ++ if (dmad.drq_pool == NULL) { ++ dmad_err("%s() failed to allocate drb pool!\n", __func__); ++ return -ENOMEM; ++ } ++ ++ memset(dmad.drq_pool, 0, ++ (DMAD_AHB_MAX_CHANNELS + DMAD_APB_MAX_CHANNELS) * ++ sizeof(dmad_drq)); ++ ++ spin_lock_init(&dmad.drq_pool_lock); ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ dmad.ahb_drq_pool = dmad.drq_pool; ++ if (unlikely(!request_region(DMAC_BASE, SZ_1K, "AHB DMAC"))) { ++ dmad_err("Cannot reserve AHB DMAC I/O region\n"); ++ err = -EBUSY; ++ } ++#endif ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++ dmad.apb_drq_pool = &dmad.drq_pool[DMAD_AHB_MAX_CHANNELS]; ++ if (unlikely(!request_region(APBBR_BASE, SZ_1K, "APB DMAC"))) { ++ dmad_err("Cannot reserve APB DMAC I/O region\n"); ++ err = -EBUSY; ++ } ++#endif ++ ++ dmad_dbg("DMA module init result: (%d)\n", err); ++ dmad_dbg(" AHB channels: %d; APB channels %d; " ++ "DRBs per channel: %d\n", ++ DMAC_MAX_CHANNELS, APBBR_DMA_MAX_CHANNELS, DMAD_DRB_POOL_SIZE); ++ ++ dmad_dbg("%s() return code (%d) <<\n", __func__, err); ++ return err; ++} ++ ++/** ++ * dmad_module_init - dma module clean up function ++ */ ++void __exit dmad_module_exit(void) ++{ ++ dmad_drq *drq; ++ u32 channel; ++ ++ dmad_dbg("%s() >>\n", __func__); ++ ++ spin_lock(&dmad.drq_pool_lock); ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ /* cancel existing requests and unregister interrupt handler */ ++ for (channel = 0; channel < DMAD_AHB_MAX_CHANNELS; ++channel) { ++ ++ /* shutdown dma requests */ ++ drq = (dmad_drq *) & dmad.ahb_drq_pool[channel]; ++ ++ if ((drq->state & DMAD_DRQ_STATE_READY) != 0) ++ dmad_channel_drain(DMAD_DMAC_AHB_CORE, drq, 1); ++ ++ /* free registered irq handlers */ ++ free_irq(ahb_irqs[channel], (void *)(channel + 1)); ++ } ++#endif ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++ /* cancel existing requests and unregister interrupt handler */ ++ for (channel = 0; channel < DMAD_APB_MAX_CHANNELS; ++channel) { ++ ++ /* shutdown dma requests */ ++ drq = (dmad_drq *) & dmad.apb_drq_pool[channel]; ++ ++ if ((drq->state & DMAD_DRQ_STATE_READY) != 0) ++ dmad_channel_drain(DMAD_DMAC_APB_CORE, drq, 1); ++ ++ /* free registered irq handlers */ ++ free_irq(apb_irqs[channel], (void *)(channel + 1)); ++ } ++#endif ++ spin_unlock(&dmad.drq_pool_lock); ++ ++ if (dmad.drq_pool) ++ kfree(dmad.drq_pool); ++ memset(&dmad, 0, sizeof(dmad)); ++ ++ /* release I/O space */ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ release_region(DMAC_BASE, SZ_1K); ++#endif /*CONFIG_PLATFORM_AHBDMA */ ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++ release_region(APBBR_BASE, SZ_1K); ++#endif /* CONFIG_PLATFORM_APBDMA */ ++ ++ dmad_dbg("DMA module unloaded!\n"); ++} ++ ++#ifndef MODULE ++arch_initcall(dmad_module_init); ++#else ++module_init(dmad_module_init); ++module_exit(dmad_module_exit); ++#endif ++ ++#endif /* CONFIG_PLATFORM_AHBDMA || CONFIG_PLATFORM_APBDMA */ +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/dmad_intc.c linux-3.4.110/arch/nds32/platforms/dmad_intc.c +--- linux-3.4.110.orig/arch/nds32/platforms/dmad_intc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/dmad_intc.c 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,124 @@ ++/* ++ * linux/arch/armnommu/mach-faraday/platform-a320/apb_intc.c ++ * ++ * Faraday AHB DMA Interrupt Process Driver Implementation ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * ++ * ChangeLog ++ * ++ * Peter Liao 09/28/2005 Created ++ */ ++ ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <asm/io.h> ++ ++#include <asm/intc.h> ++#include <asm/spec.h> ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++extern int dmad_probe_irq_source_ahb(void); ++ ++void AHBDMA_irq_rounter(unsigned int irq, struct irq_desc *desc) ++{ ++ int ahb_irq; ++ struct irq_desc *ahb_desc; ++ struct irq_data data; ++ data.irq = irq; ++ ++ raw_spin_lock(&desc->lock); ++ desc->irq_data.chip->irq_mask(&data); ++ desc->irq_data.chip->irq_ack(&data); ++ ++ ahb_irq = dmad_probe_irq_source_ahb(); ++ if (ahb_irq >= 0) { ++ ahb_irq += DMAC_FTDMAC020_IRQ0; ++ ahb_desc = irq_desc + ahb_irq; ++ ++ raw_spin_unlock(&desc->lock); ++ ahb_desc->handle_irq(ahb_irq, ahb_desc); ++ raw_spin_lock(&desc->lock); ++ } ++ ++ desc->irq_data.chip->irq_unmask(&data); ++ raw_spin_unlock(&desc->lock); ++} ++ ++int __init intc_ftdmac020_init_irq(void) ++{ ++ int i; ++ ++ /* Register all IRQ */ ++ for (i = DMAC_FTDMAC020_IRQ0; ++ i < DMAC_FTDMAC020_IRQ0 + DMAC_FTDMAC020_IRQ_COUNT; i++) { ++ // level trigger ++ irq_set_chip(i, &dummy_irq_chip); ++ irq_set_handler(i, handle_simple_irq); ++ } ++ irq_set_chained_handler(PLATFORM_AHBDMA_IRQ, AHBDMA_irq_rounter); ++ ++ return 0; ++} ++ ++arch_initcall(intc_ftdmac020_init_irq); ++#endif /* CONFIG_PLATFORM_AHBDMA */ ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++extern int dmad_probe_irq_source_apb(void); ++ ++void APBDMA_irq_rounter(unsigned int irq, struct irq_desc *desc) ++{ ++ int apb_irq; ++ struct irq_desc *apb_desc; ++ struct irq_data data; ++ data.irq = irq; ++ ++ raw_spin_lock(&desc->lock); ++ ++ //mask_ack_irq(desc, irq); ++ desc->irq_data.chip->irq_mask(&data); ++ desc->irq_data.chip->irq_ack(&data); ++ ++ apb_irq = dmad_probe_irq_source_apb(); ++ //printk(KERN_INFO "irq (%d) ch(%d)\n", irq, apb_irq); ++ ++ if (apb_irq >= 0) { ++ apb_irq += APBBRG_FTAPBBRG020S_0_IRQ0; ++ apb_desc = irq_desc + apb_irq; ++ ++ raw_spin_unlock(&desc->lock); ++ apb_desc->handle_irq(irq, apb_desc); ++ raw_spin_lock(&desc->lock); ++ } ++ ++ desc->irq_data.chip->irq_unmask(&data); ++ raw_spin_unlock(&desc->lock); ++} ++ ++int __init intc_ftapbbrg020s_init_irq(void) ++{ ++ int i; ++ ++ /* Register all IRQ */ ++ for (i = APBBRG_FTAPBBRG020S_0_IRQ0; ++ i < APBBRG_FTAPBBRG020S_0_IRQ0 + APBBRG_FTAPBBRG020S_IRQ_COUNT; ++ i++) { ++ // level trigger ++ irq_set_chip(i, &dummy_irq_chip); ++ irq_set_handler(i, handle_simple_irq); ++ } ++ ++ irq_set_chained_handler(PLATFORM_APBDMA_IRQ, APBDMA_irq_rounter); ++ ++ return 0; ++} ++ ++arch_initcall(intc_ftapbbrg020s_init_irq); ++#endif /* CONFIG_PLATFORM_APBDMA */ +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/ftpci.c linux-3.4.110/arch/nds32/platforms/ftpci.c +--- linux-3.4.110.orig/arch/nds32/platforms/ftpci.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/ftpci.c 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,497 @@ ++/* ++ * linux/arch/nds32/platforms/ftpci.c ++ * ++ * Faraday FTPCI100 PCI Bridge Controller Device Driver Implementation ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ++ * ChangeLog ++ * ++ * Peter Liao 09/28/2005 Created. ++ */ ++ ++#include <linux/sched.h> ++#include <linux/kernel.h> ++#include <linux/pci.h> ++#include <linux/ptrace.h> ++#include <linux/slab.h> ++#include <linux/ioport.h> ++#include <linux/interrupt.h> ++#include <linux/spinlock.h> ++#include <linux/init.h> ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/system.h> ++#include <asm/mach/pci.h> ++#include <asm/io.h> ++#include <asm/sizes.h> ++#include <asm/ftpci.h> ++#include <asm/spec.h> ++#include <asm/mach-types.h> ++ ++#define IPMODULE PCIC ++#define IPNAME FTPCI100 ++ ++#define DEBUGFPCI ++#undef DEBUGFPCI ++ ++#ifdef DEBUGFPCI ++#define DBGFPCI(x...) printk(x) ++#else ++#define DBGFPCI(x...) ++#endif ++#define FPCI_VA_BASE IP_VA_BASE(0) ++#define FTPCI_PCI_BRIDGE_VENID PCI_BRIDGE_VENID ++#define FPCI_IO_VA_BASE PCIIO_VA_BASE ++#define FPCI_IO_PA_BASE PCIIO_PA_BASE ++#define FPCI_IO_VA_END PCIIO_VA_LIMIT ++#define FPCI_MEM_VA_BASE PCIMEM_VA_BASE ++#define FPCI_MEM_PA_BASE PCIMEM_PA_BASE ++#define FPCI_MEM_VA_END PCIMEM_VA_LIMIT ++#define FPCI_MEM_PA_END (PCIMEM_PA_BASE + SZ_256M) ++ ++// -------------------------------------------------------------------- ++// AHB Control Register ++// -------------------------------------------------------------------- ++#define FTPCI_IOSIZE_REG 0x0 ++#define FTPCI_PROT_REG 0x4 ++#define FTPCI_CTRL_REG 0x8 ++#define FTPCI_ERREN_REG 0xc ++#define FTPCI_SOFTRST_REG 0x10 ++#define FTPCI_EN64_REG 0x14 ++#define FTPCI_ADDRH32_REG 0x18 ++#define FTPCI_CFG_ADR_REG 0x28 ++#define FTPCI_CFG_DATA_REG 0x2c ++ ++// -------------------------------------------------------------------- ++// FTPCI_IOSIZE_REG's constant definitions ++// -------------------------------------------------------------------- ++#define FTPCI_BASE_IO_SIZE_1M 0x0 ++#define FTPCI_BASE_IO_SIZE_2M 0x1 ++#define FTPCI_BASE_IO_SIZE_4M 0x2 ++#define FTPCI_BASE_IO_SIZE_8M 0x3 ++#define FTPCI_BASE_IO_SIZE_16M 0x4 ++#define FTPCI_BASE_IO_SIZE_32M 0x5 ++#define FTPCI_BASE_IO_SIZE_64M 0x6 ++#define FTPCI_BASE_IO_SIZE_128M 0x7 ++#define FTPCI_BASE_IO_SIZE_256M 0x8 ++#define FTPCI_BASE_IO_SIZE_512M 0x9 ++#define FTPCI_BASE_IO_SIZE_1G 0xa ++#define FTPCI_BASE_IO_SIZE_2G 0xb ++ ++// -------------------------------------------------------------------- ++// PCI Configuration Register ++// -------------------------------------------------------------------- ++#define PCI_INT_MASK 0x4c ++#define PCI_MEM_BASE_SIZE1 0x50 ++#define PCI_MEM_BASE_SIZE2 0x54 ++#define PCI_MEM_BASE_SIZE3 0x58 ++ ++// -------------------------------------------------------------------- ++// PCI_INT_MASK's bit definitions ++// -------------------------------------------------------------------- ++#define PCI_INTA_ENABLE (1U<<22) ++#define PCI_INTB_ENABLE (1U<<23) ++#define PCI_INTC_ENABLE (1U<<24) ++#define PCI_INTD_ENABLE (1U<<25) ++ ++// -------------------------------------------------------------------- ++// PCI_MEM_BASE_SIZE1's constant definitions ++// -------------------------------------------------------------------- ++#define FTPCI_BASE_ADR_SIZE_1MB (PHYS_OFFSET | (0x0<<16)) ++#define FTPCI_BASE_ADR_SIZE_2MB (PHYS_OFFSET | (0x1<<16)) ++#define FTPCI_BASE_ADR_SIZE_4MB (PHYS_OFFSET | (0x2<<16)) ++#define FTPCI_BASE_ADR_SIZE_8MB (PHYS_OFFSET | (0x3<<16)) ++#define FTPCI_BASE_ADR_SIZE_16MB (PHYS_OFFSET | (0x4<<16)) ++#define FTPCI_BASE_ADR_SIZE_32MB (PHYS_OFFSET | (0x5<<16)) ++#define FTPCI_BASE_ADR_SIZE_64MB (PHYS_OFFSET | (0x6<<16)) ++#define FTPCI_BASE_ADR_SIZE_128MB (PHYS_OFFSET | (0x7<<16)) ++#define FTPCI_BASE_ADR_SIZE_256MB (PHYS_OFFSET | (0x8<<16)) ++#define FTPCI_BASE_ADR_SIZE_512MB (PHYS_OFFSET | (0x9<<16)) ++#define FTPCI_BASE_ADR_SIZE_1GB (PHYS_OFFSET | (0xa<<16)) ++#define FTPCI_BASE_ADR_SIZE_2GB (PHYS_OFFSET | (0xb<<16)) ++ ++#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3) ) ++ ++struct pci_dev *pci_bridge = NULL; ++static unsigned int pci_config_addr; ++static unsigned int pci_config_data; ++int ftpci_probed = 0; ++ ++static struct resource pcic_resource = { ++ .name = "Faradat PCIC", ++ .start = IP_VA_BASE(0), ++ .end = IP_VA_LIMIT(0), ++}; ++ ++// Luke Lee 03/21/2005 mod begin ++static int ftpci_read_config_byte(struct pci_bus *bus, unsigned int devfn, ++ int where, u8 * val) ++{ ++ u32 v; ++ unsigned int shift; ++ ++ outl(CONFIG_CMD(bus->number, devfn, where), pci_config_addr); ++ v = inl(pci_config_data); ++ shift = (where & 0x3) * 8; ++ *val = (v >> shift) & 0xff; ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int ftpci_read_config_word(struct pci_bus *bus, unsigned int devfn, ++ int where, u16 * val) ++{ ++ u32 v; ++ unsigned int shift; ++ ++ outl(CONFIG_CMD(bus->number, devfn, where), pci_config_addr); ++ v = inl(pci_config_data); ++ shift = (where & 0x3) * 8; ++ *val = (v >> shift) & 0xffff; ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int ftpci_read_config_dword(struct pci_bus *bus, unsigned int devfn, ++ int where, u32 * val) ++{ ++ u32 v; ++ ++ outl(CONFIG_CMD(bus->number, devfn, where), pci_config_addr); ++ v = inl(pci_config_data); ++ *val = v; ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int ftpci_write_config_byte(struct pci_bus *bus, unsigned int devfn, ++ int where, u8 val) ++{ ++ u32 org_val; ++ unsigned int shift; ++ ++ shift = (where & 0x3) * 8; ++ outl(CONFIG_CMD(bus->number, devfn, where), pci_config_addr); ++ org_val = inl(pci_config_data); ++ org_val = (org_val & ~(0xff << shift)) | ((u32) val << shift); ++ outl(org_val, pci_config_data); ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int ftpci_write_config_word(struct pci_bus *bus, unsigned int devfn, ++ int where, u16 val) ++{ ++ u32 org_val; ++ unsigned int shift; ++ ++ shift = (where & 0x3) * 8; ++ outl(CONFIG_CMD(bus->number, devfn, where), pci_config_addr); ++ org_val = inl(pci_config_data); ++ org_val = (org_val & ~(0xffff << shift)) | ((u32) val << shift); ++ outl(org_val, pci_config_data); ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int ftpci_write_config_dword(struct pci_bus *bus, unsigned int devfn, ++ int where, u32 val) ++{ ++ outl(CONFIG_CMD(bus->number, devfn, where), pci_config_addr); ++ outl(val, pci_config_data); ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++// Luke Lee 03/21/2005 mod end ++ ++// Luke Lee 03/21/2005 ins begin ++static int ftpci_read_config(struct pci_bus *bus, unsigned int devfn, int where, ++ int size, u32 * val) ++{ ++ int r; ++ switch (size) { ++ case 1: ++ r = ftpci_read_config_byte(bus, devfn, where, (u8 *) val); // Luke Lee TOFIX 03/22/2005 : convert to (u8*) -- beware of endian ! ++ break; ++ case 2: ++ r = ftpci_read_config_word(bus, devfn, where, (u16 *) val); // Luke Lee TOFIX 03/22/2005 : convert to (u16*) -- beware of endian ! ++ break; ++ ++ default: ++ r = ftpci_read_config_dword(bus, devfn, where, val); ++ break; ++ } ++ ++ return r; ++} ++ ++static int ftpci_write_config(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 val) ++{ ++ int r; ++ switch (size) { ++ case 1: ++ r = ftpci_write_config_byte(bus, devfn, where, val); ++ break; ++ case 2: ++ r = ftpci_write_config_word(bus, devfn, where, val); ++ break; ++ ++ case 4: ++ r = ftpci_write_config_dword(bus, devfn, where, val); ++ break; ++ default: ++ printk("Invalid size for ftpci_write()\n"); ++ r = PCIBIOS_FUNC_NOT_SUPPORTED; // Luke Lee 03/23/2005 ins 1 ++ } ++ ++ return r; ++} ++ ++// Luke Lee 03/21/2005 ins end ++ ++static struct pci_ops ftpci_ops = { ++ // Luke Lee 03/21/2005 mod begin ++ .read = ftpci_read_config, ++ .write = ftpci_write_config, ++ // Luke Lee 03/21/2005 mod end ++}; ++ ++/* using virtual address for pci_resource_start() function*/ ++static struct resource pci_io = { ++ .name = "Faraday PCI I/O Space", ++ .start = FPCI_IO_VA_BASE, ++ .end = FPCI_IO_VA_END, ++ .flags = IORESOURCE_IO, ++}; ++ ++/* using physical address for memory resource*/ ++static struct resource pci_mem = { ++ .name = "Faraday PCI non-prefetchable Memory Space", ++ .start = FPCI_MEM_PA_BASE, ++ .end = FPCI_MEM_PA_END, ++ .flags = IORESOURCE_MEM, ++}; ++ ++// Luke Lee 03/23/2005 unrem 1 rem 1 ++int __init ftpci_setup_resource(struct resource **resource) ++{ ++ DBGFPCI("PCI I/O space from %08lX to %08lX\n", pci_io.start, ++ pci_io.end); ++ DBGFPCI("PCI Memory space from %08lX to %08lX\n", pci_mem.start, ++ pci_mem.end); ++ if (request_resource(&ioport_resource, &pci_io)) { ++ printk(KERN_ERR "PCI: unable to allocate io region\n"); ++ return -EBUSY; // Luke Lee 03/23/2005 unrem 1 ++ } ++ if (request_resource(&iomem_resource, &pci_mem)) { ++ printk(KERN_ERR "PCI: unable to allocate non-prefetchable " ++ "memory region\n"); ++ return -EBUSY; // Luke Lee 03/23/2005 unrem 1 ++ } ++ ++ /* ++ * bus->resource[0] is the IO resource for this bus ++ * bus->resource[1] is the mem resource for this bus ++ * bus->resource[2] is the prefetch mem resource for this bus ++ */ ++ ++ resource[0] = &pci_io; ++ resource[1] = &pci_mem; ++ resource[2] = NULL; ++ ++ return 1; // Luke Lee 03/23/2005 unrem 1 ++} ++ ++int ftpci_get_irq(void) ++{ ++ unsigned int status; ++ ftpci_read_config_dword(pci_bridge->bus, pci_bridge->devfn, 0x4c, &status); // Luke Lee 03/22/2005 mod 1 ++ DBGFPCI("ftpci_get_irq,status=0x%x\n", status); ++ status = (status >> 28); ++ if (status & 0x1) ++ return 0; ++ if (status & 0x2) ++ return 1; ++ if (status & 0x4) ++ return 2; ++ if (status & 0x8) ++ return 3; ++ return -1; ++} ++ ++void ftpci_clear_irq(unsigned int irq) ++{ ++ //int i; ++ unsigned int status; ++ ftpci_read_config_dword(pci_bridge->bus, pci_bridge->devfn, 0x4c, &status); // Luke Lee 03/22/2005 mod 1 ++ if (irq == 0) ++ status = (status & 0xfffffff) | ((0x1) << 28); ++ else if (irq == 1) ++ status = (status & 0xfffffff) | ((0x2) << 28); ++ else if (irq == 2) ++ status = (status & 0xfffffff) | ((0x4) << 28); ++ else if (irq == 3) ++ status = (status & 0xfffffff) | ((0x8) << 28); ++ ftpci_write_config_dword(pci_bridge->bus, pci_bridge->devfn, 0x4c, status); // Luke Lee 03/22/2005 mod 1 ++} ++ ++void ftpci_unmask_irq(unsigned int irq) ++{ ++ u32 val; ++ ftpci_read_config_dword(pci_bridge->bus, pci_bridge->devfn, ++ PCI_INT_MASK, &val); ++ val |= (PCI_INTA_ENABLE << irq); ++ ftpci_write_config_dword(pci_bridge->bus, pci_bridge->devfn, ++ PCI_INT_MASK, val); ++} ++ ++void ftpci_mask_irq(unsigned int irq) ++{ ++ u32 val; ++ ftpci_read_config_dword(pci_bridge->bus, pci_bridge->devfn, ++ PCI_INT_MASK, &val); ++ val &= ~(PCI_INTA_ENABLE << irq); ++ ftpci_write_config_dword(pci_bridge->bus, pci_bridge->devfn, ++ PCI_INT_MASK, val); ++} ++ ++static int ftpci_probe(unsigned int addr_p) ++{ ++ unsigned int *addr = (unsigned int *)addr_p; ++ *(volatile unsigned int *)addr = 0x80000000; ++ if (*(volatile unsigned int *)addr == 0x80000000) { ++ DBGFPCI("Faraday FPCI bridge probed ok\n"); ++ ftpci_probed = 1; ++ } else { ++ ftpci_probed = 0; ++ } ++ *(volatile unsigned int *)addr = 0x0; ++ return ftpci_probed; ++} ++ ++void __init ftpci_preinit(void /**sysdata*/ ) // Luke Lee 03/22/2005 mod 1 ++{ ++ DBGFPCI("ftpci_preinit()\n\r"); ++ ++#ifdef CONFIG_PLAT_AG101 ++ /* Walk around for A321 but remove after leopard pci */ ++ *(volatile unsigned long *)(FPCI_VA_BASE + 0x8) = 0x10; ++#endif ++ ++ pci_config_addr = FPCI_VA_BASE + FTPCI_CFG_ADR_REG; ++ pci_config_data = FPCI_VA_BASE + FTPCI_CFG_DATA_REG; ++ DBGFPCI("Config addr is %08X, data port is %08X\n", ++ (int)pci_config_addr, (int)pci_config_data); ++ ++ if (!ftpci_probe(pci_config_addr)) ++ return; ++} ++ ++void ftpci_postinit(void /**sysdata*/ ) ++{ ++ u32 val; ++ DBGFPCI("ftpci_postinit()\n\r"); ++ pci_bridge = pci_get_device(PCI_BRIDGE_VENID, PCI_BRIDGE_DEVID, NULL); ++ if (pci_bridge == NULL) ++ return; ++ // Enable the Interrupt Mask (INTA/INTB/INTC/INTD) ++ ftpci_read_config_dword(pci_bridge->bus, pci_bridge->devfn, PCI_INT_MASK, &val); // Luke Lee 03/22/2005 mod 1 ++ val |= ++ (PCI_INTA_ENABLE | PCI_INTB_ENABLE | PCI_INTC_ENABLE | ++ PCI_INTD_ENABLE); ++ ftpci_write_config_dword(pci_bridge->bus, pci_bridge->devfn, PCI_INT_MASK, val); // Luke Lee 03/22/2005 mod 1 ++ ++ // Write DMA Start Address/Size Data to the Bridge configuration space ++ ftpci_write_config_dword(pci_bridge->bus, pci_bridge->devfn, PCI_MEM_BASE_SIZE1, FTPCI_BASE_ADR_SIZE_1GB); // Luke Lee 03/22/2005 mod 1 ++ DBGFPCI("%s: Post init ok\n", __func__); ++} ++ ++/* ++ * This routine handles multiple bridges. ++ */ ++static u8 __init fpci_swizzle(struct pci_dev *dev, u8 * pinp) ++{ ++ // If there are one more bridges on our platfrom, we need to implement this function. ++ DBGFPCI("a320_swizzle(%X,%X)\n\r", (unsigned)dev, (unsigned)pinp); ++ return 0; ++} ++ ++static int __init fpci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ DBGFPCI("a320_map_irq,slot=%d pin=%d\n", PCI_SLOT(dev->devfn), pin); ++ switch ((PCI_SLOT(dev->devfn) + pin - 8 - 1) % 4) { ++ case 0: ++ return IP_IRQ0(0); ++ case 1: ++ return IP_IRQ1(0); ++ case 2: ++ return IP_IRQ2(0); ++ case 3: ++ return IP_IRQ3(0); ++ default: ++ printk(KERN_ERR "Not Support Slot %d\n", slot); ++ break; ++ } ++ return -1; ++} ++ ++int __init ftpci_setup(int nr, struct pci_sys_data *sys) ++{ ++ int ret = 0; ++ if (nr == 0) { ++ ret = ftpci_setup_resource(sys->resource); ++// sys->mem_offset = FPCI_MEM_VA_BASE - FPCI_MEM_PA_BASE; ++ sys->mem_offset = 0; ++ sys->io_offset = FPCI_IO_VA_BASE - FPCI_IO_PA_BASE; ++ } ++ return ret; ++} ++ ++static struct pci_bus *__devinit ftpci_scan_bus(int nr, ++ struct pci_sys_data *sys) ++{ ++ return pci_scan_bus(sys->busnr, &ftpci_ops, sys); ++} ++ ++static struct hw_pci a320_pci __initdata = { ++ .swizzle = fpci_swizzle, ++ .map_irq = fpci_map_irq, ++ .setup = ftpci_setup, ++ .nr_controllers = 1, ++ .scan = ftpci_scan_bus, ++ .preinit = ftpci_preinit, /* The first called init function */ ++ .postinit = ftpci_postinit, /* It is called after hw init and scanned PCI bus */ ++}; ++ ++static int __init fpci_init(void) ++{ ++#ifdef MODULE ++ printk(KERN_INFO "Faraday PCI driver Init"); ++#endif ++ printk(KERN_DEBUG "Init A321 PCI bridge controller\n"); ++ /* Register I/O address range of this PCI Bridge Controller */ ++ DBGFPCI("Name:%s, Base=%lX, End=%lX\n", pcic_resource.name, ++ pcic_resource.start, pcic_resource.end); ++ request_resource(&ioport_resource, &pcic_resource); ++ pci_common_init(&a320_pci); ++ return 0; ++} ++ ++subsys_initcall(fpci_init); ++ ++EXPORT_SYMBOL(ftpci_probed); ++EXPORT_SYMBOL(ftpci_clear_irq); ++EXPORT_SYMBOL(ftpci_get_irq); +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/intc.c linux-3.4.110/arch/nds32/platforms/intc.c +--- linux-3.4.110.orig/arch/nds32/platforms/intc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/intc.c 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,257 @@ ++/* ++ * linux/arch/nds32/platforms/intc.c ++ * ++ * Faraday FTINTC010 Master Interrupt Controller Device Driver Implementation ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * Note ++ * ++ * This program implements only the master INTC of the platform. Slave INTCs must ++ * be initialized by themselves. ++ * ++ * ChangeLog ++ * ++ * Luke Lee 09/14/2005 Created. ++ */ ++ ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <asm/io.h> ++ ++#include <asm/intc.h> ++#include <asm/spec.h> ++#include <asm/ftpci.h> ++ ++#define IPMODULE INTC ++#define IPNAME FTINTC010 ++ ++/* ++ * Edge trigger IRQ chip methods ++ */ ++#if defined(CONFIG_SMP) && defined(CONFIG_IRQ_PER_CPU) ++spinlock_t irq_chip_lock; ++#endif ++ ++static void intc_ftintc010_ack_irq(struct irq_data *data) ++{ ++ unsigned int tmp; ++ ++ // ack and disable ++#if defined(CONFIG_SMP) && defined(CONFIG_IRQ_PER_CPU) ++ spin_lock_irq(&irq_chip_lock); ++#endif ++ *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_CLEAR_REG) = 1 << data->irq; ++ tmp = *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_CLEAR_REG); ++ tmp = *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MODE_REG); ++ ++ if (!(tmp & (1UL << data->irq))) { /* level trigger */ ++ ++ *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MASK_REG) &= ++ ~(1 << data->irq); ++ tmp = *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MASK_REG); ++ } ++#if defined(CONFIG_SMP) && defined(CONFIG_IRQ_PER_CPU) ++ spin_unlock_irq(&irq_chip_lock); ++#endif ++} ++ ++static void intc_ftintc010_mask_irq(struct irq_data *data) ++{ ++ unsigned int tmp; ++ ++ // disable ++#if defined(CONFIG_SMP) && defined(CONFIG_IRQ_PER_CPU) ++ spin_lock_irq(&irq_chip_lock); ++#endif ++ *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MASK_REG) &= ++ ~(1 << data->irq); ++ tmp = *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MASK_REG); ++#if defined(CONFIG_SMP) && defined(CONFIG_IRQ_PER_CPU) ++ spin_unlock_irq(&irq_chip_lock); ++#endif ++} ++ ++static void intc_ftintc010_mask_ack_irq(struct irq_data *data) ++{ ++ unsigned int tmp; ++ ++ // disable ++#if defined(CONFIG_SMP) && defined(CONFIG_IRQ_PER_CPU) ++ spin_lock_irq(&irq_chip_lock); ++#endif ++ *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MASK_REG) &= ++ ~(1 << data->irq); ++ tmp = *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MASK_REG); ++ ++ *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_CLEAR_REG) = 1 << data->irq; ++ tmp = *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_CLEAR_REG); ++ ++#if defined(CONFIG_SMP) && defined(CONFIG_IRQ_PER_CPU) ++ spin_unlock_irq(&irq_chip_lock); ++#endif ++} ++ ++static void intc_ftintc010_unmask_irq(struct irq_data *data) ++{ ++ unsigned int tmp; ++ ++ // enable ++#if defined(CONFIG_SMP) && defined(CONFIG_IRQ_PER_CPU) ++ spin_lock_irq(&irq_chip_lock); ++#endif ++ *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MASK_REG) |= 1 << data->irq; ++ tmp = *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MASK_REG); ++#if defined(CONFIG_SMP) && defined(CONFIG_IRQ_PER_CPU) ++ spin_unlock_irq(&irq_chip_lock); ++#endif ++} ++ ++static int intc_ftintc010_set_type(struct irq_data *data, ++ unsigned int flow_type) ++{ ++#if defined(CONFIG_SMP) && defined(CONFIG_IRQ_PER_CPU) ++ spin_lock_irq(&irq_chip_lock); ++#endif ++ /* ++ * IRQ Trigger Mode Register 1: edge ++ * IRQ Trigger Level Register 1: active high ++ */ ++ ++ int tmp; ++ ++ if (flow_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW)) { ++ ++ *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_LEVEL_REG) &= ++ ~(1UL << data->irq); ++ tmp = *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_LEVEL_REG); ++ } ++ ++ if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH)) { ++ ++ *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_LEVEL_REG) |= ++ (1UL << data->irq); ++ tmp = *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_LEVEL_REG); ++ } ++ ++ if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { ++ ++ *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MODE_REG) |= ++ (1UL << data->irq); ++ tmp = *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MODE_REG); ++ (irq_desc + data->irq)->handle_irq = handle_edge_irq; ++ } ++ ++ if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) { ++ ++ *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MODE_REG) &= ++ ~(1UL << data->irq); ++ tmp = *(volatile unsigned *)(IP_VA_BASE(0) + IRQ_MODE_REG); ++ (irq_desc + data->irq)->handle_irq = handle_level_irq; ++ } ++#if defined(CONFIG_SMP) && defined(CONFIG_IRQ_PER_CPU) ++ spin_unlock_irq(&irq_chip_lock); ++#endif ++ return 0; ++} ++ ++static struct irq_chip intc_ftintc010_chip = { ++ ++ .irq_ack = intc_ftintc010_ack_irq, ++ .irq_mask = intc_ftintc010_mask_irq, ++ .irq_mask_ack = intc_ftintc010_mask_ack_irq, ++ .irq_unmask = intc_ftintc010_unmask_irq, ++ .irq_set_type = intc_ftintc010_set_type, ++}; ++ ++static struct resource intc_resource = { ++ ++ .name = "Main interrupt controller", ++ .start = IP_VA_BASE(0), ++ .end = IP_VA_BASE(0) + IP_VA_SIZE(0), ++}; ++ ++/* ++ * Initialization of master interrupt controller, after this INTC is ++ * enabled, the rest of Linux initialization codes can then be completed. ++ * For example, timer interrupts and UART interrupts must be enabled during ++ * the boot process. ++ */ ++void __init intc_ftintc010_init_irq(void) ++{ ++ int i, edge; ++ ++#if defined(CONFIG_SMP) && defined(CONFIG_IRQ_PER_CPU) ++ spin_lock_init(&irq_chip_lock); ++#endif ++ /* Initialize the INTC */ ++ outl(0x00000000, IP_VA_BASE(0) + IRQ_MASK_REG); ++ outl(0x00000000, IP_VA_BASE(0) + FIQ_MASK_REG); ++ outl(0xffffffff, IP_VA_BASE(0) + IRQ_CLEAR_REG); ++ outl(0xffffffff, IP_VA_BASE(0) + FIQ_CLEAR_REG); ++ outl(PLATFORM_IRQ_TRIGGER_MODE, IP_VA_BASE(0) + IRQ_MODE_REG); ++ /* FTINTC010: bit 0=active high or rising edge, 1=active low or falling edge. */ ++ outl(PLATFORM_IRQ_TRIGGER_LEVEL, IP_VA_BASE(0) + IRQ_LEVEL_REG); ++ ++ /* Register all IRQ */ ++ for (i = PLATFORM_IRQ_BASE, edge = 1; ++ i < PLATFORM_IRQ_BASE + PLATFORM_IRQ_TOTALCOUNT; i++, edge <<= 1) { ++ ++ irq_set_chip(i, &intc_ftintc010_chip); ++ ++ if (PLATFORM_IRQ_TRIGGER_MODE & edge) /* edge trigger */ ++ irq_set_handler(i, handle_edge_irq); ++ ++ else /* level trigger */ ++ irq_set_handler(i, handle_level_irq); ++ } ++ ++ /* Register I/O address range of this INTC */ ++ request_resource(&ioport_resource, &intc_resource); ++ ++} ++ ++unsigned int get_IntSrc(void) ++{ ++ unsigned int irq_status, irq = 31; ++ ++ irq_status = inl(IP_VA_BASE(0) + IRQ_STATUS_REG); ++ if (irq_status == 0) ++ return 32; ++ if (irq_status & 0x0000ffff) { ++ irq -= 16; ++ irq_status <<= 16; ++ } ++ if (irq_status & 0x00ff0000) { ++ irq -= 8; ++ irq_status <<= 8; ++ } ++ if (irq_status & 0x0f000000) { ++ irq -= 4; ++ irq_status <<= 4; ++ } ++ if (irq_status & 0x30000000) { ++ irq -= 2; ++ irq_status <<= 2; ++ } ++ if (irq_status & 0x40000000) { ++ irq -= 1; ++ } ++ return irq; ++} +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/Kconfig linux-3.4.110/arch/nds32/platforms/Kconfig +--- linux-3.4.110.orig/arch/nds32/platforms/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/Kconfig 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,122 @@ ++choice ++ prompt "platform type" ++ default PLAT_AG101P ++ ++config PLAT_VEP ++ bool "vep platform" ++ select CPU_CUSTOM ++ select PLATFORM_INTC ++ ++config PLAT_AG101 ++ bool "ag101 platform" ++ select CPU_N1213 ++ select CPU_N1213_43U1HA0 ++ select PLATFORM_INTC ++ ++config PLAT_AG102 ++ bool "ag102 platform" ++ select CPU_N1233F ++ select PLATFORM_AMIC ++ ++config PLAT_AG101P ++ bool "ag101p platform" ++ select CPU_CUSTOM ++ select PLATFORM_INTC if !IVIC ++ select PLATFORM_NOINTC if IVIC ++ ++config PLAT_QEMU ++ bool "qemu platform" ++ select CPU_CUSTOM ++ select PLATFORM_INTC ++endchoice ++ ++config PLATFORM_NOINTC ++ def_bool n ++ depends on PLAT_AG101P ++ ++config PLATFORM_INTC ++ def_bool n ++ depends on !PLAT_AG102 ++ ++config PLATFORM_AMIC ++ def_bool n ++ depends on PLAT_AG102 ++ ++config ARCH_WANT_OPTIONAL_GPIOLIB ++ bool "Arch Want Optional GPIOLIB" ++ default y ++ ++if PLAT_VEP ++source "arch/nds32/platforms/vep/Kconfig" ++endif ++ ++if PLAT_AG101 ++source "arch/nds32/platforms/ag101/Kconfig" ++endif ++ ++if PLAT_AG102 ++source "arch/nds32/platforms/ag102/Kconfig" ++endif ++ ++if PLAT_AG101P ++source "arch/nds32/platforms/ag101p/Kconfig" ++endif ++ ++if PLAT_QEMU ++source "arch/nds32/platforms/qemu/Kconfig" ++endif ++ ++menu "Common Platform Options" ++ ++config PLATFORM_AHBDMA ++ tristate "AHB DMA Support" ++ help ++ AHB DMA service API support for other device drivers ++ ++config PLATFORM_APBDMA ++ tristate "APB DMA Support" ++ help ++ AHB DMA service API support for other device drivers ++ ++config SYS_CLK ++ int "AHB System Clock" ++ default 67737600 ++ help ++ Manual setting of AHB clock, must match the jumper setting on ++ the board, or the system time won't be correctly calculated. ++ Notice that even when AUTO_SYS_CLK is ON, this value is still ++ required for adjusting minor time offsets. However, the influence ++ should be within micro-second to nano-second scale. ++ ++config UART_CLK ++ int "UART Clock" ++ default 18432000 ++ help ++ Change the UART clock in case of non-3.6864MHz OSC is used as main ++ clock source, or an external UART clock source is fed from GPIO23. ++ To support external UART clock from GPIO23, set PMU ++ "Multi-Function Port Setting Register" bit #8 (UartClkSel) to 1. ++ This control register can be found at physical address 0x98100028 ++ If this options is changed, please also append "38400" to your ++ kernel command line, e.g.: ++ console=uart,shift,2,io,0xF9820000,38400 ++ Note: For A320, the default UART clock is obtained by = 5 * OSC = ++ 5 * 3.6864MHz = 18.432MHz. ++ ++menu "Memory configuration" ++ ++config SDRAM_SIZE ++ hex "SDRAM Size (hex)" ++ default 4000000 ++ ---help--- ++ RAM size ++ ++config MEMORY_START ++ hex "Physical memory start address" ++ default "0x00000000" ++ ---help--- ++ Physical memory start address, you may modify it if it is porting to ++ a new SoC with different start address. ++endmenu ++ ++endmenu +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/Makefile linux-3.4.110/arch/nds32/platforms/Makefile +--- linux-3.4.110.orig/arch/nds32/platforms/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/Makefile 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,25 @@ ++obj-y := timer.o ++ ++ifdef CONFIG_FUNCTION_TRACER ++CFLAGS_REMOVE_timer.o = -pg ++endif ++ ++obj-$(CONFIG_PLATFORM_NOINTC) += nointc.o ++obj-$(CONFIG_PLATFORM_INTC) += intc.o ++obj-$(CONFIG_PLATFORM_AMIC) += amic.o ++ ++ifeq ("$(CONFIG_PLATFORM_AHBDMA)", "y") ++ obj-y += dmad_intc.o dmad.o ++else ++ ifeq ("$(CONFIG_PLATFORM_APBDMA)", "y") ++ obj-y += dmad_intc.o dmad.o ++ endif ++endif ++ ++obj-$(CONFIG_PCI) += ftpci.o pci_intc.o ++ ++obj-$(CONFIG_PLAT_VEP) += vep/ ++obj-$(CONFIG_PLAT_AG101) += ag101/ ++obj-$(CONFIG_PLAT_AG102) += ag102/ ++obj-$(CONFIG_PLAT_AG101P) += ag101p/ ++obj-$(CONFIG_PLAT_QEMU) += qemu/ +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/nointc.c linux-3.4.110/arch/nds32/platforms/nointc.c +--- linux-3.4.110.orig/arch/nds32/platforms/nointc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/nointc.c 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,134 @@ ++/* ++ * linux/arch/nds32/platforms/intc.c ++ * ++ * Faraday FTINTC010 Master Interrupt Controller Device Driver Implementation ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/irq.h> ++ ++static void nointc_ack_irq(struct irq_data *data) ++{ ++ SET_INT_PEND2(1 << data->irq); ++#if 0 ++ asm volatile ("mtsr %0, $INT_PEND2\n\t" ++ "dsb\n\t"::"r" (1 << data->irq)); ++#endif ++#if 0 ++ asm volatile ("mfsr $r6, $INT_MASK2\n\t" ++ "and $r6, $r6,%0\n\t" ++ "mtsr $r6, $INT_MASK2\n\t" ++ "dsb\n\t"::"r" (~(1 << data->irq)):"$r6"); ++#endif ++} ++ ++static void nointc_mask_irq(struct irq_data *data) ++{ ++ unsigned long int_mask2 = GET_INT_MASK2(); ++ SET_INT_MASK2(int_mask2 & (~(1 << data->irq))); ++#if 0 ++ asm volatile ("mfsr $r6, $INT_MASK2\n\t" ++ "and $r6, $r6,%0\n\t" ++ "mtsr $r6, $INT_MASK2\n\t" ++ "dsb\n\t"::"r" (~(1 << data->irq)):"$r6"); ++#endif ++} ++ ++static void nointc_mask_ack_irq(struct irq_data *data) ++{ ++ unsigned long int_mask2 = GET_INT_MASK2(); ++ SET_INT_MASK2(int_mask2 & (~(1 << data->irq))); ++ SET_INT_PEND2(1 << data->irq); ++#if 0 ++ asm volatile ("not $r7, %0\n\t" ++ "mfsr $r6, $INT_MASK2\n\t" ++ "and $r6, $r6, $r7\n\t" ++ "mtsr $r6, $INT_MASK2\n\t" ++ "mtsr %0, $INT_PEND2\n\t" ++ "dsb\n\t"::"r" (1 << data->irq):"$r6", "$r7"); ++#endif ++ ++} ++ ++static void nointc_unmask_irq(struct irq_data *data) ++{ ++ unsigned long int_mask2 = GET_INT_MASK2(); ++ SET_INT_MASK2(int_mask2 | (1 << data->irq)); ++#if 0 ++ asm volatile ("mfsr $r6, $INT_MASK2\n\t" ++ "or $r6, $r6,%0\n\t" ++ "mtsr $r6, $INT_MASK2\n\t" ++ "dsb\n\t"::"r" (1 << data->irq):"$r6"); ++#endif ++} ++ ++static int nointc_set_type(struct irq_data *data, unsigned int flow_type) ++{ ++ printk(KERN_WARNING "interrupt type is not configurable\n"); ++ return 0; ++} ++ ++static struct irq_chip nointc_chip = { ++ ++ .irq_ack = nointc_ack_irq, ++ .irq_mask = nointc_mask_irq, ++ .irq_mask_ack = nointc_mask_ack_irq, ++ .irq_unmask = nointc_unmask_irq, ++ .irq_set_type = nointc_set_type, ++}; ++ ++static unsigned int __initdata nivic_map[6] = { 6, 2, 10, 16, 24, 32 }; ++ ++void __init nointc_init_irq(void) ++{ ++ int i; ++ unsigned long int_trigger_type, int_vec_base, nivic; ++ ++ int_vec_base = GET_IVB(); ++ ++#if 0 ++ asm volatile ("mfsr %0, $IVB\n":"=r" (int_vec_base)); ++#endif ++ ++ if (((int_vec_base & IVB_mskIVIC_VER) >> IVB_offIVIC_VER) == 0) { ++ panic("Unable to use NOINTC option to boot on this cpu\n"); ++ } ++ ++ nivic = (int_vec_base & IVB_mskNIVIC) >> IVB_offNIVIC; ++ if (nivic >= (sizeof nivic_map / sizeof nivic_map[0])) { ++ panic ++ ("The number of input for IVIC Controller is not supported on this cpu\n"); ++ } ++ nivic = nivic_map[nivic]; ++ ++ int_trigger_type = GET_INT_TRIGGER(); ++#if 0 ++ asm volatile ("mfsr %0, $INT_TRIGGER\n":"=r" (int_trigger_type)); ++#endif ++ ++ for (i = 0; i < nivic; i++) { ++ irq_set_chip(i, &nointc_chip); ++ if (int_trigger_type & (1 << i)) ++ /* edge-triggered */ ++ irq_set_handler(i, handle_edge_irq); ++ else ++ /* level-triggered */ ++ irq_set_handler(i, handle_level_irq); ++ } ++} +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/pci_intc.c linux-3.4.110/arch/nds32/platforms/pci_intc.c +--- linux-3.4.110.orig/arch/nds32/platforms/pci_intc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/pci_intc.c 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,93 @@ ++/* ++ * linux/arch/nds32/platforms/pci_intc.c ++ * ++ * Faraday PCI Bridge Interrupt Process Driver Implementation ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2008 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * ++ * ChangeLog ++ * ++ * Luke Lee 09/15/2005 Created. ++ * Luke Lee 09/27/2005 Fixed for parent chip registration and notification. ++ * Peter Liao 09/28/2005 Port for PCI IP ++ */ ++ ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <asm/io.h> ++ ++#include <asm/spec.h> ++#include <asm/ftpci.h> ++ ++#define IPMODULE PCIC ++#define IPNAME FPCI010 ++ ++/* ++ * Level trigger IRQ chip methods ++ */ ++ ++static void intc_ftpci100_level_ack_irq(unsigned int irq) ++{ ++ ftpci_clear_irq(irq - PLATFORM_PCI_IRQ_BASE); ++} ++ ++static void intc_ftpci100_level_mask_irq(unsigned int irq) ++{ ++ ftpci_mask_irq(irq - PLATFORM_PCI_IRQ_BASE); ++} ++ ++static void intc_ftpci100_level_unmask_irq(unsigned int irq) ++{ ++ ftpci_unmask_irq(irq - PLATFORM_PCI_IRQ_BASE); ++} ++ ++static struct irq_chip intc_ftpci100_level_chip = { ++ .ack = intc_ftpci100_level_ack_irq, ++ .mask = intc_ftpci100_level_mask_irq, ++ .unmask = intc_ftpci100_level_unmask_irq, ++}; ++ ++void pci_irq_rounter(unsigned int irq, struct irq_desc *desc) ++{ ++ int pci_irq; ++ struct irq_desc *pci_desc; ++ ++ desc->chip->mask(irq); ++ desc->chip->ack(irq); ++ ++ pci_irq = ftpci_get_irq(); ++ if (pci_irq >= 0) { ++ pci_irq += PCIC_FTPCI100_IRQ0; ++ pci_desc = irq_desc + pci_irq; ++ pci_desc->handle_irq(pci_irq, pci_desc); ++ } ++ ++ desc->chip->unmask(irq); ++} ++ ++int __init intc_ftpci100_init_irq(void) ++{ ++ int i; ++ ++ /* Register all IRQ */ ++ for (i = PCIC_FTPCI100_IRQ0; ++ i < PCIC_FTPCI100_IRQ0 + PCIC_FTPCI100_IRQ_COUNT; i++) { ++ // level trigger ++ set_irq_chip(i, &intc_ftpci100_level_chip); ++ set_irq_handler(i, handle_level_irq); ++ } ++#ifndef CONFIG_PLAT_AG101 ++ set_irq_chained_handler(PLATFORM_PCI_IRQ, pci_irq_rounter); ++#endif ++ ++ return 0; ++} ++ ++subsys_initcall(intc_ftpci100_init_irq); +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/qemu/devices.c linux-3.4.110/arch/nds32/platforms/qemu/devices.c +--- linux-3.4.110.orig/arch/nds32/platforms/qemu/devices.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/qemu/devices.c 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,124 @@ ++#include <linux/serial_8250.h> ++#include <asm/mach-types.h> ++#include <asm/sizes.h> ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/spec.h> ++#include <asm/intc.h> ++#include <asm/timer.h> ++ ++const struct map_desc platform_io_desc[] __initdata = { ++ {UART0_VA_BASE, UART0_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {UART1_VA_BASE, UART1_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {INTC_FTINTC010_0_VA_BASE, INTC_FTINTC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {TIMER_FTTMR010_0_VA_BASE, TIMER_FTTMR010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {SSP_FTSSP010_0_VA_BASE, SSP_FTSSP010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {PMU_FTPMU010_0_VA_BASE, PMU_FTPMU010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {MAC_FTMAC100_0_VA_BASE, MAC_FTMAC100_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {SDC_FTSDC010_0_VA_BASE, SDC_FTSDC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {RTC_FTRTC010_0_VA_BASE, RTC_FTRTC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {WDT_FTWDT010_0_VA_BASE, WDT_FTWDT010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {GPIO_FTGPIO010_0_VA_BASE, GPIO_FTGPIO010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {CFC_FTCFC010_0_VA_BASE, CFC_FTCFC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {LCD_FTLCDC100_0_VA_BASE, LCD_FTLCDC100_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {I2C_FTI2C010_0_VA_BASE, I2C_FTI2C010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {DMAC_FTDMAC020_0_VA_BASE, DMAC_FTDMAC020_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {APBBRG_FTAPBBRG020S_0_VA_BASE, APBBRG_FTAPBBRG020S_0_PA_BASE, ++ PAGE_SIZE, MT_DEVICE_NCB}, ++ {PCIIO_0_VA_BASE, PCIIO_0_PA_BASE, 0x000FF000, MT_DEVICE_NCB}, ++ {PCIC_FTPCI100_0_VA_BASE, PCIC_FTPCI100_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {LED_VA_BASE, LED_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {SDMC_FTSDMC021_VA_BASE, SDMC_FTSDMC021_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {L2CC_VA_BASE, L2CC_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB} ++}; ++ ++static void __init platform_map_io(void) ++{ ++ iotable_init((struct map_desc *)platform_io_desc, ++ ARRAY_SIZE(platform_io_desc)); ++} ++ ++static struct uart_port uart0 = { ++ .membase = (void __iomem *)UART0_VA_BASE, ++ .irq = UART0_IRQ, ++ .uartclk = CONFIG_UART_CLK, ++ .regshift = 2, ++ .iotype = UPIO_MEM, ++ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, ++ .line = 0, ++ .mapbase = UART0_PA_BASE, ++}; ++ ++static struct uart_port uart1 = { ++ .membase = (void __iomem *)UART1_VA_BASE, ++ .irq = UART1_IRQ, ++ .uartclk = CONFIG_UART_CLK, ++ .regshift = 2, ++ .iotype = UPIO_MEM, ++ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, ++ .line = 1, ++ .mapbase = UART1_PA_BASE, ++}; ++ ++static void __init soc_init(void) ++{ ++ early_serial_setup(&uart0); ++ early_serial_setup(&uart1); ++} ++ ++static struct resource smc91x_resources[] = { ++ [0] = { ++ .name = "smc91x", ++ .start = 0x92100000, ++ .end = 0x92110000, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = 25, ++ .end = 25, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device smc91x_device = { ++ .name = "smc91x", ++ .id = 0, ++ .num_resources = ARRAY_SIZE(smc91x_resources), ++ .resource = smc91x_resources, ++}; ++ ++static __init int smc_init(void) ++{ ++ int ret; ++ ret = platform_device_register(&smc91x_device); ++ if (ret == 0) ++ printk("smc is installed now.\n"); ++ else ++ printk("smc failed.\n"); ++ return 0; ++} ++ ++module_init(smc_init); ++ ++MACHINE_START(FARADAY, PLATFORM_NAME) ++ .param_offset = BOOT_PARAMETER_PA_BASE, ++ .map_io = platform_map_io, ++ .init_irq = platform_init_irq, ++ .timer = &platform_timer, /* defined in timer.c */ ++ .init_machine = soc_init, ++MACHINE_END +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/qemu/Kconfig linux-3.4.110/arch/nds32/platforms/qemu/Kconfig +--- linux-3.4.110.orig/arch/nds32/platforms/qemu/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/qemu/Kconfig 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,3 @@ ++menu "QEMU Platform Options" ++ ++endmenu +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/qemu/Makefile linux-3.4.110/arch/nds32/platforms/qemu/Makefile +--- linux-3.4.110.orig/arch/nds32/platforms/qemu/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/qemu/Makefile 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1 @@ ++obj-y = devices.o +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/timer.c linux-3.4.110/arch/nds32/platforms/timer.c +--- linux-3.4.110.orig/arch/nds32/platforms/timer.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/timer.c 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,250 @@ ++/* ++ * linux/arch/nds32/platforms/timer.c ++ * ++ * Faraday FTTMR010 Timer Device Driver Implementation ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ */ ++ ++#include <linux/irq.h> ++#include <linux/clocksource.h> ++#include <linux/clockchips.h> ++ ++#include <linux/interrupt.h> ++#include <linux/ioport.h> ++#include <linux/cpufreq.h> ++ ++#include <asm/mach/time.h> ++#include <asm/timer.h> ++#include <asm/spec.h> ++ ++#define REG32_TMR(x) *(volatile unsigned long *)(TIMER_FTTMR010_VA_BASE + (x)) ++#define APB_CLK_IN (AHB_CLK_IN / 2) ++ ++static struct resource timer_resource = { ++ .name = "Timer 1~3", ++ .start = TIMER_FTTMR010_VA_BASE, ++ .end = TIMER_FTTMR010_VA_LIMIT, ++}; ++ ++static inline cycle_t clocksource_read_cycles(struct clocksource *cs) ++{ ++ return (cycle_t) REG32_TMR(TIMER3_COUNT); ++} ++ ++static void clksrc_fttmr010_resume(struct clocksource *cs) ++{ ++ REG32_TMR(TIMER_INTRMASK) |= TM3MATCH1 | TM3MATCH2 | TM3OVERFLOW; ++ REG32_TMR(TIMER_TMCR) |= TM3UPDOWN | TM3ENABLE; ++} ++ ++static struct clocksource clksrc_fttmr010 = { ++ .name = "fttmr010_tm1", ++ .rating = 300, ++ .read = clocksource_read_cycles, ++ .mask = CLOCKSOURCE_MASK(32), ++ .shift = 21, ++ .flags = CLOCK_SOURCE_IS_CONTINUOUS, ++ .resume = clksrc_fttmr010_resume, ++}; ++ ++static void __init fttmr010_clocksource_init(void) ++{ ++ clksrc_fttmr010.mult = ++ clocksource_hz2mult(APB_CLK_IN, clksrc_fttmr010.shift); ++ ++ REG32_TMR(TIMER3_LOAD) = 0; ++ REG32_TMR(TIMER_INTRMASK) |= TM3MATCH1 | TM3MATCH2 | TM3OVERFLOW; ++ REG32_TMR(TIMER_TMCR) |= TM3UPDOWN | TM3ENABLE; ++ if (clocksource_register(&clksrc_fttmr010)) ++ printk(KERN_ERR "Error: failed to register %s\n", ++ clksrc_fttmr010.name); ++} ++ ++static int fttmr010_set_next_event(unsigned long cycles, ++ struct clock_event_device *evt) ++{ ++ REG32_TMR(TIMER1_LOAD) = cycles; ++ return 0; ++} ++ ++static void fttmr010_set_mode(enum clock_event_mode mode, ++ struct clock_event_device *evt) ++{ ++ switch (mode) { ++ case CLOCK_EVT_MODE_ONESHOT: ++ REG32_TMR(TIMER1_LOAD) = 0xffffffff; ++ REG32_TMR(TIMER_TMCR) |= TM1ENABLE; ++ break; ++ ++ case CLOCK_EVT_MODE_PERIODIC: ++ REG32_TMR(TIMER1_COUNT) = APB_CLK_IN / HZ - 1; ++ REG32_TMR(TIMER1_LOAD) = APB_CLK_IN / HZ - 1; ++ REG32_TMR(TIMER_TMCR) |= TM1ENABLE; ++ break; ++ case CLOCK_EVT_MODE_UNUSED: ++ break; ++ case CLOCK_EVT_MODE_SHUTDOWN: ++ REG32_TMR(TIMER_TMCR) &= ~TM1ENABLE; ++ break; ++ case CLOCK_EVT_MODE_RESUME: ++ REG32_TMR(TIMER_INTRMASK) |= TM1MATCH1 | TM1MATCH2; ++ REG32_TMR(TIMER_TMCR) |= TM1ENABLE | TM1OFENABLE; ++ break; ++ } ++} ++ ++static struct clock_event_device clockevent_fttmr010 = { ++ .name = "fttmr010_tm1", ++ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, ++ .shift = 32, ++ .cpumask = cpu_all_mask, ++ .set_next_event = fttmr010_set_next_event, ++ .set_mode = fttmr010_set_mode, ++}; ++ ++static irqreturn_t timer1_interrupt(int irq, void *dev_id) ++{ ++ struct clock_event_device *evt = dev_id; ++ ++ REG32_TMR(TIMER_INTRSTATE) = TM1MATCH1 | TM1MATCH2 | TM1OVERFLOW; ++ ++ evt->event_handler(evt); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct irqaction timer1_irq = { ++ .name = "Timer Tick", ++ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, ++ .handler = timer1_interrupt, ++ .dev_id = &clockevent_fttmr010 ++}; ++ ++static void __init fttmr010_clockevent_init(void) ++{ ++ clockevent_fttmr010.mult = ++ div_sc(APB_CLK_IN, NSEC_PER_SEC, clockevent_fttmr010.shift); ++ clockevent_fttmr010.max_delta_ns = ++ clockevent_delta2ns(0xffffffff, &clockevent_fttmr010); ++ clockevent_fttmr010.min_delta_ns = ++ clockevent_delta2ns(3, &clockevent_fttmr010); ++ ++ clockevents_register_device(&clockevent_fttmr010); ++ setup_irq(TIMER_FTTMR010_IRQ0, &timer1_irq); ++} ++ ++static void fttmr010_resume(void) ++{ ++} ++ ++#ifdef CONFIG_CPU_FREQ ++void ag102_calc_ahb_clk(void); ++static int fttmr010_cpufreq_notifier(struct notifier_block *nb, ++ unsigned long val, void *data) ++{ ++ if (val == CPUFREQ_POSTCHANGE) { ++ ++ unsigned long flags; ++#ifdef CONFIG_PLAT_AG102 ++ ag102_calc_ahb_clk(); ++#endif ++ local_irq_save(flags); ++ ++ clocksource_unregister(&clksrc_fttmr010); ++ ++ clksrc_fttmr010.mult = ++ clocksource_hz2mult(APB_CLK_IN, clksrc_fttmr010.shift); ++#ifdef CONFIG_PLAT_AG101 ++ clksrc_fttmr010.mult_orig = ++ clocksource_hz2mult(APB_CLK_IN, clksrc_fttmr010.shift); ++#endif ++ ++ if (clocksource_register(&clksrc_fttmr010)) ++ printk(KERN_ERR "Error: failed to re-register %s\n", ++ clksrc_fttmr010.name); ++ else ++ printk("Re-register clock source %s\n", ++ clksrc_fttmr010.name); ++ ++ local_irq_restore(flags); ++ ++ clockevent_fttmr010.mult = ++ div_sc(APB_CLK_IN, NSEC_PER_SEC, clockevent_fttmr010.shift); ++ ++#ifdef CONFIG_PLAT_AG102 ++ printk("Add timer clock modifier...\n"); ++ fttmr010_set_mode(CLOCK_EVT_MODE_PERIODIC, 0); ++#endif ++ } ++ ++ return 0; ++} ++ ++static struct notifier_block fttmr010_cpufreq_notifier_block = { ++ .notifier_call = fttmr010_cpufreq_notifier ++}; ++ ++static int __init fttmr010_init_cpufreq(void) ++{ ++ if (cpufreq_register_notifier(&fttmr010_cpufreq_notifier_block, ++ CPUFREQ_TRANSITION_NOTIFIER)) ++ printk("fttmr010: Failed to setup cpufreq notifier\n"); ++ ++ return 0; ++} ++ ++core_initcall(fttmr010_init_cpufreq); ++#endif ++ ++static int clksrc_init; ++static void __init fttmr010_init(void) ++{ ++ request_resource(&ioport_resource, &timer_resource); ++ ++ printk ++ ("FTTMR010 timer 1 installed on IRQ %d, with clock %d at %d HZ.\r\n", ++ TIMER_FTTMR010_IRQ0, APB_CLK_IN, HZ); ++ ++ REG32_TMR(TIMER_TMCR) &= ++ ~(TM1ENABLE | TM1CLOCK | TM1OFENABLE | TM1UPDOWN); ++ REG32_TMR(TIMER_INTRMASK) |= TM1MATCH1 | TM1MATCH2; ++ REG32_TMR(TIMER_TMCR) |= TM1OFENABLE; ++ ++ fttmr010_clocksource_init(); ++ fttmr010_clockevent_init(); ++ clksrc_init = 1; ++} ++ ++struct sys_timer platform_timer = { ++ .init = fttmr010_init, ++ .resume = fttmr010_resume, ++}; ++ ++unsigned long long sched_clock(void) ++{ ++ if (clksrc_init) ++ return ++ clocksource_cyc2ns(clocksource_read_cycles ++ (&clksrc_fttmr010), clksrc_fttmr010.mult, ++ clksrc_fttmr010.shift); ++ else ++ return (unsigned long long)(jiffies - INITIAL_JIFFIES) ++ * (NSEC_PER_SEC / HZ); ++} +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/vep/devices.c linux-3.4.110/arch/nds32/platforms/vep/devices.c +--- linux-3.4.110.orig/arch/nds32/platforms/vep/devices.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/vep/devices.c 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,83 @@ ++#include <linux/serial_8250.h> ++#include <asm/mach-types.h> ++#include <asm/sizes.h> ++#include <asm/mach/arch.h> ++#include <asm/mach/map.h> ++#include <asm/spec.h> ++#include <asm/intc.h> ++#include <asm/timer.h> ++ ++const struct map_desc platform_io_desc[] __initdata = { ++ {UART0_VA_BASE, UART0_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {UART1_VA_BASE, UART1_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {INTC_FTINTC010_0_VA_BASE, INTC_FTINTC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {TIMER_FTTMR010_0_VA_BASE, TIMER_FTTMR010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {SSP_FTSSP010_0_VA_BASE, SSP_FTSSP010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {PMU_FTPMU010_0_VA_BASE, PMU_FTPMU010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {MAC_FTMAC100_0_VA_BASE, MAC_FTMAC100_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {SDC_FTSDC010_0_VA_BASE, SDC_FTSDC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {RTC_FTRTC010_0_VA_BASE, RTC_FTRTC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {WDT_FTWDT010_0_VA_BASE, WDT_FTWDT010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {GPIO_FTGPIO010_0_VA_BASE, GPIO_FTGPIO010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {CFC_FTCFC010_0_VA_BASE, CFC_FTCFC010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {LCD_FTLCDC100_0_VA_BASE, LCD_FTLCDC100_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {I2C_FTI2C010_0_VA_BASE, I2C_FTI2C010_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {DMAC_FTDMAC020_0_VA_BASE, DMAC_FTDMAC020_0_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {APBBRG_FTAPBBRG020S_0_VA_BASE, APBBRG_FTAPBBRG020S_0_PA_BASE, ++ PAGE_SIZE, MT_DEVICE_NCB}, ++ {LED_VA_BASE, LED_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB}, ++ {SDMC_FTSDMC021_VA_BASE, SDMC_FTSDMC021_PA_BASE, PAGE_SIZE, ++ MT_DEVICE_NCB}, ++ {L2CC_VA_BASE, L2CC_PA_BASE, PAGE_SIZE, MT_DEVICE_NCB} ++}; ++ ++static void __init platform_map_io(void) ++{ ++ iotable_init((struct map_desc *)platform_io_desc, ++ ARRAY_SIZE(platform_io_desc)); ++} ++ ++static struct uart_port uart0 = { ++ .membase = (void __iomem *)UART0_VA_BASE, ++ .irq = UART0_IRQ, ++ .uartclk = CONFIG_UART_CLK, ++ .regshift = 2, ++ .iotype = UPIO_MEM, ++ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, ++ .line = 0, ++ .mapbase = UART0_PA_BASE, ++}; ++ ++static struct uart_port uart1 = { ++ .membase = (void __iomem *)UART1_VA_BASE, ++ .irq = UART1_IRQ, ++ .uartclk = CONFIG_UART_CLK, ++ .regshift = 2, ++ .iotype = UPIO_MEM, ++ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, ++ .line = 1, ++ .mapbase = UART1_PA_BASE, ++}; ++ ++static void __init soc_init(void) ++{ ++ early_serial_setup(&uart0); ++ early_serial_setup(&uart1); ++} ++ ++MACHINE_START(FARADAY, PLATFORM_NAME) ++ .param_offset = BOOT_PARAMETER_PA_BASE,.map_io = platform_map_io,.init_irq = platform_init_irq,.timer = &platform_timer, /* defined in timer.c */ ++ .init_machine = soc_init, MACHINE_END +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/vep/Kconfig linux-3.4.110/arch/nds32/platforms/vep/Kconfig +--- linux-3.4.110.orig/arch/nds32/platforms/vep/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/vep/Kconfig 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,7 @@ ++menu "VEP Platform Options" ++ ++config CACHE_L2 ++ bool "Support L2 cache" ++ default n ++ ++endmenu +diff -Nur linux-3.4.110.orig/arch/nds32/platforms/vep/Makefile linux-3.4.110/arch/nds32/platforms/vep/Makefile +--- linux-3.4.110.orig/arch/nds32/platforms/vep/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/platforms/vep/Makefile 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1 @@ ++obj-y = devices.o +diff -Nur linux-3.4.110.orig/build_linux.sh linux-3.4.110/build_linux.sh +--- linux-3.4.110.orig/build_linux.sh 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/build_linux.sh 2016-04-07 10:20:51.018083964 +0200 +@@ -0,0 +1,202 @@ ++#!/bin/sh ++ ++export ARCH=nds32 ++ ++print_help() ++{ ++ echo "Usage: <platform> [platform_defconfig] [--bootm] [--ramdisk=<ramdisk absolute path>]" ++ echo "Stop Building." ++ exit ++} ++ ++BUILDBOOTM=0 ++BUILDBOOTPIMAGE=0 ++BUILDHEADERS=0 ++ ++case "$1" in ++ qemu) ++ TARGET=qemu_defconfig ++ IMAGE=qemu ++ export CROSS_COMPILE=nds32le-linux- ++ echo "Building $IMAGE kernel." ++ ;; ++ vep-be) ++ TARGET=vep-be_defconfig ++ IMAGE=vep-be ++ export CROSS_COMPILE=nds32be-linux- ++ echo "Building $IMAGE kernel." ++ ;; ++ vep-le) ++ TARGET=vep-le_defconfig ++ IMAGE=vep-le ++ export CROSS_COMPILE=nds32le-linux- ++ echo "Building $IMAGE kernel." ++ ;; ++ xc5) ++ TARGET=xc5_defconfig ++ IMAGE=xc5 ++ export CROSS_COMPILE=nds32le-linux- ++ echo "Building $IMAGE kernel." ++ ;; ++ xc5_8k) ++ TARGET=xc5_8k_defconfig ++ IMAGE=xc5_8k ++ export CROSS_COMPILE=nds32le-linux- ++ echo "Building $IMAGE kernel." ++ ;; ++ ag101a0) ++ TARGET=ag101a0_defconfig ++ IMAGE=ag101a0 ++ export CROSS_COMPILE=nds32le-linux- ++ echo "Building $IMAGE kernel." ++ ;; ++ ag101b0) ++ TARGET=ag101b0_defconfig ++ IMAGE=ag101b0 ++ export CROSS_COMPILE=nds32le-linux- ++ echo "Building $IMAGE kernel." ++ ;; ++ ag102) ++ TARGET=ag102_defconfig ++ IMAGE=ag102 ++ export CROSS_COMPILE=nds32le-linux- ++ echo "Building $IMAGE kernel." ++ ;; ++ u200) ++ TARGET=u200_defconfig ++ IMAGE=u200 ++ export CROSS_COMPILE=nds32le-linux- ++ echo "Building $IMAGE kernel." ++ ;; ++ xc5-qa) ++ TARGET=xc5-qa_defconfig ++ IMAGE=xc5-qa ++ export CROSS_COMPILE=nds32le-linux- ++ echo "Building $IMAGE kernel." ++ ;; ++ ag101-qa) ++ TARGET=ag101-qa_defconfig ++ IMAGE=ag101-qa ++ export CROSS_COMPILE=nds32le-linux- ++ echo "Building $IMAGE kernel." ++ ;; ++ *) ++ if [ $# = 1 ]; then ++ echo "No defconfig is given." ++ print_help ++ fi ++ if [ ! -e $2 ]; then ++ echo "Given defconfig is not exist." ++ print_help ++ elif [ ! -f $2 ]; then ++ echo "Given defconfig is not a file." ++ print_help ++ elif [ ! -s $2 ]; then ++ echo "Given defconfig is size 0." ++ print_help ++ elif [ ! -r $2 ]; then ++ echo "Given defconfig has no read attribute." ++ print_help ++ fi ++ TARGET=none ++ IMAGE=$1 ++ export CROSS_COMPILE=nds32le-linux- ++ echo "Building $IMAGE kernel." ++esac ++ ++ZIMAGE="$IMAGE"_zImage ++VMLINUZ="$IMAGE"_vmlinuz ++VMLINUX="$IMAGE"_vmlinux ++BOOTPIMAGE="$IMAGE"_bootpImage ++BOOTP="$IMAGE"_bootp ++BOOTM="$IMAGE"_bootm ++ ++for ARG in $@; do ++ if [ $ARG = $1 ]; then ++ continue ++ fi ++ ++ if [ $ARG = $2 ]; then ++ if [ $TARGET = "none" ]; then ++ continue ++ fi ++ fi ++ ++ case "$ARG" in ++ ++ --bootm) ++ BUILDBOOTM=1 ++ ;; ++ ++ --ramdisk=*) ++ BUILDBOOTPIMAGE=1 ++ RAMDISK=${ARG#*=} ++ if [ ! -e $RAMDISK ]; then ++ echo "Given ramdisk is not exist." ++ print_help ++ elif [ ! -f $RAMDISK ]; then ++ echo "Given ramdisk is not a file." ++ print_help ++ elif [ ! -s $RAMDISK ]; then ++ echo "Given ramdisk is size 0." ++ print_help ++ elif [ ! -r $RAMDISK ]; then ++ echo "Given ramdisk has no read attribute." ++ print_help ++ fi ++ ;; ++# --headers) ++# BUILDHEADERS=1 ++# git apply ../linux-2.6-patch/headers.patch ++# echo "Exporting kernel headers." ++# ;; ++ *) ++ print_help ++ esac ++done ++ ++if [ "$OSTYPE" = "cygwin" ]; then ++ HOST_LOADLIBES=-lintl\ -lcurses ++fi ++export HOST_LOADLIBES ++ ++which ${CROSS_COMPILE}gcc &> /dev/null || export CROSS_COMPILE=nds32-elf- ++ ++make mrproper | tee $IMAGE.log ++if [ $TARGET != "none" ]; then ++ make $TARGET| tee -a $IMAGE.log ++else ++ cp $2 .config ++fi ++ ++if [ $BUILDHEADERS = 1 ]; then ++ make dep | tee -a $IMAGE.log ++ make headers_install | tee -a $IMAGE.log ++else ++ make | tee -a $IMAGE.log ++ ++ cp arch/nds32/boot/zImage ./$ZIMAGE | tee -a $IMAGE.log ++ cp arch/nds32/boot/compressed/vmlinux ./$VMLINUZ | tee -a $IMAGE.log ++ cp ./vmlinux ./$VMLINUX | tee -a $IMAGE.log ++ ++ if [ $BUILDBOOTPIMAGE = 1 ]; then ++ make bootpImage INITRD=$RAMDISK | tee -a $IMAGE.log ++ cp arch/nds32/boot/bootpImage ./$BOOTPIMAGE | tee -a $IMAGE.log ++ cp arch/nds32/boot/bootp/bootp ./$BOOTP | tee -a $IMAGE.log ++ fi ++ ++ if [ $BUILDBOOTM = 1 ]; then ++ if [ -e "../u-boot/tools/mkimage" ]; then ++ ../u-boot/tools/mkimage \ ++ -A nds32 \ ++ -O linux \ ++ -T kernel \ ++ -C none \ ++ -a 0x500000 \ ++ -e 0x500040 \ ++ -d ./arch/nds32/boot/zImage $BOOTM | tee -a $IMAGE.log ++ else ++ echo "Error: ../u-boot/tools/mkimage not found" | tee -a $IMAGE.log ++ fi ++ fi ++fi +diff -Nur linux-3.4.110.orig/drivers/block/ftcfc010.c linux-3.4.110/drivers/block/ftcfc010.c +--- linux-3.4.110.orig/drivers/block/ftcfc010.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/block/ftcfc010.c 2016-04-07 10:20:51.022084119 +0200 +@@ -0,0 +1,1299 @@ ++/* drivers/block/CPESD/ftsdc010.c ++ ******************************************************************************* ++ * Faraday FTSDC010 Device Driver ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * ++ * All Rights Reserved ++ * ++ * Porting to Linux 2.6 on 20050815 ++ * Author: Chris Lee, I-Jui Sung, Peter Liao (support APB DMA) ++ * Version: 0.2 ++ * History: ++ * 0.1 new creation ++ * 0.2 Porting to meet the style of linux dma ++ * 0.3 modify dma usage to virtual irq of dma interrupt ++ * 0.4 (20050701) Improve r/w performance ++ * 0.5 Porting to Linux 2.6 and replace busy_loop checking with timer's timeout ++ * Todo: ++ ******************************************************************************* ++ */ ++ ++#define DEBUG_OFF 0 ++ ++#define DEBUG( enable, tagged, ...) \ ++do{ \ ++ if( enable){ \ ++ if( tagged) \ ++ printk( "[ %30s() ] ", __func__); \ ++ printk( __VA_ARGS__); \ ++ } \ ++} while( 0) ++ ++#include <linux/interrupt.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/ioport.h> ++#include <linux/hdreg.h> /* HDIO_GETGEO */ ++#include <linux/fs.h> ++#include <linux/blkdev.h> ++#include <linux/buffer_head.h> /* invalidate_bdev */ ++#include <linux/bio.h> ++#include <linux/pci.h> ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include <asm/spec.h> ++#include <asm/dmad.h> ++ ++#define IPMODULE CFC ++#define IPNAME FTCFC010 ++ ++#include "ftcfc010.h" ++ ++static int hardsect_size = 512; ++module_param( hardsect_size, int, 0); ++ ++static int cf_major = 0; /* must be declared before including blk.h */ ++#define DEVICE_NAME "Faraday CFC" /* name for messaging */ ++ ++#define FTCFC_VA_BASE IP_VA_BASE( 0) ++#define FTCFC_PA_BASE IP_PA_BASE( 0) ++#define FTCFC_IRQ CFC_FTCFC010_IRQ1 ++ ++#undef CF_DEBUG ++#define CF_DEBUG 0 ++struct block_device_operations cf_fops; ++ ++typedef struct cf_dev { ++ ++ int size; /* device size in sectors */ ++ int usage; /* # of users currently */ ++ int media_change; /* Flag: media changed? */ ++ struct gendisk *gd; /* The gendisk structure */ ++ spinlock_t lock; /* For mutual exclusion */ ++ struct request_queue *queue; /* The device request queue */ ++ int card_state; ++ u32 lba_sec_offset; ++ dmad_chreq ch_req; ++ ++} cf_dev_t; ++ ++static cf_dev_t *cf_devices; ++static cf_card_t cf_card_info; ++ ++static dma_addr_t dma_buf; ++struct completion cf_dma_cmpl; ++ ++static uint first_run; ++static uint cf_err_code; ++ ++static int g_cf_sectors; ++ ++static void SetTransferSize( u32 Addr, u32 Type, u32 OP_Type, u32 Inc_Addr, u32 Transize) ++{ ++ u32 ctrl_reg, buf_ctrl_reg; ++ DEBUG( CF_DEBUG, 1, "Enter\n"); ++ ++ /* set read/write command */ ++ while( cfc->HostStatus & BUF_ACTIVE_BIT) ++ ; ++ ++ /* Set Transfer size mode to default */ ++ cfc->TransSzMode2En = 0; ++ ++ /* set 8/16 bits mode */ ++ ctrl_reg = cfc->ControlReg; ++ ++ if( Transize == SIZE_1_BYTE) ++ ctrl_reg = ( ctrl_reg & ~MODE_BIT) | BYTE_MODE; ++ else ++ ctrl_reg = ( ctrl_reg & ~MODE_BIT) | WORD_MODE; ++ ++ DEBUG( CF_DEBUG, 1, "ctrl 1: 0x%08lx\n", ( unsigned long)ctrl_reg); ++ cfc->ControlReg = ctrl_reg; ++ ++ /* Write command to buffer */ ++ buf_ctrl_reg = cfc->BuffCtrlReg; ++ buf_ctrl_reg = ( buf_ctrl_reg & ~ADR_BIT & ~TYPE_BIT & ~RW_BIT & ~INCADR_BIT & ~TRANS_SIZE_CONTROL_BIT) ++ | Addr | Type | OP_Type | Inc_Addr | ( Transize << TRANS_SIZE_LOC); ++ ++ cfc->BuffCtrlReg = buf_ctrl_reg; ++ DEBUG( CF_DEBUG, 1, "buf_ctrl 1: 0x%08lx\n", ( unsigned long)buf_ctrl_reg); ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++} ++ ++static void SetTransferSizeEx( u32 Addr, u32 Type, u32 OP_Type, u32 Inc_Addr, u32 Transize) ++{ ++ u32 ctrl_reg, buf_ctrl_reg; ++ ++ DEBUG( CF_DEBUG, 1, "Enter, SetTransferSizeEx: %d\n", Transize); ++ ++ /* set read/write command */ ++ while( cfc->HostStatus & BUF_ACTIVE_BIT) ++ ; ++ ++ /* Set Transfer size mode to default */ ++ cfc->TransSzMode2En = 1; ++ ++ /* set 8/16 bits mode */ ++ ctrl_reg = cfc->ControlReg; ++ ++ if( Transize == SIZE_1_BYTE) ++ ctrl_reg = ( ctrl_reg & ~MODE_BIT) | BYTE_MODE; ++ else ++ ctrl_reg = ( ctrl_reg & ~MODE_BIT) | WORD_MODE; ++ ++ cfc->ControlReg = ctrl_reg; ++ ++ /* Set Transfer size mode2 reg in FTCFC */ ++ cfc->TransSzMode2Cnt = Transize - 1; ++ ++ /* Write command to buffer */ ++ buf_ctrl_reg = cfc->BuffCtrlReg; ++ buf_ctrl_reg = ( buf_ctrl_reg & ~ADR_BIT & ~TYPE_BIT & ~RW_BIT & ~INCADR_BIT & ~TRANS_SIZE_CONTROL_BIT) ++ | Addr | Type | OP_Type | Inc_Addr; ++ ++ cfc->BuffCtrlReg = buf_ctrl_reg; ++ ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++} ++ ++static void WriteCFCardByte( u32 Addr, u8 Value, u32 Type) ++{ ++ while( !( cfc->HostStatus & RDY_nIREQ_BIT)) ++ ; ++ ++ SetTransferSize( Addr, Type, WRITE_OP, NOINCADR, SIZE_1_BYTE); ++ ++ cfc->BufferData = Value; ++ ++ while( !( cfc->HostStatus & INTA_BIT)) ++ ; ++ ++ /* clear command complete status */ ++ cfc->HostStatus = INTA_BIT; ++} ++ ++static u8 ReadCFCardByte( u32 Addr, u32 Type) ++{ ++ u8 ret_data; ++ ++ DEBUG( CF_DEBUG, 1, "Enter\n"); ++ ++ /* wait until ready */ ++ while( !( cfc->HostStatus & RDY_nIREQ_BIT)) ++ ; ++ ++ SetTransferSize( Addr, Type, READ_OP, NOINCADR, SIZE_1_BYTE); ++ ++ while( !( cfc->HostStatus & INTA_BIT)) ++ ; ++ ++ ret_data = cfc->BufferData & 0xff; ++ DEBUG( CF_DEBUG, 1, "data: 0x%02x\n", ret_data); ++ ++ while( !( cfc->HostStatus & INTA_BIT)) ++ ; ++ ++ /* clear command complete status */ ++ cfc->HostStatus = INTA_BIT; ++ ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++ return ret_data; ++} ++ ++/* set Head-cylinder-sector on CF */ ++static u32 Translate_Config_HCS( u32 LBA, u32 Sec_count) ++{ ++ u8 DriveHead = ( u8)( 0xE0 | ( LBA >> 24)); /* 0xE0 set in LBA mode (bit 7&5 must set to 1) */ ++ u8 CylHigh = ( u8)( ( LBA >> 16) & 0xFF); ++ u8 CylLow = ( u8)( ( LBA >> 8) & 0xFF); ++ u8 SecNum = ( u8)( LBA & 0xFF); ++ ++ DEBUG( CF_DEBUG, 1, "LBA:%d, %d %d %d %d, count: %d\n", ++ LBA, DriveHead, CylHigh, CylLow, SecNum, Sec_count); ++ ++ /* Set CF-ATA reg for start sector */ ++ WriteCFCardByte( BLKMEM_DRIVE_REG, DriveHead, COMMON_MEM); ++ WriteCFCardByte( BLKMEM_CYLINDER_HIGH_REG, CylHigh, COMMON_MEM); ++ WriteCFCardByte( BLKMEM_CYLINDER_LOW_REG, CylLow, COMMON_MEM); ++ WriteCFCardByte( BLKMEM_SECTOR_NUMBER_REG, SecNum, COMMON_MEM); ++ WriteCFCardByte( BLKMEM_SECTOR_COUNT_REG, Sec_count, COMMON_MEM); ++ ++ return 1; ++} ++ ++/* ++ * SetCFCardConfiguration(): ATTRIBUTE MEMORY ++ * Set CF storgae card configuration option register ++ * Conf1 Conf0 Disk Card Mode ++ * --------------------------------------------------------------- ++ * 0 0 Memory Mapped ++ * 0 1 I/O Mapped, any 16 byte system decoded ++ * 1 0 I/O Mapped, 1F0h - 1F7h / 3F6h - 3F7h ++ * 1 1 I/O Mapped, 170h - 177h / 376h - 377h ++ */ ++static void SetCFCardMode( u8 Mode) ++{ ++ u8 Reg; ++ ++ DEBUG( CF_DEBUG, 1, "Enter\n"); ++ ++ Reg = ReadCFCardByte( CONFIG_OPTION_REG, ATTRIBUTE_MEM); /* CONFIG_OPTION_REG = 0x200 */ ++ Reg &= ( LEVLREQ_BIT | SRESET_BIT); /* clear bit0-5 */ ++ ++ WriteCFCardByte( CONFIG_OPTION_REG, Reg | Mode, ATTRIBUTE_MEM); ++ ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++} ++ ++/* return 0: fail, 1: success */ ++static u32 CF_SendCommand( u16 Cmd) ++{ ++ u16 Reg; ++ DEBUG( CF_DEBUG, 1, "Enter\n"); ++ ++ do{ ++ WriteCFCardByte( BLKMEM_COMMAND_REG, Cmd, COMMON_MEM); ++ ++ /* ++ * Check status register of Task file register is valid for access ++ * No other bits in status register are valid when BUSY bit is ++ * set to a 1 ++ */ ++ while( ( ReadCFCardByte( BLKMEM_STATUS_REG, COMMON_MEM) & BUSY_BIT)) ++ ; ++ ++ Reg = ReadCFCardByte( BLKMEM_STATUS_REG, COMMON_MEM); ++ ++ if( Reg & ERR_BIT){ ++ ++ DEBUG( CF_DEBUG, 1, "Exit ( fail)\n"); ++ return 0; ++ } ++ ++ } while( !( Reg & RDY_BIT)); ++ ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++ return 1; ++} ++ ++static void CardReset( void) ++{ ++ u32 ctrl_reg = cfc->ControlReg; ++ u8 data; ++ ++ DEBUG( CF_DEBUG, 1, "Enter\n"); ++ cfc->ControlReg = ctrl_reg | RESET_BIT | SIGNAL_ON | PWR_ON; /* set reset bit, float control, power on */ ++ ++ /* Software must manually clear this bit */ ++ mdelay( 100); ++ ++ /* clear reset bit */ ++ cfc->ControlReg = ( ctrl_reg &~ RESET_BIT) | SIGNAL_ON | PWR_ON | DATA_CMP_INT_MASK | IO_INT_MASK; ++ ++ do { ++ data = ReadCFCardByte( BLKMEM_STATUS_REG, COMMON_MEM); ++ ++ } while( data & BUSY_BIT); /* please be careful that is locked here */ ++ ++ data = ReadCFCardByte( BLKMEM_STATUS_REG, COMMON_MEM); ++ ++ /* Check if Drive Ready & Drive Seek Complete */ ++ if( data == ( RDY_BIT | DSC_BIT)) ++ DEBUG( CF_DEBUG, 1, "Reset CF OK, data: 0x%02x\n", ( unsigned char)data); ++ else ++ DEBUG( CF_DEBUG, 1, "Reset CF fail, data: 0x%02x\n", ( unsigned char)data); ++ ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++} ++ ++static u32 CFCardInit( void) ++{ ++ u8 buff[CF_SECTOR_SIZE]; ++ u32 i; ++ u32 BSA, BSM, BSIO, BSMOW, BSIORW, apb_ns; ++ ++ DEBUG( CF_DEBUG, 1, "Enter\n"); ++ ++ if( !( cfc->HostStatus & CARD_DETECT_BIT)){ ++ ++ DEBUG( CF_DEBUG, 1, "No CF Card In Socket\n"); ++ return -1; ++ } ++ ++ CardReset(); ++ ++ /* set timer */ ++ ++ apb_ns = 1000000000 / ( AHB_CLK_IN / 2 ); /* the time of APB clock */ ++ BSA = ( 50 + ( apb_ns - ( 50 % apb_ns))) / apb_ns; /* Based on the item tc( R) of BSA */ ++ BSMOW = 3; ++ BSIORW = 3; ++ BSM = ( 30 + ( apb_ns - ( 30 % apb_ns))) / apb_ns; /* Base on the item tw( WE) of BSM */ ++ BSIO = ( 35 + ( apb_ns - ( 35 % apb_ns))) / apb_ns; /* Base on the item tsuA( IORD,IOWR) of BSIO */ ++ ++ cfc->TimeCfgReg = ( ( BSMOW & 0x03) << 12) ++ | ( ( BSIORW & 0x03) << 14) ++ | ( ( BSA & 0x0f) << 0) ++ | ( ( BSM & 0x0f) << 4) ++ | ( ( BSIO & 0x0f) << 8); ++ ++ SetCFCardMode( CF_MEM_MAP_MODE); /* set memory mode read write access */ ++ ++ cfc->MultiSector = 0x1; /* enable multi sector read/write */ ++ ++ /* select drive */ ++ WriteCFCardByte( BLKMEM_DRIVE_REG, 0, COMMON_MEM); ++ ++ /* identify drive device */ ++ if( !CF_SendCommand( ATA_IDENTIFY_DRIVE)){ ++ ++ DEBUG( CF_DEBUG, 1, "Send Identify Drive command fail\n"); ++ return -1; ++ } ++ ++ SetTransferSize( BLKMEM_DATA_REG, COMMON_MEM, READ_OP, NOINCADR, SIZE_512_BYTE); ++ ++ for( i = 0; i < CF_SECTOR_SIZE / 4; i++){ ++ ++ while( !( cfc->HostStatus & BUF_DATA_RDY_BIT)) ++ ; ++ ++ *( ( u32*)&buff[ i*4]) = cfc->BufferData; ++ } ++ ++ /* clear command complete status */ ++ cfc->HostStatus = INTA_BIT; ++ ++ g_cf_sectors = ( ( u32)buff[ 15] << 24) | ( ( u32)buff[ 14] << 16) | ( ( u32)buff[ 17] << 8) | ( ( u32)buff[ 16]); ++ DEBUG( CF_DEBUG, 1, "Card identify - capicity: %d sectors, size: %d kbytes \n", g_cf_sectors, g_cf_sectors >> 1); ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++ ++ return 0; ++} ++ ++static int cfc_read_block( cf_card_t *info, uint size, uint *buf) ++{ ++ /* ++ * Please refer SanDisk SD Manual v1.9 Section 5.1.9.2 ( page 5-76) to set the timeout setting ++ */ ++ unsigned long timeout = jiffies + CFC_TIMEOUT_BASE *( ( size + 2048 + 511) >> 9); ++ uint count; ++ u8 data; ++ dmad_chreq *ch_req = (dmad_chreq *)info->private; ++ dmad_drb *drb = 0; ++ u32 drb_size = 0; ++ dma_addr_t addr_iter; ++ ++ if( info->DMAEnable){ ++ ++ DEBUG( CF_DEBUG, 1, "DMA Read - size: %d, buf: 0x%08lx, dma_buf: 0x%08lx\n", ++ size, ( unsigned long)buf, ( unsigned long)dma_buf); ++ ++ init_completion(&cf_dma_cmpl); ++ ++ if (dma_buf) ++ consistent_sync(__va(dma_buf), size, DMA_FROM_DEVICE); ++ else ++ consistent_sync(buf, size, DMA_FROM_DEVICE); ++ ++ //prepare parameter for add dma entry ++ dmad_config_channel_dir(ch_req, DMAD_DIR_A0_TO_A1); ++ ++ drb_size = dmad_max_size_per_drb(ch_req); ++ ++ if (dma_buf) ++ addr_iter = dma_buf; // given dest phy addr ++ else ++ addr_iter = __pa(buf); ++ ++ cfc->ControlReg |= ENDMA_BIT; ++ ++ while (size > 0) { ++ ++ if (unlikely(0 != dmad_alloc_drb(ch_req, &drb) || (drb == 0))) { ++ printk(KERN_ERR "%s() Failed to allocate dma request block!\n", __func__); ++ return FALSE; ++ } ++ ++ drb->addr0 = FTCFC_PA_BASE + 0x10; ++ drb->addr1 = addr_iter; ++ ++ if (size <= drb_size) { ++ drb->req_cycle = dmad_bytes_to_cycles(ch_req, size); ++ drb->sync = &cf_dma_cmpl; ++ size = 0; ++ } else { ++ drb->req_cycle = dmad_bytes_to_cycles(ch_req, drb_size); ++ drb->sync = 0; ++ size -= drb_size; ++ addr_iter += drb_size; ++ } ++ //printk(KERN_INFO "%s() size_remain 0x%08x.\n", __func__, size); ++ ++ if (unlikely(0 != dmad_submit_request(ch_req, drb, 1))) { ++ printk(KERN_ERR "%s() Failed to submit dma request block!\n", __func__); ++ return FALSE; ++ } ++ } ++ ++ if (wait_for_completion_timeout(&cf_dma_cmpl, timeout - jiffies) == 0) ++ printk("%s: read timeout\n", __func__); ++ ++ DEBUG( CF_DEBUG, 1, "ControlReg: 0x%08x, HostStatus: 0x%08x, BufCtrl: 0x%08x\n", ++ cfc->ControlReg, cfc->HostStatus, cfc->BuffCtrlReg); ++ ++ while( !( cfc->HostStatus & INTA_BIT)) ++ ; ++ ++ cfc->HostStatus = INTA_BIT; ++ ++ /* Stop DMA */ ++ cfc->ControlReg &= ~ENDMA_BIT; ++ cfc->ControlReg &= ~MODE_BIT; ++ ++ do { ++ data = ReadCFCardByte( BLKMEM_STATUS_REG, COMMON_MEM); ++ ++ } while( data & BUSY_BIT); ++ } ++ else { ++ while( size > 0){ ++ ++ /* read data from FIFO */ ++ if( size >= ( CFC_READ_FIFO_LEN << 2)) ++ count = CFC_READ_FIFO_LEN; ++ else ++ count = size >> 2; ++ ++ /* read data from FIFO */ ++ DEBUG( CF_DEBUG, 0, "\n"); ++ size -= ( count << 2); ++ } ++ } ++ ++ data = ReadCFCardByte( BLKMEM_STATUS_REG, COMMON_MEM); ++ ++ while( 1){ ++ ++ if( data & ERR_BIT){ ++ ++ DEBUG( CF_DEBUG, 1, "ERROR: ( CFReadSector) CF Read sector error.\n"); ++ return FALSE; ++ } ++ else if( data & DWF_BIT){ ++ ++ DEBUG( CF_DEBUG, 1, "ERROR: ( CFReadSector) CF write fault error.\n"); ++ return FALSE; ++ } ++ else if( data & ( RDY_BIT | DSC_BIT)){ ++ ++ break; ++ } ++ data = ReadCFCardByte( BLKMEM_STATUS_REG, COMMON_MEM); ++ } ++ ++ return TRUE; ++} ++ ++static int cfc_write_block( cf_card_t *info, uint size, uint *buf) ++{ ++ unsigned long timeout = jiffies + CFC_TIMEOUT_BASE * 3 *( ( size + 511) >> 9); ++ uint count; ++ u8 data; ++ dmad_chreq *ch_req = (dmad_chreq *)info->private; ++ dmad_drb *drb = 0; ++ u32 drb_size = 0; ++ dma_addr_t addr_iter; ++ ++ if( info->DMAEnable){ ++ ++ DEBUG( CF_DEBUG, 1, "size: %d, buf: %p) - DMA Write\n", size, buf); ++ ++ init_completion(&cf_dma_cmpl); ++ ++ if (dma_buf) ++ consistent_sync(__va(dma_buf), size, DMA_TO_DEVICE); ++ else ++ consistent_sync(buf, size, DMA_TO_DEVICE); ++ ++ //prepare parameter for add dma entry ++ dmad_config_channel_dir(ch_req, DMAD_DIR_A1_TO_A0); ++ ++ drb_size = dmad_max_size_per_drb(ch_req); ++ ++ if (dma_buf) ++ addr_iter = dma_buf; // given dest phy addr ++ else ++ addr_iter = __pa(buf); ++ ++ cfc->ControlReg |= ENDMA_BIT; ++ ++ while (size > 0) { ++ ++ if (unlikely(0 != dmad_alloc_drb(ch_req, &drb) || (drb == 0))) { ++ printk(KERN_ERR "%s() Failed to allocate dma request block!\n", __func__); ++ return FALSE; ++ } ++ ++ drb->addr0 = FTCFC_PA_BASE + 0x10; ++ drb->addr1 = addr_iter; ++ ++ if (size <= drb_size) { ++ drb->req_cycle = dmad_bytes_to_cycles(ch_req, size); ++ drb->sync = &cf_dma_cmpl; ++ size = 0; ++ } else { ++ drb->req_cycle = dmad_bytes_to_cycles(ch_req, drb_size); ++ drb->sync = 0; ++ size -= drb_size; ++ addr_iter += drb_size; ++ } ++ //printk(KERN_INFO "%s() size_remain 0x%08x.\n", __func__, size); ++ ++ if (unlikely(0 != dmad_submit_request(ch_req, drb, 1))) { ++ printk(KERN_ERR "%s() Failed to submit dma request block!\n", __func__); ++ return FALSE; ++ } ++ } ++ ++ if (wait_for_completion_timeout(&cf_dma_cmpl, timeout - jiffies) == 0) ++ printk("write timeout\n"); ++ ++ while( !( cfc->HostStatus & INTA_BIT)) ++ ; ++ ++ cfc->HostStatus = INTA_BIT; ++ /* Stop DMA */ ++ cfc->ControlReg &= ~ENDMA_BIT; ++ cfc->ControlReg &= ~MODE_BIT; ++ ++ do{ ++ data = ReadCFCardByte( BLKMEM_STATUS_REG, COMMON_MEM); ++ ++ } while( data & BUSY_BIT); ++ } ++ else { ++ while( size > 0){ ++ ++ /* write data from FIFO */ ++ if( size >= ( CFC_WRITE_FIFO_LEN << 2)) ++ count = CFC_WRITE_FIFO_LEN; ++ else ++ count = ( size >> 2); ++ ++ size -= ( count << 2); ++ } ++ } ++ ++ data = ReadCFCardByte( BLKMEM_STATUS_REG, COMMON_MEM); ++ ++ while( 1){ ++ ++ if( data & ERR_BIT){ ++ ++ DEBUG( CF_DEBUG, 1, "ERROR: ( CFReadSector) CF Read sector error.\n"); ++ return FALSE; ++ } ++ else if( data & DWF_BIT){ ++ ++ DEBUG( CF_DEBUG, 1, "ERROR: ( CFReadSector) CF write fault error.\n"); ++ return FALSE; ++ } ++ else if( data & ( RDY_BIT | DSC_BIT)) ++ break; ++ ++ data = ReadCFCardByte( BLKMEM_STATUS_REG, COMMON_MEM); ++ } ++ return TRUE; ++} ++ ++static int cf_card_insert( cf_card_t *info) ++{ ++ DEBUG( CF_DEBUG, 1, "Enter\n"); ++ CardReset(); ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++ ++ return TRUE; ++} ++ ++/* Free IRQ and DMA resources */ ++static void cf_free( cf_dev_t *dev) ++{ ++ release_region( FTCFC_VA_BASE, 0x48); /* return ioport */ ++ free_irq( FTCFC_IRQ, dev); /* return Hotswapping irq */ ++ ++ if (cf_card_info.DMAEnable) { ++#if (CF_DEBUG) ++ if (dev->ch_req.controller == DMAD_DMAC_APB_CORE) ++ printk("%s: free APB dma channel (%d)\n", __func__, dev->ch_req.channel); ++ else ++ printk("%s: free AHB dma channel (%d)\n", __func__, dev->ch_req.channel); ++#endif ++ dmad_channel_free(&dev->ch_req); ++ cf_card_info.DMAEnable = FALSE; ++ } ++} ++ ++static int cf_card_remove( cf_card_t *info) ++{ ++ cf_err_code = ERR_NO_ERROR; ++ ++ info->ActiveState = FALSE; ++ info->WriteProtect = FALSE; ++ info->RCA = 0; ++ ++ /* reset host interface controller */ ++ cfc->ControlReg |= RESET_BIT; ++ ++ mdelay( 100); ++ cfc->ControlReg &= ~RESET_BIT; /* must manually clear reset bit */ ++ return TRUE; ++} ++ ++irqreturn_t cf_hotswap_interrupt_handler( int irq, void *dev_id) ++{ ++ cf_dev_t *dev = dev_id; ++ ++ DEBUG( CF_DEBUG, 1, "irq: %d\n", irq); ++ ++ /* ++ * When the card is inserted or removed, we must delay a short time to make sure ++ * the SDC_STATUS_REG_CARD_INSERT bit of status register is stable ++ */ ++ ++ if( cfc->HostStatus & INT_CD_BIT ){ ++ ++ mdelay( 100); /* wait 0.1 sec for card stable */ ++ ++ DEBUG( CF_DEBUG, 1, "Card %s\n", cfc->HostStatus & CARD_DETECT_BIT ? "Insert" : "Remove"); ++ if( cfc->HostStatus & CARD_DETECT_BIT ){ ++ ++ dev->card_state = CF_CARD_INSERT; ++ cf_card_insert( &cf_card_info); ++ } ++ else { ++ dev->card_state = CF_CARD_REMOVE; ++ cf_card_remove( &cf_card_info); ++ } ++ ++ cfc->HostStatus = INT_CD_BIT; ++ } ++ else{ ++ DEBUG( CF_DEBUG, 1, "cfc->HostStatus & INT_CD_BIT == 0\n"); ++ } ++ ++ DEBUG( CF_DEBUG, 1, "Exit: card state = %d\n", dev->card_state); ++ return IRQ_HANDLED; ++} ++ ++int cf_read_multiple_block( cf_card_t *info, uint addr, uint count, uint size, uint timeout, unchar *buf) ++{ ++ u8 data; ++ ++ DEBUG( CF_DEBUG, 1, "read block addr: 0x%x(%d) sectors: %d\n", addr, addr, count); ++ ++ cf_err_code = ERR_NO_ERROR; ++ Translate_Config_HCS( addr, count); ++ CF_SendCommand( ATA_READ_SECTOR); ++ ++ do{ ++ data = ReadCFCardByte( BLKMEM_STATUS_REG, COMMON_MEM); ++ ++ } while( data & BUSY_BIT); ++ ++ SetTransferSizeEx( BLKMEM_DATA_REG, COMMON_MEM, READ_OP, NOINCADR, CF_SECTOR_SIZE * count); ++ ++ if( first_run == 0){ ++ ++ udelay( 100000); ++ ++ first_run = 1; ++ } ++ ++ if( !cfc_read_block( info, CF_SECTOR_SIZE * count, ( uint *)buf)) ++ return FALSE; ++ ++ if( cf_err_code != ERR_NO_ERROR){ ++ ++ DEBUG( CF_DEBUG, 1, "error = 0x%x\n", cf_err_code); ++ DEBUG( CF_DEBUG, 1, "r addr %d count %d\n", addr, count); ++ ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++int cf_write_multiple_block( cf_card_t *info, uint addr, uint count, uint size, uint timeout, unchar *buf) ++{ ++ u8 data; ++ ++ DEBUG( CF_DEBUG, 1, "write block addr: 0x%08lx, sectors: %x, sector: %x\n", ( unsigned long)addr, count, 512); ++ ++ cf_err_code = ERR_NO_ERROR; ++ Translate_Config_HCS( addr, count); ++ CF_SendCommand( ATA_WRITE_SECTOR); ++ do { ++ data = ReadCFCardByte( BLKMEM_STATUS_REG, COMMON_MEM); ++ } while( data & BUSY_BIT); ++ ++ SetTransferSizeEx( BLKMEM_DATA_REG, COMMON_MEM, WRITE_OP, NOINCADR, CF_SECTOR_SIZE * count); ++ ++ if( !cfc_write_block( info, CF_SECTOR_SIZE*count, ( uint *) buf)) ++ return FALSE; ++ ++ if( cf_err_code != ERR_NO_ERROR){ ++ ++ DEBUG( CF_DEBUG, 1, "error: 0x%08lx\n", ( unsigned long)cf_err_code); ++ DEBUG( CF_DEBUG, 1, "w addr: %d, count: %d\n", addr, count); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++ ++/*************************************************************************** ++ * SD Card Read/Write/Erase Function ++ ***************************************************************************/ ++int cf_read_sector( cf_card_t *info, uint addr, uint count, unchar *buf) ++{ ++ DEBUG( CF_DEBUG, 1, "Enter\n"); ++ ++ if( !cf_read_multiple_block( info, addr + cf_devices->lba_sec_offset, count, ++ info->CSD.ReadBlockLength, info->ReadAccessTimoutCycle, buf)){ ++ ++ DEBUG( CF_DEBUG, 1, "read failed\n"); ++ return FALSE; ++ } ++ ++ DEBUG( CF_DEBUG, 1, "read ok\n"); ++ ++ if( cf_devices->lba_sec_offset == 0){ ++ ++ if( !cf_read_multiple_block( info, 0, 1, info->CSD.ReadBlockLength, info->ReadAccessTimoutCycle, buf)) ++ return FALSE; ++ ++ /* lba ( ??) sector offset */ ++ cf_devices->lba_sec_offset = ( *( buf + 0x1C6)) ++ | ( *( buf + 0x1C7)) << 8 ++ | ( *( buf + 0x1C8)) << 16 ++ | ( *( buf + 0x1C9)) << 24; ++ ++ /* device total sector number */ ++ g_cf_sectors = ( *( buf + 0x1CA)) ++ | ( *( buf + 0x1CB)) << 8 ++ | ( *( buf + 0x1CC)) << 16 ++ | ( *( buf + 0x1CD)) << 24; ++ ++ /* only for testing , it only to let format command ok */ ++ if( ( buf[ 0x1be] != 0x0) && ( buf[ 0x1be] != 0x80)) /* partition identify */ ++ cf_devices->lba_sec_offset = 0; /* sector 0 is PBR */ ++ else ++ cf_devices->lba_sec_offset = ( buf[ 0x1c6]) ++ | ( buf[ 0x1c7] << 8) ++ | ( buf[ 0x1c8] << 16) ++ | ( buf[ 0x1c9] << 24); ++ ++ DEBUG( CF_DEBUG, 1, "lba_sec_offet is %d\n", cf_devices->lba_sec_offset); ++ DEBUG( CF_DEBUG, 1, "the device( partition) total sector number is %d\n", g_cf_sectors); ++ } ++ ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++ return TRUE; ++} ++ ++int cf_write_sector( cf_card_t *info, uint addr, uint count, unchar *buf) ++{ ++ if( !cf_write_multiple_block( info, addr+cf_devices->lba_sec_offset, count, ++ info->CSD.ReadBlockLength, info->ReadAccessTimoutCycle, buf)){ ++ ++ DEBUG( CF_DEBUG, 1, "write failed\n"); ++ ++ return FALSE; ++ } ++ ++ DEBUG( CF_DEBUG, 1, "write ok\n"); ++ ++ return TRUE; ++} ++ ++/* ++ * Perform an actual transfer: ++ * Returns: # of sectors transferred. 0 = error ++ */ ++int cf_transfer( cf_dev_t *device, const struct request *req) ++{ ++ int status = 0; ++ int count = 0; ++ ++ struct bio *bio = req->bio; ++ struct bio_vec *bvec; ++ struct req_iterator iter; ++ ++ DEBUG( CF_DEBUG, 1, "req sector: %d, phys_seg: %d, buf: 0x%08lx\n", ++ (int)req->__sector, req->nr_phys_segments, ++ (unsigned long)bio_data(bio)); ++ ++ spin_unlock_irq( &device->lock); ++ ++ rq_for_each_segment( bvec, req, iter){ ++ ++ unsigned char *buf = page_address( bvec->bv_page) + bvec->bv_offset; ++ int sectors = bio_cur_bytes( bio) >> 9; ++ ++ DEBUG( CF_DEBUG, 1, "bvec[%2d]: sector: %d, count: %d, curr: %d, buf: 0x%08lx\n", ++ iter.i, ( int)bio->bi_sector, count, ( int)sectors, ( unsigned long)buf); ++ ++ cf_card_info.private = (void *)&device->ch_req; ++ ++ if( rq_data_dir( req) == 0) /* Read */ ++ status = cf_read_sector( &cf_card_info, bio->bi_sector, sectors, buf); ++ else ++ status = cf_write_sector( &cf_card_info, bio->bi_sector, sectors, buf); ++ ++ DEBUG( CF_DEBUG, 1, "status: %d\n", status); ++ ++ if (status <= 0) { ++ spin_lock_irq( &device->lock); ++ return count; ++ } ++ ++ count += sectors; ++ bio->bi_sector += sectors; ++ } ++ ++ spin_lock_irq( &device->lock); ++ ++ if( status <= 0) ++ return 0; ++ else ++ return count; ++} ++ ++static int cf_card_setup(cf_dev_t *dev) ++{ ++ int i; ++ ++ DEBUG( CF_DEBUG, 1, "Enter\n"); ++ first_run = 0; ++ cf_err_code = ERR_NO_ERROR; ++ ++ cf_card_info.ActiveState = FALSE; ++ cf_card_info.WriteProtect = FALSE; ++ cf_card_info.IOAddr = FTCFC_VA_BASE; ++ cf_card_info.DMAEnable = TRUE; ++ cf_card_info.DMAChannel = dev->ch_req.channel; ++ cf_card_info.SysFrequency = AHB_CLK_IN / 2; ++ cf_card_info.RCA = 0; ++ ++ DEBUG( CF_DEBUG, 1, "DMA Enable is %d, Sys frequency = %d\n", cf_card_info.DMAEnable, cf_card_info.SysFrequency); ++ ++ if( !cf_card_insert( &cf_card_info)) ++ return FALSE; ++ ++ /* Marketing MB is not 1048576 */ ++ DEBUG( CF_DEBUG, 1, "FTCFC010: CF Card Capacity = %d KBytes\n", g_cf_sectors >> 1); ++ ++ for( i = 0; i < CF_DEVS; i++) ++ cf_devices[i].size = g_cf_sectors; /* unit is block, not bytes */ ++ ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++ ++ return TRUE; ++} ++ ++int cf_ioctl( struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) ++{ ++ int size; ++ struct hd_geometry geo; ++ cf_dev_t *device = bdev->bd_disk->private_data; ++ ++ DEBUG( CF_DEBUG, 1, "ioctl 0x%x 0x%lx\n", cmd, arg); ++ ++ switch ( cmd){ ++ ++ case BLKGETSIZE: ++ /* ++ * Return the device size, expressed in sectors ++ * FIXME: distinguish between kernel sector size and media sector size ++ */ ++ size = device->size; ++ __copy_to_user ( ( long *) arg, &size, sizeof ( long)); ++ return 0; ++ ++ case HDIO_GETGEO: ++ /* ++ * get geometry: we have to fake one... trim the size to a ++ * multiple of 64 ( 32k): tell we have 16 sectors, 4 heads, ++ * whatever cylinders. Tell also that data starts at sector. 4. ++ */ ++ geo.cylinders = ( device->size / 4) / 8; /* ?? only for test */ ++ geo.heads = 4; ++ geo.sectors = 8; ++ geo.start = 0; ++ __copy_to_user ( ( void *) arg, &geo, sizeof ( geo)); ++ return 0; ++ ++ default: ++ /* For ioctls we don't understand, let the block layer handle them */ ++ return -ENOTTY; ++ } ++ ++ return -ENOTTY; /* unknown command */ ++} ++ ++static void cf_request( struct request_queue *q) ++{ ++ cf_dev_t *dev; ++ int ret = 0; ++ struct request *req; ++ static int act = 0; ++ ++ if( act) ++ return; ++ ++ act = 1; ++ ++ while( ( req = blk_fetch_request( q)) != NULL){ ++ ++ dev = req->rq_disk->private_data; ++ ++ if( !dev || dev->card_state == CF_CARD_REMOVE){ ++ ++ DEBUG( CF_DEBUG, 1, "CF: locating device error\n"); ++ __blk_end_request_cur( req, -EIO); ++ ++ act = 0; ++ return; ++ } ++ ++ ret = cf_transfer( dev, req); ++ __blk_end_request( req, 0, ret << 9); ++ } ++ ++ act = 0; ++} ++ ++static int cf_dma_ch_alloc(cf_dev_t *dev) ++{ ++ dmad_chreq *ch_req = &dev->ch_req; ++ ++ memset(ch_req, 0, sizeof(dmad_chreq)); ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++ ++ ch_req->apb_req.addr0_ctrl = APBBR_ADDRINC_FIXED; /* (in) APBBR_ADDRINC_xxx */ ++ ch_req->apb_req.addr0_reqn = APBBR_REQN_CFC; /* (in) APBBR_REQN_xxx (also used to help determine bus selection) */ ++ ch_req->apb_req.addr1_ctrl = APBBR_ADDRINC_I4X; /* (in) APBBR_ADDRINC_xxx */ ++ ch_req->apb_req.addr1_reqn = APBBR_REQN_NONE; /* (in) APBBR_REQN_xxx (also used to help determine bus selection) */ ++ ch_req->apb_req.burst_mode = 0; /* (in) Burst mode (0: no burst 1-, 1: burst 4- data cycles per dma cycle) */ ++ ch_req->apb_req.data_width = APBBR_DATAWIDTH_4; /* (in) APBBR_DATAWIDTH_4(word), APBBR_DATAWIDTH_2(half-word), APBBR_DATAWIDTH_1(byte) */ ++ ch_req->apb_req.tx_dir = DMAD_DIR_A0_TO_A1; /* (in) DMAD_DIR_A0_TO_A1, DMAD_DIR_A1_TO_A0 */ ++ ++ ch_req->controller = DMAD_DMAC_APB_CORE; /* (in) DMAD_DMAC_AHB_CORE, DMAD_DMAC_APB_CORE */ ++ ch_req->flags = DMAD_FLAGS_SLEEP_BLOCK | DMAD_FLAGS_BIDIRECTION; ++ ++ if (dmad_channel_alloc(ch_req) != 0) { ++ memset(ch_req, 0, sizeof(dmad_chreq)); ++ printk(KERN_INFO "%s: APB dma channel allocation failed\n", __func__); ++ goto _try_ahb; ++ } ++ ++#if (CF_DEBUG) ++ printk("%s: APB dma channel allocated (ch: %d)\n", __func__, ch_req->channel); ++#endif ++ ++ return 0; ++ ++_try_ahb: ++ ++#endif /* CONFIG_PLATFORM_APBDMA */ ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ ++ ch_req->ahb_req.sync = 1; /* (in) non-zero if src and dst have different clock domain */ ++ ch_req->ahb_req.priority = DMAC_CSR_CHPRI_1; /* (in) DMAC_CSR_CHPRI_0 (lowest) ~ DMAC_CSR_CHPRI_3 (highest) */ ++ ch_req->ahb_req.hw_handshake = 1; /* (in) non-zero to enable hardware handshake mode */ ++ ch_req->ahb_req.burst_size = DMAC_CSR_SIZE_4; /* (in) DMAC_CSR_SIZE_1 ~ DMAC_CSR_SIZE_256 */ ++ ch_req->ahb_req.addr0_width = DMAC_CSR_WIDTH_32; /* (in) DMAC_CSR_WIDTH_8, DMAC_CSR_WIDTH_16, or DMAC_CSR_WIDTH_32 */ ++ ch_req->ahb_req.addr0_ctrl = DMAC_CSR_AD_FIX; /* (in) DMAC_CSR_AD_INC, DMAC_CSR_AD_DEC, or DMAC_CSR_AD_FIX */ ++ ch_req->ahb_req.addr0_reqn = DMAC_REQN_CFC; /* (in) DMAC_REQN_xxx (also used to help determine channel number) */ ++ ch_req->ahb_req.addr1_width = DMAC_CSR_WIDTH_32; /* (in) DMAC_CSR_WIDTH_8, DMAC_CSR_WIDTH_16, or DMAC_CSR_WIDTH_32 */ ++ ch_req->ahb_req.addr1_ctrl = DMAC_CSR_AD_INC; /* (in) DMAC_CSR_AD_INC, DMAC_CSR_AD_DEC, or DMAC_CSR_AD_FIX */ ++ ch_req->ahb_req.addr1_reqn = DMAC_REQN_NONE; /* (in) DMAC_REQN_xxx (also used to help determine channel number) */ ++ ch_req->ahb_req.tx_dir = DMAD_DIR_A0_TO_A1; /* (in) DMAD_DIR_A0_TO_A1, DMAD_DIR_A1_TO_A0 */ ++ ++ ch_req->controller = DMAD_DMAC_AHB_CORE; /* (in) DMAD_DMAC_AHB_CORE, DMAD_DMAC_APB_CORE */ ++ ch_req->flags = DMAD_FLAGS_SLEEP_BLOCK | DMAD_FLAGS_BIDIRECTION; ++ ++ if (dmad_channel_alloc(ch_req) != 0) { ++ memset(ch_req, 0, sizeof(dmad_chreq)); ++ printk(KERN_INFO "%s: AHB dma channel allocation failed\n", __func__); ++ goto _err_exit; ++ } ++ ++#if (CF_DEBUG) ++ printk("%s: AHB dma channel allocated (ch: %d)\n", __func__, ch_req->channel); ++#endif ++ ++ return 0; ++ ++_err_exit: ++ ++#endif /* CONFIG_PLATFORM_AHBDMA */ ++ ++ return -ENODEV; ++} ++ ++/* ++ * Note no locks taken out here. In a worst case scenario, we could drop ++ * a chunk of system memory. But that should never happen, since validation ++ * happens at open or mount time, when locks are held. ++ */ ++static int cf_revalidate( struct gendisk *gd) ++{ ++ cf_dev_t *dev = gd->private_data; ++ ++ DEBUG( CF_DEBUG, 1, "Enter\n"); ++ dev->card_state = cfc->HostStatus & CARD_DETECT_BIT ? CF_CARD_INSERT : CF_CARD_REMOVE; ++ ++ DEBUG( CF_DEBUG, 1, "card state: %s\n", ++ dev->card_state == CF_CARD_INSERT ? "INSERT" : ++ dev->card_state == CF_CARD_WORK ? "WORK" : "REMOVE"); ++ ++ if( !dev->usage){ ++ ++ if( cf_card_setup(dev) != TRUE){ ++ ++ DEBUG( CF_DEBUG, 1, "cf_card_setup failed\n"); ++ dev->card_state = CF_CARD_REMOVE; ++ ++ return -1; ++ } ++ else { ++ DEBUG( CF_DEBUG, 1, "CFC Driver with DMA Mode\n"); ++ ++ if (cf_card_info.DMAEnable) { ++ /* acquire dma channel */ ++ if (cf_dma_ch_alloc(dev) != 0) { ++ cf_card_info.DMAEnable = FALSE; ++ cf_free( dev); ++ DEBUG( CF_DEBUG, 1, "Request DMA resource failed\n"); ++ return -1; ++ } ++ DEBUG( CF_DEBUG, 1, "Request DMA resource success\n"); ++ } ++ ++ /* SDC interrupt, currently only for HotSwap */ ++ DEBUG( CF_DEBUG, 1, "Request CFC IRQ: %d\n", FTCFC_IRQ); ++ ++ if( request_irq( FTCFC_IRQ, cf_hotswap_interrupt_handler, IRQF_DISABLED, "CF controller", dev) != 0){ ++ ++ DEBUG( CF_DEBUG, 1, "Unable to allocate CFC IRQ: 0x%x\n", FTCFC_IRQ); ++ cf_free( dev); ++ return -1; ++ } ++ ++ /* require io port address for sd controller */ ++ if( request_region( FTCFC_VA_BASE, 0x48, "CF Controller") == NULL){ ++ ++ DEBUG( CF_DEBUG, 1, "request io port of sd controller fail\n"); ++ cf_free( dev); ++ return -1; ++ } ++ ++ dev->card_state = CF_CARD_WORK; ++ } ++ } ++ ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++ ++ return 0; ++} ++ ++/* TODO: forbids open for write when WRITE_PROTECT = 1 */ ++static int cf_open( struct block_device *bdev, fmode_t mode) ++{ ++ cf_dev_t *dev= bdev->bd_disk->private_data; /* device information */ ++ ++ DEBUG( CF_DEBUG, 1, "Enter\n"); ++ ++ if( ( cfc->HostStatus & CARD_DETECT_BIT) != CARD_DETECT_BIT){ ++ ++ DEBUG( CF_DEBUG, 1, "Error: ( ENOMEDIUM)\n"); ++ return -ENOMEDIUM; ++ } ++ ++ if( CFCardInit()){ ++ ++ DEBUG( CF_DEBUG, 1, "root initialize failed\n"); ++ return FALSE; ++ } ++ ++ if( !dev->usage){ ++ ++ dev->media_change = 1; ++ DEBUG( CF_DEBUG, 1, "forced check_disk_change check\n"); ++ check_disk_change( bdev); ++ } ++ else{ ++ dev->media_change = 0; ++ } ++ ++ DEBUG( CF_DEBUG, 1, "set_capacity() to %d blocks ( %d KBytes)\n", dev->size, dev->size >> 1); ++ set_capacity( dev->gd, dev->size); ++ dev->usage++; ++ cf_devices->lba_sec_offset = 0; ++ DEBUG( CF_DEBUG, 1, "dev: 0x%08lx, cf_devices: 0x%08lx\n", ( unsigned long)dev, ( unsigned long)cf_devices); ++ ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++ ++ return 0; /* success */ ++} ++ ++static int cf_release( struct gendisk *gd, fmode_t mode) ++{ ++ cf_dev_t *dev = gd->private_data; ++ ++ DEBUG( CF_DEBUG, 1, "Enter\n"); ++ ++ dev->usage--; ++ ++ if( !dev->usage) ++ cf_free( dev); ++ ++ DEBUG( CF_DEBUG, 1, "Exit\n"); ++ ++ return 0; ++} ++ ++static void setup_device( struct cf_dev *dev, int which) ++{ ++ memset ( dev, 0, sizeof ( struct cf_dev)); ++ dev->size = 0; ++ spin_lock_init( &dev->lock); ++ ++ dev->queue = blk_init_queue( cf_request, &dev->lock); ++ ++ if( !dev->queue) ++ goto out_vfree; ++ ++ blk_queue_logical_block_size( dev->queue, hardsect_size); ++ dev->queue->queuedata = dev; ++ ++ dev->card_state = CF_CARD_REMOVE; ++ ++ /* And the gendisk structure. */ ++ dev->gd = alloc_disk( CF_MINORS); ++ if( ! dev->gd){ ++ ++ DEBUG( CF_DEBUG, 1, "alloc_disk failure\n"); ++ goto out_vfree; ++ } ++ ++ dev->gd->flags = GENHD_FL_REMOVABLE | GENHD_FL_SUPPRESS_PARTITION_INFO; ++ dev->gd->major = cf_major; ++ dev->gd->first_minor = which * CF_MINORS; ++ dev->gd->minors = CF_MINORS; ++ dev->gd->fops = &cf_fops; ++ dev->gd->queue = dev->queue; ++ dev->gd->private_data = dev; ++ ++ snprintf ( dev->gd->disk_name, 32, "cpecf%c", which + 'a'); ++ set_capacity( dev->gd, 0); ++ add_disk( dev->gd); ++ ++ return; ++ ++out_vfree: ++ ++ return; ++} ++ ++static int cf_media_changed( struct gendisk *gd) ++{ ++ struct cf_dev *dev = gd->private_data; ++ ++ DEBUG( CF_DEBUG, 1, "cf_media_changed = %d\n", dev->media_change); ++ ++ return dev->media_change; ++} ++ ++struct block_device_operations cf_fops = { ++ ++ .owner = THIS_MODULE, ++ .open = cf_open, ++ .release = cf_release, ++ .ioctl = cf_ioctl, ++ .revalidate_disk = cf_revalidate, ++ .media_changed = cf_media_changed, ++}; ++ ++static int __init cf_module_init( void) ++{ ++ int result= -ENOMEM, i; ++ ++ DEBUG( 1, 0, "Faraday CF controller Driver (DMA mode)\n"); ++ ++ cf_major = register_blkdev( cf_major, DEVICE_NAME); ++ ++ if( cf_major <= 0){ ++ ++ DEBUG( CF_DEBUG, 1, ":unable to get major number\n"); ++ return -EBUSY; ++ } ++ ++ DEBUG( 1, 0, "CF: make node with 'mknod /dev/cpecf b %d 0'\n", cf_major); ++ ++ cf_devices = kzalloc( CF_DEVS * sizeof( cf_dev_t), GFP_KERNEL); ++ ++ if( !cf_devices) ++ goto fail_malloc; ++ ++ for( i = 0; i < CF_DEVS; i++) ++ setup_device( cf_devices + i, i); ++ ++ return 0; ++ ++fail_malloc: ++ ++ if( cf_devices) ++ kfree( cf_devices); ++ ++ unregister_blkdev( cf_major, DEVICE_NAME); ++ ++ return result; ++} ++ ++static void cf_module_cleanup( void) ++{ ++ int i; ++ ++ if( cf_devices){ ++ ++ for( i = 0; i < CF_DEVS; i++){ ++ ++ del_gendisk( cf_devices[i].gd); ++ put_disk( cf_devices[i].gd); ++ ++ if( cf_devices[i].queue) ++ blk_cleanup_queue( cf_devices[i].queue); ++ } ++ ++ kfree( cf_devices); ++ } ++ ++ unregister_blkdev( cf_major, DEVICE_NAME); ++} ++ ++module_init( cf_module_init); ++module_exit( cf_module_cleanup); ++ ++MODULE_AUTHOR( "Faraday Corp."); ++MODULE_LICENSE( "GPL"); +diff -Nur linux-3.4.110.orig/drivers/block/ftcfc010.h linux-3.4.110/drivers/block/ftcfc010.h +--- linux-3.4.110.orig/drivers/block/ftcfc010.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/block/ftcfc010.h 2016-04-07 10:20:51.022084119 +0200 +@@ -0,0 +1,438 @@ ++/* drivers/block/CPECF/ftcfc.h ++ * ++ * Faraday FTCFC010 Device Driver ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * ++ * All Rights Reserved ++ */ ++ ++#ifndef _FTCFC_H_ ++#define _FTCFC_H_ ++ ++#define CF_DEBUG 1 ++ ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#define CF_DEVS 1 /* number of disks */ ++#define CF_MINORS 16 /* minors per disk */ ++#define CF_SECTOR_SIZE 512 /* sector size */ ++ ++/* SD Card State */ ++#define CF_CARD_REMOVE 0 ++#define CF_CARD_INSERT 1 ++#define CF_CARD_WORK 2 ++ ++/* data window register */ ++#define CFC_READ_FIFO_LEN 4 ++#define CFC_WRITE_FIFO_LEN 4 ++ ++/* card type, sd or mmc */ ++#define MEMORY_CARD_TYPE_SD 0 ++#define MEMORY_CARD_TYPE_MMC 1 ++ ++/***************************************************************************** ++ * SYSTEM ERROR_CODE ++ ****************************************************************************/ ++#define ERR_NO_ERROR 0x00000000 ++ ++/* command error */ ++#define ERR_DATA_CRC_ERROR 0x00000100 ++#define ERR_RSP_CRC_ERROR 0x00000200 ++#define ERR_DATA_TIMEOUT_ERROR 0x00000400 ++#define ERR_RSP_TIMEOUT_ERROR 0x00000800 ++ ++#define ERR_WAIT_OVERRUN_TIMEOUT 0x00001000 ++#define ERR_WAIT_UNDERRUN_TIMEOUT 0x00002000 ++#define ERR_WAIT_DATA_CRC_TIMEOUT 0x00004000 ++#define ERR_WAIT_TRANSFER_END_TIMEOUT 0x00008000 ++ ++#define ERR_SEND_COMMAND_TIMEOUT 0x00010000 ++ ++/* using APB DMA error */ ++#define ERR_APBDMA_RSP_ERROR 0x02000000 ++ ++/* ++ * Please refer SanDisk SD Manual v1.9 Section 5.1.9.2 (page 5-76) to set the timeout setting ++ */ ++#if CF_DEBUG ++#define CFC_TIMEOUT_BASE (HZ/2) /* Unit is 500 ms */ ++#else ++#define CFC_TIMEOUT_BASE (HZ/3) /* Unit is 333 ms */ ++#endif ++ ++typedef struct _cf_cid_t ++{ ++ uint ManufacturerID; ++ uint ApplicationID; ++ unchar ProductName[7]; ++ uint ProductRevisionHigh; ++ uint ProductRevisionLow; ++ uint ProductSerialNumber; ++ uint ManufactureMonth; ++ uint ManufactureYear; ++} cf_cid_t; ++ ++typedef struct _cf_ccf_t ++{ ++ uint CSDStructure; ++ uint MMCSpecVersion; ++ uint TAAC_u; ++ uint NSAC_u; ++ uint TransferSpeed; ++ uint CardCmdClass; ++ uint ReadBlockLength; ++ uint ReadBlockPartial; ++ uint WriteBlockMisalign; ++ uint ReadBlockMisalign; ++ uint DSRImplemant; ++ uint BlockNumber; ++ uint MemorySize; ++ uint VDDReadMin_u; ++ uint VDDReadMax_u; ++ uint VDDWriteMin_u; ++ uint VDDWriteMax_u; ++ uint EraseBlkEnable; ++ uint EraseSectorSize; ++ uint WriteProtectGroupSize; ++ uint WriteProtectGroupEnable; ++ uint WriteSpeedFactor; ++ uint WriteBlockLength; ++ unchar WriteBlockPartial; ++ unchar CopyFlag; ++ unchar PermanentWriteProtect; ++ unchar TemporaryWriteProtect; ++ unchar FileFormat; ++} cf_ccf_t; ++ ++/***************************************************************************** ++ * SD SCR register ++ ****************************************************************************/ ++typedef struct _cf_scr_t ++{ ++ uint Reserved:16; ++ uint SD_BUS_WIDTH:4; ++ uint SD_SECURITY:3; ++ uint DATA_STAT_AFTER_ERASE:1; ++ uint SD_SPEC:4; ++ uint SCR_STRUCTURE:4; ++ ++ uint ManufacturerReserved; ++} cf_scr_t; ++ ++/***************************************************************************** ++ * sd card structure ++ ****************************************************************************/ ++typedef struct _cf_card_t ++{ ++ /* host interface configuration */ ++ uint IOAddr; /* host controller register base address */ ++ uint DMAEnable; ++ uint DMAChannel; ++ ++ uint CardType; ++ ++ uint CIDWord[4]; ++ cf_cid_t CID; ++ ++ uint CSDWord[4]; ++ cf_ccf_t CSD; ++ ++ ushort RCA; ++ cf_scr_t SCR; ++ ++ /* access time out */ ++ uint ReadAccessTimoutCycle; ++ uint WriteAccessTimoutCycle; ++ ++ /* system configurations */ ++ uint SysFrequency; ++ ++ /* card status */ ++ int ActiveState; ++ int WriteProtect; ++ ++ void *private; ++} cf_card_t; ++ ++typedef struct _CF_Dev ++{ ++ u32 dev_size; /* used same as sect_num */ ++ u32 sect_num; /* sector num */ ++ u8 blksize_bit; /* It's not used */ ++ u32 blksize; /* size of block in file system, 1024 */ ++ ++ u32 phy_blksize; /* Physical size of block on the CF. It's not used */ ++ u32 phy_sectorsize; /* the size of erasable sector. It's not used */ ++ u32 wp_grp_size; /* the size of write protected group. It's not used */ ++ ++ spinlock_t lock; /* synchronization */ ++ struct semaphore sema; /* synchronization */ ++ u32 usage; ++ ++ u8 busy; ++ ++ wait_queue_head_t select_wait; /* Kernel thread blocked on it. It's not used */ ++ u8 cmd; /* What command being executed. */ ++ u32 result; /* set by tasklet */ ++ u8 *buff; ++ ++ u32 lba_sec_offset; ++ ++ /*APB_DMA */ ++ ++ u8 DMATransDir; /* 0: IDLE, 1:READ, 2:WRITE */ ++} CF_Dev; ++ ++#define CFC_R_IDLE 0x00 ++#define CFC_R_START_TRANSFER 0x01 ++#define CFC_R_SET_CFCARD_REG 0x02 ++#define CFC_R_SET_CFCARD_READ_CMD 0x03 ++#define CFC_R_CHK_CFCARD_READY 0x04 ++#define CFC_R_SET_DMA_REG 0x05 ++#define CFC_R_DMA_START 0x06 ++#define CFC_R_DMA_INT 0x07 ++#define CFC_R_DMA_FINISH 0x08 ++#define CFC_R_PIO_START 0x09 ++#define CFC_R_PIO_FINISH 0x0A ++#define CFC_R_CHECK_CFCARD_BUSY 0x0B ++#define CFC_R_CHECK_CFCARD_READY 0x0C ++ ++#define CFC_W_IDLE 0x00 ++#define CFC_W_START_TRANSFER 0x10 ++#define CFC_W_SET_CFCARD_REG 0x20 ++#define CFC_W_SET_CFCARD_READ_CMD 0x30 ++#define CFC_W_CHK_CFCARD_READY 0x40 ++#define CFC_W_SET_DMA_REG 0x50 ++#define CFC_W_DMA_START 0x60 ++#define CFC_W_DMA_INT 0x70 ++#define CFC_W_DMA_FINISH 0x80 ++#define CFC_W_PIO_START 0x90 ++#define CFC_W_PIO_FINISH 0xA0 ++#define CFC_W_CHECK_CFCARD_BUSY 0xB0 ++#define CFC_W_CHECK_CFCARD_READY 0xC0 ++ ++#define DMA_IDLE 0x00 ++#define DMA_READ 0x01 ++#define DMA_WRITE 0x02 ++ ++typedef struct CFCTYPE ++{ ++ u32 HostStatus; /* 0x00 */ ++ u32 ControlReg; /* 0x04 */ ++ u32 TimeCfgReg; /* 0x08 */ ++ u32 BuffCtrlReg; /* 0x0C */ ++ u32 BufferData; /* 0x10 */ ++ u32 MultiSector; /* 0x14 */ ++ ++ /* Enchanced Feature */ ++ u32 TransSzMode2En; /* 0x18 */ ++ u32 TransSzMode2Cnt; /* 0x1C */ ++ u32 Reserved[4]; /* 0x20~0x2F is reserved */ ++ u32 Revision; /* 0x30 */ ++ u32 Feature; /* 0x34 (define buffer size) */ ++ ++} CFCTYPE; ++ ++#define cfc ((volatile struct CFCTYPE *) (FTCFC_VA_BASE)) ++ ++typedef struct _tag_CFCardInfo ++{ ++ u32 SectTotal; ++ u8 ConfigOptionReg; ++ u8 ConfigAndStatusReg; ++ u8 PinReplaceReg; ++ u8 SocketCopyReg; ++ ++} CF_CARD_INFO; ++ ++#define CFC_C_Complete 0x00000400 ++#define CFC_B_Ready 0x00000200 ++#define CFC_8bit 0x00000040 ++#define CFC_16bit 0x00000000 ++#define CFC_Reset 0x00000020 ++#define CFC_T_2048 0x000C0000 ++#define CFC_T_1024 0x000B0000 ++#define CFC_T_512 0x000A0000 ++#define CFC_T_256 0x00090000 ++#define CFC_T_128 0x00080000 ++#define CFC_T_64 0x00070000 ++#define CFC_T_32 0x00060000 ++#define CFC_T_16 0x00050000 ++#define CFC_T_8 0x00040000 ++#define CFC_T_4 0x00030000 ++#define CFC_T_2 0x00020000 ++#define CFC_T_1 0x00010000 ++#define CFC_Read 0x00000000 ++#define CFC_Write 0x00008000 ++#define CFC_Increment 0x00004000 ++#define CFC_Attribute 0x00000000 ++#define CFC_Memory 0x00002000 ++#define CFC_IO 0x00003000 ++ ++/* CF status register bit mapping */ ++#define RDY_nIREQ_BIT 0x0001 ++#define CARD_DETECT_BIT 0x0002 ++#define VOL33_SENSE_BIT 0x0004 ++#define VOL40_SENSE_BIT 0x0008 ++#define STATUS_CHANGE_BIT 0x0010 ++#define SPKR_BIT 0x0020 ++#define BUF_ACTIVE_BIT 0x0100 ++#define BUF_DATA_RDY_BIT 0x0200 ++#define INTA_BIT 0x0400 ++#define BUF_SIZE_BITS 0xF000 ++#define INT_CD_BIT 0x10000 ++#define INT_IO_BIT 0x20000 ++ ++/* CF control register bit mapping */ ++#define POWER_CONTROL_BIT 0x000F ++#define FLOW_CONTROL_BIT 0x0010 ++#define RESET_BIT 0x0020 ++#define MODE_BIT 0x0040 ++#define DMA_BIT 0x0100 ++ ++#define PWR_ON 1 ++#define PWR_OFF 0 ++ ++#define SIGNAL_ON 0x0010 ++#define SIGNAL_OFF 0x0000 ++ ++#define BYTE_MODE 0x0040 ++#define WORD_MODE 0x0000 ++ ++#define ENDMA_BIT 0x0100 ++#define DISDMA_BIT 0x0000 ++ ++#define CARD_DETECT_INT_MASK 0x0200 ++#define DATA_CMP_INT_MASK 0x0400 ++#define IO_INT_MASK 0x0800 ++ ++/* active buffer control register bit mapping */ ++#define ADR_BIT 0x007FF ++#define TYPE_BIT 0x03000 ++#define INCADR_BIT 0x04000 ++#define RW_BIT 0x08000 ++#define TRANS_SIZE_CONTROL_BIT 0xF0000 ++ ++#define INCADR 0x04000 ++#define NOINCADR 0x00000 ++#define TRANS_SIZE_LOC 16 ++ ++#define SIZE_1_BYTE 0x01 ++#define SIZE_2_BYTE 0x02 ++#define SIZE_4_BYTE 0x03 ++#define SIZE_8_BYTE 0x04 ++#define SIZE_16_BYTE 0x05 ++#define SIZE_32_BYTE 0x06 ++#define SIZE_64_BYTE 0x07 ++#define SIZE_128_BYTE 0x08 ++#define SIZE_256_BYTE 0x09 ++#define SIZE_512_BYTE 0x0a ++#define SIZE_1024_BYTE 0x0b ++#define SIZE_2048_BYTE 0x0c ++ ++#define READ_OP 0x00000 ++#define WRITE_OP 0x08000 ++ ++/* type description */ ++#define ATTRIBUTE_MEM 0x00000 ++#define COMMON_MEM 0x02000 ++ ++/* ++ * CF card ++ * memory map register ++ * IO block register ++ */ ++#define BLKMEM_DATA_REG 0x000 ++#define BLKMEM_ERROR_REG ( BLKMEM_DATA_REG + 0x01) ++#define BLKMEM_FEATURE_REG ( BLKMEM_DATA_REG + 0x01) ++#define BLKMEM_SECTOR_COUNT_REG ( BLKMEM_DATA_REG + 0x02) ++#define BLKMEM_SECTOR_NUMBER_REG ( BLKMEM_DATA_REG + 0x03) ++#define BLKMEM_CYLINDER_LOW_REG ( BLKMEM_DATA_REG + 0x04) ++#define BLKMEM_CYLINDER_HIGH_REG ( BLKMEM_DATA_REG + 0x05) ++#define BLKMEM_DRIVE_REG ( BLKMEM_DATA_REG + 0x06) ++#define BLKMEM_STATUS_REG ( BLKMEM_DATA_REG + 0x07) ++#define BLKMEM_COMMAND_REG ( BLKMEM_DATA_REG + 0x07) ++ ++#define BLKMEM_EVEN_DATA_REG ( BLKMEM_DATA_REG + 0x08) ++#define BLKMEM_ODD_DATA_REG ( BLKMEM_DATA_REG + 0x09) ++#define BLKMEM_DUP_ERROR_REG ( BLKMEM_DATA_REG + 0x0d) ++#define BLKMEM_DUP_FEATURE_REG ( BLKMEM_DATA_REG + 0x0d) ++#define BLKMEM_DEV_CONTROL_REG ( BLKMEM_DATA_REG + 0x0e) ++#define BLKMEM_DRIVE_ADDR_REG ( BLKMEM_DATA_REG + 0x0f) ++#define BLKMEM_WINDOW_REG ( BLKMEM_DATA_REG + 0x400) ++#define BLKMEM_MAX_WINDOW_REG ( BLKMEM_DATA_REG + 0x7ff) ++ ++/* status register */ ++#define BUSY_BIT 0x80 ++#define RDY_BIT 0x40 ++#define DWF_BIT 0x20 ++#define DSC_BIT 0x10 ++#define DRQ_BIT 0x08 ++#define CORR_BIT 0x04 ++#define ERR_BIT 0x01 ++ ++/* CF ATA command */ ++#define ATA_CHECK_POWER_MODE 0xe5 ++#define ATA_EXECUTE_DRIVE_DIAG 0x90 ++#define ATA_ERASE_SECTOR 0xc0 ++#define ATA_FORMAT_TRACK 0x50 ++#define ATA_IDENTIFY_DRIVE 0xec ++#define ATA_IDLE 0xe3 ++#define ATA_IDLE_IMMEDIATE 0xe1 ++#define ATA_INIT_DRIVE_PARA 0x91 ++#define ATA_READ_BUFFER 0xe4 ++#define ATA_READ_LONG_SECTOR 0x22 ++#define ATA_READ_MULTIPLE 0xc4 ++#define ATA_READ_SECTOR 0x21 ++#define ATA_READ_VERIFY_SECTOR 0x40 ++#define ATA_RECALIBRATE 0x10 ++#define ATA_REQUEST_SENSE 0x03 ++#define ATA_SECURITY_DISABLE_PASSWORD 0xf6 ++#define ATA_SECURITY_EREASE_PREPARE 0xf3 ++#define ATA_SECURITY_ERASE_UNIT 0xf4 ++#define ATA_SECURITY_FREEZE_LOCK 0xf5 ++#define ATA_SECURITY_SET_PASSWORD 0xf1 ++#define ATA_SECURITY_UNLOCK 0xf2 ++#define ATA_SEEK 0x70 ++#define ATA_SET_FEATURE 0xef ++#define ATA_SET_MULTIPLE_MODE 0xc6 ++#define ATA_SET_SLEEP_MODE 0xe6 ++#define ATA_STANDBY 0xe2 ++#define ATA_STANDBY_IMMEDIATE 0xe0 ++#define ATA_TRANSFER_SECTOR 0x87 ++#define ATA_WEAR_LEVEL 0xf5 ++#define ATA_WRITE_BUFFER 0xe8 ++#define ATA_WRITE_LONG_SECTOR 0x32 ++#define ATA_WRITE_MULTIPLE 0xc5 ++#define ATA_WRITE_MULTIPLE_WO_ERASE 0xcd ++#define ATA_WRITE_SECTOR 0x30 ++#define ATA_WRITE_SECTOR_WO_ERASE 0x38 ++#define ATA_WRITE_VERIFY 0x3c ++ ++#define CF_MEM_MAP_MODE 0x0 ++/* attribute memory space register description */ ++#define ATTRIBUTE_MEM_BASE 0 ++#define ATTRIBUTE_MEM_CONFIG_BASE 0x200 ++#define CONFIG_OPTION_REG ( ATTRIBUTE_MEM_CONFIG_BASE + 0x00) ++#define CARD_CONFIG_STATUS_REG ( ATTRIBUTE_MEM_CONFIG_BASE + 0x02) ++#define PIN_REPLACE_REG ( ATTRIBUTE_MEM_CONFIG_BASE + 0x04) ++#define SOCKET_COPY_REG ( ATTRIBUTE_MEM_CONFIG_BASE + 0x06) ++ ++/* configuration option register */ ++#define CONF0_BIT 0x01 ++#define CONF1_BIT 0x02 ++#define CONF2_BIT 0x04 ++#define CONF3_BIT 0x08 ++#define CONF4_BIT 0x10 ++#define CONF5_BIT 0x20 ++#define LEVLREQ_BIT 0x40 ++#define SRESET_BIT 0x80 ++ ++#endif +diff -Nur linux-3.4.110.orig/drivers/block/ftsdc010.c linux-3.4.110/drivers/block/ftsdc010.c +--- linux-3.4.110.orig/drivers/block/ftsdc010.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/block/ftsdc010.c 2016-04-07 10:20:51.022084119 +0200 +@@ -0,0 +1,2206 @@ ++/* drivers/block/CPESD/ftsdc010.c ++ ******************************************************************************* ++ * Faraday FTSDC010 Device Driver ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * ++ * All Rights Reserved ++ * ++ * Porting to Linux 2.6 on 20050815 ++ * Author: Chris Lee, I-Jui Sung, Peter Liao (support APB DMA) ++ * Version: 0.2 ++ * History: ++ * 0.1 new creation ++ * 0.2 Porting to meet the style of linux dma ++ * 0.3 modify dma usage to virtual irq of dma interrupt ++ * 0.4 (20050701) Improve r/w performance ++ * 0.5 Porting to Linux 2.6 and replace busy_loop checking with timer's timeout ++ * Todo: ++ ******************************************************************************* ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/sched.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/ioport.h> ++#include <linux/hdreg.h> /* HDIO_GETGEO */ ++#include <linux/fs.h> ++#include <linux/blkdev.h> ++#include <linux/buffer_head.h> /* invalidate_bdev */ ++#include <linux/bio.h> ++#include <linux/pci.h> ++#include <linux/mutex.h> ++#include <asm/io.h> ++#include <asm/uaccess.h> ++#include <asm/spec.h> ++#include <asm/dmad.h> ++ ++#define IPMODULE SDC ++#define IPNAME FTSDC010 ++ ++/* Define CONFIG_FTSDC010_USE_TIMER_DELAY if you want to use software timer instead of busy loop checking */ ++#define CONFIG_FTSDC010_USE_TIMER_DELAY ++#undef CONFIG_FTSDC010_USE_TIMER_DELAY ++#include "ftsdc010.h" ++#include <linux/interrupt.h> ++MODULE_AUTHOR("Faraday Corp."); ++MODULE_LICENSE("Faraday License"); ++ ++/* options */ ++#define FORCE_PCI_CONSISTENCY 1 /* define it to 1 if met consistency problems */ ++#define KERNEL_SECTOR_SIZE 512 /* Use this when we refer to kernel related sector size */ ++ ++static int hardsect_size = 512; ++module_param(hardsect_size, int, 0); ++/*------------------------------------------------------------------------------ ++ * Predefine for block device ++ */ ++#define MAJOR_NR sd_major /* force definitions on in blk.h */ ++static int sd_major=0;//SD_MAJOR; /* must be declared before including blk.h */ ++#define SD_SHIFT 4 /* max 16 partitions */ ++#define DEVICE_NAME "Faraday SDC" /* name for messaging */ ++#define DEVICE_REQUEST sd_request ++#define DEVICE_NR(device) (MINOR(device) >> SD_SHIFT) ++//#define DEVICE_INTR sd_intrptr /* pointer to the bottom half */ ++#define DEVICE_NO_RANDOM /* no entropy to contribute */ ++#define DEVICE_OFF(d) /* do-nothing */ ++ ++/*#include <linux/blk.h> ++#include <linux/blkpg.h>*/ /* blk_ioctl() */ ++ ++/*------------------------------------------------------------------------------ ++ * Macro definition ++ */ ++#define FTSDC_VA_BASE IP_VA_BASE(0) ++#define FTSDC_PA_BASE IP_PA_BASE(0) ++#define FTSDC_IRQ IP_IRQ(0) ++#define SDC_W_REG(offset, value) outl(value, IP_VA_BASE(0) + offset) ++#define SDC_R_REG(offset) inl(IP_VA_BASE(0) + offset) ++ ++ ++/*------------------------------------------------------------------------------ ++ * Global variable ++ */ ++ ++/* The following items are obtained through kmalloc() in sd_module_init() */ ++ ++struct block_device_operations sd_fops; ++/* our device structure */ ++struct sd_dev { ++ int size; /* device size in sectors */ ++ int usage; /* # of users currently */ ++ int media_change; /* Flag: media changed? */ ++ struct gendisk *gd; /* The gendisk structure */ ++ spinlock_t lock; /* For mutual exclusion */ ++ struct request_queue *queue; /* The device request queue */ ++ int card_state; ++ dmad_chreq ch_req; ++ bool dma_enable; ++}; ++static struct sd_dev *sd_devices = NULL; ++ ++static sd_card_t sd_card_info; ++static int sector_offset,Do_onetime; ++ ++dma_addr_t dma_buf = 0; /* ?? non-zero for for manually debug ?? */ ++struct completion sd_dma_cmpl; ++ ++static int sync_mode=0; ++ ++static uint first_run = 0; ++uint sd_err_code; ++ ++#define FILE_FORMAT_HARD_DISK_LIKE 0 ++#define FILE_FORMAT_FLOPPY_LIKE 1 ++#define FILE_FORMAT_UNIVERSAL 2 ++#define FILE_FORMAT_UNKNOW 3 ++#define FILE_FORMAT_RESERVED 4 ++ ++#define K 1000 ++ ++uint TAAC_TimeUnitTable[] = { // unit is ns ++ 1, 10, 100, 1 * K, 10 * K, 100 * K, 1 * K * K, 10 * K * K ++}; ++ ++uint TRANS_SPEED_RateUintTable[] = { ++ 100 * K, 1 * K * K, 10 * K * K, 100 * K * K ++}; ++ ++uint TRANS_SPEED_TimeValueTable_u[] = { // unit=1/10 ++ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 ++}; ++ ++uint VDD_CURR_MIN_Table_u[] = { // unit=1/10 ++ 5, 10, 50, 100, 250, 350, 600, 1000 ++}; ++ ++uint VDD_CURR_MAX_Table_u[] = { ++ 1, 5, 10, 25, 35, 45, 80, 200 ++}; ++ ++uint TAAC_TimeValueTable_u[] = { // unit=1/10 ++ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 ++}; ++ ++ ++unsigned int SDC_READ_FIFO_LEN; ++unsigned int SDC_WRITE_FIFO_LEN; ++ ++/*------------------------------------------------------------------------------ ++ * Local declaration of function ++ */ ++static int sd_revalidate(struct gendisk *gd); ++static int sd_media_changed(struct gendisk *gd); ++static int sd_card_setup(struct sd_dev *dev); ++int sd_check_err(uint status); ++int sd_get_scr(sd_card_t *info, uint *scr); ++int sd_set_transfer_state(sd_card_t *info); ++uint sd_block_size_convert(uint size); ++int sd_read_sector(sd_card_t *info, uint addr, uint count, unchar *buf); ++void sd_reset_host_controller(void); ++/*------------------------------------------------------------------------------ ++ * Local function ++ */ ++ ++/* ++ * SD host controller operation ++ */ ++int sdc_send_cmd(uint cmd, uint arg, uint *rsp) ++{ ++#ifndef CONFIG_FTSDC010_USE_TIMER_DELAY ++ int count = 0; ++#else ++ unsigned long timeout = jiffies + SDC_GET_STATUS_RETRY_TIMEOUT_COUNT; ++#endif ++ int i; ++ uint status; ++ P_DEBUG("SD Cmd is %d\n",cmd); ++ ++ /* clear command relative bits of status register */ ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_RSP_CRC_FAIL | SDC_STATUS_REG_RSP_TIMEOUT | SDC_STATUS_REG_RSP_CRC_OK| SDC_STATUS_REG_CMD_SEND); ++ /* write argument to arugument register if necessary */ ++ SDC_W_REG(SDC_ARGU_REG, arg); ++ /* send command */ ++ SDC_W_REG(SDC_CMD_REG, cmd | SDC_CMD_REG_CMD_EN); ++ ++ /* wait for the CMD_SEND bit of status register is set */ ++#ifndef CONFIG_FTSDC010_USE_TIMER_DELAY ++ while (count++ < SDC_GET_STATUS_RETRY_COUNT) { ++#else ++ while (time_before(jiffies, timeout)) { ++#endif ++ status = SDC_R_REG(SDC_STATUS_REG); ++ if (!(cmd & SDC_CMD_REG_NEED_RSP)) { ++ /* if this command does not need response, wait command sent flag */ ++ if (status & SDC_STATUS_REG_CMD_SEND) { ++ /* clear command sent bit */ ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_CMD_SEND); ++ sd_err_code = ERR_NO_ERROR; ++ return TRUE; ++ } ++ } else { ++ /* if this command needs response */ ++ if (status & SDC_STATUS_REG_RSP_TIMEOUT) { ++ /* clear response timeout bit */ ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_RSP_TIMEOUT); ++ sd_err_code = ERR_RSP_TIMEOUT_ERROR; ++ printk("%s() ERR_RSP_TIMEOUT_ERROR\n", __func__); ++ return FALSE; ++ } else if (status & SDC_STATUS_REG_RSP_CRC_FAIL) { ++ /* clear response fail bit */ ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_RSP_CRC_FAIL); ++ sd_err_code = ERR_RSP_CRC_ERROR; ++ printk("%s() ERR_RSP_CRC_ERROR\n", __func__); ++ return FALSE; ++ } else if (status & SDC_STATUS_REG_RSP_CRC_OK) { ++ /* clear response OK bit */ ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_RSP_CRC_OK); ++ /* if it is long response */ ++ if (cmd & SDC_CMD_REG_LONG_RSP) ++ for (i = 0; i < 4; i++, rsp++) ++ *rsp = SDC_R_REG(SDC_RESPONSE0_REG + (i * 4)); ++ else ++ *rsp = SDC_R_REG(SDC_RESPONSE0_REG); ++ sd_err_code = ERR_NO_ERROR; ++ return TRUE; ++ } ++ } ++ } ++ sd_err_code = ERR_SEND_COMMAND_TIMEOUT; ++ P_DEBUG("%s() ERR_SEND_COMMAND_TIMEOUT\n", __func__); ++ return FALSE; ++} ++ ++int sdc_check_tx_ready(void) ++{ ++ uint status; ++#ifndef CONFIG_FTSDC010_USE_TIMER_DELAY ++ int count = 0; ++ while (count++ < SDC_GET_STATUS_RETRY_COUNT) { ++#else ++ unsigned long timeout = jiffies + SDC_GET_STATUS_RETRY_TIMEOUT_COUNT; ++ while (time_before(jiffies, timeout)) { ++#endif ++ status = SDC_R_REG(SDC_STATUS_REG); ++ if (status & SDC_STATUS_REG_FIFO_UNDERRUN) { ++ /* clear FIFO underrun bit */ ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_FIFO_UNDERRUN); ++ return TRUE; ++ } else if (status & SDC_STATUS_REG_DATA_TIMEOUT) { ++ /* clear data timeout bit */ ++ printk("Wait Write FIFO TimeOut\n"); ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_TIMEOUT); ++ sd_err_code = ERR_DATA_TIMEOUT_ERROR; ++ return FALSE; ++ } ++ } ++ sd_err_code = ERR_WAIT_UNDERRUN_TIMEOUT; ++ P_DEBUG("%s() ERR_WAIT_UNDERRUN_TIMEOUT\n", __func__); ++ return FALSE; ++} ++ ++int sdc_check_rx_ready(void) ++{ ++ uint status; ++#ifndef CONFIG_FTSDC010_USE_TIMER_DELAY ++ int count = 0; ++ while (count++ < SDC_GET_STATUS_RETRY_COUNT) { ++#else ++ unsigned long timeout = jiffies + SDC_GET_STATUS_RETRY_TIMEOUT_COUNT; ++ while (time_before(jiffies, timeout)) { ++#endif ++ status = SDC_R_REG(SDC_STATUS_REG); ++ if (status & SDC_STATUS_REG_FIFO_OVERRUN) { ++ /* clear FIFO overrun bit */ ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_FIFO_OVERRUN); ++ return TRUE; ++ } else if (status & SDC_STATUS_REG_DATA_TIMEOUT) { ++ /* clear data timeout bit */ ++ printk("Wait Read FIFO TimeOut\n"); ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_TIMEOUT); ++ sd_err_code = ERR_DATA_TIMEOUT_ERROR; ++ return FALSE; ++ } ++ } ++ sd_err_code = ERR_WAIT_OVERRUN_TIMEOUT; ++ P_DEBUG("%s() ERR_WAIT_OVERRUN_TIMEOUT\n", __func__); ++ return FALSE; ++} ++ ++int sdc_check_data_crc(void) ++{ ++ uint status=0; ++#ifndef CONFIG_FTSDC010_USE_TIMER_DELAY ++ int count = 0; ++ while (count++ < SDC_GET_STATUS_RETRY_COUNT) { ++#else ++ unsigned long timeout = jiffies + SDC_GET_STATUS_RETRY_TIMEOUT_COUNT; ++ while (time_before(jiffies, timeout)) { ++#endif ++ status = SDC_R_REG(SDC_STATUS_REG); ++ if (status & SDC_STATUS_REG_DATA_CRC_OK) { ++ P_DEBUGG("%s : receive data ok, status=0x%x\n", __func__, status); ++ /* clear data CRC OK bit */ ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_CRC_OK); ++ return TRUE; ++ } else if (status & SDC_STATUS_REG_DATA_CRC_FAIL) { ++ /* clear data CRC fail bit */ ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_CRC_FAIL); ++ sd_err_code = ERR_DATA_CRC_ERROR; ++ printk("%s() ERR_DATA_CRC_ERROR\n", __func__); ++ return FALSE; ++ } else if (status & SDC_STATUS_REG_DATA_TIMEOUT) { ++ /* clear data timeout bit */ ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_TIMEOUT); ++ sd_err_code = ERR_DATA_TIMEOUT_ERROR; ++ printk("%s() ERR_DATA_TIMEOUT_ERROR\n", __func__); ++ return FALSE; ++ } ++ } ++ P_DEBUG("%s() ERR_WAIT_DATA_CRC_TIMEOUT, status=0x%x\n", __func__, status); ++ sd_err_code = ERR_WAIT_DATA_CRC_TIMEOUT; ++ return FALSE; ++} ++ ++static inline int sdc_check_data_end(void) ++{ ++ uint status; ++#ifndef CONFIG_FTSDC010_USE_TIMER_DELAY ++ int count = 0; ++ while (count++ < SDC_GET_STATUS_RETRY_COUNT) { ++#else ++ unsigned long timeout = jiffies + SDC_GET_STATUS_RETRY_TIMEOUT_COUNT; ++ while (time_before(jiffies, timeout)) { ++#endif ++ status = SDC_R_REG(SDC_STATUS_REG); ++ if (status & SDC_STATUS_REG_DATA_END) { ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_END); ++ return TRUE; ++ } else if (status & SDC_STATUS_REG_DATA_TIMEOUT) { ++ /* clear data timeout bit */ ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_DATA_TIMEOUT); ++ sd_err_code = ERR_DATA_TIMEOUT_ERROR; ++ printk("%s() ERR_DATA_TIMEOUT_ERROR\n", __func__); ++ return FALSE; ++ } ++ } ++ sd_err_code = ERR_WAIT_TRANSFER_END_TIMEOUT; ++ P_DEBUG("%s() ERR_WAIT_TRANSFER_END_TIMEOUT\n", __func__); ++ return FALSE; ++} ++ ++int sdc_set_bus_width_cmd(sd_card_t *info, uint width) ++{ ++ uint status; ++ ++ /* send CMD55 to indicate to the card that the next command is an application specific command */ ++ if (!sdc_send_cmd(SD_APP_CMD | SDC_CMD_REG_NEED_RSP, (((uint)info->RCA) << 16), &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ /* send ACMD6 to set bus width */ ++ if (!sdc_send_cmd(SD_SET_BUS_WIDTH_CMD | SDC_CMD_REG_APP_CMD | SDC_CMD_REG_NEED_RSP, width, &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++int sdc_set_bus_width(sd_card_t *info) ++{ ++ uint width; ++ ++ /* if it is not SD card, it does not support wide bus */ ++ if (info->CardType != MEMORY_CARD_TYPE_SD) ++ return TRUE; ++ /* get SCR register */ ++ if (!sd_get_scr(info, (uint *) &info->SCR)) ++ return FALSE; ++ /* if host controller does not support wide bus, return */ ++ if ((SDC_R_REG(SDC_BUS_WIDTH_REG) & SDC_WIDE_BUS_SUPPORT) != SDC_WIDE_BUS_SUPPORT) ++ return TRUE; ++ if (!sd_set_transfer_state(info)) ++ return FALSE; ++ if (info->SCR.SD_BUS_WIDTH & SD_SCR_4_BIT_BIT) ++ width = SD_BUS_WIDTH_4_BIT; ++ else ++ width = SD_BUS_WIDTH_1_BIT; ++ if (!sdc_set_bus_width_cmd(info, width)) ++ return FALSE; ++ if (width == SD_BUS_WIDTH_1_BIT) ++ SDC_W_REG(SDC_BUS_WIDTH_REG, SDC_BUS_WIDTH_REG_SINGLE_BUS); ++ else ++ SDC_W_REG(SDC_BUS_WIDTH_REG, SDC_BUS_WIDTH_REG_WIDE_BUS); ++ ++ return TRUE; ++} ++ ++static inline int sdc_pre_erase_cmd(uint nr_blocks) ++{ ++ uint status; ++ sd_card_t *info=&sd_card_info; ++ /* send CMD55 to indicate to the card that the next command is an application specific command */ ++ if (!sdc_send_cmd(SD_APP_CMD | SDC_CMD_REG_NEED_RSP, (((uint)info->RCA) << 16), &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ /* send ACMD6 to set bus width */ ++ if (!sdc_send_cmd(23 | SDC_CMD_REG_APP_CMD | SDC_CMD_REG_NEED_RSP, nr_blocks, &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++ ++uint sdc_set_bus_clock(sd_card_t *info, uint clock) ++{ ++ uint div = 0, reg; ++ ++ while (clock < (info->SysFrequency / (2 * (div + 1)))) ++ div++; ++ /* write clock divided */ ++ reg = SDC_R_REG(SDC_CLOCK_CTRL_REG); ++ reg &= (~SDC_CLOCK_REG_CLK_DIV | 0x80); //ijsung: preserv SD or MMC ++ reg += div & SDC_CLOCK_REG_CLK_DIV; ++ SDC_W_REG(SDC_CLOCK_CTRL_REG, reg); ++ P_DEBUG("%s: SD clock=%d, info->SysFrequency=%d, div=%d\n",__func__,clock, info->SysFrequency, div); ++ return info->SysFrequency / (2 * (div + 1)); ++} ++ ++static inline int sdc_set_block_size(uint size) ++{ ++ uint status; ++ static uint last_size=0; ++ if (size == last_size) ++ return TRUE; ++ else ++ last_size=size; ++ ++ if (!sdc_send_cmd(SD_SET_BLOCKLEN_CMD | SDC_CMD_REG_NEED_RSP, size, &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ return TRUE; ++} ++ ++void sdc_set_card_type(int type) ++{ ++ uint reg; ++ ++ reg = SDC_R_REG(SDC_CLOCK_CTRL_REG); ++ reg &= ~SDC_CLOCK_REG_CARD_TYPE; ++ ++ if (type == MEMORY_CARD_TYPE_SD) { ++ reg |= SDC_CARD_TYPE_SD; ++ } ++ else { ++ reg |= SDC_CARD_TYPE_MMC; ++ } ++ ++ SDC_W_REG(SDC_CLOCK_CTRL_REG, reg); ++} ++ ++int sdc_read_block(sd_card_t *info, uint size, uint *buf) ++{ ++ /* ++ * Please refer SanDisk SD Manual v1.9 Section 5.1.9.2 (page 5-76) to set the timeout setting ++ */ ++ unsigned long timeout = jiffies + SDC_TIMEOUT_BASE*((size+511)>>9); ++ uint count, i; ++ dmad_chreq *ch_req = (dmad_chreq *)info->private; ++ dmad_drb *drb = 0; ++ u32 drb_size = 0; ++ dma_addr_t addr_iter; ++ ++ //if (info->DMAEnable) { ++ if ((info->DMAEnable) && ((size & 0xf) == 0)) { ++ P_DEBUG("%s:size=%d, buf=%p) - DMA Read\n", __func__, size,buf ); ++ P_DEBUG("dma_buf = %d\n", dma_buf); ++ ++ init_completion(&sd_dma_cmpl); ++ ++ if (dma_buf) ++ consistent_sync(__va(dma_buf), size, DMA_FROM_DEVICE); ++ else ++ consistent_sync(buf, size, DMA_FROM_DEVICE); ++ ++ //prepare parameter for add dma entry ++ dmad_config_channel_dir(ch_req, DMAD_DIR_A0_TO_A1); ++ ++ drb_size = dmad_max_size_per_drb(ch_req); ++ ++ if (dma_buf) ++ addr_iter = dma_buf; // given dest phy addr ++ else ++ addr_iter = __pa(buf); ++ ++ while (size > 0) { ++ ++ if (unlikely(0 != dmad_alloc_drb(ch_req, &drb) || (drb == 0))) { ++ printk(KERN_ERR "%s() Failed to allocate dma request block!\n", __func__); ++ return FALSE; ++ } ++ ++ drb->addr0 = FTSDC_PA_BASE + SDC_DATA_WINDOW_REG; ++ drb->addr1 = addr_iter; ++ ++ if (size <= drb_size) { ++ drb->req_cycle = dmad_bytes_to_cycles(ch_req, size); ++ drb->sync = &sd_dma_cmpl; ++ size = 0; ++ } else { ++ drb->req_cycle = dmad_bytes_to_cycles(ch_req, drb_size); ++ drb->sync = 0; ++ size -= drb_size; ++ addr_iter += drb_size; ++ } ++ //printk(KERN_INFO "%s() size_remain 0x%08x.\n", __func__, size); ++ ++ if (unlikely(0 != dmad_submit_request(ch_req, drb, 1))) { ++ printk(KERN_ERR "%s() Failed to submit dma request block!\n", __func__); ++ return FALSE; ++ } ++ } ++ ++ if (wait_for_completion_timeout(&sd_dma_cmpl, timeout - jiffies) == 0) ++ printk("%s: read timeout\n", __func__); ++ } else { ++ while (size > 0) { ++ if (!sdc_check_rx_ready()) { ++ printk("error...........\n"); ++ return FALSE; ++ } ++ /* read data from FIFO */ ++ if (size >= (SDC_READ_FIFO_LEN << 2)) ++ count = SDC_READ_FIFO_LEN; ++ else ++ count = size >> 2; ++ /* read data from FIFO */ ++ P_DEBUG("\n"); ++ for (i = 1; i <= count; i++, buf++) ++ { ++ *buf = SDC_R_REG(SDC_DATA_WINDOW_REG); ++ P_DEBUG("%.8x ",*buf); ++ } ++ size -= (count << 2); ++ } ++ } ++ return sdc_check_data_crc(); ++} ++ ++int sdc_write_block(sd_card_t *info, uint size, uint *buf) ++{ ++ unsigned long timeout = jiffies + SDC_TIMEOUT_BASE*3*((size+511)>>9); ++ uint count, i; ++ dmad_chreq *ch_req = (dmad_chreq *)info->private; ++ dmad_drb *drb = 0; ++ u32 drb_size = 0; ++ dma_addr_t addr_iter; ++ ++ //if (info->DMAEnable) { ++ if ((info->DMAEnable) && ((size & 0xf) == 0)) { ++ P_DEBUG("%s:size=%d, buf=%p) - DMA Write\n", __func__, size,buf ); ++ ++ init_completion(&sd_dma_cmpl); ++ ++ if (dma_buf) ++ consistent_sync(__va(dma_buf), size, DMA_TO_DEVICE); ++ else ++ consistent_sync(buf, size, DMA_TO_DEVICE); ++ ++ //prepare parameter for add dma entry ++ dmad_config_channel_dir(ch_req, DMAD_DIR_A1_TO_A0); ++ ++ drb_size = dmad_max_size_per_drb(ch_req); ++ ++ if (dma_buf) ++ addr_iter = dma_buf; // given dest phy addr ++ else ++ addr_iter = __pa(buf); ++ ++ while (size > 0) { ++ ++ if (unlikely(0 != dmad_alloc_drb(ch_req, &drb) || (drb == 0))) { ++ printk(KERN_ERR "%s() Failed to allocate dma request block!\n", __func__); ++ return FALSE; ++ } ++ ++ drb->addr0 = FTSDC_PA_BASE + SDC_DATA_WINDOW_REG; ++ drb->addr1 = addr_iter; ++ ++ if (size <= drb_size) { ++ drb->req_cycle = dmad_bytes_to_cycles(ch_req, size); ++ drb->sync = &sd_dma_cmpl; ++ size = 0; ++ } else { ++ drb->req_cycle = dmad_bytes_to_cycles(ch_req, drb_size); ++ drb->sync = 0; ++ size -= drb_size; ++ addr_iter += drb_size; ++ } ++ //printk(KERN_INFO "%s() size_remain 0x%08x.\n", __func__, size); ++ ++ if (unlikely(0 != dmad_submit_request(ch_req, drb, 1))) { ++ printk(KERN_ERR "%s() Failed to submit dma request block!\n", __func__); ++ return FALSE; ++ } ++ } ++ ++ if (wait_for_completion_timeout(&sd_dma_cmpl, timeout - jiffies) == 0) ++ printk("write timeout\n"); ++ } else { ++ while (size > 0) { ++ if (!sdc_check_tx_ready()) ++ return FALSE; ++ /* write data from FIFO */ ++ if (size >= (SDC_WRITE_FIFO_LEN << 2)) ++ count = SDC_WRITE_FIFO_LEN; ++ else ++ count = (size >> 2) ; ++ /* write data from FIFO */ ++ for (i = 0; i < count; i++, buf++) ++ SDC_W_REG(SDC_DATA_WINDOW_REG, *buf); ++ size -= (count << 2); ++ } ++ } ++ return sdc_check_data_crc(); ++} ++ ++void sdc_config_transfer(sd_card_t *SDCard, uint len, uint size, uint rw, uint timeout) ++{ ++ u32 con; ++ /* write timeout */ ++ SDC_W_REG(SDC_DATA_TIMER_REG, timeout * 2); ++ /* set data length */ ++ SDC_W_REG(SDC_DATA_LEN_REG, len); ++ ++ /* set data block */ ++ if (SDCard->DMAEnable) { ++ con = sd_block_size_convert(size) | SDC_DATA_CTRL_REG_DMA_EN | rw | SDC_DATA_CTRL_REG_DATA_EN; ++ con |= SDC_DMA_TYPE_4; ++ P_DEBUG("%s() transfer DMA mode\n", __func__); ++ SDC_W_REG(SDC_DATA_CTRL_REG, con); ++ } else { ++ P_DEBUG("%s() transfer nonDMA mode\n", __func__); ++ SDC_W_REG(SDC_DATA_CTRL_REG, sd_block_size_convert(size) | rw | SDC_DATA_CTRL_REG_DATA_EN); ++ } ++} ++ ++/* Note: This funciton may be called by interrupt handler */ ++void sdc_reset(void) ++{ ++ uint ret; ++ unsigned long delay = jiffies + (HZ/10)*3; //Delay 300ms ++ ++ /* reset host interface */ ++ SDC_W_REG(SDC_CMD_REG, SDC_CMD_REG_SDC_RST); ++ ++ /* loop, until the reset bit is clear */ ++ do { ++ ret = SDC_R_REG(SDC_CMD_REG); ++ } while ((ret & SDC_CMD_REG_SDC_RST) != 0); ++ #if 0 ++ udelay(1000); ++ #else ++ while(time_before(jiffies, delay)); ++ #endif ++} ++ ++/* ++ * SD card operation ++ */ ++void sd_endian_change(uint *dt, int len) ++{ ++ uint ul; ++ ++ for(; len > 0; len--, dt++) { ++ ul = *dt; ++ ((unchar *)dt)[0] = ((unchar *)&ul)[3]; ++ ((unchar *)dt)[1] = ((unchar *)&ul)[2]; ++ ((unchar *)dt)[2] = ((unchar *)&ul)[1]; ++ ((unchar *)dt)[3] = ((unchar *)&ul)[0]; ++ } ++} ++ ++int sd_get_ocr(sd_card_t *info, uint hocr, uint *cocr) ++{ ++ uint status; ++ int count = 0; ++ ++ do { ++ if (info->CardType == MEMORY_CARD_TYPE_SD) { ++ /* send CMD55 to indicate to the card that the next command is an application specific command */ ++ if (!sdc_send_cmd(SD_APP_CMD | SDC_CMD_REG_NEED_RSP, ((uint) info->RCA) << 16, &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ /* send ACMD41 to get OCR register */ ++ if (!sdc_send_cmd(SD_APP_OP_COND | SDC_CMD_REG_APP_CMD | SDC_CMD_REG_NEED_RSP, (uint) hocr, (uint *) cocr)) ++ return FALSE; ++ } else { ++ /* send CMD1 to get OCR register */ ++ if (!sdc_send_cmd(SD_MMC_OP_COND | SDC_CMD_REG_NEED_RSP, (uint) hocr, (uint *) cocr)) ++ return FALSE; ++ } ++ if (count++ > SD_CARD_GET_OCR_RETRY_COUNT) { ++ sd_err_code = ERR_SD_CARD_IS_BUSY; ++ printk("%s : ERR_SD_CARD_IS_BUSY\n", __func__); ++ return FALSE; ++ } ++ udelay(1000); /* According to spec, at most 1 msec or 74 clock cycles */ ++ } while ((*cocr & SD_OCR_BUSY_BIT) != SD_OCR_BUSY_BIT); ++ ++ return TRUE; ++} ++ ++int sd_get_scr(sd_card_t *info, uint *scr) ++{ ++ uint status; ++ ++ if (!sd_set_transfer_state(info)) ++ return FALSE; ++ if (!sdc_set_block_size(8)) ++ return FALSE; ++ sdc_config_transfer(info, 8, 8, SDC_DATA_CTRL_REG_DATA_READ, 0xFFFFFFFF); ++ /* send CMD55 to indicate to the card that the next command is an application specific command */ ++ if (!sdc_send_cmd(SD_APP_CMD | SDC_CMD_REG_NEED_RSP, ((uint) info->RCA) << 16, &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ /* send ACMD51 to get SCR */ ++ if (!sdc_send_cmd(SD_SEND_SCR_CMD | SDC_CMD_REG_APP_CMD | SDC_CMD_REG_NEED_RSP, 0, &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ if (!sdc_read_block(info, 8, (uint *) scr)) ++ return FALSE; ++ if (!sdc_check_data_end()) ++ return FALSE; ++ sd_endian_change(scr, 2); ++ ++ return TRUE; ++} ++ ++int sd_check_err(uint status) ++{ ++ if (status & SD_STATUS_ERROR_BITS) { ++ sd_err_code = ERR_SD_CARD_STATUS_ERROR; ++ printk("%s() ERR_SD_CARD_STATUS_ERROR %X\n", __func__, status); ++ return FALSE; ++ } ++ sd_err_code = ERR_NO_ERROR; ++ return TRUE; ++} ++ ++int sd_get_card_state(sd_card_t *info, uint *ret) ++{ ++ uint status; ++ ++ /* send CMD13 to get card status */ ++ if (!sdc_send_cmd(SD_SEND_STATUS_CMD | SDC_CMD_REG_NEED_RSP, ((uint) info->RCA) << 16, &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ *ret = (status & SD_STATUS_CURRENT_STATE) >> SD_STATUS_CURRENT_STATE_LOC; ++ return TRUE; ++} ++ ++int sd_operation_complete(sd_card_t *info, uint finish) ++{ ++ uint state; ++ int count = 0; ++ while (count++ < SD_CARD_WAIT_OPERATION_COMPLETE_RETRY_COUNT) { ++ if (!sd_get_card_state(info, &state)) ++ return FALSE; ++ if (state == finish) ++ return TRUE; ++ } ++ P_DEBUG("%s() error\n", __func__); ++ return FALSE; ++} ++ ++int sd_stop_transmission(void) ++{ ++ uint status; ++ ++ /* send CMD12 to stop transmission */ ++ if (!sdc_send_cmd(SD_STOP_TRANSMISSION_CMD | SDC_CMD_REG_NEED_RSP, 0, &status)) ++ return FALSE; ++ ++ if (!sd_check_err(status)) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++int sd_set_card_standby(sd_card_t *info) ++{ ++ uint state; ++ int count = 0; ++ while (count++ < SD_CARD_STATE_CHANGE_RETRY_COUNT) { ++ if (!sd_get_card_state(info, &state)) ++ return FALSE; ++ ++ switch (state) { ++ case SD_IDLE_STATE: ++ case SD_READY_STATE: ++ case SD_IDENT_STATE: ++ printk("%s() error\n", __func__); ++ return FALSE; ++ case SD_DIS_STATE: ++ return sd_operation_complete(info, SD_STBY_STATE); ++ case SD_TRAN_STATE: ++ if (!sdc_send_cmd(SD_SELECT_CARD_CMD, 0, NULL)) ++ return FALSE; ++ break; ++ case SD_DATA_STATE: ++ if (sd_operation_complete(info, SD_TRAN_STATE)) ++ return TRUE; ++ if (sd_err_code != ERR_NO_ERROR) ++ return FALSE; ++ if (!sd_stop_transmission()) ++ return FALSE; ++ break; ++ case SD_RCV_STATE: ++ if (sd_operation_complete(info, SD_TRAN_STATE)) ++ return TRUE; ++ if (sd_err_code != ERR_NO_ERROR) ++ return FALSE; ++ if (!sd_stop_transmission()) ++ return FALSE; ++ break; ++ case SD_PRG_STATE: ++ if (!sd_operation_complete(info, SD_TRAN_STATE)) ++ return FALSE; ++ break; ++ case SD_STBY_STATE: ++ return TRUE; ++ } ++ } ++ P_DEBUG("%s() error\n", __func__); ++ return FALSE; ++} ++ ++uint two_power(uint n) ++{ ++ uint pow = 1; ++ ++ for (; n > 0; n--) ++ pow <<= 1; ++ return pow; ++} ++ ++int sd_csd_parse(sd_csd_t *csd, uint *csd_word) ++{ ++ sd_csd_bit_t *csd_bit; ++ uint mult, blocks, len; ++ ++ if ((csd_word[0] & 0x00000001) != 1) { ++ sd_err_code = ERR_CSD_REGISTER_ERROR; ++ printk("%s() ERR_CSD_REGISTER_ERROR\n", __func__); ++ return FALSE; ++ } ++ ++ csd_bit = (sd_csd_bit_t *) csd_word; ++ csd->CSDStructure = csd_bit->CSD_STRUCTURE; ++ csd->MMCSpecVersion = csd_bit->MMC_SPEC_VERS; ++ csd->TAAC_u = TAAC_TimeValueTable_u[csd_bit->TAAC_TimeValue] * TAAC_TimeUnitTable[csd_bit->TAAC_TimeUnit] / 10; ++ csd->NSAC_u = csd_bit->NSAC * 100; ++ csd->TransferSpeed = TRANS_SPEED_RateUintTable[csd_bit->TRAN_SPEED_RateUnit] * TRANS_SPEED_TimeValueTable_u[csd_bit->TRAN_SPEED_TimeValue] / 10; ++ csd->CardCmdClass = csd_bit->CCC; ++ csd->ReadBlockLength = two_power(csd_bit->READ_BL_LEN); ++ csd->ReadBlockPartial = csd_bit->READ_BL_PARTIAL; ++ csd->WriteBlockMisalign = csd_bit->WRITE_BLK_MISALIGN; ++ csd->ReadBlockMisalign = csd_bit->READ_BLK_MISALIGN; ++ csd->DSRImplemant = csd_bit->DSR_IMP; ++ mult = 1 << (csd_bit->C_SIZE_MULT + 2); ++ blocks = ((csd_bit->C_SIZE_1 | (csd_bit->C_SIZE_2 << 2)) + 1) * mult; ++ len = 1 << (csd_bit->READ_BL_LEN); ++ csd->BlockNumber = blocks; ++ csd->MemorySize = blocks * len; ++ csd->VDDReadMin_u = VDD_CURR_MIN_Table_u[csd_bit->VDD_R_CURR_MIN]; ++ csd->VDDReadMax_u = VDD_CURR_MAX_Table_u[csd_bit->VDD_R_CURR_MAX]; ++ csd->VDDWriteMin_u = VDD_CURR_MIN_Table_u[csd_bit->VDD_W_CURR_MIN]; ++ csd->VDDWriteMax_u = VDD_CURR_MAX_Table_u[csd_bit->VDD_W_CURR_MAX]; ++ csd->EraseBlkEnable = csd_bit->ERASE_BLK_ENABLE; ++ csd->EraseSectorSize = csd_bit->ERASE_SECTOR_SIZE + 1; ++ csd->WriteProtectGroupSize = csd_bit->WP_GRP_SIZE + 1; ++ csd->WriteProtectGroupEnable = csd_bit->WP_GRP_ENABLE; ++ csd->WriteSpeedFactor = two_power(csd_bit->R2W_FACTOR); ++ csd->WriteBlockLength = two_power(csd_bit->WRITE_BL_LEN); ++ csd->WriteBlockPartial = csd_bit->WRITE_BL_PARTIAL; ++ csd->CopyFlag = csd_bit->COPY; ++ csd->PermanentWriteProtect = csd_bit->PERM_WRITE_PROTECT; ++ csd->TemporaryWriteProtect = csd_bit->TMP_WRITE_PROTECT; ++ ++ if (csd_bit->FILE_FORMAT_GRP == 0) ++ csd->FileFormat = csd_bit->FILE_FORMAT; ++ else ++ csd->FileFormat = FILE_FORMAT_RESERVED; ++ ++ return TRUE; ++} ++ ++int sd_cid_parse(sd_cid_t *cid, uint *cid_word) ++{ ++ unchar *ptr; ++ int i; ++ ++ if ((cid_word[0] & 0x00000001) != 1) ++ { ++ sd_err_code = ERR_CID_REGISTER_ERROR; ++ printk("%s() ERR_CID_REGISTER_ERROR\n", __func__); ++ return FALSE; ++ } ++ ++ cid->ManufacturerID = (cid_word[3] & 0xFF000000) >> 24; ++ cid->ApplicationID = (cid_word[3] & 0x00FFFF00) >> 8; ++ ++ ptr = (unchar *) cid_word; ++ ptr += 15 - 3; ++ for (i = 0; i < 6; i++, ptr--) ++ cid->ProductName[i] = *ptr; ++ cid->ProductName[6] = '\0' ; ++ ++ cid->ProductRevisionLow = (cid_word[1] & 0x00F00000) >> 20; ++ cid->ProductRevisionHigh = (cid_word[1] & 0x000F0000) >> 16; ++ cid->ProductSerialNumber = ((cid_word[1] & 0x0000FFFF) << 16) + ((cid_word[0] & 0xFFFF0000) >> 16); ++ cid->ManufactureMonth = ((cid_word[0] & 0x00000F00) >> 8); ++ cid->ManufactureYear = ((cid_word[0] & 0x0000F000) >> 12) + SD_DEFAULT_YEAR_CODE; ++ ++ return TRUE; ++} ++ ++uint sd_read_timeout_cycle(uint clock, sd_csd_t *csd) ++{ ++#if 1 //ivan for 100ms maximux from document "ProdManualIndGradeSDv1.0[1].pdf" chapter A-2 ++ return clock/10; // /10; ++#else ++ uint ret, total, per; ++ ++ per = 1000000000 / clock; ++ total = (csd->TAAC_u + (csd->NSAC_u * 100 * per)) * 100; ++ ++ if (total > (100 * 1000 * 1000)) ++ total = 100 * 1000 * 1000; ++ ret = total / per; ++ ++ return ret; ++#endif ++} ++ ++uint sd_block_size_convert(uint size) ++{ ++ uint ret = 0; ++ ++ while (size >= 2) { ++ size >>= 1; ++ ret++; ++ } ++ return ret; ++} ++ ++int sd_select_card(sd_card_t *info) ++{ ++ uint status; ++ ++ /* send CMD7 with valid RCA to select */ ++ if (!sdc_send_cmd(SD_SELECT_CARD_CMD | SDC_CMD_REG_NEED_RSP, ((uint)info->RCA) << 16, &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ return TRUE; ++} ++ ++int sd_set_transfer_state(sd_card_t *info) ++{ ++ uint state; ++ int count = 0; ++ while (count++ < SD_CARD_STATE_CHANGE_RETRY_COUNT) { ++ if (!sd_get_card_state(info, &state)) ++ return FALSE; ++ ++ switch (state) { ++ case SD_IDLE_STATE: ++ case SD_READY_STATE: ++ case SD_IDENT_STATE: ++ printk("%s() error\n", __func__); ++ return FALSE; ++ case SD_DIS_STATE: ++ if (!sd_operation_complete(info, SD_STBY_STATE)) ++ return FALSE; ++ break; ++ case SD_TRAN_STATE: ++ return TRUE; ++ case SD_DATA_STATE: ++ if (sd_operation_complete(info, SD_TRAN_STATE)) ++ return TRUE; ++ if (sd_err_code != ERR_NO_ERROR) ++ return FALSE; ++ if (!sd_stop_transmission()) ++ return FALSE; ++ break; ++ case SD_RCV_STATE: ++ if (sd_operation_complete(info, SD_TRAN_STATE)) ++ return TRUE; ++ if (sd_err_code != ERR_NO_ERROR) ++ return FALSE; ++ if (!sd_stop_transmission()) ++ return FALSE; ++ break; ++ case SD_PRG_STATE: ++ if (!sd_operation_complete(info, SD_TRAN_STATE)) ++ return FALSE; ++ break; ++ case SD_STBY_STATE: ++ if (!sd_select_card(info)) ++ return FALSE; ++ } ++ } ++ P_DEBUG("%s() error\n", __func__); ++ return FALSE; ++} ++ ++uint sd_write_timeout_cycle(uint clock, sd_csd_t *CSD) ++{ ++#if 1 //ivan for 250ms maximux from document ++ return clock/4; //ijsung hack ++#else ++ uint ret, total, pre; ++ ++ pre = 1000000000 / clock; ++ total = CSD->WriteSpeedFactor * 100 * (CSD->TAAC_u + (CSD->NSAC_u * 100 * pre)); ++ ++ if (total > (100 * 1000 * 1000)) ++ total = 100 * 1000 * 1000; ++ ret = total / pre; ++ ++ return ret; ++#endif ++} ++ ++int sd_card_identify(sd_card_t *info) ++{ ++ uint rca, status, cid[4]; ++ ++ /* reset all cards */ ++ if (!sdc_send_cmd(SD_GO_IDLE_STATE_CMD, 0, NULL)) ++ return FALSE; ++ udelay(1000); ++ /* Do operating voltage range validation */ ++ /* get OCR register */ ++ if (!sd_get_ocr(info, SDC_OCR, (uint *) &info->OCR)) ++ return FALSE; ++ /* ckeck the operation conditions */ ++ if ((info->OCR & SDC_OCR) == 0) { ++ sd_err_code = ERR_OUT_OF_VOLF_RANGE; ++ return FALSE; ++ } ++ ++ /* send CMD2 to get CID register */ ++ if (!sdc_send_cmd(SD_ALL_SEND_CID_CMD | SDC_CMD_REG_NEED_RSP | SDC_CMD_REG_LONG_RSP, 0, cid)) ++ return FALSE; ++ if (info->CardType == MEMORY_CARD_TYPE_SD) { ++ /* send CMD3 to get RCA register */ ++ if (!sdc_send_cmd(SD_SEND_RELATIVE_ADDR_CMD | SDC_CMD_REG_NEED_RSP, 0, &rca)) ++ return FALSE; ++ info->RCA = (ushort) (rca >> 16); ++ } else { ++ /* so far, we only support one interface, so we can give RCA any value */ ++ info->RCA = 0x1; ++ /* send CMD3 to set RCA register */ ++ if (!sdc_send_cmd(SD_SEND_RELATIVE_ADDR_CMD | SDC_CMD_REG_NEED_RSP, (info->RCA << 16), &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++int sd_card_init(sd_card_t *info) ++{ ++ uint clock; ++ ++ P_DEBUG("--> %s\n", __func__); ++ if ((SDC_R_REG(SDC_STATUS_REG) & SDC_STATUS_REG_CARD_INSERT) != SDC_CARD_INSERT) ++ return FALSE; ++ sd_err_code = ERR_NO_ERROR; ++ /* At first, set card type to SD */ ++ info->CardType = MEMORY_CARD_TYPE_SD; ++ /* set memory card type */ ++ sdc_set_card_type(info->CardType); ++ /* start card idenfication process */ ++ if (!sd_card_identify(info)) { ++ printk("this is not SD card\n"); ++ sd_err_code = ERR_NO_ERROR; ++ info->CardType = MEMORY_CARD_TYPE_MMC; ++ /* set memory card type */ ++ sdc_set_card_type(info->CardType); ++ if (!sd_card_identify(info)) ++ return FALSE; ++ } ++ ++ /* get CSD */ ++ if (!sd_set_card_standby(info)) ++ return FALSE; ++ /* send CMD9 to get CSD register */ ++ if (!sdc_send_cmd(SD_SEND_CSD_CMD | SDC_CMD_REG_NEED_RSP | SDC_CMD_REG_LONG_RSP, ((uint) info->RCA) << 16, info->CSDWord)) ++ return FALSE; ++ sd_csd_parse(&info->CSD, info->CSDWord); ++ ++ if (info->CSD.ReadBlockLength != SD_SECTOR_SIZE) { ++ printk("Sector size is mis-matched (SD CSD report=0x%X,SD_SECTOR_SIZE=0x%X)\n", info->CSD.ReadBlockLength, SD_SECTOR_SIZE); ++ info->CSD.ReadBlockLength = SD_SECTOR_SIZE; ++// return FALSE; ++ } ++ ++ /* get CID */ ++ /* send CMD10 to get CID register */ ++ if (!sdc_send_cmd(SD_SEND_CID_CMD | SDC_CMD_REG_NEED_RSP | SDC_CMD_REG_LONG_RSP, ((uint) info->RCA) << 16, info->CIDWord)) ++ return FALSE; ++ sd_cid_parse(&info->CID, info->CIDWord); ++ ++ /* Set card bus clock. sdc_set_bus_clock() will give the real card bus clock has been set. */ ++ clock = sdc_set_bus_clock(info, info->CSD.TransferSpeed); ++ info->ReadAccessTimoutCycle = sd_read_timeout_cycle(clock, &(info->CSD)); ++ info->WriteAccessTimoutCycle = sd_write_timeout_cycle(clock, &(info->CSD)); ++ /* set bus width */ ++ if (!sdc_set_bus_width(info)) ++ return FALSE; ++ ++ /* check write protect */ ++ info->WriteProtect = ((SDC_R_REG(SDC_STATUS_REG) & SDC_STATUS_REG_CARD_LOCK) == SDC_STATUS_REG_CARD_LOCK) ? TRUE : FALSE; ++ if(info->WriteProtect == TRUE) ++ printk("SD/MMC Card is Write Protected\n"); ++ info->ActiveState = TRUE; ++ P_DEBUG("<-- %s\n", __func__); ++ ++ return TRUE; ++} ++ ++int sd_card_insert(sd_card_t *info) ++{ ++ P_DEBUG("--> %s\n", __func__); ++ /* reset host interface controller */ ++ sdc_reset(); ++ /* turn on clock using default clock*/ ++ SDC_W_REG(SDC_CLOCK_CTRL_REG, SDC_R_REG(SDC_CLOCK_CTRL_REG)&0xff); ++ ++ if (!sd_card_init(info)) { ++ printk("root initialize failed\n"); ++ return FALSE; ++ } ++ /* set interrupt mask register */ ++ SDC_W_REG(SDC_INT_MASK_REG, SDC_STATUS_REG_CARD_CHANGE | SDC_STATUS_REG_DATA_TIMEOUT); ++ P_DEBUG("<-- %s\n", __func__); ++ ++ return TRUE; ++} ++ ++int sd_card_remove(sd_card_t *info) ++{ ++ sd_err_code = ERR_NO_ERROR; ++ ++ info->ActiveState = FALSE; ++ info->WriteProtect = FALSE; ++ info->RCA = 0; ++ /* reset host interface controller */ ++ sdc_reset(); ++ /* set interrupt mask register */ ++ SDC_W_REG(SDC_INT_MASK_REG, SDC_STATUS_REG_CARD_CHANGE | SDC_STATUS_REG_DATA_TIMEOUT); ++ sd_err_code = ERR_CARD_NOT_EXIST; ++ /* turn off clock */ ++ SDC_W_REG(SDC_CLOCK_CTRL_REG, SDC_R_REG(SDC_CLOCK_CTRL_REG) | 0x100); ++ return TRUE; ++} ++ ++irqreturn_t sd_hotswap_interrupt_handler(int irq, void *dev_id) ++{ ++ uint status; ++ struct sd_dev *dev = dev_id; ++ ++ P_DEBUG("--> %s, irq=%d\n", __func__, irq); ++ /* When the card is inserted or removed, we must delay a short time to make sure */ ++ /* the SDC_STATUS_REG_CARD_INSERT bit of status register is stable */ ++ udelay(1000); ++ status = SDC_R_REG(SDC_STATUS_REG); ++ if ((status & SDC_STATUS_REG_CARD_CHANGE) == SDC_STATUS_REG_CARD_CHANGE) { ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_CARD_CHANGE | SDC_STATUS_REG_DATA_TIMEOUT); ++ if ((status & SDC_STATUS_REG_CARD_INSERT) == SDC_CARD_INSERT) { ++ dev->card_state = SD_CARD_INSERT; ++ printk("Card Insert\n"); ++ sd_card_insert(&sd_card_info); ++ } else { ++ dev->card_state = SD_CARD_REMOVE; ++ printk("Card Remove\n"); ++ sd_card_remove(&sd_card_info); ++ /* remove all current transfers as I/O error*/ ++#if 0 //ASYNC ++ spin_lock_irqsave(&io_request_lock, status); ++ INIT_REQUEST; ++ while(!QUEUE_EMPTY) ++ end_request(0); ++ bh_busy=0; ++ spin_unlock_irqrestore(&io_request_lock, status); ++#endif ++ } ++ } else if ((status & SDC_STATUS_REG_DATA_TIMEOUT) == SDC_STATUS_REG_DATA_TIMEOUT) { ++ SDC_W_REG(SDC_CLEAR_REG, SDC_STATUS_REG_CARD_CHANGE | SDC_STATUS_REG_DATA_TIMEOUT); ++ ++#if 0 //ASYNC ++ printk("Data timeout. Retry.\n"); ++ sd_clustered_bh(2); ++#else ++ printk("Data timeout. Retry.\n"); ++#endif ++ } ++ P_DEBUGG("card state=%d\n", dev->card_state); ++ P_DEBUG("<-- %s\n", __func__); ++ return IRQ_HANDLED; ++} ++ ++/*------------------------------------ ++ * Block-driver specific functions ++ */ ++/* ++ * Find the device for this request. ++ */ ++#if 0 ++static inline struct sd_dev *sd_locate_device(const struct request *req) ++{ ++ int devno; ++ struct sd_dev *dev; ++ ++ P_DEBUG("--> %s\n", __func__); ++#if 0 ++ /* Check if the minor number is in range */ ++ devno = DEVICE_NR(req->rq_dev); ++ P_DEBUGG("minor=%d\n", devno); ++ if (devno >= SD_DEVS) { ++ static int count = 0; ++ ++ if (count++ < 5) /* print the message at most five times */ ++ P_DEBUG("request for unknown device\n"); ++ return NULL; ++ } ++#endif ++ dev = sd_devices + devno; ++ P_DEBUGG("card_state=%d\n", dev->card_state); ++ P_DEBUG("<-- %s\n", __func__); ++ return dev; ++} ++ ++int sd_card_check_exist(sd_card_t *info) ++{ ++ /* if card is not exist */ ++ if ((SDC_R_REG(SDC_STATUS_REG) & SDC_STATUS_REG_CARD_INSERT) != SDC_CARD_INSERT) { ++ sd_card_remove(info); ++ return FALSE; ++ } ++ /* if card is not active */ ++ if (!info->ActiveState) ++ { ++ return sd_card_insert(info); ++ } ++ return TRUE; ++} ++#endif ++ ++void sd_reset_host_controller(void) ++{ ++ uint clock, mask, width; ++ ++ /* read register */ ++ clock = SDC_R_REG(SDC_CLOCK_CTRL_REG); ++ width = SDC_R_REG(SDC_BUS_WIDTH_REG); ++ mask = SDC_R_REG(SDC_INT_MASK_REG); ++ /* reset host interface */ ++ sdc_reset(); ++ /* restore register */ ++ SDC_W_REG(SDC_CLOCK_CTRL_REG, clock); ++ SDC_W_REG(SDC_BUS_WIDTH_REG, width); ++ SDC_W_REG(SDC_INT_MASK_REG, mask); ++} ++ ++int sd_read_single_block(sd_card_t *info, uint addr, uint size, uint timeout, unchar *buf) ++{ ++ uint status; ++ ++ if (!sdc_set_block_size(size)) ++ return FALSE; ++ ++ sdc_config_transfer(info, size, size, SDC_DATA_CTRL_REG_DATA_READ, timeout); ++ ++ if (!sdc_send_cmd(SD_READ_SINGLE_BLOCK_CMD | SDC_CMD_REG_NEED_RSP, addr, &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ ++#ifdef DELAY_FOR_DMA_READ ++ if (first_run==0) { ++ int i=0; ++ for(i=0;i<10;i++) ++ udelay(1000); ++ first_run=1; ++ } ++#endif ++ if (!sdc_read_block(info, size, (uint *) buf)) ++ return FALSE; ++ ++ if (sd_err_code != ERR_NO_ERROR) { ++ printk("%s() error=0x%X\n", __func__, sd_err_code); ++ sd_reset_host_controller(); ++ return FALSE; ++ } else { ++ if (!sdc_check_data_end()) { ++ sd_stop_transmission(); ++ printk("%s()2 error=0x%X\n", __func__, sd_err_code); ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++int sd_write_single_block(sd_card_t *info, uint addr, uint size, uint timeout, unchar *buf) ++{ ++ uint status; ++ ++ if (!sdc_set_block_size(size)) ++ return FALSE; ++ ++ sdc_config_transfer(info, size, size, SDC_DATA_CTRL_REG_DATA_WRITE, timeout); ++ ++ if (!sdc_send_cmd(SD_WRITE_SINGLE_BLOCK_CMD | SDC_CMD_REG_NEED_RSP, addr, &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ ++ if (!sdc_write_block(info, size, (uint *) buf)) ++ return FALSE; ++ if (sd_err_code != ERR_NO_ERROR) { ++ printk("%s() error=0x%X\n", __func__, sd_err_code); ++ sd_reset_host_controller(); ++ return FALSE; ++ } else { ++ if (!sdc_check_data_end()) { ++ sd_stop_transmission(); ++ printk("%s()2 error=0x%X\n", __func__, sd_err_code); ++ return FALSE; ++ } ++ } ++ ++ return TRUE; ++} ++ ++int sd_read_multiple_block(sd_card_t *info, uint addr, uint count, uint size, uint timeout, unchar *buf) ++{ ++ uint err, status; ++ ++ if (!sdc_set_block_size(size)) ++ return FALSE; ++ ++ sdc_config_transfer(info, count * size, size, SDC_DATA_CTRL_REG_DATA_READ, timeout); ++ ++ if (!sdc_send_cmd(SD_READ_MULTIPLE_BLOCK_CMD | SDC_CMD_REG_NEED_RSP, addr, &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++ ++#ifdef DELAY_FOR_DMA_READ ++ if (first_run==0) { ++ int i=0; ++ for(i=0;i<10;i++) ++ udelay(1000); ++ first_run=1; ++ } ++#endif ++#if 0 //ijsung: Sometimes this will cause IRQ lost, and is slower. Use method below ++ while (count > 0) { ++ if (!sdc_read_block(info, size, (uint *) buf)) ++ return FALSE; ++ count--; ++ buf += size; ++ } ++#else //ijsung: DMA at once. ++ if (!sdc_read_block(info, size*count, (uint *) buf)) ++ return FALSE; ++#endif ++ if (sd_err_code != ERR_NO_ERROR) { ++ err = sd_err_code; ++ sd_stop_transmission(); ++ sd_reset_host_controller(); ++ sd_err_code |= err; ++ printk("%s() error=0x%X\n", __func__, sd_err_code); ++ return FALSE; ++ } else { ++ if (!sdc_check_data_end()) { ++ err = sd_err_code; ++ sd_stop_transmission(); ++ sd_err_code |= err; ++ printk("%s()2 error=0x%X\n", __func__, sd_err_code); ++ return FALSE; ++ } ++ if (!sd_stop_transmission()) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++int sd_write_multiple_block(sd_card_t *info, uint addr, uint count, uint size, uint timeout, unchar *buf) ++{ ++ uint ErrorCode, status; ++ ++ if(!sdc_set_block_size(size)) ++ return FALSE; ++ ++ sdc_config_transfer(info, count * size, size, SDC_DATA_CTRL_REG_DATA_WRITE, timeout); ++ sdc_pre_erase_cmd(count); //ijsung: pre-erase ++ if (!sdc_send_cmd(SD_WRITE_MULTIPLE_BLOCK_CMD | SDC_CMD_REG_NEED_RSP, addr, &status)) ++ return FALSE; ++ if (!sd_check_err(status)) ++ return FALSE; ++#if 0 //ijsung: Sometimes this will cause IRQ lost, and is slower. Use method below ++ while (count > 0) { ++ if (!sdc_write_block(info, size, (uint *) buf)) ++ return FALSE; ++ count--; ++ buf += size; ++ } ++#else //ijsung: DMA at once. ++ if (!sdc_write_block(info, size*count, (uint *) buf)) ++ return FALSE; ++#endif ++ ++ if (sd_err_code != ERR_NO_ERROR) ++ { ++ ErrorCode = sd_err_code; ++ sd_stop_transmission(); ++ sd_reset_host_controller(); ++ sd_err_code |= ErrorCode; ++ printk("%s() error=0x%X\n", __func__, sd_err_code); ++ return FALSE; ++ } else { ++ if (!sdc_check_data_end()) { ++ ErrorCode = sd_err_code; ++ sd_stop_transmission(); ++ sd_err_code |= ErrorCode; ++ printk("%s()2 error=0x%X\n", __func__, sd_err_code); ++ return FALSE; ++ } ++ if (!sd_stop_transmission()) ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++int sd_wait_transfer_state(sd_card_t *info) ++{ ++ uint state; ++ int count = 0; ++ while (count++ < SD_CARD_WAIT_TRANSFER_STATE_RETRY_COUNT) { ++ if (!sd_get_card_state(info, &state)) ++ return FALSE; ++ ++ switch (state) { ++ case SD_IDLE_STATE: ++ case SD_READY_STATE: ++ case SD_IDENT_STATE: ++ case SD_DIS_STATE: ++ case SD_STBY_STATE: ++ printk("%s() error\n", __func__); ++ return FALSE; ++ case SD_TRAN_STATE: ++ return TRUE; ++ case SD_DATA_STATE: ++ case SD_RCV_STATE: ++ case SD_PRG_STATE: ++ break; ++ } ++ } ++ sd_err_code = ERR_SD_CARD_IS_BUSY; ++ P_DEBUG("%s() ERR_SD_CARD_IS_BUSY\n", __func__); ++ return FALSE; ++} ++ ++/*************************************************************************** ++SD Card Read/Write/Erase Function ++***************************************************************************/ ++int sd_read_sector(sd_card_t *info, uint addr, uint count, unchar *buf) ++{ ++ int cnt; ++ uint start; ++ sync_mode=1; ++ P_DEBUG("%s : sector = %d,count = %d\n",__func__,addr,count); ++ if (count > MAX_READ_SECTOR_NR) { ++ P_DEBUG("Readable Block Number Per Commands is 0x%X\n",MAX_READ_SECTOR_NR); ++ return FALSE; ++ } ++ ++ sd_err_code = ERR_NO_ERROR; ++ ++ if (!info->ActiveState) { ++ P_DEBUG("%s : SD card not active!!\n", __func__); ++ return FALSE; ++ } ++ ++ if (!sd_set_transfer_state(info)) ++ return FALSE; ++ ++ start = addr * info->CSD.ReadBlockLength; ++ cnt = (int) count; ++ ++ while (cnt > 0) { ++ if (cnt > 1) { ++ if (!sd_read_multiple_block(info, start, (cnt > MAX_MULTI_BLOCK_NUM) ? MAX_MULTI_BLOCK_NUM : cnt, ++ info->CSD.ReadBlockLength, info->ReadAccessTimoutCycle, buf)) ++ return FALSE; ++ } else { ++ if (!sd_read_single_block(info, start, info->CSD.ReadBlockLength, info->ReadAccessTimoutCycle, buf)) ++ return FALSE; ++ return TRUE; ++ } ++ ++ if (!sd_wait_transfer_state(info)) ++ return FALSE; ++ ++ cnt -= MAX_MULTI_BLOCK_NUM; ++ start += MAX_MULTI_BLOCK_NUM * info->CSD.ReadBlockLength; ++ buf += MAX_MULTI_BLOCK_NUM * info->CSD.ReadBlockLength; ++ } ++ ++ return TRUE; ++} ++ ++int sd_write_sector(sd_card_t *info, uint addr, uint count, unchar *buf) ++{ ++ int cnt; ++ uint start; ++ ++ if (count > MAX_WRITE_SECTOR_NR) { ++ P_DEBUG("Writable Block Number Per Commands is 0x%X\n",MAX_WRITE_SECTOR_NR); ++ return FALSE; ++ } ++ ++ sd_err_code = ERR_NO_ERROR; ++ ++ if (!info->ActiveState) { ++ P_DEBUG("%s : SD card not active!!\n", __func__); ++ return FALSE; ++ } ++ ++ if (info->WriteProtect == TRUE) { ++ sd_err_code = ERR_SD_CARD_IS_LOCK; ++ printk("Write Protected!!\n"); ++ return FALSE; ++ } ++ if (!sd_set_transfer_state(info)) ++ return FALSE; ++ ++ start = addr * info->CSD.ReadBlockLength; ++ cnt = (int) count; ++ ++ while (cnt > 0) { ++ if (cnt > 1) { ++ if (!sd_write_multiple_block(info, start, (cnt > MAX_MULTI_BLOCK_NUM) ? MAX_MULTI_BLOCK_NUM : cnt, ++ info->CSD.ReadBlockLength, info->WriteAccessTimoutCycle, buf)) ++ return FALSE; ++ } else { ++ if (!sd_write_single_block(info, start, info->CSD.ReadBlockLength, info->WriteAccessTimoutCycle, buf)) ++ return FALSE; ++ return TRUE; ++ } ++ ++ if (!sd_wait_transfer_state(info)) ++ return FALSE; ++ ++ cnt -= MAX_MULTI_BLOCK_NUM; ++ start += MAX_MULTI_BLOCK_NUM * info->CSD.ReadBlockLength; ++ buf += MAX_MULTI_BLOCK_NUM * info->CSD.ReadBlockLength; ++ } ++ ++ return TRUE; ++} ++/*---------------------------------------------- ++ * Perform an actual transfer: ++ * Returns: # of sectors transferred. 0 = error ++ */ ++static int sd_transfer(struct sd_dev *device, const struct request *req) ++{ ++ int status = 0; ++ int count = 0; ++ ++ struct bio *bio = req->bio; ++ struct bio_vec *bvec; ++ struct req_iterator iter; ++ ++ spin_unlock_irq( &device->lock); ++ ++#if 0 ++ P_DEBUG("\nreq sector: %d, nr_sectors: %d, hard_cur_sectors: %d phys_seg: %d, buf: 0x%08lx\n", ++ (int)req->sector, (int)req->nr_sectors, (int)req->hard_cur_sectors, ++ (int)req->nr_phys_segments, (ulong)bio_data( bio)); ++#endif ++ ++ rq_for_each_segment( bvec, req, iter) { ++ ++ unsigned char *buf = page_address( bvec->bv_page) + bvec->bv_offset; ++ int sectors = bio_cur_bytes(bio) >> 9; ++ ++ P_DEBUG("bvec[%2d]: sector: %d, count: %d, curr: %d, buf: 0x%08lx, ", ++ iter.i, (int)bio->bi_sector, count, (int)sectors, (unsigned long)buf); ++ ++ sd_card_info.private = (void *)&device->ch_req; ++ ++ if( rq_data_dir(req) == 0) /* Read */ ++ status = sd_read_sector( &sd_card_info, sector_offset + bio->bi_sector, sectors, buf); ++ else ++ status = sd_write_sector( &sd_card_info, sector_offset + bio->bi_sector, sectors, buf); ++ ++ P_DEBUG("status: %d\n", status); ++ ++ if (status <= 0) { ++ spin_lock_irq( &device->lock); ++ return count; ++ } ++ ++ count += sectors; ++ bio->bi_sector += sectors; ++ } ++ ++ if( ( req->__sector == 0) && !Do_onetime){ ++ ++ unsigned char *buf = bio_data( bio); ++ ++ if( ( buf[ 0x1be] != 0x0) && ( buf[ 0x1be] != 0x80)) /* partition identify */ ++ sector_offset = 0; //sector 0 is PBR ++ else ++ sector_offset = ( buf[ 0x1c6]) | ( buf[ 0x1c7] << 8) | ( buf[ 0x1c8] <<16) |( buf[ 0x1c9] << 24); ++ ++ P_DEBUG( "sector_offset = %d\n", sector_offset); ++ Do_onetime = 1; ++ } ++ ++ spin_lock_irq( &device->lock); ++ ++ if( status <= 0) ++ return 0; ++ else ++ return count; ++} ++ ++#ifdef SD_DEBUG ++uint sd_dev_info(void) ++{ ++ sd_csd_t *CSD; ++ sd_cid_t *CID; ++ ++ P_DEBUG("============SDCard=====================================\n"); ++#if 0 ++ if (!sd_card_check_exist(&sd_card_info)) ++ { ++ P_DEBUG("SD Card does not exist!!!"); ++ return FALSE; ++ } ++#else ++ if (!sd_card_info.ActiveState) { ++ P_DEBUG("%s : SD card not active!!\n", __func__); ++ return FALSE; ++ } ++#endif ++ ++ /* print OCR, RCA register */ ++ P_DEBUG("OCR>> 0x%08X RCA>> 0x%04X\n", (uint) sd_card_info.OCR, sd_card_info.RCA); ++ /* print CID register */ ++ P_DEBUG("CID>> 0x%08X 0x%08X 0x%08X 0x%08X\n", sd_card_info.CIDWord[0], sd_card_info.CIDWord[1], sd_card_info.CIDWord[2], sd_card_info.CIDWord[3]); ++ CID = &(sd_card_info.CID); ++ P_DEBUG(" MID:0x%02X OID:0x%04X PNM:%s PRV:%d.%d PSN:0x%08X\n", CID->ManufacturerID, CID->ApplicationID, CID->ProductName, ++ CID->ProductRevisionHigh, CID->ProductRevisionLow, CID->ProductSerialNumber); ++ P_DEBUG(" MDT:%d/%d\n", CID->ManufactureMonth, CID->ManufactureYear); ++ /* print CSD register */ ++ P_DEBUG("CSD>> 0x%08X 0x%08X 0x%08X 0x%08X\n", sd_card_info.CSDWord[0], sd_card_info.CSDWord[1], sd_card_info.CSDWord[2], sd_card_info.CSDWord[3]); ++ CSD = &(sd_card_info.CSD); ++ P_DEBUG(" CSDStructure:%d Spec.Version:%d\n", CSD->CSDStructure, CSD->MMCSpecVersion); ++ P_DEBUG(" TAAC:%dns NSAC:%d clock cycles\n", CSD->TAAC_u, CSD->NSAC_u); ++ P_DEBUG(" TransferSpeed:%d bit/s CardCommandClass:0x%03X\n", CSD->TransferSpeed, CSD->CardCmdClass); ++ P_DEBUG(" ReadBlLen:%d ReadBlPartial:%X WriteBlkMisalign:%X ReadBlkMisalign:%X\n", CSD->ReadBlockLength, CSD->ReadBlockPartial, CSD->WriteBlockMisalign, CSD->ReadBlockMisalign); ++ P_DEBUG(" DSP:%X BlockNumber:%d MemorySize:%d \n", CSD->DSRImplemant, CSD->BlockNumber, CSD->MemorySize); ++ P_DEBUG(" VDD_R_MIN:%d/10mA VDD_R_MAX:%dmA\n", (uint) CSD->VDDReadMin_u, (uint) CSD->VDDReadMax_u); ++ P_DEBUG(" VDD_W_MIN:%d/10mA VDD_W_MAX:%dmA\n", (uint) CSD->VDDWriteMin_u, (uint) CSD->VDDWriteMax_u); ++ P_DEBUG(" EraseBlkEnable:%d EraseSectorSize:%d WpGrpSize:%d WpGrpEnable:%X\n", CSD->EraseBlkEnable, CSD->EraseSectorSize, CSD->WriteProtectGroupSize, CSD->WriteProtectGroupEnable); ++ P_DEBUG(" WriteSpeedFactor:%d WriteBlLen:%d WriteBlPartial:%X\n", CSD->WriteSpeedFactor, CSD->WriteBlockLength, CSD->WriteBlockPartial); ++ P_DEBUG(" Copy:%X PermWrProtect:%X TmpWrProtect:%X FileFormat:%X\n", CSD->CopyFlag, CSD->PermanentWriteProtect, CSD->TemporaryWriteProtect, CSD->FileFormat); ++ P_DEBUG(" ReadTimoutCycle:0x%08X WriteTimoutCycle:0x%08X\n", sd_card_info.ReadAccessTimoutCycle, sd_card_info.WriteAccessTimoutCycle); ++ /* print SCR register */ ++ P_DEBUG("SCR>> 0x%08X 0x%08X \n", *(((uint *) &sd_card_info.SCR)), *(((uint *) &sd_card_info.SCR) + 1)); ++ P_DEBUG(" SCR_STRUCTURE:%d, SD_SPEC:%d, Data_status_after_erase:%d\n", sd_card_info.SCR.SCR_STRUCTURE, sd_card_info.SCR.SD_SPEC, sd_card_info.SCR.DATA_STAT_AFTER_ERASE); ++ P_DEBUG(" sd_security:%d, SD_BUS_WIDTH:%X\n", sd_card_info.SCR.SD_SECURITY, sd_card_info.SCR.SD_BUS_WIDTH); ++ ++ return TRUE; ++} ++#endif ++ ++static int sd_card_setup(struct sd_dev *dev) ++{ ++ uint sd_card_size; ++ int i; ++ ++ P_DEBUG("--> %s\n", __func__); ++ first_run = 0; ++ sd_err_code = ERR_NO_ERROR; ++ ++ sd_card_info.ActiveState = FALSE; ++ sd_card_info.WriteProtect = FALSE; ++ sd_card_info.IOAddr = FTSDC_VA_BASE; ++ sd_card_info.DMAEnable = FALSE; ++ ++ sd_card_info.SysFrequency = AHB_CLK_IN/2; ++ P_DEBUG("DMA Enable is %d, Sys frequency = %d\n", sd_card_info.DMAEnable, sd_card_info.SysFrequency); ++ sd_card_info.RCA = 0; ++ sd_card_info.Drive = 'S'; ++ ++ if (!sd_card_insert(&sd_card_info)) ++ return FALSE; ++#ifdef SD_DEBUG ++ if (!sd_dev_info()) ++ return FALSE; ++#endif ++ sd_card_size = sd_card_info.CSD.MemorySize; ++ printk(KERN_NOTICE "FTSDC010: SD Card Capacity=%d MB\n", sd_card_size/1000000); /* Marketing MB is not 1048576 */ ++ ++ for (i = 0; i < SD_DEVS; i++) { ++ sd_devices[i].size = sd_card_size / SD_SECTOR_SIZE; //unit is block, not bytes ++ ++#if 0 ++ sd_partitions[i << SD_SHIFT].nr_sects =sd_size * (SD_BLKSIZE / SD_SECTOR_SIZE); ++ P_DEBUG ("%s() %d-th device, size=%d blks(blks=%d),nr_sects=%ld\n", __func__, i, sd_size, SD_BLKSIZE, sd_partitions[i << SD_SHIFT].nr_sects); ++#endif ++ //sd_devices[i].card_state = SD_CARD_WORK; ++ //sema_init(&(sd_devices[i].sema), 1); // add by Charles Tsai*/ ++ } ++ ++ sd_card_info.DMAEnable = dev->dma_enable; ++ ++ P_DEBUG("<-- %s\n", __func__); ++ return TRUE; ++} ++ ++/* ++ * Driver stuff ++ */ ++/*------------------------------------ ++ * The ioctl implementation ++ */ ++int sd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) ++{ ++ int size; ++ struct hd_geometry geo; ++ struct sd_dev *device=bdev->bd_disk->private_data; ++ P_DEBUG ("ioctl 0x%x 0x%lx\n", cmd, arg); ++ switch (cmd) { ++ case BLKGETSIZE: ++ /* Return the device size, expressed in sectors */ ++ /* FIXME: distinguish between kernel sector size and media sector size */ ++ size = device->size; ++ __copy_to_user ((long *) arg, &size, sizeof (long)); ++ return 0; ++#if 0 ++ case BLKFLSBUF: /* flush */ ++ return blk_ioctl(inode->i_rdev, cmd, arg); ++ case BLKRAGET: /* return the readahead value */ ++ return blk_ioctl(inode->i_rdev, cmd, arg); ++ case BLKRASET: /* set the readahead value */ ++ if (!capable (CAP_SYS_RAWIO)) ++ return -EACCES; ++ if (arg > 0xff) ++ return -EINVAL; /* limit it */ ++ return 0; ++// case BLKRRPART: /* re-read partition table */ ++// return sd_revalidate (inode->i_rdev); ++#endif ++ case HDIO_GETGEO: ++ /* ++ * get geometry: we have to fake one... trim the size to a ++ * multiple of 64 (32k): tell we have 16 sectors, 4 heads, ++ * whatever cylinders. Tell also that data starts at sector. 4. ++ */ ++ geo.cylinders = (device->size/4)/8; /* ?? only for test */ ++ geo.heads = 4; ++ geo.sectors = 8; ++ geo.start = 0; ++ __copy_to_user ((void *) arg, &geo, sizeof (geo)); ++ return 0; ++ default: ++ /* ++ * For ioctls we don't understand, let the block layer handle them. ++ */ ++ return -ENOTTY;//blk_ioctl (inode->i_rdev, cmd, arg); ++ } ++ ++ return -ENOTTY; /* unknown command */ ++} ++ ++static void sd_request(struct request_queue *q) ++{ ++ struct sd_dev *dev; ++ static int active; ++#ifndef A320_SD_USE_ASYNC_DMA ++ int ret; ++ struct request *req; ++#else ++ if(bh_busy) ++ return; ++#endif ++ if(active) ++ return; ++ active = 1; ++ P_DEBUG("--> %s\n", __func__); ++repeat: ++ /* Locate the device */ ++ if((req=blk_fetch_request(q))==NULL) { ++ active = 0; ++ return; ++ } ++ dev = req->rq_disk->private_data; ++ if (!dev||dev->card_state == SD_CARD_REMOVE) { ++ if(!dev) ++ printk(KERN_NOTICE"SD: locating device error\n"); ++ __blk_end_request_cur(req, -EIO); ++ goto repeat; ++ } ++#ifndef A320_SD_USE_ASYNC_DMA ++ sync_mode=1; ++ //spin_unlock_irq(&io_request_lock); ++ ret = sd_transfer(dev, req); ++ __blk_end_request(req, 0, ret << 9); ++ //spin_lock_irq(&io_request_lock); ++ goto repeat; ++ ++#else ++ sync_mode=0; //Use new async DMA machanism ++ //printk("%s: set up initial DMA, from sector %d to buffer 0x%X\n", __func__, CURRENT->sector+sector_offset, CURRENT->buffer); ++ //sd_init_async_dma(); ++ sd_clustered_bh(1); ++ //bh_busy=1; ++#endif ++ P_DEBUG("<-- %s\n", __func__); ++} ++ ++#if 0 ++/*----------------------------------------- ++ * Support for removable devices ++ */ ++int sd_check_change(kdev_t i_rdev) ++{ ++ int minor = DEVICE_NR(i_rdev); ++ struct sd_dev *dev = sd_devices + minor; ++ ++ P_DEBUG("--> %s\n", __func__); ++ P_DEBUG("minor=%d\n", minor); ++ if (minor >= SD_DEVS) /* paranoid */ ++ return 0; ++ P_DEBUG("check change for dev %d\n", minor); ++ if (dev->usage) { ++ P_DEBUG("disk not change\n"); ++ P_DEBUG("<-- %s\n", __func__); ++ return 0; /* still valid */ ++ } ++ P_DEBUG("disk changed\n"); ++ P_DEBUG("<-- %s\n", __func__); ++ return 1; /* expired */ ++} ++#endif ++ ++static int sd_dma_ch_alloc(struct sd_dev *dev) ++{ ++ dmad_chreq *ch_req = &dev->ch_req; ++ ++ memset(ch_req, 0, sizeof(dmad_chreq)); ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++ ++ ch_req->apb_req.addr0_ctrl = APBBR_ADDRINC_FIXED; /* (in) APBBR_ADDRINC_xxx */ ++/* for amerald */ ++ if((inl(PMU_BASE) & AMERALD_MASK) == AMERALD_PRODUCT_ID){ ++ ch_req->apb_req.addr0_reqn = APBBR_REQN_SDC_AMERALD; ++ }else ++ ch_req->apb_req.addr0_reqn = APBBR_REQN_SDC; /* (in) APBBR_REQN_xxx (also used to help determine bus selection) */ ++ ch_req->apb_req.addr1_ctrl = APBBR_ADDRINC_I4X; /* (in) APBBR_ADDRINC_xxx */ ++ ch_req->apb_req.addr1_reqn = APBBR_REQN_NONE; /* (in) APBBR_REQN_xxx (also used to help determine bus selection) */ ++ ch_req->apb_req.burst_mode = 1; /* (in) Burst mode (0: no burst 1-, 1: burst 4- data cycles per dma cycle) */ ++ ch_req->apb_req.data_width = APBBR_DATAWIDTH_4; /* (in) APBBR_DATAWIDTH_4(word), APBBR_DATAWIDTH_2(half-word), APBBR_DATAWIDTH_1(byte) */ ++ ch_req->apb_req.tx_dir = DMAD_DIR_A0_TO_A1; /* (in) DMAD_DIR_A0_TO_A1, DMAD_DIR_A1_TO_A0 */ ++ ++ ch_req->controller = DMAD_DMAC_APB_CORE; /* (in) DMAD_DMAC_AHB_CORE, DMAD_DMAC_APB_CORE */ ++ ch_req->flags = DMAD_FLAGS_SLEEP_BLOCK | DMAD_FLAGS_BIDIRECTION; ++ ++ if (dmad_channel_alloc(ch_req) != 0) { ++ memset(ch_req, 0, sizeof(dmad_chreq)); ++ printk(KERN_INFO "%s: APB dma channel allocation failed\n", __func__); ++ goto _try_ahb; ++ } ++ ++ P_DEBUG("%s: APB dma channel allocated (ch: %d)\n", __func__, ch_req->channel); ++ //printk("%s: APB dma channel allocated (ch: %d)\n", __func__, ch_req->channel); ++ ++ return 0; ++ ++_try_ahb: ++ ++#endif /* CONFIG_PLATFORM_APBDMA */ ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ ++ ch_req->ahb_req.sync = 1; /* (in) non-zero if src and dst have different clock domain */ ++ ch_req->ahb_req.priority = DMAC_CSR_CHPRI_1; /* (in) DMAC_CSR_CHPRI_0 (lowest) ~ DMAC_CSR_CHPRI_3 (highest) */ ++ ch_req->ahb_req.hw_handshake = 1; /* (in) non-zero to enable hardware handshake mode */ ++ ch_req->ahb_req.burst_size = DMAC_CSR_SIZE_4; /* (in) DMAC_CSR_SIZE_1 ~ DMAC_CSR_SIZE_256 */ ++ ch_req->ahb_req.addr0_width = DMAC_CSR_WIDTH_32; /* (in) DMAC_CSR_WIDTH_8, DMAC_CSR_WIDTH_16, or DMAC_CSR_WIDTH_32 */ ++ ch_req->ahb_req.addr0_ctrl = DMAC_CSR_AD_FIX; /* (in) DMAC_CSR_AD_INC, DMAC_CSR_AD_DEC, or DMAC_CSR_AD_FIX */ ++ ch_req->ahb_req.addr0_reqn = DMAC_REQN_SDC; /* (in) DMAC_REQN_xxx (also used to help determine channel number) */ ++ ch_req->ahb_req.addr1_width = DMAC_CSR_WIDTH_32; /* (in) DMAC_CSR_WIDTH_8, DMAC_CSR_WIDTH_16, or DMAC_CSR_WIDTH_32 */ ++ ch_req->ahb_req.addr1_ctrl = DMAC_CSR_AD_INC; /* (in) DMAC_CSR_AD_INC, DMAC_CSR_AD_DEC, or DMAC_CSR_AD_FIX */ ++ ch_req->ahb_req.addr1_reqn = DMAC_REQN_NONE; /* (in) DMAC_REQN_xxx (also used to help determine channel number) */ ++ ch_req->ahb_req.tx_dir = DMAD_DIR_A0_TO_A1; /* (in) DMAD_DIR_A0_TO_A1, DMAD_DIR_A1_TO_A0 */ ++ ++ ch_req->controller = DMAD_DMAC_AHB_CORE; /* (in) DMAD_DMAC_AHB_CORE, DMAD_DMAC_APB_CORE */ ++ ch_req->flags = DMAD_FLAGS_SLEEP_BLOCK | DMAD_FLAGS_BIDIRECTION; ++ ++ if (dmad_channel_alloc(ch_req) != 0) { ++ memset(ch_req, 0, sizeof(dmad_chreq)); ++ printk(KERN_INFO "%s: AHB dma channel allocation failed\n", __func__); ++ goto _err_exit; ++ } ++ ++ P_DEBUG("%s: AHB dma channel allocated (ch: %d)\n", __func__, ch_req->channel); ++ //printk("%s: AHB dma channel allocated (ch: %d)\n", __func__, ch_req->channel); ++ ++ return 0; ++ ++_err_exit: ++ ++#endif /* CONFIG_PLATFORM_AHBDMA */ ++ ++ return -ENODEV; ++} ++ ++/*-------------------------------- ++ * Note no locks taken out here. In a worst case scenario, we could drop ++ * a chunk of system memory. But that should never happen, since validation ++ * happens at open or mount time, when locks are held. ++ */ ++static int sd_revalidate(struct gendisk *gd) ++{ ++ struct sd_dev *dev = gd->private_data; ++ ++ P_DEBUG("--> %s\n", __func__); ++ P_DEBUG("card state=%s\n", dev->card_state == SD_CARD_INSERT ? "INSERT" : dev->card_state == SD_CARD_WORK ? "WORK" : "REMOVE"); ++ ++ if (dev->usage == 0) { ++ if (sd_card_setup(dev) != TRUE) { ++ dev->card_state = SD_CARD_REMOVE; ++ return -1; ++ } else { ++ enable_irq(FTSDC_IRQ); ++ dev->card_state = SD_CARD_WORK; ++ } ++ } ++ P_DEBUG("<-- %s\n", __func__); ++ ++ return 0; ++} ++ ++/* ++ * Device open and close ++ * TODO: forbids open for write when WRITE_PROTECT=1 ++ */ ++int sd_open(struct block_device *bdev, fmode_t mode) ++{ ++ struct sd_dev *dev= bdev->bd_disk->private_data; /* device information */ ++ P_DEBUG("--> %s\n", __func__); ++ /* Early return if there's nothing in the card slot */ ++ if ((SDC_R_REG(SDC_STATUS_REG) & SDC_STATUS_REG_CARD_INSERT) != SDC_CARD_INSERT) { ++ P_DEBUG("<-- %s (ENOMEDIUM)\n", __func__); ++ return -ENOMEDIUM; ++ } ++ //spin_lock(&dev->lock); ++ if (!dev->usage) { ++ dev->media_change=1; ++ P_DEBUG("%s: forced check_disk_change check\n", __func__); ++ check_disk_change(bdev); ++ sector_offset=0; ++ Do_onetime=0; ++ } else ++ dev->media_change=0; ++ ++ /* Set size HERE: ++ * must rely on sd_revalidate to set correct size ++ * (seems on check_disk_change()) */ ++ P_DEBUG("%s: set_capacity() to %d blocks (%d bytes)\n",__func__, dev->size, dev->size*SD_SECTOR_SIZE); ++ set_capacity(dev->gd, dev->size); ++ dev->usage++; ++ P_DEBUG("<-- %s\n", __func__); ++ ++ return 0; /* success */ ++} ++ ++int sd_release(struct gendisk *gd, fmode_t mode) ++{ ++ struct sd_dev *dev = gd->private_data; ++ ++ disable_irq(FTSDC_IRQ); ++ printk(" + sd_release : umount SD\n"); ++ ++ P_DEBUG("--> %s\n", __func__); ++ dev->usage--; ++ P_DEBUG("<-- %s\n", __func__); ++ ++ return 0; ++} ++ ++/*-------------------------------------- ++ * The file operations ++ */ ++struct block_device_operations sd_fops = { ++ owner: THIS_MODULE, ++ open: sd_open, ++ release: sd_release, ++ ioctl: sd_ioctl, ++ revalidate_disk: sd_revalidate, ++ media_changed: sd_media_changed, ++}; ++ ++void init_sd_pmu(void) ++{ ++ ++#ifdef CONFIG_FIE8100_PLATFORM ++ unsigned int u32temp; ++ u32temp = *(volatile unsigned int *)(A320_PMU_VA_BASE + 0x14); ++ u32temp &= ~0x3000; ++ u32temp |= 0x2000; ++ *(volatile unsigned int *)(A320_PMU_VA_BASE + 0x14)=u32temp; ++#endif ++ ++#ifdef CONFIG_FIE7000_PLATFORM ++ *(volatile unsigned int *)(A320_PMU_VA_BASE + 0x114) = (*(volatile unsigned int *)(A320_PMU_VA_BASE + 0x114) & 0xFFFF0FFF) | 0x00002000; ++#endif ++} ++ ++/* ++ * Set up our internal device. ++ */ ++static int setup_device(struct sd_dev *dev) ++{ ++ /* ++ * Get some memory. ++ */ ++ memset (dev, 0, sizeof (struct sd_dev)); ++ dev->size = 0;//SD_DUMMY_SIZE/SD_SECTOR_SIZE; /* We'll fill this with correct size later*/ ++ spin_lock_init(&dev->lock); ++ /* Request Queue */ ++ dev->queue = blk_init_queue(sd_request, &dev->lock); ++ if (dev->queue == NULL) ++ return -EFAULT; ++ ++ blk_queue_logical_block_size(dev->queue, hardsect_size); ++ dev->queue->queuedata = dev; ++ ++ dev->card_state = SD_CARD_REMOVE; ++ ++ /* ++ * And the gendisk structure. ++ */ ++ dev->gd = alloc_disk(SD_MINORS); ++ if (! dev->gd) { ++ printk (KERN_NOTICE "alloc_disk failure\n"); ++ return -EFAULT; ++ } ++ ++ dev->gd->flags = GENHD_FL_REMOVABLE|GENHD_FL_SUPPRESS_PARTITION_INFO; ++ dev->gd->major = sd_major; ++ dev->gd->first_minor = 0; ++ dev->gd->minors = SD_MINORS; ++ dev->gd->fops = &sd_fops; ++ dev->gd->queue = dev->queue; ++ dev->gd->private_data = dev; ++ snprintf (dev->gd->disk_name, 32, "cpesd%c", 'a'); ++ set_capacity(dev->gd, 0); //SD_DUMMY_SIZE/SD_SECTOR_SIZE*(hardsect_size/KERNEL_SECTOR_SIZE)); ++ add_disk(dev->gd); ++ ++ /* ++ * dma alloc ++ */ ++ if (sd_dma_ch_alloc(dev) == 0) { ++ printk(KERN_NOTICE "Faraday SD controller Driver (DMA mode)\n"); ++ dev->dma_enable = true; ++ } else { ++ printk(KERN_NOTICE "Faraday SD controller Driver (PIO mode)\n"); ++ } ++ ++ return 0; ++} ++/* ++ * Look for a media change. ++ */ ++static int sd_media_changed(struct gendisk *gd) ++{ ++ struct sd_dev *dev = gd->private_data; ++ return dev->media_change; ++} ++ ++/* ++ * module stuff ++ */ ++static int __init sd_module_init(void) ++{ ++ int result=-ENOMEM; ++ spinlock_t complete_lock; ++ unsigned long iflags; ++ spin_lock_init(&complete_lock); ++ ++#ifdef CONFIG_PLAT_QEMU ++ SDC_READ_FIFO_LEN = SDC_WRITE_FIFO_LEN = SDC_R_REG(0x44) & 0xff; ++#else ++ if(SDC_R_REG(0xa0) == 0x00030101) ++ SDC_READ_FIFO_LEN = SDC_WRITE_FIFO_LEN = SDC_R_REG(0x9c) & 0xff; ++ else ++ SDC_READ_FIFO_LEN = SDC_WRITE_FIFO_LEN = SDC_R_REG(SDC_FEATURE_REG) & 0xff; ++#endif ++ /* Register SD driver */ ++ sd_major = register_blkdev(sd_major, DEVICE_NAME); ++ if (sd_major <= 0) { ++ printk(KERN_WARNING DEVICE_NAME ":unable to get major number\n"); ++ return -EBUSY; ++ } ++ init_sd_pmu(); /* Power on SDC */ ++ P_DEBUG("SD Major Number = %d\n", sd_major); ++ printk(KERN_ALERT "SD: make node with 'mknod /dev/cpesd b %d 0'\n", sd_major); ++ ++ sd_devices = kmalloc(sizeof(struct sd_dev), GFP_KERNEL); ++ if (!sd_devices) ++ goto fail_malloc; ++ memset(sd_devices, 0, sizeof(struct sd_dev)); ++ ++ if (setup_device(sd_devices)) ++ goto fail_malloc; ++ ++ P_DEBUG("Request SDC IRQ=%d\n", FTSDC_IRQ); ++ spin_lock_irqsave(&complete_lock, iflags); ++ if (request_irq(FTSDC_IRQ, sd_hotswap_interrupt_handler, IRQF_DISABLED, "SD controller", sd_devices) != 0) { ++ printk(KERN_ERR "Unable to allocate SDC IRQ=0x%X\n", FTSDC_IRQ); ++ goto fail_malloc; ++ } ++ disable_irq(FTSDC_IRQ); ++ spin_unlock_irqrestore(&complete_lock, iflags); ++ if (request_region(FTSDC_VA_BASE, 0x48, "SD Controller") == NULL) { ++ printk(KERN_ERR "request io port of sd controller fail\n"); ++ goto fail_mem; ++ } ++ ++ return 0; /* succeed */ ++ ++fail_mem: ++ free_irq(FTSDC_IRQ, sd_devices); ++ ++fail_malloc: ++ if (sd_devices) ++ kfree(sd_devices); ++ unregister_blkdev(sd_major, DEVICE_NAME); ++ return result; ++} ++ ++static void sd_module_cleanup(void) ++{ ++ P_DEBUG("--> %s\n", __func__); ++ ++ /* unregister the device now to avoid further operations during cleanup */ ++ ++ if (sd_devices) { ++ del_gendisk(sd_devices->gd); ++ put_disk(sd_devices->gd); ++ if(sd_devices->queue) ++ blk_cleanup_queue(sd_devices->queue); ++ ++ if (sd_devices->dma_enable) ++ dmad_channel_free(&sd_devices->ch_req); ++ ++ kfree(sd_devices); ++ } ++ ++ release_region(FTSDC_VA_BASE, 0x48); ++ free_irq(FTSDC_IRQ, sd_devices); ++ ++ unregister_blkdev(sd_major, DEVICE_NAME); ++ P_DEBUG("<-- %s\n", __func__); ++} ++ ++module_init(sd_module_init); ++module_exit(sd_module_cleanup); +diff -Nur linux-3.4.110.orig/drivers/block/ftsdc010.h linux-3.4.110/drivers/block/ftsdc010.h +--- linux-3.4.110.orig/drivers/block/ftsdc010.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/block/ftsdc010.h 2016-04-07 10:20:51.022084119 +0200 +@@ -0,0 +1,477 @@ ++/* drivers/block/CPESD/ftsdc010.h ++ * ++ * Faraday FTSDC010 Device Driver ++ * ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * ++ * All Rights Reserved ++ */ ++ ++#ifndef _FTSDC010_H_ ++#define _FTSDC010_H_ ++ ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++//#define SD_DEBUG ++#define DELAY_FOR_DMA_READ ++ ++#ifdef SD_DEBUG ++ #define P_DEBUG(fmt, args...) printk(KERN_ALERT "SD: " fmt, ## args) ++#else ++ #define P_DEBUG(a...) ++#endif ++#define P_DEBUGG(a...) ++ ++#define MAX_READ_SECTOR_NR 96 //16 ++#define MAX_WRITE_SECTOR_NR MAX_READ_SECTOR_NR ++ ++#define SD_MAJOR 6 /* default major number, if zero, it means dynamic allocate */ ++#define SD_DEVS 1 /* number of disks */ ++#define SD_MINORS 16 /* minors per disk */ ++#define SD_RAHEAD 2 /* number of sectors */ ++#define SD_BLKSIZE 1024 /* block size */ ++#define SD_SECTOR_SIZE 512 /* sector size */ ++#define SD_DUMMY_SIZE (256*1024*1024) // for sake of hotswap/hotplug ++#if 0 ++typedef struct _sd_dev_t { ++ int size; ++ int usage; ++ //struct timer_list timer; ++ spinlock_t lock; ++ struct semaphore sema; // synchronization ++ int card_state; ++} sd_dev_t; ++#endif ++//---------SD Card State ++#define SD_CARD_REMOVE 0 ++#define SD_CARD_INSERT 1 ++#define SD_CARD_WORK 2 ++ ++/* so far, SD controller support 3.2-3.3 VDD */ ++#define SDC_OCR 0x00FF8000 ++ ++/* sd controller register */ ++#define SDC_CMD_REG 0x00000000 ++#define SDC_ARGU_REG 0x00000004 ++#define SDC_RESPONSE0_REG 0x00000008 ++#define SDC_RESPONSE1_REG 0x0000000C ++#define SDC_RESPONSE2_REG 0x00000010 ++#define SDC_RESPONSE3_REG 0x00000014 ++#define SDC_RSP_CMD_REG 0x00000018 ++#define SDC_DATA_CTRL_REG 0x0000001C ++#define SDC_DATA_TIMER_REG 0x00000020 ++#define SDC_DATA_LEN_REG 0x00000024 ++#define SDC_STATUS_REG 0x00000028 ++#define SDC_CLEAR_REG 0x0000002C ++#define SDC_INT_MASK_REG 0x00000030 ++#define SDC_POWER_CTRL_REG 0x00000034 ++#define SDC_CLOCK_CTRL_REG 0x00000038 ++#define SDC_BUS_WIDTH_REG 0x0000003C ++#define SDC_DATA_WINDOW_REG 0x00000040 ++#ifdef A320D_BUILDIN_SDC ++#define SDC_FEATURE_REG 0x00000044 ++#define SDC_REVISION_REG 0x00000048 ++#else ++#define SDC_MMC_INT_RSP_REG 0x00000044 ++#define SDC_GP_OUTPUT_REG 0x00000048 ++#define SDC_FEATURE_REG 0x0000009C ++#define SDC_REVISION_REG 0x000000A0 ++#endif ++ ++/* bit mapping of command register */ ++#define SDC_CMD_REG_INDEX 0x0000003F ++#define SDC_CMD_REG_NEED_RSP 0x00000040 ++#define SDC_CMD_REG_LONG_RSP 0x00000080 ++#define SDC_CMD_REG_APP_CMD 0x00000100 ++#define SDC_CMD_REG_CMD_EN 0x00000200 ++#define SDC_CMD_REG_SDC_RST 0x00000400 ++ ++/* bit mapping of response command register */ ++#define SDC_RSP_CMD_REG_INDEX 0x0000003F ++#define SDC_RSP_CMD_REG_APP 0x00000040 ++ ++/* bit mapping of data control register */ ++#define SDC_DATA_CTRL_REG_BLK_SIZE 0x0000000F ++#define SDC_DATA_CTRL_REG_DATA_WRITE 0x00000010 ++#define SDC_DATA_CTRL_REG_DATA_READ 0x00000000 ++#define SDC_DATA_CTRL_REG_DMA_EN 0x00000020 ++#define SDC_DATA_CTRL_REG_DATA_EN 0x00000040 ++ ++#define SDC_DMA_TYPE_1 0x00000000 ++#define SDC_DMA_TYPE_4 0x00000100 ++#define SDC_DMA_TYPE_8 0x00000200 ++ ++/* bit mapping of status/clear/mask register */ ++#define SDC_STATUS_REG_RSP_CRC_FAIL 0x00000001 ++#define SDC_STATUS_REG_DATA_CRC_FAIL 0x00000002 ++#define SDC_STATUS_REG_RSP_TIMEOUT 0x00000004 ++#define SDC_STATUS_REG_DATA_TIMEOUT 0x00000008 ++#define SDC_STATUS_REG_RSP_CRC_OK 0x00000010 ++#define SDC_STATUS_REG_DATA_CRC_OK 0x00000020 ++#define SDC_STATUS_REG_CMD_SEND 0x00000040 ++#define SDC_STATUS_REG_DATA_END 0x00000080 ++#define SDC_STATUS_REG_FIFO_UNDERRUN 0x00000100 ++#define SDC_STATUS_REG_FIFO_OVERRUN 0x00000200 ++#define SDC_STATUS_REG_CARD_CHANGE 0x00000400 ++#define SDC_STATUS_REG_CARD_INSERT 0x00000800 ++#define SDC_STATUS_REG_CARD_LOCK 0x00001000 ++ ++#define SDC_CARD_INSERT 0x0 ++#define SDC_CARD_REMOVE SDC_STATUS_REG_CARD_INSERT ++ ++/* bit mapping of power control register */ ++#define SDC_POWER_REG_POWER_ON 0x00000010 ++#define SDC_POWER_REG_POWER_BITS 0x0000000F ++ ++/* bit mapping of clock control register */ ++#define SDC_CLOCK_REG_CARD_TYPE 0x00000080 ++#define SDC_CLOCK_REG_CLK_DIV 0x0000007F ++ ++/* card type */ ++#define SDC_CARD_TYPE_SD SDC_CLOCK_REG_CARD_TYPE ++#define SDC_CARD_TYPE_MMC 0x0 ++ ++/* bit mapping of bus width register */ ++#define SDC_BUS_WIDTH_REG_SINGLE_BUS 0x00000001 ++#define SDC_BUS_WIDTH_REG_WIDE_BUS 0x00000004 ++#define SDC_WIDE_BUS_SUPPORT 0x00000008 ++ ++/* data window register */ ++//#define SDC_READ_FIFO_LEN 4 ++//#define SDC_WRITE_FIFO_LEN 4 ++ ++/* card type, sd or mmc */ ++#define MEMORY_CARD_TYPE_SD 0 ++#define MEMORY_CARD_TYPE_MMC 1 ++ ++/********************************************************************/ ++/* SYSTEM ERROR_CODE */ ++/********************************************************************/ ++#define ERR_NO_ERROR 0x00000000 ++ ++/* general error */ ++#define ERR_CARD_NOT_EXIST 0x00000001 ++#define ERR_OUT_OF_VOLF_RANGE 0x00000002 ++#define ERR_SD_PARTITIAL_READ_ERROR 0x00000004 ++#define ERR_SD_PARTITIAL_WRITE_ERROR 0x00000008 ++ ++#define ERR_SD_CARD_IS_LOCK 0x00000010 ++ ++/* command error */ ++#define ERR_DATA_CRC_ERROR 0x00000100 ++#define ERR_RSP_CRC_ERROR 0x00000200 ++#define ERR_DATA_TIMEOUT_ERROR 0x00000400 ++#define ERR_RSP_TIMEOUT_ERROR 0x00000800 ++ ++#define ERR_WAIT_OVERRUN_TIMEOUT 0x00001000 ++#define ERR_WAIT_UNDERRUN_TIMEOUT 0x00002000 ++#define ERR_WAIT_DATA_CRC_TIMEOUT 0x00004000 ++#define ERR_WAIT_TRANSFER_END_TIMEOUT 0x00008000 ++ ++#define ERR_SEND_COMMAND_TIMEOUT 0x00010000 ++ ++/* sd error */ ++#define ERR_SD_CARD_IS_BUSY 0x00100000 ++#define ERR_CID_REGISTER_ERROR 0x00200000 ++#define ERR_CSD_REGISTER_ERROR 0x00400000 ++ ++/* sd card status error */ ++#define ERR_SD_CARD_STATUS_ERROR 0x01000000 ++/* SDC using APB DMA error */ ++#define ERR_DMA_RSP_ERROR 0x02000000 ++ ++#define SD_SCR_1_BIT_BIT 0x0001 ++#define SD_SCR_4_BIT_BIT 0x0004 ++ ++/********************************************************************/ ++/* The bit mapping of SD Status register */ ++/********************************************************************/ ++#define SD_STATUS_OUT_OF_RANGE 0x80000000 ++#define SD_STATUS_ADDRESS_ERROR 0x40000000 ++#define SD_STATUS_BLOCK_LEN_ERROR 0x20000000 ++#define SD_STATUS_ERASE_SEQ_ERROR 0x10000000 ++#define SD_STATUS_ERASE_PARAM 0x08000000 ++#define SD_STATUS_WP_VIOLATION 0x04000000 ++#define SD_STATUS_CARD_IS_LOCK 0x02000000 ++#define SD_STATUS_LOCK_UNLOCK_FILED 0x01000000 ++#define SD_STATUS_COM_CRC_ERROR 0x00800000 ++#define SD_STATUS_ILLEGAL_COMMAND 0x00400000 ++#define SD_STATUS_CARD_ECC_FAILED 0x00200000 ++#define SD_STATUS_CC_ERROR 0x00100000 ++#define SD_STATUS_ERROR 0x00080000 ++#define SD_STATUS_UNDERRUN 0x00040000 ++#define SD_STATUS_OVERRUN 0x00020000 ++#define SD_STATUS_CID_CSD_OVERWRITE 0x00010000 ++#define SD_STATUS_WP_ERASE_SKIP 0x00008000 ++#define SD_STATUS_CARD_ECC_DISABLE 0x00004000 ++#define SD_STATUS_ERASE_RESET 0x00002000 ++#define SD_STATUS_CURRENT_STATE 0x00001E00 ++#define SD_STATUS_READY_FOR_DATA 0x00000100 ++#define SD_STATUS_APP_CMD 0x00000020 ++#define SD_STATUS_AKE_SEQ_ERROR 0x00000008 ++#define SD_STATUS_ERROR_BITS (SD_STATUS_ADDRESS_ERROR | SD_STATUS_BLOCK_LEN_ERROR | SD_STATUS_ERASE_SEQ_ERROR | SD_STATUS_ERASE_PARAM | SD_STATUS_WP_VIOLATION | SD_STATUS_LOCK_UNLOCK_FILED | SD_STATUS_CARD_ECC_FAILED | SD_STATUS_CC_ERROR | SD_STATUS_ERROR | SD_STATUS_UNDERRUN | SD_STATUS_OVERRUN | SD_STATUS_CID_CSD_OVERWRITE | SD_STATUS_WP_ERASE_SKIP | SD_STATUS_AKE_SEQ_ERROR) ++#define SD_STATUS_CURRENT_STATE_LOC 9 ++ ++/********************************************************************/ ++/* SD command response type */ ++/********************************************************************/ ++#define SD_NO_RESPONSE 0 ++#define SD_RESPONSE_R1 1 ++#define SD_RESPONSE_R1b 2 ++#define SD_RESPONSE_R2 3 ++#define SD_RESPONSE_R3 4 ++#define SD_RESPONSE_R6 5 ++ ++/********************************************************************/ ++/* SD command */ ++/********************************************************************/ ++#define SD_GO_IDLE_STATE_CMD 0 ++#define SD_MMC_OP_COND 1 ++#define SD_ALL_SEND_CID_CMD 2 ++#define SD_SEND_RELATIVE_ADDR_CMD 3 ++#define SD_SET_DSR_CMD 4 ++#define SD_SET_BUS_WIDTH_CMD 6 ++#define SD_SELECT_CARD_CMD 7 ++#define SD_SEND_CSD_CMD 9 ++#define SD_SEND_CID_CMD 10 ++#define SD_STOP_TRANSMISSION_CMD 12 ++#define SD_SEND_STATUS_CMD 13 ++#define SD_GO_INACTIVE_STATE_CMD 15 ++#define SD_SET_BLOCKLEN_CMD 16 ++#define SD_READ_SINGLE_BLOCK_CMD 17 ++#define SD_READ_MULTIPLE_BLOCK_CMD 18 ++#define SD_WRITE_SINGLE_BLOCK_CMD 24 ++#define SD_WRITE_MULTIPLE_BLOCK_CMD 25 ++#define SD_PROGRAM_CSD_CMD 27 ++#define SD_ERASE_SECTOR_START_CMD 32 ++#define SD_ERASE_SECTOR_END_CMD 33 ++#define SD_ERASE_CMD 38 ++#define SD_APP_OP_COND 41 ++#define SD_LOCK_UNLOCK_CMD 42 ++#define SD_SEND_SCR_CMD 51 ++#define SD_APP_CMD 55 ++#define SD_GET_CMD 56 ++ ++/* retry count */ ++#ifndef CONFIG_FTSDC010_USE_TIMER_DELAY ++#define SD_CARD_GET_OCR_RETRY_COUNT 0x1000 ++#define SD_CARD_WAIT_OPERATION_COMPLETE_RETRY_COUNT 8000 ++#define SD_CARD_STATE_CHANGE_RETRY_COUNT 30000 ++#define SD_CARD_WAIT_TRANSFER_STATE_RETRY_COUNT 30000 ++#define SDC_GET_STATUS_RETRY_COUNT 0x300000 ++#else ++#define SD_CARD_GET_OCR_RETRY_COUNT 0x1000 ++#define SD_CARD_WAIT_OPERATION_COMPLETE_RETRY_COUNT 8000 ++#define SD_CARD_STATE_CHANGE_RETRY_COUNT 10000 ++#define SD_CARD_WAIT_TRANSFER_STATE_RETRY_COUNT 10000 ++#endif ++ ++/* ++ * Please refer SanDisk SD Manual v1.9 Section 5.1.9.2 (page 5-76) to set the timeout setting ++ */ ++#ifdef SD_DEBUG ++#define SDC_TIMEOUT_BASE (HZ/2) // Unit is 500 ms ++#else ++#define SDC_TIMEOUT_BASE (HZ/3) // Unit is 333 ms ++#endif ++#define SDC_GET_STATUS_RETRY_TIMEOUT_COUNT (HZ*4) ++ ++/* sd card standby state */ ++#define SD_IDLE_STATE 0 ++#define SD_READY_STATE 1 ++#define SD_IDENT_STATE 2 ++#define SD_STBY_STATE 3 ++#define SD_TRAN_STATE 4 ++#define SD_DATA_STATE 5 ++#define SD_RCV_STATE 6 ++#define SD_PRG_STATE 7 ++#define SD_DIS_STATE 8 ++ ++#define SD_BUS_WIDTH_1_BIT 0 ++#define SD_BUS_WIDTH_4_BIT 2 ++ ++/********************************************************************/ ++/* SD card OCR register */ ++/********************************************************************/ ++#define SD_OCR_BUSY_BIT 0x80000000 ++ ++/********************************************************************/ ++/* SD CID register */ ++/********************************************************************/ ++#define SD_DEFAULT_MONTH_CODE 1 ++#define SD_DEFAULT_YEAR_CODE 2000 ++#define MAX_MULTI_BLOCK_NUM 126 ++ ++typedef struct _sd_cid_t ++{ ++ uint ManufacturerID; ++ uint ApplicationID; ++ unchar ProductName[7]; ++ uint ProductRevisionHigh; ++ uint ProductRevisionLow; ++ uint ProductSerialNumber; ++ uint ManufactureMonth; ++ uint ManufactureYear; ++} sd_cid_t; ++ ++/********************************************************************/ ++/* SD CSD register */ ++/********************************************************************/ ++#define SD_CSD_STRUCTURE_1_0 0 ++#define SD_CSD_STRUCTURE_1_1 1 ++ ++#define SD_CSD_SPEC_VERS_1_0_1_2 0 ++#define SD_CSD_SPEC_VERS_1_4 1 ++#define SD_CSD_SPEC_VERS_2_1 2 ++ ++#define SD_TAAC_TIME_UINT_BITS 0x07 ++#define SD_TAAC_TIME_VALUE_BITS 0x78 ++ ++typedef struct _sd_csd_t ++{ ++ uint CSDStructure; ++ uint MMCSpecVersion; ++ uint TAAC_u; ++ uint NSAC_u; ++ uint TransferSpeed; ++ uint CardCmdClass; ++ uint ReadBlockLength; ++ uint ReadBlockPartial; ++ uint WriteBlockMisalign; ++ uint ReadBlockMisalign; ++ uint DSRImplemant; ++ uint BlockNumber; ++ uint MemorySize; ++ uint VDDReadMin_u; ++ uint VDDReadMax_u; ++ uint VDDWriteMin_u; ++ uint VDDWriteMax_u; ++ uint EraseBlkEnable; ++ uint EraseSectorSize; ++ uint WriteProtectGroupSize; ++ uint WriteProtectGroupEnable; ++ uint WriteSpeedFactor; ++ uint WriteBlockLength; ++ unchar WriteBlockPartial; ++ unchar CopyFlag; ++ unchar PermanentWriteProtect; ++ unchar TemporaryWriteProtect; ++ unchar FileFormat; ++} sd_csd_t; ++ ++typedef struct _sd_csd_bit_t ++{ ++ uint NotUsed:1; ++ uint CRC:7; ++ uint MMCardReserved1:2; ++ uint FILE_FORMAT:2; ++ uint TMP_WRITE_PROTECT:1; ++ uint PERM_WRITE_PROTECT:1; ++ uint COPY:1; ++ uint FILE_FORMAT_GRP:1; ++ ++ uint Reserved2:5; ++ uint WRITE_BL_PARTIAL:1; ++ uint WRITE_BL_LEN:4; ++ uint R2W_FACTOR:3; ++ uint MMCardReserved0:2; ++ uint WP_GRP_ENABLE:1; ++ ++ uint WP_GRP_SIZE:7; ++ uint ERASE_SECTOR_SIZE:7; ++ uint ERASE_BLK_ENABLE:1; ++ uint C_SIZE_MULT:3; ++ uint VDD_W_CURR_MAX:3; ++ uint VDD_W_CURR_MIN:3; ++ uint VDD_R_CURR_MAX:3; ++ uint VDD_R_CURR_MIN:3; ++ ++ uint C_SIZE_1:2; ++ uint C_SIZE_2:10; // divide its into 2, 10bits ++ ++ uint Reserved1:2; ++ uint DSR_IMP:1; ++ uint READ_BLK_MISALIGN:1; ++ uint WRITE_BLK_MISALIGN:1; ++ uint READ_BL_PARTIAL:1; ++ ++ uint READ_BL_LEN:4; ++ uint CCC:12; ++ ++ uint TRAN_SPEED_RateUnit:3; ++ uint TRAN_SPEED_TimeValue:4; ++ uint TRAN_SPEED_Reserved:1; ++ ++ uint NSAC:8; ++ ++ uint TAAC_TimeUnit:3; ++ uint TAAC_TimeValue:4; ++ uint TAAC_Reserved:1; ++ ++ uint Reserved0:2; ++ uint MMC_SPEC_VERS:4; ++ uint CSD_STRUCTURE:2; ++} sd_csd_bit_t; ++ ++/********************************************************************/ ++/* SD SCR register */ ++/********************************************************************/ ++typedef struct _sd_scr_t ++{ ++ uint Reserved:16; ++ uint SD_BUS_WIDTH:4; ++ uint SD_SECURITY:3; ++ uint DATA_STAT_AFTER_ERASE:1; ++ uint SD_SPEC:4; ++ uint SCR_STRUCTURE:4; ++ ++ uint ManufacturerReserved; ++} sd_scr_t; ++ ++/********************************************************************/ ++/* sd card structure */ ++/********************************************************************/ ++typedef struct _sd_card_t ++{ ++ /* host interface configuration */ ++ uint IOAddr; /* host controller register base address */ ++ uint DMAEnable; ++ ++ uint CardType; ++ ++ /* card register */ ++ uint OCR; ++ ++ uint CIDWord[4]; ++ sd_cid_t CID; ++ ++ uint CSDWord[4]; ++ sd_csd_t CSD; ++ ++ ushort RCA; ++ sd_scr_t SCR; ++ ++ /* access time out */ ++ uint ReadAccessTimoutCycle; ++ uint WriteAccessTimoutCycle; ++ ++ /* Drive Name */ ++ uint Drive; ++ ++ /* system configurations */ ++ uint SysFrequency; ++ ++ /* card status */ ++ int ActiveState; ++ int WriteProtect; ++ ++ void *private; ++} sd_card_t; ++ ++#endif +diff -Nur linux-3.4.110.orig/drivers/block/Kconfig linux-3.4.110/drivers/block/Kconfig +--- linux-3.4.110.orig/drivers/block/Kconfig 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/block/Kconfig 2016-04-07 10:20:51.022084119 +0200 +@@ -498,6 +498,14 @@ + block device driver. It communicates with a back-end driver + in another domain which drives the actual block device. + ++config FTSDC010 ++ tristate "Faraday FTSDC010 driver" ++ depends on NDS32 ++ ++config FTCFC010 ++ tristate "Faraday FTCFC010 driver" ++ depends on NDS32 ++ + config XEN_BLKDEV_BACKEND + tristate "Xen block-device backend driver" + depends on XEN_BACKEND +diff -Nur linux-3.4.110.orig/drivers/block/Makefile linux-3.4.110/drivers/block/Makefile +--- linux-3.4.110.orig/drivers/block/Makefile 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/block/Makefile 2016-04-07 10:20:51.050085202 +0200 +@@ -43,3 +43,5 @@ + obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx/ + + swim_mod-y := swim.o swim_asm.o ++obj-$(CONFIG_FTSDC010) += ftsdc010.o ++obj-$(CONFIG_FTCFC010) += ftcfc010.o +diff -Nur linux-3.4.110.orig/drivers/gpio/gpio-ftgpio010.c linux-3.4.110/drivers/gpio/gpio-ftgpio010.c +--- linux-3.4.110.orig/drivers/gpio/gpio-ftgpio010.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/gpio/gpio-ftgpio010.c 2016-04-07 10:20:51.050085202 +0200 +@@ -0,0 +1,218 @@ ++#include <linux/module.h> ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/gpio.h> ++ ++#define GPIO_DATA_OUT 0x00 ++#define GPIO_DATA_IN 0x04 ++#define PIN_DIR 0x08 ++#define PIN_BYPASS 0x0C ++#define GPIO_DATA_SET 0x10 ++#define GPIO_DATA_CLEAR 0x14 ++#define PIN_PULL_ENABLE 0x18 ++#define PIN_PULL_TYPE 0x1C ++#define INT_ENABLE 0x20 ++#define INT_RAW_STATE 0x24 ++#define INT_MASKED_STATE 0x28 ++#define INT_MASK 0x2C ++#define INT_CLEAR 0x30 ++#define INT_TRIGGER 0x34 ++#define INT_BOTH 0x38 ++#define INT_RISE_NEG 0x3C ++#define BOUNCE_ENABLE 0x40 ++#define BOUNCE_PRE_SCALE 0x44 ++ ++#define GPIO_READL(offset) \ ++ readl(GPIO_FTGPIO010_VA_BASE + (offset)) ++ ++#define GPIO_WRITEL(val, offset) \ ++ writel((val), GPIO_FTGPIO010_VA_BASE + (offset)) ++ ++#define FTGPIO010_VIRTUAL_IRQ_BASE 100 ++ ++static int irq_to_gpio(unsigned int irq) ++{ ++ return irq - FTGPIO010_VIRTUAL_IRQ_BASE; ++} ++ ++static int ftgpio_to_irq(struct gpio_chip *gc, unsigned int offset) ++{ ++ return FTGPIO010_VIRTUAL_IRQ_BASE + offset; ++} ++ ++static int ftgpio_get(struct gpio_chip *gc, unsigned int gpio) ++{ ++ return (GPIO_READL(GPIO_DATA_IN) >> gpio & 1); ++} ++ ++static void ftgpio_set(struct gpio_chip *gc, unsigned int gpio, int data) ++{ ++ unsigned long val; ++ ++ if (data) ++ val = GPIO_READL(GPIO_DATA_OUT) | (0x1UL << gpio); ++ else ++ val = GPIO_READL(GPIO_DATA_OUT) & ~(0x1UL << gpio); ++ ++ GPIO_WRITEL(val, GPIO_DATA_OUT); ++} ++ ++static int ftgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) ++{ ++ unsigned long val; ++ ++ val = GPIO_READL(PIN_DIR) & ~(0x1UL << gpio); ++ GPIO_WRITEL(val, PIN_DIR); ++ ++ return 0; ++} ++ ++static int ftgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int data) ++{ ++ unsigned long val; ++ ++ val = GPIO_READL(PIN_DIR) | (0x1UL << gpio); ++ GPIO_WRITEL(val, PIN_DIR); ++ ++ gc->set(gc, gpio, data); ++ ++ return 0; ++} ++ ++static struct gpio_chip ftgpio_chip = { ++ ++ .label = "FTGPIO010", ++ .base = 0, ++ .ngpio = 16, ++ .direction_input = ftgpio_dir_in, ++ .direction_output = ftgpio_dir_out, ++ .get = ftgpio_get, ++ .set = ftgpio_set, ++ .to_irq = ftgpio_to_irq, ++}; ++ ++static void ftgpio_irq_ack(struct irq_data *data) ++{ ++ GPIO_WRITEL(0x1UL << irq_to_gpio(data->irq), INT_CLEAR); ++} ++ ++static void ftgpio_irq_mask(struct irq_data *data) ++{ ++ unsigned long val; ++ ++ val = GPIO_READL(INT_MASK) | (0x1UL << irq_to_gpio(data->irq)); ++ GPIO_WRITEL(val, INT_MASK); ++} ++ ++static void ftgpio_irq_unmask(struct irq_data *data) ++{ ++ unsigned long val; ++ val = GPIO_READL(INT_MASK) & ~(0x1UL << irq_to_gpio(data->irq)); ++ GPIO_WRITEL(val, INT_MASK); ++} ++ ++static int ftgpio_irq_set_type(struct irq_data *data, unsigned int flow_type) ++{ ++ unsigned long bit = 0x1UL << irq_to_gpio(data->irq); ++ unsigned long val; ++ val = GPIO_READL(INT_BOTH); ++ ++ if (flow_type & IRQF_TRIGGER_RISING && flow_type & IRQF_TRIGGER_FALLING) ++ GPIO_WRITEL(val | bit, INT_BOTH); ++ else ++ GPIO_WRITEL(val & ~bit, INT_BOTH); ++ ++ val = GPIO_READL(INT_RISE_NEG); ++ ++ if (flow_type & IRQF_TRIGGER_FALLING) ++ GPIO_WRITEL(val | bit, INT_RISE_NEG); ++ else if (flow_type & IRQF_TRIGGER_RISING) ++ GPIO_WRITEL(val & ~bit, INT_RISE_NEG); ++ ++ return 0; ++} ++ ++static struct irq_chip ftgpio_irq_chip = { ++ ++ .name = "FTGPIO010_irq", ++ .irq_ack = ftgpio_irq_ack, ++ .irq_mask = ftgpio_irq_mask, ++ .irq_unmask = ftgpio_irq_unmask, ++ .irq_set_type = ftgpio_irq_set_type, ++}; ++ ++static void gpio_irq_router(unsigned int irq, struct irq_desc *desc) ++{ ++ unsigned long status; ++ int i = 0; ++ ++ status = GPIO_READL(INT_RAW_STATE); ++ status &= ~((1 << 22) | (1 << 25) | (1 << 26)); ++ ++ while (status) { ++ ++ if (status & 0x1UL) ++ generic_handle_irq(gpio_to_irq(i)); ++ ++ status >>= 1; ++ i++; ++ } ++} ++ ++static int gpio_init(void) ++{ ++ int i; ++ ++ /* disable interrupt */ ++ GPIO_WRITEL(0x00000000UL, INT_ENABLE); ++ ++ /* mask interrupt */ ++ GPIO_WRITEL(0x0000FFFFUL, INT_MASK); ++ ++ /* triggered interrupt on both edge */ ++ GPIO_WRITEL(0x0000FFFFUL, INT_BOTH); ++ ++ /* clear interrupt */ ++ GPIO_WRITEL(0x0000FFFFUL, INT_CLEAR); ++ ++ /* enable de-bouncing */ ++ GPIO_WRITEL(0x0000FFFFUL, BOUNCE_ENABLE); ++ ++ /* enable interrupt */ ++ GPIO_WRITEL(0x0000FFFFUL, INT_ENABLE); ++ ++ gpiochip_add(&ftgpio_chip); ++ ++ for (i = 0; i < ftgpio_chip.ngpio; i++) { ++ ++ irq_set_chip(gpio_to_irq(i), &ftgpio_irq_chip); ++ irq_set_handler(gpio_to_irq(i), handle_level_irq); ++ } ++ ++ irq_set_chained_handler(GPIO_FTGPIO010_IRQ, gpio_irq_router); ++ ++ pr_info("GPIO module inserted\n"); ++ ++ return 0; ++} ++ ++static void __exit gpio_exit(void) ++{ ++ int i=0; ++ /* disable interrupt */ ++ GPIO_WRITEL(0x00000000UL, INT_ENABLE); ++ while(i<ftgpio_chip.ngpio) ++ gpio_free(i++); ++ ++ if (gpiochip_remove(&ftgpio_chip)) ++ pr_info("failed to remove gpiochip\n"); ++ ++ pr_info("GPIO module removed\n"); ++} ++ ++MODULE_DESCRIPTION("FTGPIO010"); ++MODULE_LICENSE("GPL"); ++ ++module_init(gpio_init); ++module_exit(gpio_exit); +diff -Nur linux-3.4.110.orig/drivers/gpio/Kconfig linux-3.4.110/drivers/gpio/Kconfig +--- linux-3.4.110.orig/drivers/gpio/Kconfig 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/gpio/Kconfig 2016-04-07 10:20:51.050085202 +0200 +@@ -492,6 +492,10 @@ + This enables support for the Philips UCB1400 GPIO pins. + The UCB1400 is an AC97 audio codec. + ++config GPIO_FTGPIO010 ++ tristate "Farady FTGPIO010 GPIO support" ++ depends on NDS32 && GENERIC_GPIO && ARCH_WANT_OPTIONAL_GPIOLIB ++ + comment "MODULbus GPIO expanders:" + + config GPIO_JANZ_TTL +diff -Nur linux-3.4.110.orig/drivers/gpio/Makefile linux-3.4.110/drivers/gpio/Makefile +--- linux-3.4.110.orig/drivers/gpio/Makefile 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/gpio/Makefile 2016-04-07 10:20:51.050085202 +0200 +@@ -64,3 +64,4 @@ + obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o + obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o + obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o ++obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o +\ No newline at end of file +diff -Nur linux-3.4.110.orig/drivers/input/touchscreen/cpe_ts/cpe_ts.c linux-3.4.110/drivers/input/touchscreen/cpe_ts/cpe_ts.c +--- linux-3.4.110.orig/drivers/input/touchscreen/cpe_ts/cpe_ts.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/input/touchscreen/cpe_ts/cpe_ts.c 2016-04-07 10:20:51.050085202 +0200 +@@ -0,0 +1,376 @@ ++#include <linux/input.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <linux/io.h> ++ ++#include <asm/irq.h> ++#include "cpe_ts.h" ++ ++ ++#include <linux/module.h> ++ ++#include <linux/irqnr.h> ++#include <linux/irq.h> ++ ++#define TOUCHSCREEN_IRQ 28 ++ ++#define ads_dbg( enabled, tagged, ...) \ ++ do{ \ ++ if( enabled){ \ ++ if( tagged) \ ++ printk( "[ %30s() ] ", __func__); \ ++ printk( __VA_ARGS__); \ ++ } \ ++ } while( 0) ++ ++#define TS_POLL_DELAY ( 1 * 1000000) /* ns delay before the first sample */ ++#define TS_POLL_PERIOD ( delay * 1000000) /* ns delay between samples */ ++ ++static int debug = 0; ++static int delay = 25; ++ ++module_param(debug, int, 0); ++module_param(delay, int, 0); ++ ++struct ads7846 ++{ ++ void __iomem * regs; ++ struct input_dev *input; ++ char phys[32]; ++ struct hrtimer timer; ++ int irq; ++ spinlock_t lock; ++ bool disabled; ++}; ++ ++struct ts_event ++{ ++ int x; ++ int y; ++ int z1, z2; ++ int Rt; ++}; ++ ++struct ads7846 touchscreen; ++ ++#define ADS_START ( 0x1UL << 7) ++#define ADS_A2A1A0_d_y ( 0x1UL << 4) /* differential */ ++#define ADS_A2A1A0_d_z1 ( 0x3UL << 4) /* differential */ ++#define ADS_A2A1A0_d_z2 ( 0x4UL << 4) /* differential */ ++#define ADS_A2A1A0_d_x ( 0x5UL << 4) /* differential */ ++#define ADS_12_BIT ( 0x0UL << 3) ++#define ADS_SER ( 0x1UL << 2) /* non-differential */ ++#define ADS_DFR ( 0x0UL << 2) /* differential */ ++#define ADS_PD10_PDOWN ( 0x0UL << 0) /* lowpower mode + penirq */ ++#define ADS_PD10_ADC_ON ( 0x1UL << 0) /* ADC on */ ++#define ADS_PD10_REF_ON ( 0x2UL << 0) /* vREF on + penirq */ ++#define ADS_PD10_ALL_ON ( 0x3UL << 0) /* ADC + vREF on */ ++ ++#define MAX_12BIT ( ( 0x1UL << 12) - 1) ++ ++#define READ_X ( ADS_A2A1A0_d_x | ADS_12_BIT | ADS_DFR) ++#define READ_Y ( ADS_A2A1A0_d_y | ADS_12_BIT | ADS_DFR) ++#define READ_Z1 ( ADS_A2A1A0_d_z1 | ADS_12_BIT | ADS_DFR) ++#define READ_Z2 ( ADS_A2A1A0_d_z2 | ADS_12_BIT | ADS_DFR) ++ ++static int ++read_val(struct ads7846 *ts, unsigned long cmd) ++{ ++ unsigned long data = 0; ++ int repeat = 5; ++ int i; ++ ++ ads_dbg(0, 1, "Queuing data: 0x%08lx\n", cmd << 16); ++ ++ for (i = 0; i < repeat; i++) ++ { ++ while (!(REG32(ts->regs + SSP_REG_SR) & SSP_SR_mskTFNF)); ++ REG32(ts->regs + SSP_REG_DR) = (ADS_START | cmd | ADS_PD10_ALL_ON) << 16; ++ } ++ ++ for (i = 0; i < repeat; i++) ++ { ++ while (!(REG32(ts->regs + SSP_REG_SR) & SSP_SR_mskRFVE)); ++ data = (REG32(ts->regs + SSP_REG_DR) >> 3) & 0xFFF; ++ } ++ ++ while (!(REG32(ts->regs + SSP_REG_SR) & SSP_SR_mskTFNF)); ++ REG32(ts->regs + SSP_REG_DR) = (ADS_START | cmd) << 16; ++ ++ while (!(REG32(ts->regs + SSP_REG_SR) & SSP_SR_mskRFVE)); ++ ++ data = (REG32(ts->regs + SSP_REG_DR) >> 3) & 0xFFF; ++ ads_dbg(0, 1, "CMD <%02lx> data: 0x%08lx( %ld)\n", cmd, data, data); ++ ++ return data; ++} ++ ++static int pendown(struct ads7846 *ts) ++{ ++ return read_val(ts, READ_Z1) > 40; ++} ++ ++static void report(struct ads7846 *ts, struct ts_event *e) ++{ ++ e->x = read_val(ts, READ_X); ++ e->y = read_val(ts, READ_Y); ++ e->z1 = read_val(ts, READ_Z1); ++ e->z2 = read_val(ts, READ_Z2); ++ ++ ads_dbg(debug, 1, "x: %4d, y: %4d, z1: %4d, z2: %4d\n", e->x, e->y, e->z1, e->z2); ++} ++ ++#define FILTER_LIMIT 35 ++ ++static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) ++{ ++ struct ads7846 *ts = container_of(handle, struct ads7846, timer); ++ struct ts_event e; ++ struct irq_desc *desc = (struct irq_desc *)irq_get_irq_data((unsigned int)ts->irq); ++ static int xp = 0, yp = 0; ++ ++ if (ts->disabled) ++ return HRTIMER_NORESTART; ++ ++ if (!pendown(ts)) ++ { ++ ads_dbg(debug, 1, "Release\n"); ++ ++ input_report_key(ts->input, BTN_TOUCH, 0); ++ input_report_abs(ts->input, ABS_PRESSURE, 0); ++ input_sync(ts->input); ++ ++ if(desc->irq_data.chip->irq_ack) ++ desc->irq_data.chip->irq_ack(&desc->irq_data); ++ enable_irq(ts->irq); ++ return HRTIMER_NORESTART; ++ } ++ report(ts, &e); ++ ++#ifdef CONFIG_TOUCHSCREEN_CPE_TS_DEJITTER ++ if (abs(xp - e.x) > FILTER_LIMIT || abs(yp - e.y) > FILTER_LIMIT) ++ { ++#endif ++ input_report_key(ts->input, BTN_TOUCH, 1); ++ input_report_abs(ts->input, ABS_X, e.x); ++ input_report_abs(ts->input, ABS_Y, e.y); ++ input_report_abs(ts->input, ABS_PRESSURE, 50); ++ xp = e.x; ++ yp = e.y; ++#ifdef CONFIG_TOUCHSCREEN_CPE_TS_DEJITTER ++ } ++#endif ++ input_sync(ts->input); ++ hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_MODE_REL); ++ ads_dbg(0, 1, "Leave\n"); ++ return HRTIMER_NORESTART; ++} ++ ++static irqreturn_t ads7846_irq(int irq, void *handle) ++{ ++ struct ads7846 *ts = handle; ++ ++ if (ts->disabled) ++ return IRQ_HANDLED; ++ ++ disable_irq_nosync(irq); ++ hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY), HRTIMER_MODE_REL); ++ ++ return IRQ_HANDLED; ++} ++ ++static int xspi_init_hw(void __iomem *regs_base) ++{ ++ int rev = REG32(regs_base + SSP_REG_REV); ++ int reva = REG32(regs_base + SSP_REG_REV-0x20); ++ ++ if ((((rev & SSP_REV_mskMAJOR_REV) >> SSP_REV_offMAJOR_REV) != 1)&& ++ (((reva & SSP_REV_mskMAJOR_REV) >> SSP_REV_offMAJOR_REV) != 1)) ++ { ++ ads_dbg(1, 0, "ADS7846 Touchscreen controller initialized failed:\n" ++ "\tcannot detect Faraday SSP Controller\n"); ++ return -ENXIO; ++ } ++ REG32(regs_base + SSP_REG_CR2) |= (1UL << SSP_CR2_offSSPRST); ++ ++ REG32(regs_base + SSP_REG_CR1) = ++ (0UL << SSP_CR1_offPDL) | /* Padding Data Length */ ++ (23UL << SSP_CR1_offSDL) | /* Serial Data Length */ ++ (5UL << SSP_CR1_offSCLKDIV); /* SCLK Divider */ ++ ++ REG32(regs_base + SSP_REG_CR0) = ++ (1UL << SSP_CR0_offFFMT) | /* Frame Format */ ++ (3UL << SSP_CR0_offOPM) | /* Operation Mode */ ++ (0UL << SSP_CR0_offSCLKPO) | /* SCLK Polarity */ ++ (0UL << SSP_CR0_offSCLKPH); /* SCLK Phase */ ++ ++ REG32(regs_base + SSP_REG_CR2) |= (1UL << SSP_CR2_offTXFCLR) | (1UL << SSP_CR2_offRXFCLR); ++ REG32(regs_base + SSP_REG_CR2) |= (1UL << SSP_CR2_offSSPEN) | (1UL << SSP_CR2_offTXDOE); ++ return 0; ++} ++ ++static int ads7846_probe(struct platform_device *pdev) ++{ ++ struct ads7846 *ts = &touchscreen; ++ struct input_dev *input_dev; ++ int err = 0; ++ platform_set_drvdata(pdev, ts); ++ ++ ts->regs = ioremap(0x98b00000, 44); ++ err = xspi_init_hw(ts->regs); ++ if (err) ++ goto err_unmap; ++ input_dev = input_allocate_device(); ++ if (!input_dev) ++ { ++ err = -ENOMEM; ++ goto err_free_mem; ++ } ++ ++ ts->input = input_dev; ++ ++ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ++ ts->timer.function = ads7846_timer; ++ ++ input_dev->name = "ADS7846 Touchscreen"; ++ input_dev->phys = ts->phys; ++ ++ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); ++ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); ++ input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); ++ ++ ts->irq = TOUCHSCREEN_IRQ; ++ ++ if (request_irq(ts->irq, ads7846_irq, IRQF_TRIGGER_RISING, "touch screen", ts)) ++ goto err_free_mem; ++ ++ err = input_register_device(input_dev); ++ if (err) ++ goto err_free_irq; ++ ++ spin_lock_init(&ts->lock); ++ return 0; ++err_free_irq: ++ free_irq(ts->irq, ts); ++err_free_mem: ++ input_free_device(input_dev); ++err_unmap: ++ iounmap(ts->regs); ++ ++ return err; ++} ++ ++static int __devexit ads7846_remove(struct platform_device *pdev) ++{ ++ struct ads7846 *ts = platform_get_drvdata(pdev); ++ ++ disable_irq(ts->irq); ++ free_irq(ts->irq, ts); ++ iounmap(ts->regs); ++ input_unregister_device(ts->input); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int ads7846_suspend( struct platform_device *pdev, pm_message_t message) ++{ ++ struct ads7846 *ts = platform_get_drvdata(pdev); ++ ++ spin_lock_irq(&ts->lock); ++ ts->disabled = true; ++ disable_irq(ts->irq); ++ spin_unlock_irq(&ts->lock); ++ ++ return 0; ++} ++ ++static int ads7846_resume( struct platform_device *pdev) ++{ ++ struct ads7846 *ts = platform_get_drvdata(pdev); ++ ++ spin_lock_irq(&ts->lock); ++ ++ enable_irq(ts->irq); ++ ts->disabled = false; ++ ++ spin_unlock_irq(&ts->lock); ++ ++ return 0; ++} ++#else ++#define ads7846_suspend NULL ++#define ads7846_resume NULL ++#endif ++ ++static void platform_device_release(struct device *dev){ ++} ++ ++static struct resource ads7846_resources[] = ++{ ++ [0] = { ++ .start = SSP_FTSSP010_PA_BASE, ++ .end = SSP_FTSSP010_PA_LIMIT, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = TOUCHSCREEN_IRQ, //feed me! SSP_FTSSP010_IRQ in spec.h ++ .end = TOUCHSCREEN_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_device ads7846_device = ++{ ++ .name = "ads7846", ++ .id = -1, ++ .resource = ads7846_resources, ++ .num_resources = ARRAY_SIZE(ads7846_resources), ++ .dev = { ++ .release = platform_device_release, ++ }, ++}; ++ ++#if 0 ++static struct platform_driver ads7846_driver = ++{ ++ .driver = { ++ .name = "ads7846", ++ .owner = THIS_MODULE, ++ }, ++ .probe = ads7846_probe, ++ .remove = __devexit_p(ads7846_remove), ++ .suspend = ads7846_suspend, ++ .resume = ads7846_resume, ++}; ++#else ++static struct platform_driver ads7846_driver = ++{ ++ .driver = { ++ .name = "ads7846", ++ }, ++ .probe = ads7846_probe, ++ .remove = __devexit_p(ads7846_remove), ++ .suspend = ads7846_suspend, ++ .resume = ads7846_resume, ++}; ++#endif ++ ++static int __init ads7846_init(void) ++{ ++ platform_device_register(&ads7846_device); ++ return platform_driver_register(&ads7846_driver); ++} ++ ++static void __exit ads7846_exit(void) ++{ ++ platform_device_unregister(&ads7846_device); ++ platform_driver_unregister(&ads7846_driver); ++} ++ ++module_init(ads7846_init); ++module_exit(ads7846_exit); ++MODULE_DESCRIPTION("ADS7846 TouchScreen Driver"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.4.110.orig/drivers/input/touchscreen/cpe_ts/cpe_ts.h linux-3.4.110/drivers/input/touchscreen/cpe_ts/cpe_ts.h +--- linux-3.4.110.orig/drivers/input/touchscreen/cpe_ts/cpe_ts.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/input/touchscreen/cpe_ts/cpe_ts.h 2016-04-07 10:20:51.050085202 +0200 +@@ -0,0 +1,218 @@ ++#ifndef SSP_FARADAY_H ++#define SSP_FARADAY_H ++ ++#define XILINX_SPI_NAME "faraday-spi" ++ ++/* ++ * Register definitions as per "OPB Serial Peripheral Interface ( SPI) ( v1.00e) ++ * Product Specification", DS464 ++ */ ++#define XSPI_CR_OFFSET 0x62 /* 16-bit Control Register */ ++ ++#define XSPI_CR_ENABLE 0x02 ++#define XSPI_CR_MASTER_MODE 0x04 ++#define XSPI_CR_CPOL 0x08 ++#define XSPI_CR_CPHA 0x10 ++#define XSPI_CR_MODE_MASK ( XSPI_CR_CPHA | XSPI_CR_CPOL) ++#define XSPI_CR_TXFIFO_RESET 0x20 ++#define XSPI_CR_RXFIFO_RESET 0x40 ++#define XSPI_CR_MANUAL_SSELECT 0x80 ++#define XSPI_CR_TRANS_INHIBIT 0x100 ++ ++#define XSPI_SR_OFFSET 0x67 /* 8-bit Status Register */ ++ ++#define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */ ++#define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */ ++#define XSPI_SR_TX_EMPTY_MASK 0x04 /* Transmit FIFO is empty */ ++#define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */ ++#define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */ ++ ++#define XSPI_TXD_OFFSET 0x6b /* 8-bit Data Transmit Register */ ++#define XSPI_RXD_OFFSET 0x6f /* 8-bit Data Receive Register */ ++ ++#define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */ ++ ++/* Register definitions as per "OPB IPIF ( v3.01c) Product Specification", DS414 ++ * IPIF registers are 32 bit ++ */ ++#define XIPIF_V123B_DGIER_OFFSET 0x1c /* IPIF global int enable reg */ ++#define XIPIF_V123B_GINTR_ENABLE 0x80000000 ++ ++#define XIPIF_V123B_IISR_OFFSET 0x20 /* IPIF interrupt status reg */ ++#define XIPIF_V123B_IIER_OFFSET 0x28 /* IPIF interrupt enable reg */ ++ ++#define XSPI_INTR_MODE_FAULT 0x01 /* Mode fault error */ ++#define XSPI_INTR_SLAVE_MODE_FAULT 0x02 /* Selected as slave while disabled */ ++#define XSPI_INTR_TX_EMPTY 0x04 /* TxFIFO is empty */ ++#define XSPI_INTR_TX_UNDERRUN 0x08 /* TxFIFO was underrun */ ++#define XSPI_INTR_RX_FULL 0x10 /* RxFIFO is full */ ++#define XSPI_INTR_RX_OVERRUN 0x20 /* RxFIFO was overrun */ ++ ++#define XIPIF_V123B_RESETR_OFFSET 0x40 /* IPIF reset register */ ++#define XIPIF_V123B_RESET_MASK 0x0a /* the value to write */ ++ ++/*************************************************************************/ ++#if 0 ++#define SSP_REG_CR0 ( SSP_FTSSP010_VA_BASE + 0x00) /* SSP Control Register 0 */ ++#define SSP_REG_CR1 ( SSP_FTSSP010_VA_BASE + 0x04) /* SSP Control Register 1 */ ++#define SSP_REG_CR2 ( SSP_FTSSP010_VA_BASE + 0x08) /* SSP Control Register 2 */ ++#define SSP_REG_SR ( SSP_FTSSP010_VA_BASE + 0x0c) /* SSP Status Register */ ++#define SSP_REG_ICR ( SSP_FTSSP010_VA_BASE + 0x10) /* SSP Interrupt Control Register */ ++#define SSP_REG_ISR ( SSP_FTSSP010_VA_BASE + 0x14) /* SSP Interrupt Status Register */ ++#define SSP_REG_DR ( SSP_FTSSP010_VA_BASE + 0x18) /* SSP Data Register */ ++#define SSP_REG_ACL ( SSP_FTSSP010_VA_BASE + 0x20) /* AC-Link Slot Valid Register */ ++#define SSP_REG_REV ( SSP_FTSSP010_VA_BASE + 0x40) /* SSP Revision Register */ ++#define SSP_REG_FEA ( SSP_FTSSP010_VA_BASE + 0x44) /* SSP Feature Register */ ++#endif ++#define SSP_REG_CR0 0x00 /* SSP Control Register 0 */ ++#define SSP_REG_CR1 0x04 /* SSP Control Register 1 */ ++#define SSP_REG_CR2 0x08 /* SSP Control Register 2 */ ++#define SSP_REG_SR 0x0C /* SSP Status Register */ ++#define SSP_REG_ICR 0x10 /* SSP Interrupt Control Register */ ++#define SSP_REG_ISR 0x14 /* SSP Interrupt Status Register */ ++#define SSP_REG_DR 0x18 /* SSP Data Register */ ++#define SSP_REG_ACL 0x20 /* AC-Link Slot Valid Register */ ++#define SSP_REG_REV 0x60 /* SSP Revision Register */ ++#define SSP_REG_FEA 0x64 /* SSP Feature Register */ ++ ++#define SSP_CR0_offFFMT 12 /* Frame Format */ ++#define SSP_CR0_offFSDIST 8 /* Frame/Sync and Data Distance */ ++#define SSP_CR0_offLBM 7 /* Loopback Mode */ ++#define SSP_CR0_offLSB 6 /* Bit Sequence Indicator */ ++#define SSP_CR0_offFSPO 5 /* Frame/Sync Polarity */ ++#define SSP_CR0_offFSJSFY 4 /* Data Justify */ ++#define SSP_CR0_offOPM 2 /* Operation Mode */ ++#define SSP_CR0_offSCLKPO 1 /* SCLK Polarity */ ++#define SSP_CR0_offSCLKPH 0 /* SCLK Phase */ ++ ++#define SSP_CR0_mskFFMT ( 0x07UL << SSP_CR0_offFFMT) ++#define SSP_CR0_mskFSDIST ( 0x03UL << SSP_CR0_offFSDIST) ++#define SSP_CR0_mskLBM ( 0x01UL << SSP_CR0_offLBM) ++#define SSP_CR0_mskLSB ( 0x01UL << SSP_CR0_offLSB) ++#define SSP_CR0_mskFSPO ( 0x01UL << SSP_CR0_offFSPO) ++#define SSP_CR0_mskFSJSFY ( 0x01UL << SSP_CR0_offFSJSFY) ++#define SSP_CR0_mskOPM ( 0x03UL << SSP_CR0_offOPM) ++#define SSP_CR0_mskSCLKPO ( 0x01UL << SSP_CR0_offSCLKPO) ++#define SSP_CR0_mskSCLKPH ( 0x01UL << SSP_CR0_offSCLKPH) ++ ++#define SSP_CR1_offPDL 24 /* Padding Data Length */ ++#define SSP_CR1_offSDL 16 /* Serial Data Length */ ++#define SSP_CR1_offSCLKDIV 0 /* SCLK Divider */ ++ ++#define SSP_CR1_mskPDL ( 0xFFUL << SSP_CR1_offPDL) ++#define SSP_CR1_mskSDL ( 0x1FUL << SSP_CR1_offSDL) ++#define SSP_CR1_mskSCLKDIV ( 0xFFUL << SSP_CR1_offSCLKDIV) ++ ++#define SSP_CR2_offSSPRST 6 /* SSP Reset */ ++#define SSP_CR2_offACCRST 5 /* AC-Link Cold Reset Enable */ ++#define SSP_CR2_offACWRST 4 /* AC-Link Warm Reset Enable */ ++#define SSP_CR2_offTXFCLR 3 /* Transmit FIFO Clear */ ++#define SSP_CR2_offRXFCLR 2 /* Recieve FIFO clear */ ++#define SSP_CR2_offTXDOE 1 /* Transmit Data Output Enable */ ++#define SSP_CR2_offSSPEN 0 /* The SSP Enable */ ++ ++#define SSP_CR2_mskSSPRST ( 0x01UL << SSP_CR2_offSSPRST) ++#define SSP_CR2_mskACCRST ( 0x01UL << SSP_CR2_offACCRST) ++#define SSP_CR2_mskACWRST ( 0x01UL << SSP_CR2_offACWRST) ++#define SSP_CR2_mskTXFCLR ( 0x01UL << SSP_CR2_offTXFCLR) ++#define SSP_CR2_mskRXFCLR ( 0x01UL << SSP_CR2_offRXFCLR) ++#define SSP_CR2_mskTXDOE ( 0x01UL << SSP_CR2_offTXDOE) ++#define SSP_CR2_mskSSPEN ( 0x01UL << SSP_CR2_offSSPEN) ++ ++#define SSP_SR_offTFVE 12 /* Transmit FIFO Valid Entries */ ++#define SSP_SR_offRFVE 4 /* Recieve FIFO Valid Entries */ ++#define SSP_SR_offBUSY 2 /* Busy Indicator */ ++#define SSP_SR_offTFNF 1 /* Transmit FIFO not full */ ++#define SSP_SR_offRFF 0 /* Recieve FIFO full */ ++ ++#define SSP_SR_mskTFVE ( 0x1FUL << SSP_SR_offTFVE) ++#define SSP_SR_mskRFVE ( 0x1FUL << SSP_SR_offRFVE) ++#define SSP_SR_mskBUSY ( 0x01UL << SSP_SR_offBUSY) ++#define SSP_SR_mskTFNF ( 0x01UL << SSP_SR_offTFNF) ++#define SSP_SR_mskRFF ( 0x01UL << SSP_SR_offRFF) ++ ++#define SSP_ICR_offTFTHOD 12 /* Transmit FIFO Threshold */ ++#define SSP_ICR_offRFTHOD 8 /* Recieve FIFO Threshold */ ++#define SSP_ICR_offAC97FCEN 6 /* AC97 Frame Complete */ ++#define SSP_ICR_offTFDMAEN 5 /* Transmit DMA Request Enable */ ++#define SSP_ICR_offRFDMAEN 4 /* Recieve DMA Request Enable */ ++#define SSP_ICR_offTFTHIEN 3 /* Transmit FIFO Threshold Interrupt */ ++#define SSP_ICR_offRFTHIEN 2 /* Recieve FIFO Threshold Interrupt */ ++#define SSP_ICR_offTFURIEN 1 /* Transmit FIFO Underrun Interrupt Enable */ ++#define SSP_ICR_offRFORIEN 0 /* Recieve FIFO Overrun Interrupt Enable */ ++ ++#define SSP_ICR_mskTFTHOD ( 0x0FUL << SSP_ICR_offTFTHOD) ++#define SSP_ICR_mskRFTHOD ( 0x0FUL << SSP_ICR_offRFTHOD) ++#define SSP_ICR_mskAC97FCEN ( 0x01UL << SSP_ICR_offAC97FCEN) ++#define SSP_ICR_mskTFDMAEN ( 0x01UL << SSP_ICR_offTFDMAEN) ++#define SSP_ICR_mskRFDMAEN ( 0x01UL << SSP_ICR_offRFDMAEN) ++#define SSP_ICR_mskTFTHIEN ( 0x01UL << SSP_ICR_offTFTHIEN) ++#define SSP_ICR_mskRFTHIEN ( 0x01UL << SSP_ICR_offRFTHIEN) ++#define SSP_ICR_mskTFURIEN ( 0x01UL << SSP_ICR_offTFURIEN) ++#define SSP_ICR_mskRFORIEN ( 0x01UL << SSP_ICR_offRFORIEN) ++ ++#define SSP_ISR_offAC97FCI 4 /* AC97 Frame Complete Interrupt */ ++#define SSP_ISR_offTFTHI 3 /* Transmit FIFO Threshold Interrupt */ ++#define SSP_ISR_offRFTHI 2 /* Recieve FIFO Threshold Interrupt */ ++#define SSP_ISR_offTFURI 1 /* Transmit FIFO underrun Interrupt */ ++#define SSP_ISR_offRFORI 0 /* Recieve FIFO Overun Interrupt */ ++ ++#define SSP_ISR_mskAC97FCI ( 0x01UL << SSP_ISR_offAC97FCI) ++#define SSP_ISR_mskTFTHI ( 0x01UL << SSP_ISR_offTFTHI) ++#define SSP_ISR_mskRFTHI ( 0x01UL << SSP_ISR_offRFTHI) ++#define SSP_ISR_mskTFURI ( 0x01UL << SSP_ISR_offTFURI) ++#define SSP_ISR_mskRFORI ( 0x01UL << SSP_ISR_offRFORI) ++ ++#define SSP_ACL_offSLOT1V 14 /* The 1st Slot is Valid */ ++#define SSP_ACL_offSLOT2V 13 /* The 2nd Slot is Valid */ ++#define SSP_ACL_offSLOT3V 12 /* The 3th Slot is Valid */ ++#define SSP_ACL_offSLOT4V 11 /* The 4th Slot is Valid */ ++#define SSP_ACL_offSLOT5V 10 /* The 5th Slot is Valid */ ++#define SSP_ACL_offSLOT6V 9 /* The 6th Slot is Valid */ ++#define SSP_ACL_offSLOT7V 8 /* The 7th Slot is Valid */ ++#define SSP_ACL_offSLOT8V 7 /* The 8th Slot is Valid */ ++#define SSP_ACL_offSLOT9V 6 /* The 9th Slot is Valid */ ++#define SSP_ACL_offSLOT10V 5 /* The 10th Slot is Valid */ ++#define SSP_ACL_offSLOT11V 4 /* The 11th Slot is Valid */ ++#define SSP_ACL_offSLOT12V 3 /* The 12th Slot is Valid */ ++#define SSP_ACL_offCODECID 0 /* Codec ID, which will be shifted out as tag slot */ ++ ++#define SSP_ACL_mskSLOT1V ( 0x01UL << SSP_ACL_offSLOT1V) ++#define SSP_ACL_mskSLOT2V ( 0x01UL << SSP_ACL_offSLOT2V) ++#define SSP_ACL_mskSLOT3V ( 0x01UL << SSP_ACL_offSLOT3V) ++#define SSP_ACL_mskSLOT4V ( 0x01UL << SSP_ACL_offSLOT4V) ++#define SSP_ACL_mskSLOT5V ( 0x01UL << SSP_ACL_offSLOT5V) ++#define SSP_ACL_mskSLOT6V ( 0x01UL << SSP_ACL_offSLOT6V) ++#define SSP_ACL_mskSLOT7V ( 0x01UL << SSP_ACL_offSLOT7V) ++#define SSP_ACL_mskSLOT8V ( 0x01UL << SSP_ACL_offSLOT8V) ++#define SSP_ACL_mskSLOT9V ( 0x01UL << SSP_ACL_offSLOT9V) ++#define SSP_ACL_mskSLOT10V ( 0x01UL << SSP_ACL_offSLOT10V) ++#define SSP_ACL_mskSLOT11V ( 0x01UL << SSP_ACL_offSLOT11V) ++#define SSP_ACL_mskSLOT12V ( 0x01UL << SSP_ACL_offSLOT12V) ++#define SSP_ACL_mskCODECID ( 0x03UL << SSP_ACL_offCODECID) ++ ++#define SSP_REV_offMAJOR_REV 16 /* Major Revision Number */ ++#define SSP_REV_offMINOR_REV 8 /* Minor Revision Number */ ++#define SSP_REV_offREL_REV 0 /* Release Number */ ++ ++#define SSP_REV_mskMAJOR_REV ( 0xFFUL << SSP_REV_offMAJOR_REV) ++#define SSP_REV_mskMINOR_REV ( 0xFFUL << SSP_REV_offMINOR_REV) ++#define SSP_REV_mskREL_REV ( 0xFFUL << SSP_REV_offREL_REV) ++ ++#define SSP_FEA_offSSP_FCFG 27 /* The SSP Functional Configurations */ ++#define SSP_FEA_offSPIMWR_FCFG 26 /* Motorola's SPI and National Semiconductor's Microwire Configurations */ ++#define SSP_FEA_offI2S_FCFG 25 /* Philips's I2S Functional Configurations */ ++#define SSP_FEA_offAC97_FCFG 24 /* Intel's AC-Link Functional Configurations */ ++#define SSP_FEA_offTXFIFO_WIDTH 16 /* Transmit FIFO Size Configurations */ ++#define SSP_FEA_offRXFIFO_WIDTH 8 /* Recieve FIFO Size Configuration */ ++#define SSP_FEA_offFIFO_WIDTH 0 /* Transmit/Recieve FIFO Width */ ++ ++#define SSP_FEA_mskSSP_FCFG ( 0x01UL << SSP_FEA_offSSP_FCFG) ++#define SSP_FEA_mskSPIMWR_FCFG ( 0x01UL << SSP_FEA_offSPIMWR_FCFG) ++#define SSP_FEA_mskI2S_FCFG ( 0x01UL << SSP_FEA_offI2S_FCFG) ++#define SSP_FEA_mskAC97_FCFG ( 0x01UL << SSP_FEA_offAC97_FCFG) ++#define SSP_FEA_mskTXFIFO_WIDTH ( 0xFFUL << SSP_FEA_offTXFIFO_WIDTH) ++#define SSP_FEA_mskRXFIFO_WIDTH ( 0xFFUL << SSP_FEA_offRXFIFO_WIDTH) ++#define SSP_FEA_mskFIFO_WIDTH ( 0xFFUL << SSP_FEA_offFIFO_WIDTH) ++ ++#endif /* SSP_FARADAY */ +diff -Nur linux-3.4.110.orig/drivers/input/touchscreen/cpe_ts/Makefile linux-3.4.110/drivers/input/touchscreen/cpe_ts/Makefile +--- linux-3.4.110.orig/drivers/input/touchscreen/cpe_ts/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/input/touchscreen/cpe_ts/Makefile 2016-04-07 10:20:51.050085202 +0200 +@@ -0,0 +1 @@ ++obj-$(CONFIG_TOUCHSCREEN_CPE_TS) += cpe_ts.o +diff -Nur linux-3.4.110.orig/drivers/input/touchscreen/Kconfig linux-3.4.110/drivers/input/touchscreen/Kconfig +--- linux-3.4.110.orig/drivers/input/touchscreen/Kconfig 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/input/touchscreen/Kconfig 2016-04-07 10:20:51.050085202 +0200 +@@ -86,6 +86,26 @@ + To compile this driver as a module, choose M here: the + module will be called ad7879-spi. + ++config TOUCHSCREEN_CPE_TS ++ tristate "Touchscreen Driver for AG101/XC5" ++ help ++ This driver directly accesses SPI controller to communicate with ++ the ads7846 chip. ++ ++ Once we have a SPI controller driver ++ , we can adopt to the SPI ++ framework that kernel provides. ++ ++config TOUCHSCREEN_CPE_TS_DEJITTER ++ bool "Dejitter Detection" ++ depends on TOUCHSCREEN_CPE_TS ++ default y ++ help ++ Say Y here to enable dejitter detection in AG101/Leopard Touchscreen Driver. ++ ++ If unsure, say y. ++ ++ + config TOUCHSCREEN_ATMEL_MXT + tristate "Atmel mXT I2C Touchscreen" + depends on I2C +diff -Nur linux-3.4.110.orig/drivers/input/touchscreen/Makefile linux-3.4.110/drivers/input/touchscreen/Makefile +--- linux-3.4.110.orig/drivers/input/touchscreen/Makefile 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/input/touchscreen/Makefile 2016-04-07 10:20:51.050085202 +0200 +@@ -69,3 +69,4 @@ + obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o + obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o + obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o ++obj-$(CONFIG_TOUCHSCREEN_CPE_TS) += cpe_ts/ +diff -Nur linux-3.4.110.orig/drivers/mmc/core/bus.c linux-3.4.110/drivers/mmc/core/bus.c +--- linux-3.4.110.orig/drivers/mmc/core/bus.c 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/mmc/core/bus.c 2016-04-07 10:20:51.050085202 +0200 +@@ -26,7 +26,9 @@ + #include "bus.h" + + #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) +- ++#ifdef CONFIG_MMC_TEST ++static struct mmc_driver *mmc_test_drv; ++#endif + static ssize_t mmc_type_show(struct device *dev, + struct device_attribute *attr, char *buf) + { +@@ -109,6 +111,11 @@ + struct mmc_driver *drv = to_mmc_driver(dev->driver); + struct mmc_card *card = mmc_dev_to_card(dev); + ++ #ifdef CONFIG_MMC_TEST ++ mmc_test_drv->probe(card); ++ printk("debug mmc_bus_probe\n"); ++ #endif ++ + return drv->probe(card); + } + +@@ -200,6 +207,11 @@ + int mmc_register_driver(struct mmc_driver *drv) + { + drv->drv.bus = &mmc_bus_type; ++ #ifdef CONFIG_MMC_TEST ++ printk("debug defined config_mmc_test in mmc_register_driver\n"); ++ if(!strcmp(drv->drv.name,"mmc_test")) ++ mmc_test_drv = drv; ++ #endif + return driver_register(&drv->drv); + } + +diff -Nur linux-3.4.110.orig/drivers/mmc/host/ftsdc010.c linux-3.4.110/drivers/mmc/host/ftsdc010.c +--- linux-3.4.110.orig/drivers/mmc/host/ftsdc010.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/mmc/host/ftsdc010.c 2016-04-07 10:20:51.050085202 +0200 +@@ -0,0 +1,1586 @@ ++/* drivers/mmc/host/ftsdc010.c ++ * Copyright (C) 2010 Andestech ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include <linux/module.h> ++#include <linux/dma-mapping.h> ++#include <linux/clk.h> ++#include <linux/mmc/host.h> ++#include <linux/mmc/mmc.h> ++#include <linux/mmc/card.h> ++#include <linux/platform_device.h> ++#include <linux/debugfs.h> ++#include <linux/seq_file.h> ++#include <linux/irq.h> ++#include <linux/interrupt.h> ++#include <linux/delay.h> ++#include <linux/slab.h> ++ ++#include <asm/io.h> ++#include <asm/spec.h> ++#include <asm/dmad.h> ++ ++#include "ftsdc010.h" ++ ++#define DRIVER_NAME "ftsdc010" ++ ++#define REG_READ(addr) readl((host->base + addr)) ++#define REG_WRITE(data, addr) writel((data), (host->base + addr)) ++ ++#define APB_CLK_IN (AHB_CLK_IN / 2) ++ ++enum dbg_channels { ++ dbg_err = (1 << 0), ++ dbg_debug = (1 << 1), ++ dbg_info = (1 << 2), ++ dbg_irq = (1 << 3), ++ dbg_sg = (1 << 4), ++ dbg_dma = (1 << 5), ++ dbg_pio = (1 << 6), ++ dbg_fail = (1 << 7), ++ dbg_conf = (1 << 8), ++}; ++ ++static struct workqueue_struct *mywq; ++ ++static const int dbgmap_err = dbg_fail; ++static const int dbgmap_info = dbg_info | dbg_conf; ++static const int dbgmap_debug = dbg_err | dbg_debug | dbg_info | dbg_conf; ++#if 1 ++#define dbg(host, channels, args...) \ ++ do { \ ++ if (dbgmap_err & channels) \ ++ dev_err(&host->pdev->dev, args); \ ++ else if (dbgmap_info & channels) \ ++ dev_info(&host->pdev->dev, args); \ ++ else if (dbgmap_debug & channels) \ ++ dev_dbg(&host->pdev->dev, args); \ ++ } while (0) ++#endif ++#if 0 ++#define dbg(host, channels, args...) \ ++ do { \ ++ printk(KERN_INFO "%s: ", "ftsdc");\ ++ printk(args); \ ++ } while(0) ++#endif ++ ++static void finalize_request(struct ftsdc_host *host); ++static void ftsdc_send_request(struct mmc_host *mmc); ++ ++#ifdef CONFIG_MMC_DEBUG ++ ++static void dbg_dumpregs(struct ftsdc_host *host, char *prefix) ++{ ++ u32 con, cmdarg, r0, r1, r2, r3, rcmd, dcon, dtimer, ++ dlen, sta, clr, imask, pcon, ccon, bwidth, scon1, ++ scon2, ssta, fea; ++ ++ con = REG_READ(SDC_CMD_REG); ++ cmdarg = REG_READ(SDC_ARGU_REG); ++ r0 = REG_READ(SDC_RESPONSE0_REG); ++ r1 = REG_READ(SDC_RESPONSE1_REG); ++ r2 = REG_READ(SDC_RESPONSE2_REG); ++ r3 = REG_READ(SDC_RESPONSE3_REG); ++ rcmd = REG_READ(SDC_RSP_CMD_REG); ++ dcon = REG_READ(SDC_DATA_CTRL_REG); ++ dtimer = REG_READ(SDC_DATA_TIMER_REG); ++ dlen = REG_READ(SDC_DATA_LEN_REG); ++ sta = REG_READ(SDC_STATUS_REG); ++ clr = REG_READ(SDC_CLEAR_REG); ++ imask = REG_READ(SDC_INT_MASK_REG); ++ pcon = REG_READ(SDC_POWER_CTRL_REG); ++ ccon = REG_READ(SDC_CLOCK_CTRL_REG); ++ bwidth = REG_READ(SDC_BUS_WIDTH_REG); ++ scon1 = REG_READ(SDC_SDIO_CTRL1_REG); ++ scon2 = REG_READ(SDC_SDIO_CTRL2_REG); ++ ssta = REG_READ(SDC_SDIO_STATUS_REG); ++ fea = REG_READ(SDC_FEATURE_REG); ++ ++ dbg(host, dbg_debug, "%s CON:[%08x] STA:[%08x] INT:[%08x], PWR:[%08x], CLK:[%08x]\n", ++ prefix, con, sta, imask, pcon, ccon); ++ ++ dbg(host, dbg_debug, "%s DCON:[%08x] DTIME:[%08x]" ++ " DLEN:[%08x] DWIDTH:[%08x]\n", ++ prefix, dcon, dtimer, dlen, bwidth); ++ ++ dbg(host, dbg_debug, "%s R0:[%08x] R1:[%08x]" ++ " R2:[%08x] R3:[%08x]\n", ++ prefix, r0, r1, r2, r3); ++ ++ dbg(host, dbg_debug, "%s SCON1:[%08x] SCON2:[%08x]" ++ " SSTA:[%08x] FEA:[%08x]\n", ++ prefix, scon1, scon2, ssta, fea); ++} ++ ++static void prepare_dbgmsg(struct ftsdc_host *host, struct mmc_command *cmd, ++ int stop) ++{ ++ snprintf(host->dbgmsg_cmd, 300, ++ "#%u%s op:%i arg:0x%08x flags:0x08%x retries:%u", ++ host->ccnt, (stop ? " (STOP)" : ""), ++ cmd->opcode, cmd->arg, cmd->flags, cmd->retries); ++ ++ if (cmd->data) { ++ snprintf(host->dbgmsg_dat, 300, ++ "#%u bsize:%u blocks:%u bytes:%u", ++ host->dcnt, cmd->data->blksz, ++ cmd->data->blocks, ++ cmd->data->blocks * cmd->data->blksz); ++ } else { ++ host->dbgmsg_dat[0] = '\0'; ++ } ++} ++ ++static void dbg_dumpcmd(struct ftsdc_host *host, struct mmc_command *cmd, ++ int fail) ++{ ++ unsigned int dbglvl = fail ? dbg_fail : dbg_debug; ++ ++ if (!cmd) ++ return; ++ ++ if (cmd->error == 0) { ++ dbg(host, dbglvl, "CMD[OK] %s R0:0x%08x\n", ++ host->dbgmsg_cmd, cmd->resp[0]); ++ } else { ++ dbg(host, dbglvl, "CMD[ERR %i] %s Status:%s\n", ++ cmd->error, host->dbgmsg_cmd, host->status); ++ } ++ ++ if (!cmd->data) ++ return; ++ ++ if (cmd->data->error == 0) { ++ dbg(host, dbglvl, "DAT[OK] %s\n", host->dbgmsg_dat); ++ } else { ++ dbg(host, dbglvl, "DAT[ERR %i] %s DCNT:0x%08x\n", ++ cmd->data->error, host->dbgmsg_dat, ++ REG_READ(SDC_DATA_LEN_REG)); ++ } ++} ++#else ++static void dbg_dumpcmd(struct ftsdc_host *host, ++ struct mmc_command *cmd, int fail) { } ++ ++static void prepare_dbgmsg(struct ftsdc_host *host, struct mmc_command *cmd, ++ int stop) { } ++ ++static void dbg_dumpregs(struct ftsdc_host *host, char *prefix) { } ++ ++#endif /* CONFIG_MMC_DEBUG */ ++ ++static inline bool ftsdc_dmaexist(struct ftsdc_host *host) ++{ ++ return (host->dma_req != NULL); ++} ++ ++static inline u32 enable_imask(struct ftsdc_host *host, u32 imask) ++{ ++ u32 newmask; ++ ++#ifdef CONFIG_MMC_DEBUG ++ if (imask & SDC_STATUS_REG_SDIO_INTR) printk("\n*** E ***\n"); ++#endif ++ newmask = REG_READ(SDC_INT_MASK_REG); ++ newmask |= imask; ++ ++ REG_WRITE(newmask, SDC_INT_MASK_REG); ++ ++ return newmask; ++} ++ ++static inline u32 disable_imask(struct ftsdc_host *host, u32 imask) ++{ ++ u32 newmask; ++ ++#ifdef CONFIG_MMC_DEBUG ++ if (imask & SDC_STATUS_REG_SDIO_INTR) printk("\n*** D ***\n"); ++#endif ++ newmask = REG_READ(SDC_INT_MASK_REG); ++ newmask &= ~imask; ++ ++ REG_WRITE(newmask, SDC_INT_MASK_REG); ++ ++ return newmask; ++} ++ ++static inline void clear_imask(struct ftsdc_host *host) ++{ ++ u32 mask = REG_READ(SDC_INT_MASK_REG); ++ ++ /* preserve the SDIO IRQ mask state */ ++ mask &= (SDC_INT_MASK_REG_SDIO_INTR | SDC_INT_MASK_REG_CARD_CHANGE); ++ REG_WRITE(mask, SDC_INT_MASK_REG); ++} ++ ++//static void ftsdc_check_sdio_irq(struct ftsdc_host *host) ++//{ ++// if (host->sdio_irqen) { ++// u32 con = REG_READ(SDC_STATUS_REG); ++// if (con & SDC_STATUS_REG_SDIO_INTR) { ++// printk(KERN_DEBUG "%s: signalling irq\n", __func__); ++// mmc_signal_sdio_irq(host->mmc); ++// } ++// } ++//} ++ ++static inline void get_data_buffer(struct ftsdc_host *host) ++{ ++ struct scatterlist *sg; ++ ++ BUG_ON(host->buf_sgptr >= host->mrq->data->sg_len); ++ ++ sg = &host->mrq->data->sg[host->buf_sgptr]; ++ ++ host->buf_bytes = sg->length; ++ host->buf_ptr = host->dodma ? (u32 *)sg->dma_address : sg_virt(sg); ++ host->buf_sgptr++; ++} ++ ++static inline u32 cal_blksz(unsigned int blksz) ++{ ++ u32 blksztwo = 0; ++ ++ while (blksz >>= 1) ++ blksztwo++; ++ ++ return blksztwo; ++} ++ ++/** ++ * ftsdc_enable_irq - enable IRQ, after having disabled it. ++ * @host: The device state. ++ * @more: True if more IRQs are expected from transfer. ++ * ++ * Enable the main IRQ if needed after it has been disabled. ++ * ++ * The IRQ can be one of the following states: ++ * - enable after data read/write ++ * - disable when handle data read/write ++ */ ++static void ftsdc_enable_irq(struct ftsdc_host *host, bool enable) ++{ ++ unsigned long flags; ++ local_irq_save(flags); ++ ++ host->irq_enabled = enable; ++ ++ if (enable) ++ enable_irq(host->irq); ++ else ++ disable_irq(host->irq); ++ ++ local_irq_restore(flags); ++} ++ ++static void do_pio_read(struct ftsdc_host *host) ++{ ++ u32 fifo; ++ u32 fifo_words; ++ u32 *ptr; ++ u32 status; ++ u32 retry = 0; ++ ++ ++ BUG_ON(host->buf_bytes != 0); ++ ++ while (host->buf_sgptr < host->mrq->data->sg_len) { ++ get_data_buffer(host); ++ ++ dbg(host, dbg_pio, ++ "pio_read(): new target: [%i]@[%p]\n", ++ host->buf_bytes, host->buf_ptr); ++ ++ while (host->buf_bytes) { ++ status = REG_READ(SDC_STATUS_REG); ++ ++ if (status & SDC_STATUS_REG_FIFO_OVERRUN) { ++ fifo = host->fifo_len > host->buf_bytes ? ++ host->buf_bytes : host->fifo_len; ++ ++#if 1 ++ dbg(host, dbg_pio, ++ "pio_read(): fifo:[%02i] buffer:[%03i] dcnt:[%08X]\n", ++ fifo, host->buf_bytes, ++ REG_READ(SDC_DATA_LEN_REG)); ++#endif ++ ++ host->buf_bytes -= fifo; ++ host->buf_count += fifo; ++ ++ fifo_words = fifo >> 2; ++ ptr = host->buf_ptr; ++ while (fifo_words--) ++ *ptr++ = REG_READ(SDC_DATA_WINDOW_REG); ++ ++ host->buf_ptr = ptr; ++ //ADD by river 2010.10.26 for adding some delays for SD card to put data into FIFO again ++ //mdelay(1); ++ udelay(800); ++ //End ADD by river 2010.10.26 for adding some delays for SD card to put data into FIFO again ++ ++ /* sdio allow non-power-of-2 blksz */ ++ if (fifo & 3) { ++ u32 n = fifo & 3; ++ u32 data = REG_READ(SDC_DATA_WINDOW_REG); ++ u8 *p = (u8 *)host->buf_ptr; ++ ++ while (n--) { ++ *p++ = data; ++ data >>= 8; ++ } ++ } ++ } else { ++ udelay(1); ++ if (++retry >= SDC_PIO_RETRY) { ++ host->mrq->data->error = -EIO; ++ goto err; ++ } ++ } ++ } ++ } ++ ++err: ++ ++ host->buf_active = XFER_NONE; ++ host->complete_what = COMPLETION_FINALIZE; ++} ++ ++static void do_pio_write(struct ftsdc_host *host) ++{ ++ u32 fifo; ++ u32 *ptr; ++ u32 status; ++ u32 retry = 0; ++ ++ BUG_ON(host->buf_bytes != 0); ++ ++ while (host->buf_sgptr < host->mrq->data->sg_len) { ++ get_data_buffer(host); ++ ++ dbg(host, dbg_pio, ++ "pio_write(): new source: [%i]@[%p]\n", ++ host->buf_bytes, host->buf_ptr); ++ ++ while (host->buf_bytes) { ++ status = REG_READ(SDC_STATUS_REG); ++ if (status & SDC_STATUS_REG_FIFO_UNDERRUN) { ++ fifo = host->fifo_len > host->buf_bytes ? ++ host->buf_bytes : host->fifo_len; ++ ++ dbg(host, dbg_pio, ++ "pio_write(): fifo:[%02i] buffer:[%03i] dcnt:[%08X]\n", ++ fifo, host->buf_bytes, ++ REG_READ(SDC_DATA_LEN_REG)); ++ ++ host->buf_bytes -= fifo; ++ host->buf_count += fifo; ++ ++ fifo = (fifo + 3) >> 2; ++ ptr = host->buf_ptr; ++ while (fifo--) { ++ REG_WRITE(*ptr, SDC_DATA_WINDOW_REG); ++ ptr++; ++ } ++ host->buf_ptr = ptr; ++ } else { ++ udelay(1); ++ if (++retry >= SDC_PIO_RETRY) { ++ host->mrq->data->error = -EIO; ++ goto err; ++ } ++ } ++ } ++ } ++ ++err: ++ host->buf_active = XFER_NONE; ++ host->complete_what = COMPLETION_FINALIZE; ++} ++ ++static void do_dma_access(struct ftsdc_host *host) ++{ ++ int res; ++ unsigned long timeout; ++ dmad_chreq *req = host->dma_req; ++ dmad_drb *drb = 0; ++ ++ while (host->buf_sgptr < host->mrq->data->sg_len) { ++ ++ INIT_COMPLETION(host->dma_complete); ++ get_data_buffer(host); ++ ++ dbg(host, dbg_dma, ++ "dma_%s(): new target: [%i]@[%p]\n", ++ host->buf_active == XFER_READ ? "read" : "write", ++ host->buf_bytes, host->buf_ptr); ++ ++ res = dmad_alloc_drb(req, &drb); ++ if (res != 0 || (drb == 0)) { ++ dbg(host, dbg_err, "%s() Failed to allocate dma request block!\n", __func__); ++ host->mrq->data->error = -ENODEV; ++ goto err; ++ } ++ ++ drb->addr0 = SDC_FTSDC010_0_PA_BASE + SDC_DATA_WINDOW_REG; ++ drb->addr1 = (dma_addr_t)host->buf_ptr; ++ drb->req_cycle = dmad_bytes_to_cycles(req, host->buf_bytes); ++ drb->sync = &host->dma_complete; ++ ++ timeout = SDC_TIMEOUT_BASE*((host->buf_bytes+511)>>9); ++ ++ res = dmad_submit_request(req, drb, 1); ++ if (res != 0) { ++ dbg(host, dbg_err, "%s() Failed to submit dma request block!\n", __func__); ++ host->mrq->data->error = -ENODEV; ++ goto err; ++ } ++ ++ dbg(host, dbg_err, "reach here!\n"); ++ if (wait_for_completion_timeout(&host->dma_complete, timeout) == 0) { ++ dbg(host, dbg_err, "%s: read timeout\n", __func__); ++ host->mrq->data->error = -ETIMEDOUT; ++ goto err; ++ } ++ } ++ ++ host->dma_finish = true; ++err: ++ host->buf_active = XFER_NONE; ++ host->complete_what = COMPLETION_FINALIZE; ++} ++ ++static void ftsdc_work(struct work_struct *work) ++{ ++ struct ftsdc_host *host = ++ container_of(work, struct ftsdc_host, work); ++ ++ ftsdc_enable_irq(host, false); ++ ++ if (host->dodma) { ++ do_dma_access(host); ++ } else { ++ if (host->buf_active == XFER_WRITE) ++ do_pio_write(host); ++ ++ if (host->buf_active == XFER_READ) ++ do_pio_read(host); ++ } ++ ++ tasklet_schedule(&host->pio_tasklet); ++ ftsdc_enable_irq(host, true); ++} ++ ++ ++static void pio_tasklet(unsigned long data) ++{ ++ struct ftsdc_host *host = (struct ftsdc_host *) data; ++ ++ if (host->complete_what == COMPLETION_XFER_PROGRESS) { ++ queue_work(mywq, (struct work_struct *)&host->work); ++ return; ++ } ++ ++ if (host->complete_what == COMPLETION_FINALIZE) { ++ clear_imask(host); ++ if (host->buf_active != XFER_NONE) { ++ dbg(host, dbg_err, "unfinished %s " ++ "- buf_count:[%u] buf_bytes:[%u]\n", ++ (host->buf_active == XFER_READ) ? "read" : "write", ++ host->buf_count, host->buf_bytes); ++ ++ if (host->mrq->data) ++ host->mrq->data->error = -EINVAL; ++ } ++ ++ finalize_request(host); ++ } ++} ++ ++ ++static void finalize_request(struct ftsdc_host *host) ++{ ++ struct mmc_request *mrq = host->mrq; ++ struct mmc_command *cmd; ++ u32 con; ++ int debug_as_failure = 0; ++ ++ if (host->complete_what != COMPLETION_FINALIZE) ++ return; ++ ++ if (!mrq) ++ return; ++ ++ cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; ++ ++ if (cmd->data && (cmd->error == 0) && ++ (cmd->data->error == 0)) { ++ if (host->dodma && (!host->dma_finish)) { ++ dbg(host, dbg_dma, "DMA Missing (%d)!\n", ++ host->dma_finish); ++ return; ++ } ++ host->dodma = false; ++ } ++ ++ /* Read response from controller. */ ++ if (cmd->flags & MMC_RSP_136) { ++ cmd->resp[3] = REG_READ(SDC_RESPONSE0_REG); ++ cmd->resp[2] = REG_READ(SDC_RESPONSE1_REG); ++ cmd->resp[1] = REG_READ(SDC_RESPONSE2_REG); ++ cmd->resp[0] = REG_READ(SDC_RESPONSE3_REG); ++ } else if (cmd->flags & MMC_RSP_PRESENT) { ++ cmd->resp[0] = REG_READ(SDC_RESPONSE0_REG); ++ } ++ ++ if (cmd->error) ++ debug_as_failure = 1; ++ ++ if (cmd->data && cmd->data->error) ++ debug_as_failure = 1; ++ ++ dbg_dumpcmd(host, cmd, debug_as_failure); ++ ++ clear_imask(host); ++ con = REG_READ(SDC_STATUS_REG); ++ con &= ~SDC_CLEAR_REG_SDIO_INTR; ++ REG_WRITE(con, SDC_CLEAR_REG); ++ ++ if (cmd->data && cmd->error) ++ cmd->data->error = cmd->error; ++ ++ if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) { ++ host->cmd_is_stop = 1; ++ ftsdc_send_request(host->mmc); ++ return; ++ } ++ ++ /* If we have no data transfer we are finished here */ ++ if (!mrq->data) ++ goto request_done; ++ ++ /* Calulate the amout of bytes transfer if there was no error */ ++ if (mrq->data->error == 0) { ++ mrq->data->bytes_xfered = ++ (mrq->data->blocks * mrq->data->blksz); ++ } else { ++ mrq->data->bytes_xfered = 0; ++ } ++ ++request_done: ++ host->complete_what = COMPLETION_NONE; ++ host->mrq = NULL; ++ ++ host->last_opcode = mrq->cmd->opcode; ++ mmc_request_done(host->mmc, mrq); ++} ++ ++static void ftsdc_send_command(struct ftsdc_host *host, ++ struct mmc_command *cmd) ++{ ++ u32 ccon = 0; ++ u32 newmask = 0; ++ u32 scon; ++ ++ if (cmd->data) { ++ host->complete_what = COMPLETION_XFER_PROGRESS; ++ newmask |= SDC_INT_MASK_REG_RSP_TIMEOUT; ++ } else if (cmd->flags & MMC_RSP_PRESENT) { ++ host->complete_what = COMPLETION_RSPFIN; ++ newmask |= SDC_INT_MASK_REG_RSP_TIMEOUT; ++ } else { ++ host->complete_what = COMPLETION_CMDSENT; ++ newmask |= SDC_INT_MASK_REG_CMD_SEND; ++ } ++ ++ ccon |= cmd->opcode & SDC_CMD_REG_INDEX; ++ ccon |= SDC_CMD_REG_CMD_EN; ++ ++ if (cmd->flags & MMC_RSP_PRESENT) { ++ ccon |= SDC_CMD_REG_NEED_RSP; ++ newmask |= SDC_INT_MASK_REG_RSP_CRC_OK | ++ SDC_INT_MASK_REG_RSP_CRC_FAIL; ++ } ++ ++ if (cmd->flags & MMC_RSP_136) ++ ccon |= SDC_CMD_REG_LONG_RSP; ++ ++ /* applicatiion specific cmd must follow an MMC_APP_CMD. The ++ * value will be updated in finalize_request function */ ++ if (host->last_opcode == MMC_APP_CMD) ++ ccon |= SDC_CMD_REG_APP_CMD; ++ ++ enable_imask(host, newmask); ++ REG_WRITE(cmd->arg, SDC_ARGU_REG); ++ ++ scon = REG_READ(SDC_SDIO_CTRL1_REG); ++ if (host->mmc->card != NULL && mmc_card_sdio(host->mmc->card)) ++ scon |= SDC_SDIO_CTRL1_REG_SDIO_ENABLE; ++ else ++ scon &= ~SDC_SDIO_CTRL1_REG_SDIO_ENABLE; ++ REG_WRITE(scon, SDC_SDIO_CTRL1_REG); ++ ++ dbg_dumpregs(host, ""); ++ dbg(host, dbg_debug, "CON[%x]\n", ccon); ++ ++ REG_WRITE(ccon, SDC_CMD_REG); ++} ++ ++static int ftsdc_setup_data(struct ftsdc_host *host, struct mmc_data *data) ++{ ++ u32 dcon, newmask = 0; ++ ++ /* configure data transfer paramter */ ++ ++ if (!data) ++ return 0; ++ if(host->mmc->card && host->mmc->card->type==(unsigned int)MMC_TYPE_SD){ ++ if (((data->blksz - 1) & data->blksz) != 0) { ++ pr_warning("%s: can't do non-power-of 2 sized block transfers (blksz %d)\n", __func__, data->blksz); ++ return -EINVAL; ++ } ++ } ++ ++ if (data->blksz <= 2) { ++ /* We cannot deal with unaligned blocks with more than ++ * one block being transfered. */ ++ ++ if (data->blocks > 1) { ++ pr_warning("%s: can't do non-word sized block transfers (blksz %d)\n", __func__, data->blksz); ++ return -EINVAL; ++ } ++ } ++ ++ /* data length */ ++ dcon = data->blksz * data->blocks; ++ REG_WRITE(dcon, SDC_DATA_LEN_REG); ++ ++ /* write data control */ ++ dcon = 0; ++ dcon = cal_blksz(data->blksz); ++ ++ /* enable UNDERFUN will trigger interrupt immediatedly ++ * So setup it when rsp is received successfully ++ */ ++ if (data->flags & MMC_DATA_WRITE) { ++ dcon |= SDC_DATA_CTRL_REG_DATA_WRITE; ++ } else { ++ dcon &= ~SDC_DATA_CTRL_REG_DATA_WRITE; ++ newmask |= SDC_INT_MASK_REG_FIFO_OVERRUN; ++ } ++ ++ /* always reset fifo since last transfer may fail */ ++ dcon |= SDC_DATA_CTRL_REG_FIFO_RST; ++ ++ /* enable data transfer which will be pended until cmd is send */ ++ dcon |= SDC_DATA_CTRL_REG_DATA_EN; ++ ++ if (ftsdc_dmaexist(host) && ++ ((data->blksz * data->blocks) & 0xf) == 0) { ++ newmask &= ~SDC_INT_MASK_REG_FIFO_OVERRUN; ++ dcon |= SDC_DATA_CTRL_REG_DMA_EN; ++ dcon |= SDC_DMA_TYPE_4; ++ host->dodma = true; ++ ++ } ++ ++ REG_WRITE(dcon, SDC_DATA_CTRL_REG); ++ ++ /* add to IMASK register */ ++ newmask |= SDC_INT_MASK_REG_DATA_CRC_FAIL | ++ SDC_INT_MASK_REG_DATA_TIMEOUT; ++ ++ enable_imask(host, newmask); ++ ++ /* handle sdio */ ++ dcon = SDC_SDIO_CTRL1_REG_READ_WAIT_ENABLE & REG_READ(SDC_SDIO_CTRL1_REG); ++ dcon |= data->blksz | data->blocks << 15; ++ if (1 < data->blocks) ++ dcon |= SDC_SDIO_CTRL1_REG_SDIO_BLK_MODE; ++ REG_WRITE(dcon, SDC_SDIO_CTRL1_REG); ++ ++ return 0; ++} ++ ++#define BOTH_DIR (MMC_DATA_WRITE | MMC_DATA_READ) ++ ++static int ftsdc_prepare_buffer(struct ftsdc_host *host, struct mmc_data *data) ++{ ++ int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0; ++ ++ if ((!host->mrq) || (!host->mrq->data)) ++ return -EINVAL; ++ ++ BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); ++ ++ host->buf_sgptr = 0; ++ host->buf_bytes = 0; ++ host->buf_count = 0; ++ host->buf_active = rw ? XFER_WRITE : XFER_READ; ++ ++ if (host->dodma) { ++ u32 dma_len; ++ u32 drb_size; ++ dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, ++ rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE); ++ if (dma_len == 0) ++ return -ENOMEM; ++ ++ ++ dmad_config_channel_dir(host->dma_req, ++ rw ? DMAD_DIR_A1_TO_A0 : DMAD_DIR_A0_TO_A1); ++ ++ drb_size = dmad_max_size_per_drb(host->dma_req); ++ if (drb_size < (data->blksz & data->blocks)) ++ return -ENODEV; ++ ++ host->dma_finish = false; ++ } ++ ++ return 0; ++} ++ ++static irqreturn_t ftsdc_irq(int irq, void *dev_id) ++{ ++ struct ftsdc_host *host = dev_id; ++ struct mmc_command *cmd; ++ u32 mci_status; ++ u32 mci_clear; ++ u32 mci_imsk; ++ unsigned long iflags; ++ ++ mci_status = REG_READ(SDC_STATUS_REG); ++ mci_imsk = REG_READ(SDC_INT_MASK_REG); ++ ++ dbg(host, dbg_debug, "irq: status:0x%08x, mask : %08x\n", mci_status, mci_imsk); ++ ++ if (mci_status & SDC_STATUS_REG_SDIO_INTR) { ++ if (mci_imsk & SDC_INT_MASK_REG_SDIO_INTR) { ++ mci_clear = SDC_CLEAR_REG_SDIO_INTR; ++ REG_WRITE(mci_clear, SDC_CLEAR_REG); ++ ++ mmc_signal_sdio_irq(host->mmc); ++ return IRQ_HANDLED; ++ } ++ } ++ ++ spin_lock_irqsave(&host->complete_lock, iflags); ++ ++ mci_status = REG_READ(SDC_STATUS_REG); ++ mci_clear = 0; ++ ++ if (mci_status & SDC_STATUS_REG_CARD_CHANGE) { ++ if ((mci_status & SDC_STATUS_REG_CARD_DETECT) ++ == SDC_CARD_INSERT) { ++ host->status = "card insert"; ++ mmc_detect_change(host->mmc, msecs_to_jiffies(500)); ++ } else { ++ host->status = "card remove"; ++ } ++ ++ mci_clear |= SDC_CLEAR_REG_CARD_CHANGE; ++ dbg(host, dbg_irq, "%s\n", host->status); ++ ++ if (host->complete_what != COMPLETION_NONE) { ++ host->mrq->cmd->error = -EIO; ++ goto close_transfer; ++ } ++ ++ goto irq_out; ++ } ++ ++ if ((host->complete_what == COMPLETION_NONE) || ++ (host->complete_what == COMPLETION_FINALIZE)) { ++ host->status = "nothing to complete"; ++ mci_clear = -1u; ++ goto irq_out; ++ } ++ ++ if (!host->mrq) { ++ host->status = "no active mrq"; ++ clear_imask(host); ++ goto irq_out; ++ } ++ ++ cmd = host->cmd_is_stop ? host->mrq->stop : host->mrq->cmd; ++ ++ if (!cmd) { ++ host->status = "no active cmd"; ++ clear_imask(host); ++ goto irq_out; ++ } ++ ++ if (mci_status & SDC_STATUS_REG_CMD_SEND) { ++ mci_clear |= SDC_CLEAR_REG_CMD_SEND; ++ ++ if (host->complete_what == COMPLETION_CMDSENT) { ++ host->status = "ok: command sent"; ++ goto close_transfer; ++ } else { ++ host->status = "error: command sent(status not match)"; ++ cmd->error = -EINVAL; ++ goto fail_transfer; ++ } ++ } ++ ++ /* handle error status */ ++ if (mci_status & SDC_STATUS_REG_RSP_TIMEOUT) { ++ dbg(host, dbg_err, "CMDSTAT: error RSP TIMEOUT\n"); ++ mci_clear |= SDC_CLEAR_REG_RSP_TIMEOUT; ++ cmd->error = -ETIMEDOUT; ++ host->status = "error: response timeout"; ++ goto fail_transfer; ++ } ++ ++ if (mci_status & SDC_STATUS_REG_RSP_CRC_FAIL) { ++ mci_clear |= SDC_CLEAR_REG_RSP_CRC_FAIL; ++ /* This is wierd hack */ ++ if (cmd->flags & MMC_RSP_CRC) { ++ dbg(host, dbg_err, "CMDSTAT: error RSP CRC\n"); ++ cmd->error = -EILSEQ; ++ host->status = "error: RSP CRC failed"; ++ goto fail_transfer; ++ } else { ++ host->status = "R3 or R4 type command"; ++ goto close_transfer; ++ } ++ } ++ ++ if (mci_status & SDC_STATUS_REG_RSP_CRC_OK) { ++ mci_clear |= SDC_CLEAR_REG_RSP_CRC_OK; ++ ++ if (host->complete_what == COMPLETION_XFER_PROGRESS) { ++ REG_WRITE(mci_clear, SDC_CLEAR_REG); ++ ++ host->status = "RSP recv OK"; ++ if (!cmd->data) ++ goto close_transfer; ++ ++ if (host->dodma) { ++ tasklet_schedule(&host->pio_tasklet); ++ host->status = "dma access"; ++ goto irq_out; ++ } ++ ++ if (host->buf_active == XFER_WRITE) ++ enable_imask(host, SDC_INT_MASK_REG_FIFO_UNDERRUN); ++ } else if (host->complete_what == COMPLETION_RSPFIN) { ++ goto close_transfer; ++ } ++ } ++ ++ /* handler data transfer */ ++ if (mci_status & SDC_STATUS_REG_DATA_TIMEOUT) { ++ dbg(host, dbg_err, "CMDSTAT: error DATA TIMEOUT\n"); ++ mci_clear |= SDC_CLEAR_REG_DATA_TIMEOUT; ++ cmd->error = -ETIMEDOUT; ++ host->status = "error: data timeout"; ++ goto fail_transfer; ++ } ++ ++ if (mci_status & SDC_STATUS_REG_DATA_CRC_FAIL) { ++ dbg(host, dbg_err, "CMDSTAT: error DATA CRC\n"); ++ mci_clear |= SDC_CLEAR_REG_DATA_CRC_FAIL; ++ cmd->error = -EILSEQ; ++ host->status = "error: data CRC fail"; ++ goto fail_transfer; ++ } ++ ++ if ((mci_status & SDC_STATUS_REG_FIFO_UNDERRUN) || ++ mci_status & SDC_STATUS_REG_FIFO_OVERRUN) { ++ ++ disable_imask(host, SDC_INT_MASK_REG_FIFO_OVERRUN | ++ SDC_INT_MASK_REG_FIFO_UNDERRUN); ++ ++ if (!host->dodma) { ++ if (host->buf_active == XFER_WRITE) { ++ tasklet_schedule(&host->pio_tasklet); ++ host->status = "pio tx"; ++ } else if (host->buf_active == XFER_READ) { ++ ++ tasklet_schedule(&host->pio_tasklet); ++ host->status = "pio rx"; ++ } ++ } ++ } ++ ++ goto irq_out; ++ ++fail_transfer: ++ host->buf_active = XFER_NONE; ++ ++close_transfer: ++ host->complete_what = COMPLETION_FINALIZE; ++ ++ clear_imask(host); ++ tasklet_schedule(&host->pio_tasklet); ++ ++irq_out: ++ REG_WRITE(mci_clear, SDC_CLEAR_REG); ++ ++ dbg(host, dbg_debug, "irq: %s\n", host->status); ++ spin_unlock_irqrestore(&host->complete_lock, iflags); ++ return IRQ_HANDLED; ++} ++ ++static void ftsdc_send_request(struct mmc_host *mmc) ++{ ++ struct ftsdc_host *host = mmc_priv(mmc); ++ struct mmc_request *mrq = host->mrq; ++ struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; ++ ++ host->ccnt++; ++ prepare_dbgmsg(host, cmd, host->cmd_is_stop); ++ dbg(host, dbg_debug, "%s\n", host->dbgmsg_cmd); ++ ++ if (cmd->data) { ++ int res = ftsdc_setup_data(host, cmd->data); ++ ++ host->dcnt++; ++ ++ if (res) { ++ dbg(host, dbg_err, "setup data error %d\n", res); ++ cmd->error = res; ++ cmd->data->error = res; ++ ++ mmc_request_done(mmc, mrq); ++ return; ++ } ++ ++ res = ftsdc_prepare_buffer(host, cmd->data); ++ ++ if (res) { ++ dbg(host, dbg_err, "data prepare error %d\n", res); ++ cmd->error = res; ++ cmd->data->error = res; ++ ++ mmc_request_done(mmc, mrq); ++ return; ++ } ++ } ++ ++ /* Send command */ ++ ftsdc_send_command(host, cmd); ++} ++ ++static int ftsdc_get_cd(struct mmc_host *mmc) ++{ ++ struct ftsdc_host *host = mmc_priv(mmc); ++ ++ u32 con = REG_READ(SDC_STATUS_REG); ++ dbg(host, dbg_debug, "get_cd status:%.8x\n\n", con); ++ ++ return (con & SDC_STATUS_REG_CARD_DETECT) ? 0 : 1; ++} ++ ++static void ftsdc_request(struct mmc_host *mmc, struct mmc_request *mrq) ++{ ++ struct ftsdc_host *host = mmc_priv(mmc); ++ ++/* work_around_for_amerald(mrq);*/ ++ host->status = "mmc request"; ++ host->cmd_is_stop = 0; ++ host->mrq = mrq; ++ if (ftsdc_get_cd(mmc) == 0) { ++ dbg(host, dbg_err, "%s: no medium present\n", __func__); ++ host->mrq->cmd->error = -ENOMEDIUM; ++ mmc_request_done(mmc, mrq); ++ } else { ++ ftsdc_send_request(mmc); ++ } ++ ++ dbg(host, dbg_debug, "send request \n"); ++} ++ ++static void ftsdc_set_clk(struct ftsdc_host *host, struct mmc_ios *ios) ++{ ++ u32 clk_div = 0; ++ u32 con; ++ ++ dbg(host, dbg_debug, "request clk : %u \n", ios->clock); ++ con = REG_READ(SDC_CLOCK_CTRL_REG); ++ if (ios->clock == 0) { ++ host->real_rate = 0; ++ con |= SDC_CLOCK_CTRL_REG_CLK_DIS; ++ } else { ++ clk_div = (APB_CLK_IN / (ios->clock << 1)) - 1; ++ host->real_rate = APB_CLK_IN / ((clk_div+1)<<1); ++ if (host->real_rate > ios->clock) { ++ ++clk_div; ++ host->real_rate = APB_CLK_IN / ((clk_div+1)<<1); ++ } ++ if (clk_div > 127) ++ dbg(host, dbg_err, "%s: no match clock rate, %u\n", __func__, ios->clock); ++ ++ con = (con & ~SDC_CLOCK_CTRL_REG_CLK_DIV) | (clk_div & SDC_CLOCK_CTRL_REG_CLK_DIV); ++ con &= ~SDC_CLOCK_CTRL_REG_CLK_DIS; ++ } ++ ++ REG_WRITE(con, SDC_CLOCK_CTRL_REG); ++} ++ ++static void ftsdc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ++{ ++ struct ftsdc_host *host = mmc_priv(mmc); ++ u32 con; ++ ++ con = REG_READ(SDC_POWER_CTRL_REG); ++ switch (ios->power_mode) { ++ case MMC_POWER_ON: ++ case MMC_POWER_UP: ++ con |= SDC_POWER_CTRL_REG_POWER_ON; ++ break; ++ case MMC_POWER_OFF: ++ default: ++ con &= ~SDC_POWER_CTRL_REG_POWER_ON; ++ break; ++ } ++ ++ REG_WRITE(con, SDC_POWER_CTRL_REG); ++ ++ ftsdc_set_clk(host, ios); ++ ++ if ((ios->power_mode == MMC_POWER_ON) || ++ (ios->power_mode == MMC_POWER_UP)) { ++ dbg(host, dbg_debug, "running at %ukHz (requested: %ukHz).\n", ++ host->real_rate/1000, ios->clock/1000); ++ } else { ++ dbg(host, dbg_debug, "powered down.\n"); ++ } ++ ++ host->bus_width = ios->bus_width; ++ /* write bus configure */ ++ con = REG_READ(SDC_BUS_WIDTH_REG); ++ ++ con &= ~(SDC_BUS_WIDTH_REG_SINGLE_BUS | ++ SDC_BUS_WIDTH_REG_WIDE_4_BUS | ++ SDC_BUS_WIDTH_REG_WIDE_8_BUS); ++ if (host->bus_width == MMC_BUS_WIDTH_1) ++ con |= SDC_BUS_WIDTH_REG_SINGLE_BUS; ++ else if (host->bus_width == MMC_BUS_WIDTH_4) ++ con |= SDC_BUS_WIDTH_REG_WIDE_4_BUS; ++ else if (host->bus_width == MMC_BUS_WIDTH_8) ++ con |= SDC_BUS_WIDTH_REG_WIDE_8_BUS; ++ else { ++ dbg(host, dbg_err, "set_ios: can't support bus mode"); ++ } ++ REG_WRITE(con, SDC_BUS_WIDTH_REG); ++ ++ /*set rsp and data timeout */ ++ con = -1; ++ REG_WRITE(con, SDC_DATA_TIMER_REG); ++} ++ ++static int ftsdc_get_ro(struct mmc_host *mmc) ++{ ++ struct ftsdc_host *host = mmc_priv(mmc); ++ u32 con = REG_READ(SDC_STATUS_REG); ++ dbg(host, dbg_debug, "get_ro status:%.8x\n", con); ++ ++ return (con & SDC_STATUS_REG_CARD_LOCK) ? 1 : 0; ++} ++ ++ ++static void ftsdc_enable_sdio_irq(struct mmc_host *mmc, int enable) ++{ ++ struct ftsdc_host *host = mmc_priv(mmc); ++ unsigned long flags; ++ u32 con; ++#ifdef CONFIG_MMC_DEBUG ++ u32 ena; ++#endif ++ ++ local_irq_save(flags); ++ ++ con = REG_READ(SDC_INT_MASK_REG); ++#ifdef CONFIG_MMC_DEBUG ++ ena = (con & SDC_STATUS_REG_SDIO_INTR) ? 1:0; ++ if (ena == enable) ++ printk("\n*** XXX ***\n"); ++#endif ++ ++ con = enable ? (con | SDC_STATUS_REG_SDIO_INTR) : (con & ~SDC_STATUS_REG_SDIO_INTR); ++ REG_WRITE(con, SDC_INT_MASK_REG); ++ ++#ifdef CONFIG_MMC_DEBUG ++ //check and ensure data out to SD host controller ++ ena = (REG_READ(SDC_INT_MASK_REG) & SDC_STATUS_REG_SDIO_INTR) ? 1:0; ++ if (ena != enable) { ++ printk("\n*** YYY ***\n"); ++ } ++#endif ++ ++ local_irq_restore(flags); ++} ++ ++static struct mmc_host_ops ftsdc_ops = { ++ .request = ftsdc_request, ++ .set_ios = ftsdc_set_ios, ++ .get_ro = ftsdc_get_ro, ++ .get_cd = ftsdc_get_cd, ++ .enable_sdio_irq = ftsdc_enable_sdio_irq, ++}; ++ ++#ifdef CONFIG_DEBUG_FS ++ ++static int ftsdc_state_show(struct seq_file *seq, void *v) ++{ ++ struct ftsdc_host *host = seq->private; ++ ++ seq_printf(seq, "Register base = 0x%08x\n", (u32)host->base); ++ seq_printf(seq, "Clock rate = %u\n", host->real_rate); ++ seq_printf(seq, "host status = %s\n", host->status); ++ seq_printf(seq, "IRQ = %d\n", host->irq); ++ seq_printf(seq, "IRQ enabled = %d\n", host->irq_enabled); ++ seq_printf(seq, "complete what = %d\n", host->complete_what); ++ seq_printf(seq, "dma support = %d\n", ftsdc_dmaexist(host)); ++ seq_printf(seq, "use dma = %d\n", host->dodma); ++ ++ return 0; ++} ++ ++static int ftsdc_state_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, ftsdc_state_show, inode->i_private); ++} ++ ++static const struct file_operations ftsdc_fops_state = { ++ .owner = THIS_MODULE, ++ .open = ftsdc_state_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++#define DBG_REG(_r) { .addr = SDC_## _r ## _REG, .name = #_r } ++ ++struct ftsdc_reg { ++ unsigned short addr; ++ unsigned char *name; ++} debug_regs[] = { ++ DBG_REG(CMD), ++ DBG_REG(ARGU), ++ DBG_REG(RESPONSE0), ++ DBG_REG(RESPONSE1), ++ DBG_REG(RESPONSE2), ++ DBG_REG(RESPONSE3), ++ DBG_REG(RSP_CMD), ++ DBG_REG(DATA_CTRL), ++ DBG_REG(DATA_TIMER), ++ DBG_REG(DATA_LEN), ++ DBG_REG(STATUS), ++ DBG_REG(CLEAR), ++ DBG_REG(INT_MASK), ++ DBG_REG(POWER_CTRL), ++ DBG_REG(CLOCK_CTRL), ++ DBG_REG(BUS_WIDTH), ++ DBG_REG(SDIO_CTRL1), ++ DBG_REG(SDIO_CTRL2), ++ DBG_REG(SDIO_STATUS), ++ DBG_REG(FEATURE), ++ DBG_REG(REVISION), ++ {} ++}; ++ ++static int ftsdc_regs_show(struct seq_file *seq, void *v) ++{ ++ struct ftsdc_host *host = seq->private; ++ struct ftsdc_reg *rptr = debug_regs; ++ ++ for (; rptr->name; rptr++) ++ seq_printf(seq, "SDI%s\t=0x%08x\n", rptr->name, ++ REG_READ(rptr->addr)); ++ ++ return 0; ++} ++ ++static int ftsdc_regs_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, ftsdc_regs_show, inode->i_private); ++} ++ ++static const struct file_operations ftsdc_fops_regs = { ++ .owner = THIS_MODULE, ++ .open = ftsdc_regs_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ ++static void ftsdc_debugfs_attach(struct ftsdc_host *host) ++{ ++ struct device *dev = &host->pdev->dev; ++ ++ host->debug_root = debugfs_create_dir(dev_name(dev), NULL); ++ if (IS_ERR(host->debug_root)) { ++ dev_err(dev, "failed to create debugfs root\n"); ++ return; ++ } ++ ++ host->debug_state = debugfs_create_file("state", 0444, ++ host->debug_root, host, ++ &ftsdc_fops_state); ++ ++ if (IS_ERR(host->debug_state)) ++ dev_err(dev, "failed to create debug state file\n"); ++ ++ host->debug_regs = debugfs_create_file("regs", 0444, ++ host->debug_root, host, ++ &ftsdc_fops_regs); ++ ++ if (IS_ERR(host->debug_regs)) ++ dev_err(dev, "failed to create debug regs file\n"); ++} ++ ++static void ftsdc_debugfs_remove(struct ftsdc_host *host) ++{ ++ debugfs_remove(host->debug_regs); ++ debugfs_remove(host->debug_state); ++ debugfs_remove(host->debug_root); ++} ++ ++#else ++static inline void ftsdc_debugfs_attach(struct ftsdc_host *host) { } ++static inline void ftsdc_debugfs_remove(struct ftsdc_host *host) { } ++ ++#endif /* CONFIG_DEBUG_FS */ ++ ++#if (defined(CONFIG_PLATFORM_AHBDMA) || defined(CONFIG_PLATFORM_APBDMA)) ++static int ftsdc_alloc_dma(struct ftsdc_host *host) ++{ ++ dmad_chreq *req = host->dma_req; ++ ++ req = kzalloc(sizeof(dmad_chreq), GFP_KERNEL); ++#ifdef CONFIG_PLATFORM_APBDMA ++#ifdef CONFIG_PLAT_AG102 ++ //ADD by river 2010.10.20 ++ outl(inl(PCU_VA_BASE + 0x38) | 0x00000300, PCU_VA_BASE + 0x38); ++ //End ADD by river 2010.10.20 ++#endif ++ req->apb_req.addr0_ctrl = APBBR_ADDRINC_FIXED; /* (in) APBBR_ADDRINC_xxx */ ++/* for amerald */ ++ if((inl(PMU_BASE) & AMERALD_MASK) == AMERALD_PRODUCT_ID){ ++ req->apb_req.addr0_reqn = APBBR_REQN_SDC_AMERALD; ++ }else ++ { ++ req->apb_req.addr0_reqn = APBBR_REQN_SDC; /* (in) APBBR_REQN_xxx (also used to help determine bus selection) */ ++ } ++ req->apb_req.addr1_ctrl = APBBR_ADDRINC_I4X; /* (in) APBBR_ADDRINC_xxx */ ++ req->apb_req.addr1_reqn = APBBR_REQN_NONE; /* (in) APBBR_REQN_xxx (also used to help determine bus selection) */ ++ req->apb_req.burst_mode = 1; /* (in) Burst mode (0: no burst 1-, 1: burst 4- data cycles per dma cycle) */ ++ req->apb_req.data_width = APBBR_DATAWIDTH_4; /* (in) APBBR_DATAWIDTH_4(word), APBBR_DATAWIDTH_2(half-word), APBBR_DATAWIDTH_1(byte) */ ++ req->apb_req.tx_dir = DMAD_DIR_A0_TO_A1; /* (in) DMAD_DIR_A0_TO_A1, DMAD_DIR_A1_TO_A0 */ ++ req->controller = DMAD_DMAC_APB_CORE; /* (in) DMAD_DMAC_AHB_CORE, DMAD_DMAC_APB_CORE */ ++ req->flags = DMAD_FLAGS_SLEEP_BLOCK | DMAD_FLAGS_BIDIRECTION; ++ ++ if (dmad_channel_alloc(req) == 0) { ++ dbg(host, dbg_debug, "%s: APB dma channel allocated (ch: %d)\n", __func__, req->channel); ++ host->dma_req = req; ++ return 0; ++ } ++ ++ memset(req, 0, sizeof(dmad_chreq)); ++ dbg(host, dbg_info, "%s: APB dma channel allocation failed\n", __func__); ++#endif /* CONFIG_PLATFORM_APBDMA */ ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ req->ahb_req.sync = 1; /* (in) non-zero if src and dst have different clock domain */ ++ req->ahb_req.priority = DMAC_CSR_CHPRI_1; /* (in) DMAC_CSR_CHPRI_0 (lowest) ~ DMAC_CSR_CHPRI_3 (highest) */ ++ req->ahb_req.hw_handshake = 1; /* (in) non-zero to enable hardware handshake mode */ ++ req->ahb_req.burst_size = DMAC_CSR_SIZE_4; /* (in) DMAC_CSR_SIZE_1 ~ DMAC_CSR_SIZE_256 */ ++ req->ahb_req.addr0_width = DMAC_CSR_WIDTH_32; /* (in) DMAC_CSR_WIDTH_8, DMAC_CSR_WIDTH_16, or DMAC_CSR_WIDTH_32 */ ++ req->ahb_req.addr0_ctrl = DMAC_CSR_AD_FIX; /* (in) DMAC_CSR_AD_INC, DMAC_CSR_AD_DEC, or DMAC_CSR_AD_FIX */ ++ req->ahb_req.addr0_reqn = DMAC_REQN_SDC; /* (in) DMAC_REQN_xxx (also used to help determine channel number) */ ++ req->ahb_req.addr1_width = DMAC_CSR_WIDTH_32; /* (in) DMAC_CSR_WIDTH_8, DMAC_CSR_WIDTH_16, or DMAC_CSR_WIDTH_32 */ ++ req->ahb_req.addr1_ctrl = DMAC_CSR_AD_INC; /* (in) DMAC_CSR_AD_INC, DMAC_CSR_AD_DEC, or DMAC_CSR_AD_FIX */ ++ req->ahb_req.addr1_reqn = DMAC_REQN_NONE; /* (in) DMAC_REQN_xxx (also used to help determine channel number) */ ++ req->ahb_req.tx_dir = DMAD_DIR_A0_TO_A1; /* (in) DMAD_DIR_A0_TO_A1, DMAD_DIR_A1_TO_A0 */ ++ ++ req->controller = DMAD_DMAC_AHB_CORE; /* (in) DMAD_DMAC_AHB_CORE, DMAD_DMAC_APB_CORE */ ++ req->flags = DMAD_FLAGS_SLEEP_BLOCK | DMAD_FLAGS_BIDIRECTION; ++ ++ if (dmad_channel_alloc(req) == 0) { ++ dbg(host, dbg_debug, "%s: AHB dma channel allocated (ch: %d)\n", __func__, req->channel); ++ host->dma_req = req; ++ return 0; ++ } ++ ++ dbg(host, dbg_info, "%s: AHB dma channel allocation failed\n", __func__); ++#endif ++ ++ kfree(req); ++ return -ENODEV; ++ ++} ++#endif ++ ++static int __devinit ftsdc_probe(struct platform_device *pdev) ++{ ++ struct ftsdc_host *host; ++ struct mmc_host *mmc; ++ int ret = -ENOMEM; ++ u32 con; ++ ++ mmc = mmc_alloc_host(sizeof(struct ftsdc_host), &pdev->dev); ++ if (!mmc) { ++// ret = -ENOMEM; ++ goto probe_out; ++ } ++ ++ host = mmc_priv(mmc); ++ host->mmc = mmc; ++ host->pdev = pdev; ++ ++ mywq = create_workqueue("atcsdc_queue"); ++ if (NULL == mywq) ++ goto probe_free_host; ++ ++ spin_lock_init(&host->complete_lock); ++ tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host); ++ init_completion(&host->dma_complete); ++ INIT_WORK(&host->work, ftsdc_work); ++ ++ host->complete_what = COMPLETION_NONE; ++ host->buf_active = XFER_NONE; ++ ++#if (defined(CONFIG_PLATFORM_AHBDMA) || defined(CONFIG_PLATFORM_APBDMA)) ++ ftsdc_alloc_dma(host); ++#endif ++ ++ host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!host->mem) { ++ dev_err(&pdev->dev, ++ "failed to get io memory region resouce.\n"); ++ ++ ret = -ENOENT; ++ goto probe_free_host; ++ } ++ ++ host->mem = request_mem_region(host->mem->start, ++ resource_size(host->mem), pdev->name); ++ ++ if (!host->mem) { ++ dev_err(&pdev->dev, "failed to request io memory region.\n"); ++ ret = -ENOENT; ++ goto probe_free_wq; ++ } ++ ++ host->base = (void __iomem *) SDC_FTSDC010_0_VA_BASE; ++ host->irq = SDC_FTSDC010_IRQ; ++ if (request_irq(host->irq, ftsdc_irq, IRQF_DISABLED, DRIVER_NAME, host)) { ++ dev_err(&pdev->dev, "failed to request mci interrupt.\n"); ++ ret = -ENOENT; ++ goto probe_free_mem_region; ++ } ++ host->irq_enabled = true; ++ ++ /* enable card change interruption */ ++ con = REG_READ(SDC_INT_MASK_REG); ++ con |= SDC_INT_MASK_REG_CARD_CHANGE; ++ REG_WRITE(con, SDC_INT_MASK_REG); ++ ++ con = REG_READ(SDC_BUS_WIDTH_REG); ++ ++ mmc->ops = &ftsdc_ops; ++ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; ++ ++ if (con & SDC_WIDE_4_BUS_SUPPORT) ++ mmc->caps |= MMC_CAP_4_BIT_DATA; ++ else if (con & SDC_WIDE_8_BUS_SUPPORT) ++ mmc->caps |= MMC_CAP_8_BIT_DATA; ++ ++#ifndef A320D_BUILDIN_SDC ++ mmc->caps |= MMC_CAP_SDIO_IRQ; ++#endif ++ ++ mmc->f_min = APB_CLK_IN / (2 * 128); ++ mmc->f_max = APB_CLK_IN / 2; ++ ++ /* limit SDIO mode max size */ ++ mmc->max_req_size = 128 * 1024 * 1024 - 1; ++ mmc->max_blk_size = 2047; ++ mmc->max_req_size = (mmc->max_req_size + 1) / (mmc->max_blk_size + 1); ++ mmc->max_seg_size = mmc->max_req_size; ++ mmc->max_blk_count = (1<<17)-1; ++ ++ /* kernel default value. see Doc/block/biodocs.txt */ ++ /* ++ 'struct mmc_host' has no member named 'max_phys_segs' ++ 'struct mmc_host' has no member named 'max_hw_segs' ++ */ ++// mmc->max_phys_segs = 128; ++// mmc->max_hw_segs = 128; ++ ++ /* set fifo lenght and default threshold half */ ++ con = REG_READ(SDC_FEATURE_REG); ++ host->fifo_len = (con & SDC_FEATURE_REG_FIFO_DEPTH) * sizeof(u32); ++ ++ dbg(host, dbg_debug, ++ "probe: mapped mci_base:%p irq:%u.\n", ++ host->base, host->irq); ++ ++ dbg_dumpregs(host, ""); ++ ++ ret = mmc_add_host(mmc); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to add mmc host.\n"); ++ goto probe_free_irq; ++ } ++ ++ ftsdc_debugfs_attach(host); ++ ++ platform_set_drvdata(pdev, mmc); ++ dev_info(&pdev->dev, "%s - using %s SDIO IRQ\n", mmc_hostname(mmc), ++ mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw"); ++ ++ return 0; ++ ++ probe_free_irq: ++ free_irq(host->irq, host); ++ ++ probe_free_mem_region: ++ release_mem_region(host->mem->start, resource_size(host->mem)); ++ ++probe_free_wq: ++ destroy_workqueue(mywq); ++ ++ probe_free_host: ++ mmc_free_host(mmc); ++ ++ probe_out: ++ return ret; ++} ++ ++static void ftsdc_shutdown(struct platform_device *pdev) ++{ ++ struct mmc_host *mmc = platform_get_drvdata(pdev); ++ struct ftsdc_host *host = mmc_priv(mmc); ++ ++ flush_workqueue(mywq); ++ destroy_workqueue(mywq); ++ ++ ftsdc_debugfs_remove(host); ++ mmc_remove_host(mmc); ++} ++ ++static int __devexit ftsdc_remove(struct platform_device *pdev) ++{ ++ struct mmc_host *mmc = platform_get_drvdata(pdev); ++ struct ftsdc_host *host = mmc_priv(mmc); ++ ++ ftsdc_shutdown(pdev); ++ ++ tasklet_disable(&host->pio_tasklet); ++ ++ if (ftsdc_dmaexist(host)) ++ kfree(host->dma_req); ++ ++ free_irq(host->irq, host); ++ ++ release_mem_region(host->mem->start, resource_size(host->mem)); ++ ++ mmc_free_host(mmc); ++ return 0; ++} ++ ++ ++#ifdef CONFIG_PM ++static int ftsdc_free_dma(struct ftsdc_host *host) ++{ ++ dmad_channel_free(host->dma_req); ++ return 0; ++} ++ ++static int ftsdc_suspend(struct platform_device *pdev, pm_message_t state) ++{ ++ struct mmc_host *mmc = platform_get_drvdata(pdev); ++ struct ftsdc_host *host = mmc_priv(mmc); ++ int ret = 0; ++ if (mmc) { ++ ftsdc_free_dma(host); ++ ret = mmc_suspend_host(mmc); ++ } ++ return ret; ++ ++} ++ ++static int ftsdc_resume(struct platform_device *pdev) ++{ ++ struct mmc_host *mmc = platform_get_drvdata(pdev); ++ int ret = 0; ++ struct ftsdc_host *host = mmc_priv(mmc); ++ if (mmc) { ++#if (defined(CONFIG_PLATFORM_AHBDMA) || defined(CONFIG_PLATFORM_APBDMA)) ++ ftsdc_alloc_dma(host); ++#endif ++ ret = mmc_resume_host(mmc); ++ } ++ return ret; ++} ++ ++static void platform_device_release(struct device *dev){ ++} ++ ++ ++#else ++#define ftsdc_suspend NULL ++#define ftsdc_resume NULL ++#endif ++ ++ ++static struct platform_driver ftsdc_driver = { ++ .driver = { ++ .name = "ftsdc010", ++ .owner = THIS_MODULE, ++ }, ++ .probe = ftsdc_probe, ++ .remove = __devexit_p(ftsdc_remove), ++ .shutdown = ftsdc_shutdown, ++ .suspend = ftsdc_suspend, ++ .resume = ftsdc_resume, ++}; ++ ++static struct resource sdc_resource[] = { ++ [0] = { ++ .start = SDC_FTSDC010_0_VA_BASE, ++ .end = SDC_FTSDC010_0_VA_BASE + 0x1000 - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ [1] = { ++ .start = SDC_FTSDC010_0_IRQ, ++ .flags = IORESOURCE_IRQ, ++ } ++ ++}; ++ ++struct platform_device sdc_device = { ++ .name = "ftsdc010", ++ .id = 0, ++ .num_resources = ARRAY_SIZE(sdc_resource), ++ .resource = sdc_resource, ++ .dev = { ++ .release = platform_device_release, ++ }, ++}; ++ ++static int __init ftsdc_init(void) ++{ ++ platform_device_register(&sdc_device); ++ return platform_driver_register(&ftsdc_driver); ++} ++ ++static void __exit ftsdc_exit(void) ++{ ++ platform_driver_unregister(&ftsdc_driver); ++ platform_device_unregister(&sdc_device); ++} ++module_init(ftsdc_init); ++module_exit(ftsdc_exit); ++ ++MODULE_DESCRIPTION("Andestech Leopard MMC/SD Card Interface driver"); ++MODULE_LICENSE("GPL v2"); +diff -Nur linux-3.4.110.orig/drivers/mmc/host/ftsdc010.h linux-3.4.110/drivers/mmc/host/ftsdc010.h +--- linux-3.4.110.orig/drivers/mmc/host/ftsdc010.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/mmc/host/ftsdc010.h 2016-04-07 10:20:51.050085202 +0200 +@@ -0,0 +1,240 @@ ++/* ++ * linux/driver/mmc/ftsdc010.h - Andestech MMC/SD driver ++ * Andestech FTSDC010 Device Driver ++ * ++ * Andestech (C) 2005 Faraday Corp. (http://www.Andestech.com) ++ * ++ * All Rights Reserved ++ */ ++ ++#ifndef _FTSDC010_H_ ++#define _FTSDC010_H_ ++ ++//#define SD_DEBUG ++#define DELAY_FOR_DMA_READ ++ ++#ifdef SD_DEBUG ++ #define P_DEBUG(fmt, args...) printk(KERN_ALERT "SD: " fmt, ## args) ++#else ++ #define P_DEBUG(a...) ++#endif ++#define P_DEBUGG(a...) ++ ++/* used for dma timeout */ ++#define SDC_TIMEOUT_BASE (HZ/2) // Unit is 500 ms ++ ++/* used for pio retry times */ ++#define SDC_PIO_RETRY 0x300000 ++ ++/* sd controller register */ ++#define SDC_CMD_REG 0x00000000 ++#define SDC_ARGU_REG 0x00000004 ++#define SDC_RESPONSE0_REG 0x00000008 ++#define SDC_RESPONSE1_REG 0x0000000C ++#define SDC_RESPONSE2_REG 0x00000010 ++#define SDC_RESPONSE3_REG 0x00000014 ++#define SDC_RSP_CMD_REG 0x00000018 ++#define SDC_DATA_CTRL_REG 0x0000001C ++#define SDC_DATA_TIMER_REG 0x00000020 ++#define SDC_DATA_LEN_REG 0x00000024 ++#define SDC_STATUS_REG 0x00000028 ++#define SDC_CLEAR_REG 0x0000002C ++#define SDC_INT_MASK_REG 0x00000030 ++#define SDC_POWER_CTRL_REG 0x00000034 ++#define SDC_CLOCK_CTRL_REG 0x00000038 ++#define SDC_BUS_WIDTH_REG 0x0000003C ++#define SDC_DATA_WINDOW_REG 0x00000040 ++ ++#ifdef A320D_BUILDIN_SDC ++#define SDC_FEATURE_REG 0x00000044 ++#define SDC_REVISION_REG 0x00000048 ++#else ++#define SDC_MMC_INT_RSP_REG 0x00000044 ++#define SDC_GP_OUTPUT_REG 0x00000048 ++#define SDC_FEATURE_REG 0x0000009C ++#define SDC_REVISION_REG 0x000000A0 ++#endif ++ ++#define SDC_SDIO_CTRL1_REG 0x0000006C ++#define SDC_SDIO_CTRL2_REG 0x00000070 ++#define SDC_SDIO_STATUS_REG 0x00000074 ++ ++/* bit mapping of command register */ ++#define SDC_CMD_REG_INDEX 0x0000003F ++#define SDC_CMD_REG_NEED_RSP 0x00000040 ++#define SDC_CMD_REG_LONG_RSP 0x00000080 ++#define SDC_CMD_REG_APP_CMD 0x00000100 ++#define SDC_CMD_REG_CMD_EN 0x00000200 ++#define SDC_CMD_REG_SDC_RST 0x00000400 ++#define SDC_CMD_MMC_INT_STOP 0x00000800 ++ ++/* bit mapping of response command register */ ++#define SDC_RSP_CMD_REG_INDEX 0x0000003F ++#define SDC_RSP_CMD_REG_APP 0x00000040 ++ ++/* bit mapping of data control register */ ++#define SDC_DATA_CTRL_REG_BLK_SIZE 0x0000000F ++#define SDC_DATA_CTRL_REG_DATA_WRITE 0x00000010 ++#define SDC_DATA_CTRL_REG_DMA_EN 0x00000020 ++#define SDC_DATA_CTRL_REG_DATA_EN 0x00000040 ++#define SDC_DATA_CTRL_REG_FIFOTH 0x00000080 ++#define SDC_DATA_CTRL_REG_DMA_TYPE 0x00000300 ++#define SDC_DATA_CTRL_REG_FIFO_RST 0x00000400 ++#define SDC_CPRM_DATA_CHANGE_ENDIAN_EN 0x00000800 ++#define SDC_CPRM_DATA_SWAP_HL_EN 0x00001000 ++ ++#define SDC_DMA_TYPE_1 0x00000000 ++#define SDC_DMA_TYPE_4 0x00000100 ++#define SDC_DMA_TYPE_8 0x00000200 ++ ++/* bit mapping of status register */ ++#define SDC_STATUS_REG_RSP_CRC_FAIL 0x00000001 ++#define SDC_STATUS_REG_DATA_CRC_FAIL 0x00000002 ++#define SDC_STATUS_REG_RSP_TIMEOUT 0x00000004 ++#define SDC_STATUS_REG_DATA_TIMEOUT 0x00000008 ++#define SDC_STATUS_REG_RSP_CRC_OK 0x00000010 ++#define SDC_STATUS_REG_DATA_CRC_OK 0x00000020 ++#define SDC_STATUS_REG_CMD_SEND 0x00000040 ++#define SDC_STATUS_REG_DATA_END 0x00000080 ++#define SDC_STATUS_REG_FIFO_UNDERRUN 0x00000100 ++#define SDC_STATUS_REG_FIFO_OVERRUN 0x00000200 ++#define SDC_STATUS_REG_CARD_CHANGE 0x00000400 ++#define SDC_STATUS_REG_CARD_DETECT 0x00000800 ++#define SDC_STATUS_REG_CARD_LOCK 0x00001000 ++#define SDC_STATUS_REG_CP_READY 0x00002000 ++#define SDC_STATUS_REG_CP_BUF_READY 0x00004000 ++#define SDC_STATUS_REG_PLAIN_TEXT_READY 0x00008000 ++#define SDC_STATUS_REG_SDIO_INTR 0x00010000 ++ ++/* bit mapping of clear register */ ++#define SDC_CLEAR_REG_RSP_CRC_FAIL 0x00000001 ++#define SDC_CLEAR_REG_DATA_CRC_FAIL 0x00000002 ++#define SDC_CLEAR_REG_RSP_TIMEOUT 0x00000004 ++#define SDC_CLEAR_REG_DATA_TIMEOUT 0x00000008 ++#define SDC_CLEAR_REG_RSP_CRC_OK 0x00000010 ++#define SDC_CLEAR_REG_DATA_CRC_OK 0x00000020 ++#define SDC_CLEAR_REG_CMD_SEND 0x00000040 ++#define SDC_CLEAR_REG_DATA_END 0x00000080 ++#define SDC_CLEAR_REG_CARD_CHANGE 0x00000400 ++#define SDC_CLEAR_REG_SDIO_INTR 0x00010000 ++ ++/* bit mapping of int_mask register */ ++#define SDC_INT_MASK_REG_RSP_CRC_FAIL 0x00000001 ++#define SDC_INT_MASK_REG_DATA_CRC_FAIL 0x00000002 ++#define SDC_INT_MASK_REG_RSP_TIMEOUT 0x00000004 ++#define SDC_INT_MASK_REG_DATA_TIMEOUT 0x00000008 ++#define SDC_INT_MASK_REG_RSP_CRC_OK 0x00000010 ++#define SDC_INT_MASK_REG_DATA_CRC_OK 0x00000020 ++#define SDC_INT_MASK_REG_CMD_SEND 0x00000040 ++#define SDC_INT_MASK_REG_DATA_END 0x00000080 ++#define SDC_INT_MASK_REG_FIFO_UNDERRUN 0x00000100 ++#define SDC_INT_MASK_REG_FIFO_OVERRUN 0x00000200 ++#define SDC_INT_MASK_REG_CARD_CHANGE 0x00000400 ++#define SDC_INT_MASK_REG_CARD_LOCK 0x00001000 ++#define SDC_INT_MASK_REG_CP_READY 0x00002000 ++#define SDC_INT_MASK_REG_CP_BUF_READY 0x00004000 ++#define SDC_INT_MASK_REG_PLAIN_TEXT_READY 0x00008000 ++#define SDC_INT_MASK_REG_SDIO_INTR 0x00010000 ++ ++ ++#define SDC_CARD_INSERT 0x0 ++#define SDC_CARD_REMOVE SDC_STATUS_REG_CARD_DETECT ++ ++/* bit mapping of power control register */ ++#define SDC_POWER_CTRL_REG_POWER_ON 0x00000010 ++#define SDC_POWER_CTRL_REG_POWER_BITS 0x0000000F ++ ++/* bit mapping of clock control register */ ++#define SDC_CLOCK_CTRL_REG_CLK_DIV 0x0000007F ++#define SDC_CLOCK_CTRL_REG_CARD_TYPE 0x00000080 ++#define SDC_CLOCK_CTRL_REG_CLK_DIS 0x00000100 ++ ++/* card type */ ++#define SDC_CARD_TYPE_SD SDC_CLOCK_REG_CARD_TYPE ++#define SDC_CARD_TYPE_MMC 0x0 ++ ++/* bit mapping of bus width register */ ++#define SDC_BUS_WIDTH_REG_SINGLE_BUS 0x00000001 ++#define SDC_BUS_WIDTH_REG_WIDE_8_BUS 0x00000002 ++#define SDC_BUS_WIDTH_REG_WIDE_4_BUS 0x00000004 ++#define SDC_BUS_WIDTH_REG_WIDE_BUS_SUPPORT 0x00000018 ++#define SDC_BUS_WIDTH_REG_CARD_DETECT 0x00000020 ++ ++#define SDC_WIDE_4_BUS_SUPPORT 0x00000008 ++#define SDC_WIDE_8_BUS_SUPPORT 0x00000010 ++ ++/* bit mapping of feature register */ ++#define SDC_FEATURE_REG_FIFO_DEPTH 0x000000FF ++#define SDC_FEATURE_REG_CPRM_FUNCTION 0x00000100 ++ ++/* bit mapping of sdio control register */ ++#define SDC_SDIO_CTRL1_REG_SDIO_BLK_NO 0xFFFF8000 ++#define SDC_SDIO_CTRL1_REG_SDIO_ENABLE 0x00004000 ++#define SDC_SDIO_CTRL1_REG_READ_WAIT_ENABLE 0x00002000 ++#define SDC_SDIO_CTRL1_REG_SDIO_BLK_MODE 0x00001000 ++#define SDC_SDIO_CTRL1_REG_SDIO_BLK_SIZE 0x00000FFF ++ ++/* bit mapping of sdio status register */ ++#define SDC_SDIO_SDIO_STATUS_REG_FIFO_REMAIN_NO 0x00FE0000 ++#define SDC_SDIO_SDIO_STATUS_REG_SDIO_BLK_CNT 0x0001FFFF ++ ++enum ftsdc_waitfor { ++ COMPLETION_NONE, ++ COMPLETION_FINALIZE, ++ COMPLETION_CMDSENT, ++ COMPLETION_RSPFIN, ++ COMPLETION_XFER_PROGRESS, ++}; ++ ++struct ftsdc_host { ++ struct platform_device *pdev; ++ struct mmc_host *mmc; ++ struct resource *mem; ++ struct clk *clk; ++ void __iomem *base; ++ int irq; ++ ++ unsigned int real_rate; ++ bool irq_enabled; ++ unsigned int fifo_len; /* bytes */ ++ unsigned int last_opcode; /* keep last successful cmd to judge application specific command */ ++ ++ struct mmc_request *mrq; ++ int cmd_is_stop; ++ ++ spinlock_t complete_lock; ++ enum ftsdc_waitfor complete_what; ++ ++ struct completion dma_complete; ++ dmad_chreq *dma_req; ++ bool dodma; ++ bool dma_finish; ++ ++ ++ u32 buf_sgptr; /* keep next scallterlist buffer index */ ++ u32 buf_bytes; /* keep current total scallterlist buffer length */ ++ u32 buf_count; /* keep real data size rw from sd */ ++ u32 *buf_ptr; /* keep current scallterlist buffer address */ ++#define XFER_NONE 0 ++#define XFER_READ 1 ++#define XFER_WRITE 2 ++ u32 buf_active; /* keep current transfer mode */ ++ ++ int bus_width; ++ ++ char dbgmsg_cmd[301]; ++ char dbgmsg_dat[301]; ++ char *status; ++ ++ unsigned int ccnt, dcnt; ++ struct tasklet_struct pio_tasklet; ++ struct work_struct work; ++ ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *debug_root; ++ struct dentry *debug_state; ++ struct dentry *debug_regs; ++#endif ++}; ++ ++#endif +diff -Nur linux-3.4.110.orig/drivers/mmc/host/Kconfig linux-3.4.110/drivers/mmc/host/Kconfig +--- linux-3.4.110.orig/drivers/mmc/host/Kconfig 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/mmc/host/Kconfig 2016-04-07 10:20:51.050085202 +0200 +@@ -609,3 +609,8 @@ + + Note: These controllers only support SDIO cards and do not + support MMC or SD memory cards. ++ ++config MMC_FTSDC010 ++ tristate "Andestech MMC/SD function support" ++ depends on NDS32 && !FTSDC010 ++ +diff -Nur linux-3.4.110.orig/drivers/mmc/host/Makefile linux-3.4.110/drivers/mmc/host/Makefile +--- linux-3.4.110.orig/drivers/mmc/host/Makefile 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/mmc/host/Makefile 2016-04-07 10:20:51.050085202 +0200 +@@ -45,6 +45,7 @@ + obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o + obj-$(CONFIG_MMC_VUB300) += vub300.o + obj-$(CONFIG_MMC_USHC) += ushc.o ++obj-$(CONFIG_MMC_FTSDC010) += ftsdc010.o + + obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o + obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o +diff -Nur linux-3.4.110.orig/drivers/net/ethernet/faraday/ftmac100.c linux-3.4.110/drivers/net/ethernet/faraday/ftmac100.c +--- linux-3.4.110.orig/drivers/net/ethernet/faraday/ftmac100.c 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/net/ethernet/faraday/ftmac100.c 2016-04-07 10:20:51.054085357 +0200 +@@ -1,1202 +1,1210 @@ + /* +- * Faraday FTMAC100 10/100 Ethernet ++ * drivers/net/ftmac100.c + * +- * (C) Copyright 2009-2011 Faraday Technology +- * Po-Yu Chuang <ratbert@faraday-tech.com> ++ * Faraday FTMAC100 Device 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. ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * ++ * All Rights Reserved + * +- * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +- +-#include <linux/dma-mapping.h> +-#include <linux/etherdevice.h> +-#include <linux/ethtool.h> ++#include <linux/module.h> + #include <linux/init.h> ++#include <linux/moduleparam.h> ++ ++#include <linux/sched.h> ++#include <linux/kernel.h> /* printk() */ ++#include <linux/slab.h> /* kmalloc() */ ++#include <linux/errno.h> /* error codes */ ++#include <linux/types.h> /* size_t */ + #include <linux/interrupt.h> +-#include <linux/io.h> +-#include <linux/mii.h> +-#include <linux/module.h> +-#include <linux/netdevice.h> ++ ++#include <linux/in.h> + #include <linux/platform_device.h> ++#include <linux/netdevice.h> /* struct device, and other headers */ ++#include <linux/etherdevice.h> /* eth_type_trans */ ++#include <linux/ip.h> /* struct iphdr */ ++#include <linux/tcp.h> /* struct tcphdr */ ++#include <linux/skbuff.h> ++ ++#include <linux/in6.h> ++#include <asm/checksum.h> ++ ++ ++#include <linux/version.h> ++#include <linux/kernel.h> ++#include <linux/fcntl.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/slab.h> ++#include <linux/string.h> ++#include <linux/proc_fs.h> ++#include <asm/bitops.h> ++#include <asm/io.h> ++#include <asm/hardware.h> ++#include <linux/pci.h> ++#include <linux/delay.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> + ++#include <asm/cacheflush.h> // dma_clean_range ++#include <asm/spec.h> + #include "ftmac100.h" + +-#define DRV_NAME "ftmac100" +-#define DRV_VERSION "0.2" +- +-#define RX_QUEUE_ENTRIES 128 /* must be power of 2 */ +-#define TX_QUEUE_ENTRIES 16 /* must be power of 2 */ ++#define IPMODULE MAC ++#define IPNAME FTMAC100 + +-#define MAX_PKT_SIZE 1518 +-#define RX_BUF_SIZE 2044 /* must be smaller than 0x7ff */ ++#define ENABLE_BOTTOM_HALF 0 ++#define ZERO_COPY 1 + +-#if MAX_PKT_SIZE > 0x7ff +-#error invalid MAX_PKT_SIZE +-#endif +- +-#if RX_BUF_SIZE > 0x7ff || RX_BUF_SIZE > PAGE_SIZE +-#error invalid RX_BUF_SIZE +-#endif +- +-/****************************************************************************** +- * private data +- *****************************************************************************/ +-struct ftmac100_descs { +- struct ftmac100_rxdes rxdes[RX_QUEUE_ENTRIES]; +- struct ftmac100_txdes txdes[TX_QUEUE_ENTRIES]; +-}; +- +-struct ftmac100 { +- struct resource *res; +- void __iomem *base; +- int irq; +- +- struct ftmac100_descs *descs; +- dma_addr_t descs_dma_addr; +- +- unsigned int rx_pointer; +- unsigned int tx_clean_pointer; +- unsigned int tx_pointer; +- unsigned int tx_pending; +- +- spinlock_t tx_lock; +- +- struct net_device *netdev; +- struct device *dev; +- struct napi_struct napi; ++#define FTMAC100_DEBUG 0 ++#define CARDNAME "FTMAC100" + +- struct mii_if_info mii; +-}; +- +-static int ftmac100_alloc_rx_page(struct ftmac100 *priv, +- struct ftmac100_rxdes *rxdes, gfp_t gfp); +- +-/****************************************************************************** +- * internal functions (hardware register access) +- *****************************************************************************/ +-#define INT_MASK_ALL_ENABLED (FTMAC100_INT_RPKT_FINISH | \ +- FTMAC100_INT_NORXBUF | \ +- FTMAC100_INT_XPKT_OK | \ +- FTMAC100_INT_XPKT_LOST | \ +- FTMAC100_INT_RPKT_LOST | \ +- FTMAC100_INT_AHB_ERR | \ +- FTMAC100_INT_PHYSTS_CHG) ++MODULE_AUTHOR("Faraday Corp."); ++MODULE_LICENSE("GPL"); + +-#define INT_MASK_ALL_DISABLED 0 ++static const char version[] = "Faraday FTMAC100 Driver (Linux 2.6) 09/28/05 - (C) 2005 Faraday Corp.\n"; ++static volatile int trans_busy = 0; ++static const char mac_string[] = "Faraday MAC"; + +-static void ftmac100_enable_all_int(struct ftmac100 *priv) +-{ +- iowrite32(INT_MASK_ALL_ENABLED, priv->base + FTMAC100_OFFSET_IMR); +-} ++#if FTMAC100_DEBUG > 2 ++static void print_packet( unsigned char * buf, int length ); ++#endif + +-static void ftmac100_disable_all_int(struct ftmac100 *priv) +-{ +- iowrite32(INT_MASK_ALL_DISABLED, priv->base + FTMAC100_OFFSET_IMR); +-} ++#if FTMAC100_DEBUG > 0 ++#define PRINTK printk ++#else ++#define PRINTK(x...) ++#endif + +-static void ftmac100_set_rx_ring_base(struct ftmac100 *priv, dma_addr_t addr) +-{ +- iowrite32(addr, priv->base + FTMAC100_OFFSET_RXR_BADR); ++static int ftmac100_open(struct net_device *dev); ++static void ftmac100_timeout (struct net_device *dev); ++static int ftmac100_close(struct net_device *dev); ++static struct net_device_stats * ftmac100_query_statistics( struct net_device *dev); ++#ifdef HAVE_MULTICAST ++static void ftmac100_set_multicast_list(struct net_device *dev); ++#endif ++static void ftmac100_phy_configure(struct net_device* dev) {}; ++static irqreturn_t ftmac100_interrupt(int irq, void * dev_id); ++static void ftmac100_rcv(void *dev); ++static int ftmac100_setup(struct net_device *dev); ++static int ftmac100_reset( struct net_device* dev ); ++static void ftmac100_enable( struct net_device *dev ); ++ ++static void put_mac(int base, unsigned char *mac_addr) ++{ ++ int val; ++ ++ val = ((u32)mac_addr[0])<<8 | (u32)mac_addr[1]; ++ outl(val, base); ++ val = ((((u32)mac_addr[2])<<24)&0xff000000) | ++ ((((u32)mac_addr[3])<<16)&0xff0000) | ++ ((((u32)mac_addr[4])<<8)&0xff00) | ++ ((((u32)mac_addr[5])<<0)&0xff); ++ outl(val, base+4); ++} ++ ++static void get_mac(int base, unsigned char *mac_addr) ++{ ++ int val; ++ ++ //printk("+get_mac\n"); ++ ++ val = inl(base); ++ mac_addr[0] = (val>>8)&0xff; ++ mac_addr[1] = val&0xff; ++ val = inl(base+4); //john add +4 ++ mac_addr[2] = (val>>24)&0xff; ++ mac_addr[3] = (val>>16)&0xff; ++ mac_addr[4] = (val>>8)&0xff; ++ mac_addr[5] = val&0xff; ++} ++ ++static void auto_get_mac(int id,unsigned char *mac_addr) ++{ ++ get_mac(MAC_FTMAC100_0_VA_BASE + MAC_MADR_REG, mac_addr); ++ ++ if (memcmp(mac_addr, "\0\0\0\0\0\0", 6) == 0) { ++ mac_addr[0]=0; ++ mac_addr[1]=0x23; ++ mac_addr[2]=0x96; ++ mac_addr[3]=0x00; ++ mac_addr[4]=0xff; ++ mac_addr[5]=0x00; ++ } + } + +-static void ftmac100_set_tx_ring_base(struct ftmac100 *priv, dma_addr_t addr) ++/* ++ * Print the Ethernet address ++ */ ++static void ft_print_mac(unsigned char *mac_addr) + { +- iowrite32(addr, priv->base + FTMAC100_OFFSET_TXR_BADR); ++ printk("ADDR: %pM\n", mac_addr); + } + +-static void ftmac100_txdma_start_polling(struct ftmac100 *priv) +-{ +- iowrite32(1, priv->base + FTMAC100_OFFSET_TXPD); +-} + +-static int ftmac100_reset(struct ftmac100 *priv) ++#ifdef HAVE_MULTICAST ++/* ++ * Finds the CRC32 of a set of bytes. ++ * Again, from Peter Cammaert's code. ++ */ ++static int crc32( char * s, int length ) + { +- struct net_device *netdev = priv->netdev; +- int i; +- +- /* NOTE: reset clears all registers */ +- iowrite32(FTMAC100_MACCR_SW_RST, priv->base + FTMAC100_OFFSET_MACCR); +- +- for (i = 0; i < 5; i++) { +- unsigned int maccr; +- +- maccr = ioread32(priv->base + FTMAC100_OFFSET_MACCR); +- if (!(maccr & FTMAC100_MACCR_SW_RST)) { +- /* +- * FTMAC100_MACCR_SW_RST cleared does not indicate +- * that hardware reset completed (what the f*ck). +- * We still need to wait for a while. +- */ +- udelay(500); +- return 0; ++ /* indices */ ++ int perByte; ++ int perBit; ++ /* crc polynomial for Ethernet */ ++ const unsigned long poly = 0xedb88320; ++ /* crc value - preinitialized to all 1's */ ++ unsigned long crc_value = 0xffffffff; ++ ++ //printk("+crc32\n"); ++ ++ for ( perByte = 0; perByte < length; perByte ++ ) { ++ unsigned char c; ++ ++ c = *(s++); ++ for ( perBit = 0; perBit < 8; perBit++ ) { ++ crc_value = (crc_value>>1)^ ++ (((crc_value^c)&0x01)?poly:0); ++ c >>= 1; + } +- +- udelay(1000); + } +- +- netdev_err(netdev, "software reset failed\n"); +- return -EIO; +-} +- +-static void ftmac100_set_mac(struct ftmac100 *priv, const unsigned char *mac) +-{ +- unsigned int maddr = mac[0] << 8 | mac[1]; +- unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; +- +- iowrite32(maddr, priv->base + FTMAC100_OFFSET_MAC_MADR); +- iowrite32(laddr, priv->base + FTMAC100_OFFSET_MAC_LADR); ++ return crc_value; + } ++#endif + +-#define MACCR_ENABLE_ALL (FTMAC100_MACCR_XMT_EN | \ +- FTMAC100_MACCR_RCV_EN | \ +- FTMAC100_MACCR_XDMA_EN | \ +- FTMAC100_MACCR_RDMA_EN | \ +- FTMAC100_MACCR_CRC_APD | \ +- FTMAC100_MACCR_FULLDUP | \ +- FTMAC100_MACCR_RX_RUNT | \ +- FTMAC100_MACCR_RX_BROADPKT) +- +-static int ftmac100_start_hw(struct ftmac100 *priv) ++static int ftmac100_reset( struct net_device* dev ) + { +- struct net_device *netdev = priv->netdev; ++ unsigned ioaddr = dev->base_addr; ++ int rcount; + +- if (ftmac100_reset(priv)) +- return -EIO; ++ PRINTK("+ftmac100_reset:I/O addr=%X\n", ioaddr); + +- /* setup ring buffer base registers */ +- ftmac100_set_rx_ring_base(priv, +- priv->descs_dma_addr + +- offsetof(struct ftmac100_descs, rxdes)); +- ftmac100_set_tx_ring_base(priv, +- priv->descs_dma_addr + +- offsetof(struct ftmac100_descs, txdes)); ++ outl( SW_RST_bit, ioaddr + MACCR_REG ); + +- iowrite32(FTMAC100_APTC_RXPOLL_CNT(1), priv->base + FTMAC100_OFFSET_APTC); ++ /* this should pause enough for the chip to be happy */ ++ for (rcount = 0; (inl( ioaddr + MACCR_REG ) & SW_RST_bit) != 0; rcount++) { ++ //mdelay(10); ++ msleep_interruptible(10); ++ if (rcount > 5) // Retry 5 times ++ return -ENODEV; ++ } + +- ftmac100_set_mac(priv, netdev->dev_addr); ++ outl( 0, ioaddr + IMR_REG ); /* Disable all interrupts */ ++ if (inl(ioaddr+IMR_REG)!=0) ++ return -ENODEV; + +- iowrite32(MACCR_ENABLE_ALL, priv->base + FTMAC100_OFFSET_MACCR); +- return 0; ++ return 0; + } + +-static void ftmac100_stop_hw(struct ftmac100 *priv) +-{ +- iowrite32(0, priv->base + FTMAC100_OFFSET_MACCR); +-} + +-/****************************************************************************** +- * internal functions (receive descriptor) +- *****************************************************************************/ +-static bool ftmac100_rxdes_first_segment(struct ftmac100_rxdes *rxdes) +-{ +- return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FRS); +-} +- +-static bool ftmac100_rxdes_last_segment(struct ftmac100_rxdes *rxdes) ++/* ++ . Function: ftmac100_enable ++ . Purpose: let the chip talk to the outside work ++ . Method: ++ . 1. Enable the transmitter ++ . 2. Enable the receiver ++ . 3. Enable interrupts ++*/ ++static void ftmac100_enable( struct net_device *dev ) + { +- return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_LRS); +-} ++ unsigned int ioaddr = dev->base_addr; ++ int i; ++ struct ftmac100_local *priv = (struct ftmac100_local *)netdev_priv(dev); ++ char mac_addr[6]; + +-static bool ftmac100_rxdes_owned_by_dma(struct ftmac100_rxdes *rxdes) +-{ +- return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN); +-} ++ //printk("+ftmac100_enable\n"); ++ PRINTK("%s:ftmac100_enable ioaddr=%X\n", dev->name, ioaddr); + +-static void ftmac100_rxdes_set_dma_own(struct ftmac100_rxdes *rxdes) +-{ +- /* clear status bits */ +- rxdes->rxdes0 = cpu_to_le32(FTMAC100_RXDES0_RXDMA_OWN); ++ for (i=0; i<RXDES_NUM; ++i) { ++ priv->rx_descs[i].RXDMA_OWN = OWNBY_FTMAC100; // owned by FTMAC100 ++ } ++ priv->rx_idx = 0; ++ ++ for (i=0; i<TXDES_NUM; ++i) { ++ priv->tx_descs[i].TXDMA_OWN = OWNBY_SOFTWARE; // owned by software ++ } ++ priv->tx_idx = 0; ++ ++ ++ /* set the MAC address */ ++ put_mac(ioaddr + MAC_MADR_REG, dev->dev_addr); ++ ++ //john add ++ get_mac(ioaddr + MAC_MADR_REG, mac_addr); ++ ft_print_mac(mac_addr); ++ ++ outl( priv->rx_descs_dma, ioaddr + RXR_BADR_REG); ++ outl( priv->tx_descs_dma, ioaddr + TXR_BADR_REG); ++ outl( 0x00001010, ioaddr + ITC_REG); // TODO: threshold too small ++ outl( (0UL<<TXPOLL_CNT)|(0x1<<RXPOLL_CNT), ioaddr + APTC_REG); // TODO: bandwidth overhead maybe too big, polling too often ?! ++ outl( 0x1d8, ioaddr + DBLAC_REG ); //Luke Lee: 1 110 010 111 (0x397) ++ ++ /* now, enable interrupts */ ++ outl( PHYSTS_CHG_bit ++ | AHB_ERR_bit ++ | RPKT_LOST_bit ++ | RPKT_SAV_bit ++ | XPKT_LOST_bit ++ | XPKT_OK_bit ++ | NOTXBUF_bit ++ | XPKT_FINISH_bit ++ | NORXBUF_bit ++ | RPKT_FINISH_bit ++ , ioaddr + IMR_REG); ++ ++ /// enable trans/recv,... ++ outl( priv->maccr_val, ioaddr + MACCR_REG ); ++ PRINTK("%s:ftmac100_enable DONE\n", dev->name); + } + +-static bool ftmac100_rxdes_rx_error(struct ftmac100_rxdes *rxdes) ++/* ++ . Function: ftmac100_shutdown ++ . Purpose: closes down the SMC91xxx chip. ++ . Method: ++ . 1. zero the interrupt mask ++ . 2. clear the enable receive flag ++ . 3. clear the enable xmit flags ++ . ++ . TODO: ++ . (1) maybe utilize power down mode. ++ . Why not yet? Because while the chip will go into power down mode, ++ . the manual says that it will wake up in response to any I/O requests ++ . in the register space. Empirical results do not show this working. ++*/ ++static void ftmac100_shutdown( unsigned int ioaddr ) + { +- return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ERR); +-} ++ //printk("+ftmac100_shutdown\n"); + +-static bool ftmac100_rxdes_crc_error(struct ftmac100_rxdes *rxdes) +-{ +- return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_CRC_ERR); ++ outl( 0, ioaddr + IMR_REG ); ++ outl( 0, ioaddr + MACCR_REG ); + } + +-static bool ftmac100_rxdes_frame_too_long(struct ftmac100_rxdes *rxdes) ++/* ++ * Function: ftmac100_wait_to_send_packet( struct sk_buff * skb, struct device * ) ++ * Purpose: ++ * Attempt to allocate memory for a packet, if chip-memory is not ++ * available, then tell the card to generate an interrupt when it ++ * is available* ++ * ++ * Algorithm: ++ * ++ * o if the saved_skb is not currently null, then drop this packet ++ * on the floor. This should never happen, because of TBUSY. ++ * o if the saved_skb is null, then replace it with the current packet, ++ * o See if I can sending it now. ++ * o (NO): Enable interrupts and let the interrupt handler deal with it. ++ * o (YES):Send it now. ++ */ ++static int ftmac100_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev ) + { +- return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_FTL); +-} ++ struct ftmac100_local *priv=(struct ftmac100_local *)netdev_priv(dev); ++ unsigned int ioaddr=dev->base_addr; ++ volatile TX_DESC *cur_desc; ++ int length; ++ unsigned long flags; ++ ++ //printk("+ftmac100_wait_to_send_packet\n"); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ if (skb==NULL) { ++ printk("%s(%d): NULL skb???\n", __FILE__,__LINE__); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ return 0; ++ } ++ ++ cur_desc = &priv->tx_descs[priv->tx_idx]; ++#if ZERO_COPY ++ /* Record buffer address to be freed later */ ++ priv->tx_skbuff[priv->tx_idx] = skb; ++#endif ++ ++#ifdef not_complete_yet ++ if (cur_desc->TXDMA_OWN != TX_OWNBY_SOFTWARE) /// no empty transmit descriptor ++ { ++ DO_PRINT("no empty transmit descriptor\n"); ++ DO_PRINT("jiffies = %d\n", jiffies); ++ lp->stats.tx_dropped++; ++ netif_stop_queue(dev); /// waiting to do: ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ return 1; ++ } ++#endif /* end_of_not */ ++ ++ for (; cur_desc->TXDMA_OWN != OWNBY_SOFTWARE; ) { ++ PRINTK( KERN_WARNING "NO empty TX\n"); //printk("no empty TX descriptor:0x%x:0x%x\n",(unsigned)cur_desc,(unsigned)cur_desc[0]); ++ udelay(1); ++ } ++ length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; ++ length = min(length, TX_BUF_SIZE); // truncate jumbo packets ++ ++#if FTMAC100_DEBUG > 2 ++ printk("Transmitting Packet at 0x%x\n",(unsigned int)cur_desc->VIR_TXBUF_BADR); ++ print_packet( skb->data, length ); ++#endif + +-static bool ftmac100_rxdes_runt(struct ftmac100_rxdes *rxdes) +-{ +- return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RUNT); +-} ++#if ZERO_COPY ++ cur_desc->VIR_TXBUF_BADR = (unsigned)skb->data; ++ cur_desc->TXBUF_BADR = virt_to_phys(skb->data); ++ cpu_dma_wb_range((unsigned)skb->data, ((unsigned)(skb->data) + length + CACHE_LINE_SIZE( DCACHE) - 1 )&(~(CACHE_LINE_SIZE( DCACHE)-1)) ); + +-static bool ftmac100_rxdes_odd_nibble(struct ftmac100_rxdes *rxdes) +-{ +- return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_RX_ODD_NB); +-} ++#else ++ memcpy((char *)cur_desc->VIR_TXBUF_BADR, skb->data, length); ++#endif + +-static unsigned int ftmac100_rxdes_frame_length(struct ftmac100_rxdes *rxdes) +-{ +- return le32_to_cpu(rxdes->rxdes0) & FTMAC100_RXDES0_RFL; ++ cur_desc->TXBUF_Size = length; ++ cur_desc->LTS = 1; ++ cur_desc->FTS = 1; ++ ++ cur_desc->TX2FIC = 0; ++ cur_desc->TXIC = 0; ++ ++ cur_desc->TXDMA_OWN = OWNBY_FTMAC100; ++ ++ outl( 0xffffffff, ioaddr + TXPD_REG ); ++ ++ priv->tx_idx = (priv->tx_idx + 1) & (TXDES_NUM-1); ++ priv->stats.tx_packets++; ++ priv->stats.tx_bytes += skb->len; ++#if !ZERO_COPY ++ dev_kfree_skb_any (skb); ++#endif ++ dev->trans_start = jiffies; ++ spin_unlock_irqrestore(&priv->lock, flags); ++ return 0; + } + +-static bool ftmac100_rxdes_multicast(struct ftmac100_rxdes *rxdes) +-{ +- return rxdes->rxdes0 & cpu_to_le32(FTMAC100_RXDES0_MULTICAST); +-} ++//#define dma_allocate(x,y,z,w) dma_alloc_coherent((x),(y),(dma_addr_t*)(z),(w)) ++#define dma_allocate(x,y,z,w) dma_alloc_writecombine((x),(y),(dma_addr_t*)(z),(w)) + +-static void ftmac100_rxdes_set_buffer_size(struct ftmac100_rxdes *rxdes, +- unsigned int size) ++static int ftmac100_ringbuf_alloc(struct net_device *dev,struct ftmac100_local *priv) + { +- rxdes->rxdes1 &= cpu_to_le32(FTMAC100_RXDES1_EDORR); +- rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_RXBUF_SIZE(size)); +-} ++ int i; + +-static void ftmac100_rxdes_set_end_of_ring(struct ftmac100_rxdes *rxdes) +-{ +- rxdes->rxdes1 |= cpu_to_le32(FTMAC100_RXDES1_EDORR); +-} ++ //printk("+ftmac100_ringbuf_alloc\n"); + +-static void ftmac100_rxdes_set_dma_addr(struct ftmac100_rxdes *rxdes, +- dma_addr_t addr) +-{ +- rxdes->rxdes2 = cpu_to_le32(addr); +-} ++ priv->rx_descs = dma_allocate( NULL, sizeof(RX_DESC)*RXDES_NUM, &(priv->rx_descs_dma), GFP_KERNEL ); ++ if (priv->rx_descs == NULL || (( (u32)priv->rx_descs & 0xf)!=0)) { ++ printk("Receive Ring Buffer allocation error\n"); ++ return -ENOMEM; ++ } ++#if FTMAC100_DEBUG > 2 ++ else ++ printk( KERN_INFO "* Allocated RX descs=%X, bus addr=%X, size=%d*%d=%d\n", ++ (unsigned)priv->rx_descs, (unsigned)priv->rx_descs_dma, ++ sizeof(RX_DESC),RXDES_NUM,sizeof(RX_DESC)*RXDES_NUM ); ++#endif ++ memset((unsigned int *)priv->rx_descs, 0, sizeof(RX_DESC)*RXDES_NUM); + +-static dma_addr_t ftmac100_rxdes_get_dma_addr(struct ftmac100_rxdes *rxdes) +-{ +- return le32_to_cpu(rxdes->rxdes2); ++ priv->rx_buf = dma_allocate( NULL, RX_BUF_SIZE*RXDES_NUM, &(priv->rx_buf_dma), GFP_KERNEL ); ++ if (priv->rx_buf == NULL || (( (u32)priv->rx_buf & 3)!=0)) { ++ printk("Receive Ring Buffer allocation error\n"); ++ return -ENOMEM; ++ } ++#if FTMAC100_DEBUG > 2 ++ else ++ printk( KERN_INFO "* Allocated RX buf=%X, bus addr=%X, size=%d*%d=%d\n", ++ (unsigned)priv->rx_buf, (unsigned)priv->rx_buf_dma, ++ RX_BUF_SIZE, RXDES_NUM, RX_BUF_SIZE*RXDES_NUM ); ++#endif ++ ++ memset((void *)priv->rx_buf,0,sizeof(RX_BUF_SIZE)*RXDES_NUM); ++ ++ for (i=0; i<RXDES_NUM; ++i) { ++ priv->rx_descs[i].RXBUF_Size = RX_BUF_SIZE; ++ priv->rx_descs[i].EDOTR = 0; // not last descriptor ++ priv->rx_descs[i].RXBUF_BADR = priv->rx_buf_dma+RX_BUF_SIZE*i; ++ priv->rx_descs[i].VIR_RXBUF_BADR=(unsigned int)priv->rx_buf+RX_BUF_SIZE*i; ++ } ++ priv->rx_descs[RXDES_NUM-1].EDOTR = 1; // is last descriptor ++ ++ priv->tx_descs = dma_allocate( NULL, sizeof(TX_DESC)*TXDES_NUM, &(priv->tx_descs_dma), GFP_KERNEL ); ++ if (priv->tx_descs == NULL || (( (u32)priv->tx_descs & 0xf)!=0)) { ++ printk("Transmit Ring Buffer allocation error\n"); ++ return -ENOMEM; ++ } ++#if FTMAC100_DEBUG > 2 ++ else ++ printk( KERN_INFO "* Allocated TX descs=%X, bus addr=%X, size=%d*%d=%d\n", ++ (unsigned)priv->tx_descs, (unsigned)priv->tx_descs_dma, sizeof(TX_DESC),TXDES_NUM,sizeof(TX_DESC)*TXDES_NUM); ++#endif ++ memset((void *)priv->tx_descs,0,sizeof(TX_DESC)*TXDES_NUM); ++ ++ priv->tx_buf = dma_allocate( NULL, TX_BUF_SIZE*TXDES_NUM, &(priv->tx_buf_dma), GFP_KERNEL ); ++ if (priv->tx_buf == NULL || (( (u32)priv->tx_buf & 0x3)!=0)) { ++ printk("Transmit Ring Buffer allocation error\n"); ++ return -ENOMEM; ++ } ++#if FTMAC100_DEBUG > 2 ++ else ++ printk( KERN_INFO "* Allocated TX buf=%X, bus addr=%X, size=%d*%d=%d\n", ++ (unsigned)priv->tx_buf, (unsigned)priv->tx_buf_dma, ++ TX_BUF_SIZE, TXDES_NUM, TX_BUF_SIZE*TXDES_NUM ); ++#endif ++ ++ memset((void *)priv->tx_buf,0,sizeof(TX_BUF_SIZE)*TXDES_NUM); ++ ++ for (i=0; i<TXDES_NUM; ++i) { ++ priv->tx_descs[i].EDOTR = 0; // not last descriptor ++ priv->tx_descs[i].TXBUF_BADR=priv->tx_buf_dma+TX_BUF_SIZE*i; ++ priv->tx_descs[i].VIR_TXBUF_BADR=(unsigned int)priv->tx_buf+TX_BUF_SIZE*i; ++ } ++ priv->tx_descs[TXDES_NUM-1].EDOTR = 1; // is last descriptor ++ return 0; + } + + /* +- * rxdes3 is not used by hardware. We use it to keep track of page. +- * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu(). ++ * Function: ftmac100_poll( struct net_device *dev ) ++ * ++ * Purpose: ++ * poll interface callback function. + */ +-static void ftmac100_rxdes_set_page(struct ftmac100_rxdes *rxdes, struct page *page) ++void ftmac100_poll(struct net_device *dev) + { +- rxdes->rxdes3 = (unsigned int)page; ++ disable_irq(dev->irq); ++ ftmac100_interrupt(dev->irq, dev); ++ enable_irq(dev->irq); + } + +-static struct page *ftmac100_rxdes_get_page(struct ftmac100_rxdes *rxdes) +-{ +- return (struct page *)rxdes->rxdes3; +-} +- +-/****************************************************************************** +- * internal functions (receive) +- *****************************************************************************/ +-static int ftmac100_next_rx_pointer(int pointer) ++/* ++ * Function: ftmac100_setup( struct net_device *dev ) ++ * ++ * Purpose: ++ * Tests to see if the device 'dev' points to an ftmac100 chip. ++ * Returns a 0 on success ++ */ ++static const struct net_device_ops ftmac100_ops = { ++ .ndo_init = ftmac100_setup, ++ .ndo_open = ftmac100_open, ++ .ndo_stop = ftmac100_close, ++ .ndo_start_xmit = ftmac100_wait_to_send_packet, ++ .ndo_get_stats = ftmac100_query_statistics, ++ .ndo_tx_timeout = ftmac100_timeout, ++#ifdef HAVE_MULTICAST ++ .ndo_set_multicast_list = ftmac100_set_multicast_list, ++#endif ++ .ndo_set_mac_address = eth_mac_addr, ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ .ndo_poll_controller = ftmac100_poll, ++#endif ++}; ++static int ftmac100_setup(struct net_device *dev) + { +- return (pointer + 1) & (RX_QUEUE_ENTRIES - 1); +-} ++ int retval; ++ static unsigned version_printed = 0; ++ struct ftmac100_local *priv; ++ ++ if (version_printed++ == 0) ++ printk(KERN_INFO "%s", version); ++ ++ /* Now, print out the card info, in a short format.. */ ++ printk(KERN_INFO "%s: device at %#3x IRQ:%d NOWAIT:%d\n",dev->name, ++ (unsigned)dev->base_addr, dev->irq, dev->dma); ++ ++ /* Initialize priviate data */ ++ priv = (struct ftmac100_local *)netdev_priv(dev); ++ memset(priv, 0, sizeof(struct ftmac100_local)); ++ spin_lock_init(&priv->lock); ++ priv->maccr_val = FULLDUP_bit ++ | CRC_APD_bit ++ | MDC_SEL_bit ++ | RCV_EN_bit ++ | XMT_EN_bit ++ | RDMA_EN_bit ++ | XDMA_EN_bit ; ++ retval = ftmac100_ringbuf_alloc(dev,priv); ++ if (retval) ++ goto err_out; ++ ++ /* now, reset the chip, and put it into a known state */ ++ retval = ftmac100_reset( dev ); ++ if (retval) { ++ printk( "%s: unable to reset.\n", dev->name ); ++ goto err_out; ++ } ++ ++ /* Fill in the fields of the device structure with ethernet values. */ ++ ether_setup(dev); ++ ++ /* Grab the IRQ */ ++ retval = request_irq(dev->irq, &ftmac100_interrupt, IRQF_DISABLED, dev->name, dev); ++ if (retval) { ++ printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, retval); ++ goto err_out; ++ } ++ ++#if 0 ++ if ((proc_ftmac100 = create_proc_entry( "ftmac100", 0, 0 ))) { ++ proc_ftmac100->read_proc = ftmac100_read_proc; ++ proc_ftmac100->data = dev; ++ proc_ftmac100->owner = THIS_MODULE; ++ } ++#endif + +-static void ftmac100_rx_pointer_advance(struct ftmac100 *priv) +-{ +- priv->rx_pointer = ftmac100_next_rx_pointer(priv->rx_pointer); +-} ++ return 0; + +-static struct ftmac100_rxdes *ftmac100_current_rxdes(struct ftmac100 *priv) +-{ +- return &priv->descs->rxdes[priv->rx_pointer]; ++err_out: ++ dma_free_coherent( NULL, sizeof(RX_DESC)*RXDES_NUM, (void*)priv->rx_descs, (dma_addr_t)priv->rx_descs_dma ); ++ dma_free_coherent( NULL, RX_BUF_SIZE*RXDES_NUM, (void*)priv->rx_buf, (dma_addr_t)priv->rx_buf_dma ); ++ dma_free_coherent( NULL, sizeof(TX_DESC)*TXDES_NUM, (void*)priv->tx_descs, (dma_addr_t)priv->tx_descs_dma ); ++ dma_free_coherent( NULL, TX_BUF_SIZE*TXDES_NUM, (void*)priv->tx_buf, (dma_addr_t)priv->tx_buf_dma ); ++ priv->rx_descs = NULL; priv->rx_descs_dma = 0; ++ priv->rx_buf = NULL; priv->rx_buf_dma = 0; ++ priv->tx_descs = NULL; priv->tx_descs_dma = 0; ++ priv->tx_buf = NULL; priv->tx_buf_dma = 0; ++ return retval; + } + +-static struct ftmac100_rxdes * +-ftmac100_rx_locate_first_segment(struct ftmac100 *priv) +-{ +- struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv); + +- while (!ftmac100_rxdes_owned_by_dma(rxdes)) { +- if (ftmac100_rxdes_first_segment(rxdes)) +- return rxdes; ++#if FTMAC100_DEBUG > 2 ++static void print_packet( unsigned char * buf, int length ) ++{ ++#if FTMAC100_DEBUG > 3 ++ int i; ++ int remainder; ++ int lines; ++#endif + +- ftmac100_rxdes_set_dma_own(rxdes); +- ftmac100_rx_pointer_advance(priv); +- rxdes = ftmac100_current_rxdes(priv); +- } ++// printk("Packet of length %d \n", length ); + +- return NULL; ++#if FTMAC100_DEBUG > 3 ++ lines = length >> 4; ++ remainder = length & 15; ++ ++ for ( i = 0; i < lines ; i ++ ) { ++ int cur; ++ for ( cur = 0; cur < 8; cur ++ ) { ++ unsigned char a, b; ++ a = *(buf ++ ); ++ b = *(buf ++ ); ++ printk("%02x%02x ", a, b ); ++ } ++ printk("\n"); ++ } ++ for ( i = 0; i < remainder/2 ; i++ ) { ++ unsigned char a, b; ++ ++ a = *(buf ++ ); ++ b = *(buf ++ ); ++ printk("%02x%02x ", a, b ); ++ } ++ printk("\n"); ++#endif + } ++#endif + +-static bool ftmac100_rx_packet_error(struct ftmac100 *priv, +- struct ftmac100_rxdes *rxdes) +-{ +- struct net_device *netdev = priv->netdev; +- bool error = false; +- +- if (unlikely(ftmac100_rxdes_rx_error(rxdes))) { +- if (net_ratelimit()) +- netdev_info(netdev, "rx err\n"); +- +- netdev->stats.rx_errors++; +- error = true; +- } +- +- if (unlikely(ftmac100_rxdes_crc_error(rxdes))) { +- if (net_ratelimit()) +- netdev_info(netdev, "rx crc err\n"); +- +- netdev->stats.rx_crc_errors++; +- error = true; +- } +- +- if (unlikely(ftmac100_rxdes_frame_too_long(rxdes))) { +- if (net_ratelimit()) +- netdev_info(netdev, "rx frame too long\n"); +- +- netdev->stats.rx_length_errors++; +- error = true; +- } else if (unlikely(ftmac100_rxdes_runt(rxdes))) { +- if (net_ratelimit()) +- netdev_info(netdev, "rx runt\n"); +- +- netdev->stats.rx_length_errors++; +- error = true; +- } else if (unlikely(ftmac100_rxdes_odd_nibble(rxdes))) { +- if (net_ratelimit()) +- netdev_info(netdev, "rx odd nibble\n"); +- +- netdev->stats.rx_length_errors++; +- error = true; +- } +- +- return error; +-} + +-static void ftmac100_rx_drop_packet(struct ftmac100 *priv) ++/* ++ * Open and Initialize the board ++ * ++ * Set up everything, reset the card, etc .. ++ * ++ */ ++static int ftmac100_open(struct net_device *dev) + { +- struct net_device *netdev = priv->netdev; +- struct ftmac100_rxdes *rxdes = ftmac100_current_rxdes(priv); +- bool done = false; +- +- if (net_ratelimit()) +- netdev_dbg(netdev, "drop packet %p\n", rxdes); ++ int retval = 0; ++ PRINTK("+%s:ftmac100_open\n", dev->name); + +- do { +- if (ftmac100_rxdes_last_segment(rxdes)) +- done = true; ++ //netif_start_queue(dev); + +- ftmac100_rxdes_set_dma_own(rxdes); +- ftmac100_rx_pointer_advance(priv); +- rxdes = ftmac100_current_rxdes(priv); +- } while (!done && !ftmac100_rxdes_owned_by_dma(rxdes)); +- +- netdev->stats.rx_dropped++; ++ /* reset the hardware */ ++ ftmac100_reset( dev ); ++ retval = ftmac100_reset( dev ); ++ if (retval) { ++ printk( "%s: unable to reset.\n", dev->name ); ++ retval = -ENODEV; ++ } else { ++ ftmac100_enable( dev ); ++ ++ /* Configure the PHY */ ++ ftmac100_phy_configure(dev); ++ ++ netif_start_queue(dev); ++ ++ PRINTK("+%s:ftmac100_open DONE\n", dev->name); ++ } ++ ++ return retval; + } + +-static bool ftmac100_rx_packet(struct ftmac100 *priv, int *processed) +-{ +- struct net_device *netdev = priv->netdev; +- struct ftmac100_rxdes *rxdes; +- struct sk_buff *skb; +- struct page *page; +- dma_addr_t map; +- int length; + +- rxdes = ftmac100_rx_locate_first_segment(priv); +- if (!rxdes) +- return false; +- +- if (unlikely(ftmac100_rx_packet_error(priv, rxdes))) { +- ftmac100_rx_drop_packet(priv); +- return true; +- } +- +- /* +- * It is impossible to get multi-segment packets +- * because we always provide big enough receive buffers. +- */ +- if (unlikely(!ftmac100_rxdes_last_segment(rxdes))) +- BUG(); +- +- /* start processing */ +- skb = netdev_alloc_skb_ip_align(netdev, 128); +- if (unlikely(!skb)) { +- if (net_ratelimit()) +- netdev_err(netdev, "rx skb alloc failed\n"); +- +- ftmac100_rx_drop_packet(priv); +- return true; +- } +- +- if (unlikely(ftmac100_rxdes_multicast(rxdes))) +- netdev->stats.multicast++; +- +- map = ftmac100_rxdes_get_dma_addr(rxdes); +- dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE); +- +- length = ftmac100_rxdes_frame_length(rxdes); +- page = ftmac100_rxdes_get_page(rxdes); +- skb_fill_page_desc(skb, 0, page, 0, length); +- skb->len += length; +- skb->data_len += length; +- +- /* page might be freed in __pskb_pull_tail() */ +- if (length > 64) +- skb->truesize += PAGE_SIZE; +- __pskb_pull_tail(skb, min(length, 64)); +- +- ftmac100_alloc_rx_page(priv, rxdes, GFP_ATOMIC); +- +- ftmac100_rx_pointer_advance(priv); +- +- skb->protocol = eth_type_trans(skb, netdev); +- +- netdev->stats.rx_packets++; +- netdev->stats.rx_bytes += skb->len; ++/* ++ * Called by the kernel to send a packet out into the void ++ * of the net. This routine is largely based on ++ * skeleton.c, from Becker. ++ * ++ */ ++static void ftmac100_timeout (struct net_device *dev) ++{ ++ /* If we get here, some higher level has decided we are broken. ++ There should really be a "kick me" function call instead. */ ++ printk(KERN_WARNING "%s: transmit timed out?\n",dev->name); + +- /* push packet to protocol stack */ +- netif_receive_skb(skb); ++ //printk("+ftmac100_timeout\n"); + +- (*processed)++; +- return true; ++ ftmac100_reset( dev ); ++ ftmac100_enable( dev ); ++ ftmac100_phy_configure(dev); ++ netif_wake_queue(dev); ++ dev->trans_start = jiffies; + } + +-/****************************************************************************** +- * internal functions (transmit descriptor) +- *****************************************************************************/ +-static void ftmac100_txdes_reset(struct ftmac100_txdes *txdes) ++#if ZERO_COPY ++/* ++ * Free transmitted skb buffer when it's safe. ++ */ ++static void ftmac100_free_tx (struct net_device *dev, int irq) + { +- /* clear all except end of ring bit */ +- txdes->txdes0 = 0; +- txdes->txdes1 &= cpu_to_le32(FTMAC100_TXDES1_EDOTR); +- txdes->txdes2 = 0; +- txdes->txdes3 = 0; +-} ++ struct ftmac100_local *priv = (struct ftmac100_local *)netdev_priv(dev); ++ //volatile TX_DESC *cur_desc; ++ int entry = priv->old_tx & (TXDES_NUM-1); ++ ++ //enter spinlock ++ if (!irq) ++ spin_lock(&priv->lock); ++ ++ /* Free used tx skbuffs */ ++ while (entry != priv->tx_idx) { ++ struct sk_buff *skb; ++ ++ skb = priv->tx_skbuff[entry]; ++ if(skb) { ++ dev_kfree_skb_any (skb); ++ priv->tx_skbuff[entry] = 0; ++ } + +-static bool ftmac100_txdes_owned_by_dma(struct ftmac100_txdes *txdes) +-{ +- return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN); +-} ++ entry = (entry + 1) & (TXDES_NUM-1); ++ } + +-static void ftmac100_txdes_set_dma_own(struct ftmac100_txdes *txdes) +-{ +- /* +- * Make sure dma own bit will not be set before any other +- * descriptor fields. +- */ +- wmb(); +- txdes->txdes0 |= cpu_to_le32(FTMAC100_TXDES0_TXDMA_OWN); +-} ++ if (!irq) ++ spin_unlock(&priv->lock); ++ //exit spinloc + +-static bool ftmac100_txdes_excessive_collision(struct ftmac100_txdes *txdes) +-{ +- return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_EXSCOL); ++ priv->old_tx = entry; ++ netif_wake_queue (dev); + } ++#endif + +-static bool ftmac100_txdes_late_collision(struct ftmac100_txdes *txdes) +-{ +- return txdes->txdes0 & cpu_to_le32(FTMAC100_TXDES0_TXPKT_LATECOL); +-} ++/* ++ . ++ . This is the main routine of the driver, to handle the net_device when ++ . it needs some attention. ++ . ++ . So: ++ . first, save state of the chipset ++ . branch off into routines to handle each case, and acknowledge ++ . each to the interrupt register ++ . and finally restore state. ++ . ++ */ + +-static void ftmac100_txdes_set_end_of_ring(struct ftmac100_txdes *txdes) +-{ +- txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_EDOTR); +-} ++#if FTMAC100_DEBUG > 2 + +-static void ftmac100_txdes_set_first_segment(struct ftmac100_txdes *txdes) ++static void dump_intc(void) + { +- txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_FTS); ++ printk( " INTC[0] IRQSRC=%08X,MASK=%08X,MOD=%08X,LEV=%08X,STAT=%08X\n", ++ *((volatile unsigned*)(INTC_FTINTC010_VA_BASE+0)), ++ *((volatile unsigned*)(INTC_FTINTC010_VA_BASE+0x4)), ++ *((volatile unsigned*)(INTC_FTINTC010_VA_BASE+0xc)), ++ *((volatile unsigned*)(INTC_FTINTC010_VA_BASE+0x10)), ++ *((volatile unsigned*)(INTC_FTINTC010_VA_BASE+0x14)) ); ++ printk( " INTC[1] IRQSRC=%08X,MASK=%08X,MOD=%08X,LEV=%08X,STAT=%08X\n", ++ *((volatile unsigned*)(INTC_FTINTC010_1_VA_BASE+0)), ++ *((volatile unsigned*)(INTC_FTINTC010_1_VA_BASE+0x4)), ++ *((volatile unsigned*)(INTC_FTINTC010_1_VA_BASE+0xc)), ++ *((volatile unsigned*)(INTC_FTINTC010_1_VA_BASE+0x10)), ++ *((volatile unsigned*)(INTC_FTINTC010_1_VA_BASE+0x14)) ); + } ++#else ++#define dump_intc() ++#endif + +-static void ftmac100_txdes_set_last_segment(struct ftmac100_txdes *txdes) ++#if FTMAC100_DEBUG > 2 ++static void show_intstatus(unsigned char status) + { +- txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_LTS); ++ static int count = 0; ++ if (status & PHYSTS_CHG_bit) ++ printk( "[%d]%s ", count, "PHYSTS_CHG" ); ++ if (status & AHB_ERR_bit) ++ printk( "[%d]%s ", count, "AHB_ERR" ); ++ if (status & RPKT_LOST_bit) ++ printk( "[%d]%s ", count, "RPKT_LOST" ); ++ if (status & RPKT_SAV_bit) ++ printk( "[%d]%s ", count, "RPKT_SAV" ); ++ if (status & XPKT_LOST_bit) ++ printk( "[%d]%s ", count, "XPKT_LOST" ); ++ if (status & XPKT_OK_bit) ++ printk( "[%d]%s ", count, "XPKT_OK" ); ++ if (status & NOTXBUF_bit) ++ printk( "[%d]%s ", count, "NOTXBUF" ); ++ if (status & XPKT_FINISH_bit) ++ printk( "[%d]%s ", count, "XPKT_FINISH" ); ++ if (status & NORXBUF_bit) ++ printk( "[%d]%s ", count, "NORXBUF" ); ++ if (status & RPKT_FINISH_bit) ++ printk( "[%d]%s ", count, "RPKT_FINISH" ); ++ if (status & ~(PHYSTS_CHG_bit | AHB_ERR_bit | RPKT_LOST_bit | RPKT_SAV_bit ++ | XPKT_LOST_bit | XPKT_OK_bit | NOTXBUF_bit | XPKT_FINISH_bit ++ | NORXBUF_bit | RPKT_FINISH_bit)) ++ printk( "[%d]%s ", count, "<Unknown>" ); ++ count++; + } ++#else ++#define show_intstatus(x) ++#endif ++ + +-static void ftmac100_txdes_set_txint(struct ftmac100_txdes *txdes) ++/* ++ * The interrupt handler ++ */ ++static irqreturn_t ftmac100_interrupt(int irq, void * dev_id) + { +- txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXIC); +-} ++ struct net_device *dev = dev_id; ++ unsigned int ioaddr = dev->base_addr; ++ unsigned status; // interrupt status ++ unsigned char mask; // interrupt mask ++ struct ftmac100_local *priv = (struct ftmac100_local *)netdev_priv(dev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock,flags); // Luke 08/18/2005 ins ++ PRINTK(KERN_INFO "+ftmac100_interrupt\n"); ++ dump_intc(); ++ ++ if (dev == NULL||priv == NULL) { ++ printk(KERN_WARNING "%s: irq %d for unknown device.\n", "ftmac100_interrupt", irq); ++ return IRQ_HANDLED; ++ } ++ ++ /* read the interrupt status register */ ++ mask = inl( ioaddr + IMR_REG ); ++ ++ /* read the status flag, and mask it */ ++ status = inl( ioaddr + ISR_REG ) & mask; ++ ++ show_intstatus(status); ++ ++ if ( status & RPKT_FINISH_bit ) ++ ftmac100_rcv(dev); ++ ++ if (status & NORXBUF_bit) { ++ //printk("<0x%x:NORXBUF>",status); ++ outl( mask & ~NORXBUF_bit, ioaddr + IMR_REG); ++ trans_busy = 1; ++ ++#if ENABLE_BOTTOM_HALF ++ priv->rcv_tq.sync = 0; ++ priv->rcv_tq.routine=ftmac100_rcv; ++ priv->rcv_tq.data = dev; ++ queue_task(&priv->rcv_tq, &tq_timer); ++ //queue_task(&priv->rcv_tq, &tq_immediate); ++#else ++ ftmac100_rcv( dev ); ++#endif ++ } ++ ++ if (status & AHB_ERR_bit) ++ printk("<0x%x:AHB_ERR>",status); ++ ++ if (status & XPKT_FINISH_bit) ++ printk( "[XPKT_FINISH]" ); ++ ++ /* ++ if (status & PHYSTS_CHG_bit) { ++ } ++ */ ++ if (status & XPKT_OK_bit) { ++#if ZERO_COPY ++ ftmac100_free_tx(dev,1); ++#endif ++ } ++ /* ++ if (status & NOTXBUF_bit) { ++ } ++ */ ++ ++ if (status & RPKT_LOST_bit) ++ priv->stats.rx_errors++; ++ ++ if (status & XPKT_LOST_bit) { ++#if ZERO_COPY ++ ftmac100_free_tx(dev,1); ++#endif ++ priv->stats.tx_errors++; ++ } ++ ++ PRINTK(KERN_INFO "+ftmac100_interrupt DONE\n"); ++ dump_intc(); ++ PRINTK(KERN_INFO "\n"); ++ spin_unlock_irqrestore(&priv->lock,flags); // Luke 08/18/2005 ins + +-static void ftmac100_txdes_set_buffer_size(struct ftmac100_txdes *txdes, +- unsigned int len) +-{ +- txdes->txdes1 |= cpu_to_le32(FTMAC100_TXDES1_TXBUF_SIZE(len)); ++ return IRQ_HANDLED; + } + +-static void ftmac100_txdes_set_dma_addr(struct ftmac100_txdes *txdes, +- dma_addr_t addr) +-{ +- txdes->txdes2 = cpu_to_le32(addr); +-} + +-static dma_addr_t ftmac100_txdes_get_dma_addr(struct ftmac100_txdes *txdes) +-{ +- return le32_to_cpu(txdes->txdes2); +-} + + /* +- * txdes3 is not used by hardware. We use it to keep track of socket buffer. +- * Since hardware does not touch it, we can skip cpu_to_le32()/le32_to_cpu(). ++ . ftmac100_rcv - receive a packet from the card ++ . ++ . There is ( at least ) a packet waiting to be read from ++ . chip-memory. ++ . ++ . o Read the status ++ . o If an error, record it ++ . o otherwise, read in the packet + */ +-static void ftmac100_txdes_set_skb(struct ftmac100_txdes *txdes, struct sk_buff *skb) +-{ +- txdes->txdes3 = (unsigned int)skb; +-} + +-static struct sk_buff *ftmac100_txdes_get_skb(struct ftmac100_txdes *txdes) ++static void ftmac100_rcv(void *devp) + { +- return (struct sk_buff *)txdes->txdes3; ++ struct net_device *dev=(struct net_device *)devp; ++ struct ftmac100_local *priv = (struct ftmac100_local *)netdev_priv(dev); ++ unsigned int ioaddr=dev->base_addr; ++ int packet_length; ++ int rcv_cnt; ++ volatile RX_DESC *cur_desc; ++ int cpy_length; ++ int cur_idx; ++ int seg_length; ++ int have_package; ++ int have_frs; ++ int start_idx; ++ ++ struct sk_buff * skb; ++ unsigned char * data; ++ ++ PRINTK("+ ftmac100_rcv\n"); ++ ++ start_idx = priv->rx_idx; ++ ++ for (rcv_cnt=0; rcv_cnt<8 ; ++rcv_cnt) { ++ packet_length = 0; ++ cur_idx = priv->rx_idx; ++ ++ have_package = 0; ++ have_frs = 0; ++ for (; (cur_desc = &priv->rx_descs[priv->rx_idx])->RXDMA_OWN==0; ) { ++ have_package = 1; ++ priv->rx_idx = (priv->rx_idx+1) & (RXDES_NUM-1); ++ if (cur_desc->FRS) { ++ have_frs = 1; ++ if (cur_desc->RX_ERR || cur_desc->CRC_ERR || cur_desc->FTL ++ || cur_desc->RUNT || cur_desc->RX_ODD_NB) { ++ priv->stats.rx_errors++; // error frame.... ++ break; ++ } ++ if (cur_desc->MULTICAST) ++ priv->stats.multicast++; ++ packet_length = cur_desc->ReceiveFrameLength; // normal frame ++ } ++ if ( cur_desc->LRS ) // packet's last frame ++ break; ++ } ++ if (have_package==0) ++ goto done; ++ if (have_frs == 0) ++ priv->stats.rx_over_errors++; ++ ++ if (packet_length>0) { ++ // Allocate enough memory for entire receive frame, to be safe ++ skb = dev_alloc_skb( packet_length + 2 ); ++ ++ if ( skb == NULL ) { ++ printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", dev->name); ++ priv->stats.rx_dropped++; ++ goto done; ++ } ++ ++ skb_reserve( skb, 2 ); /* 16 bit alignment */ ++ skb->dev = dev; ++ ++ data = skb_put( skb, packet_length ); ++ cpy_length = 0; ++ for (; cur_idx!=priv->rx_idx; cur_idx = (cur_idx+1) & (RXDES_NUM-1)) { ++ seg_length = min(packet_length - cpy_length, RX_BUF_SIZE); ++ memcpy(data+cpy_length, (char *)priv->rx_descs[cur_idx].VIR_RXBUF_BADR, seg_length); ++ cpy_length += seg_length; ++ } ++ ++ skb->protocol = eth_type_trans(skb, dev); ++ netif_rx(skb); ++ dev->last_rx = jiffies; ++ priv->stats.rx_packets++; ++ priv->stats.rx_bytes += skb->len; ++ } ++ } ++ ++done: ++ if (start_idx != priv->rx_idx) { ++ for (cur_idx = (start_idx+1)%RXDES_NUM; cur_idx != priv->rx_idx; cur_idx = (cur_idx+1)%RXDES_NUM) { ++ priv->rx_descs[cur_idx].RXDMA_OWN = 1; ++ } ++ priv->rx_descs[start_idx].RXDMA_OWN = 1; ++ } ++ if (trans_busy == 1) { ++ outl( priv->maccr_val, ioaddr + MACCR_REG ); ++ outl( inl(ioaddr + IMR_REG) | NORXBUF_bit, ioaddr + IMR_REG); ++ } ++ ++ PRINTK("+ ftmac100_rcv DONE\n"); ++ ++ return; + } + +-/****************************************************************************** +- * internal functions (transmit) +- *****************************************************************************/ +-static int ftmac100_next_tx_pointer(int pointer) ++/* ++ . ftmac100_close ++ . ++ . this makes the board clean up everything that it can ++ . and not talk to the outside world. Caused by ++ . an 'ifconfig ethX down' ++ . ++ */ ++static int ftmac100_close(struct net_device *dev) + { +- return (pointer + 1) & (TX_QUEUE_ENTRIES - 1); +-} ++ //printk("+ftmac100_close\n"); + +-static void ftmac100_tx_pointer_advance(struct ftmac100 *priv) +-{ +- priv->tx_pointer = ftmac100_next_tx_pointer(priv->tx_pointer); ++ netif_stop_queue(dev); ++ ++ ftmac100_shutdown( dev->base_addr ); ++#if ZERO_COPY ++ ftmac100_free_tx(dev,0); ++#endif ++ return 0; + } + +-static void ftmac100_tx_clean_pointer_advance(struct ftmac100 *priv) ++/* ++ . Get the current statistics. ++ . This may be called with the card open or closed. ++ */ ++static struct net_device_stats* ftmac100_query_statistics(struct net_device *dev) + { +- priv->tx_clean_pointer = ftmac100_next_tx_pointer(priv->tx_clean_pointer); +-} ++ struct ftmac100_local *priv = (struct ftmac100_local *)netdev_priv(dev); + +-static struct ftmac100_txdes *ftmac100_current_txdes(struct ftmac100 *priv) +-{ +- return &priv->descs->txdes[priv->tx_pointer]; +-} ++ PRINTK("+ftmac100_query_statistics\n"); + +-static struct ftmac100_txdes *ftmac100_current_clean_txdes(struct ftmac100 *priv) +-{ +- return &priv->descs->txdes[priv->tx_clean_pointer]; ++ return &priv->stats; + } + +-static bool ftmac100_tx_complete_packet(struct ftmac100 *priv) +-{ +- struct net_device *netdev = priv->netdev; +- struct ftmac100_txdes *txdes; +- struct sk_buff *skb; +- dma_addr_t map; +- +- if (priv->tx_pending == 0) +- return false; + +- txdes = ftmac100_current_clean_txdes(priv); +- +- if (ftmac100_txdes_owned_by_dma(txdes)) +- return false; +- +- skb = ftmac100_txdes_get_skb(txdes); +- map = ftmac100_txdes_get_dma_addr(txdes); +- +- if (unlikely(ftmac100_txdes_excessive_collision(txdes) || +- ftmac100_txdes_late_collision(txdes))) { +- /* +- * packet transmitted to ethernet lost due to late collision +- * or excessive collision +- */ +- netdev->stats.tx_aborted_errors++; +- } else { +- netdev->stats.tx_packets++; +- netdev->stats.tx_bytes += skb->len; +- } ++#ifdef HAVE_MULTICAST + +- dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE); +- dev_kfree_skb(skb); +- +- ftmac100_txdes_reset(txdes); +- +- ftmac100_tx_clean_pointer_advance(priv); +- +- spin_lock(&priv->tx_lock); +- priv->tx_pending--; +- spin_unlock(&priv->tx_lock); +- netif_wake_queue(netdev); +- +- return true; +-} ++/* ++ . Function: ftmac100_setmulticast( unsigned int ioaddr, int count, dev_mc_list * adds ) ++ . Purpose: ++ . This sets the internal hardware table to filter out unwanted multicast ++ . packets before they take up memory. ++ */ + +-static void ftmac100_tx_complete(struct ftmac100 *priv) ++static void ftmac100_setmulticast( unsigned int ioaddr, int count, struct dev_mc_list * addrs ) + { +- while (ftmac100_tx_complete_packet(priv)) +- ; ++ struct dev_mc_list * cur_addr; ++ int crc_val; ++ ++ //printk("+ftmac100_setmulticast\n"); ++ ++ for (cur_addr = addrs ; cur_addr!=NULL ; cur_addr = cur_addr->next ) { ++ if ( !( *cur_addr->dmi_addr & 1 ) ) ++ continue; ++ crc_val = crc32( cur_addr->dmi_addr, 6 ); ++ crc_val = (crc_val>>26)&0x3f; // ¨ú MSB 6 bit ++ if (crc_val >= 32) ++ outl(inl(ioaddr+MAHT1_REG) | (1UL<<(crc_val-32)), ioaddr+MAHT1_REG); ++ else ++ outl(inl(ioaddr+MAHT0_REG) | (1UL<<crc_val), ioaddr+MAHT0_REG); ++ } + } + +-static int ftmac100_xmit(struct ftmac100 *priv, struct sk_buff *skb, +- dma_addr_t map) +-{ +- struct net_device *netdev = priv->netdev; +- struct ftmac100_txdes *txdes; +- unsigned int len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; +- +- txdes = ftmac100_current_txdes(priv); +- ftmac100_tx_pointer_advance(priv); +- +- /* setup TX descriptor */ +- ftmac100_txdes_set_skb(txdes, skb); +- ftmac100_txdes_set_dma_addr(txdes, map); +- +- ftmac100_txdes_set_first_segment(txdes); +- ftmac100_txdes_set_last_segment(txdes); +- ftmac100_txdes_set_txint(txdes); +- ftmac100_txdes_set_buffer_size(txdes, len); + +- spin_lock(&priv->tx_lock); +- priv->tx_pending++; +- if (priv->tx_pending == TX_QUEUE_ENTRIES) +- netif_stop_queue(netdev); +- +- /* start transmit */ +- ftmac100_txdes_set_dma_own(txdes); +- spin_unlock(&priv->tx_lock); ++/* ++ . ftmac100_set_multicast_list ++ . ++ . This routine will, depending on the values passed to it, ++ . either make it accept multicast packets, go into ++ . promiscuous mode ( for TCPDUMP and cousins ) or accept ++ . a select set of multicast packets ++*/ ++static void ftmac100_set_multicast_list(struct net_device *dev) ++{ ++ unsigned int ioaddr = dev->base_addr; ++ struct ftmac100_local *priv = (struct ftmac100_local *)netdev_priv(dev); ++ ++ //printk("+ftmac100_set_multicast_list\n"); ++ ++ if (dev->flags & IFF_PROMISC) ++ priv->maccr_val |= RCV_ALL_bit; ++ else ++ priv->maccr_val &= ~RCV_ALL_bit; ++ ++ if ( !(dev->flags & IFF_ALLMULTI) ) ++ priv->maccr_val |= RX_MULTIPKT_bit; ++ else ++ priv->maccr_val &= ~RX_MULTIPKT_bit; ++ ++ if (dev->mc_count) { ++ priv->maccr_val |= HT_MULTI_EN_bit; ++ ftmac100_setmulticast( ioaddr, dev->mc_count, dev->mc_list ); ++ } ++ else ++ priv->maccr_val &= ~HT_MULTI_EN_bit; + +- ftmac100_txdma_start_polling(priv); +- return NETDEV_TX_OK; ++ outl( priv->maccr_val, ioaddr + MACCR_REG ); + } ++#endif + +-/****************************************************************************** +- * internal functions (buffer) +- *****************************************************************************/ +-static int ftmac100_alloc_rx_page(struct ftmac100 *priv, +- struct ftmac100_rxdes *rxdes, gfp_t gfp) +-{ +- struct net_device *netdev = priv->netdev; +- struct page *page; +- dma_addr_t map; +- +- page = alloc_page(gfp); +- if (!page) { +- if (net_ratelimit()) +- netdev_err(netdev, "failed to allocate rx page\n"); +- return -ENOMEM; +- } +- +- map = dma_map_page(priv->dev, page, 0, RX_BUF_SIZE, DMA_FROM_DEVICE); +- if (unlikely(dma_mapping_error(priv->dev, map))) { +- if (net_ratelimit()) +- netdev_err(netdev, "failed to map rx page\n"); +- __free_page(page); +- return -ENOMEM; +- } +- +- ftmac100_rxdes_set_page(rxdes, page); +- ftmac100_rxdes_set_dma_addr(rxdes, map); +- ftmac100_rxdes_set_buffer_size(rxdes, RX_BUF_SIZE); +- ftmac100_rxdes_set_dma_own(rxdes); +- return 0; +-} ++/* ++ * Module initialization function ++ */ + +-static void ftmac100_free_buffers(struct ftmac100 *priv) ++static int ftmac100_probe(struct platform_device *pdev) + { +- int i; ++ int result,thisresult; ++ struct net_device *dev; ++ struct resource *iores; + +- for (i = 0; i < RX_QUEUE_ENTRIES; i++) { +- struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i]; +- struct page *page = ftmac100_rxdes_get_page(rxdes); +- dma_addr_t map = ftmac100_rxdes_get_dma_addr(rxdes); ++ PRINTK("+init_module\n"); + +- if (!page) +- continue; ++ result = -ENODEV; + +- dma_unmap_page(priv->dev, map, RX_BUF_SIZE, DMA_FROM_DEVICE); +- __free_page(page); ++ dev = alloc_etherdev(sizeof(struct ftmac100_local)); ++ if (!dev) { ++ printk(KERN_ERR "Fail allocating ethernet device"); ++ return -ENODEV; + } +- +- for (i = 0; i < TX_QUEUE_ENTRIES; i++) { +- struct ftmac100_txdes *txdes = &priv->descs->txdes[i]; +- struct sk_buff *skb = ftmac100_txdes_get_skb(txdes); +- dma_addr_t map = ftmac100_txdes_get_dma_addr(txdes); +- +- if (!skb) +- continue; +- +- dma_unmap_single(priv->dev, map, skb_headlen(skb), DMA_TO_DEVICE); +- dev_kfree_skb(skb); ++ iores = platform_get_resource(pdev, IORESOURCE_IO, 0); ++ /* Copy the parameters from the platform specification */ ++ dev->base_addr = iores->start; ++ dev->irq = platform_get_irq(pdev, 0); ++ dev->netdev_ops = &ftmac100_ops; ++ ++ //dev->dma = nowait; // Use DMA field for nowait ++ /* Setup initial mac address */ ++ auto_get_mac(pdev->id,dev->dev_addr); ++ ++ if ((thisresult = register_netdev(dev)) != 0) { ++ free_irq( dev->irq, dev ); ++ free_netdev(dev); ++ } else { ++ platform_set_drvdata(pdev, dev); + } ++ if (thisresult == 0) // any of the devices initialized, run ++ result = 0; + +- dma_free_coherent(priv->dev, sizeof(struct ftmac100_descs), +- priv->descs, priv->descs_dma_addr); ++ return result; + } + +-static int ftmac100_alloc_buffers(struct ftmac100 *priv) +-{ +- int i; +- +- priv->descs = dma_alloc_coherent(priv->dev, sizeof(struct ftmac100_descs), +- &priv->descs_dma_addr, GFP_KERNEL); +- if (!priv->descs) +- return -ENOMEM; +- +- memset(priv->descs, 0, sizeof(struct ftmac100_descs)); +- +- /* initialize RX ring */ +- ftmac100_rxdes_set_end_of_ring(&priv->descs->rxdes[RX_QUEUE_ENTRIES - 1]); +- +- for (i = 0; i < RX_QUEUE_ENTRIES; i++) { +- struct ftmac100_rxdes *rxdes = &priv->descs->rxdes[i]; +- +- if (ftmac100_alloc_rx_page(priv, rxdes, GFP_KERNEL)) +- goto err; +- } +- +- /* initialize TX ring */ +- ftmac100_txdes_set_end_of_ring(&priv->descs->txdes[TX_QUEUE_ENTRIES - 1]); +- return 0; +- +-err: +- ftmac100_free_buffers(priv); +- return -ENOMEM; +-} + +-/****************************************************************************** +- * struct mii_if_info functions +- *****************************************************************************/ +-static int ftmac100_mdio_read(struct net_device *netdev, int phy_id, int reg) ++/* ++ * Cleanup when module is removed with rmmod ++ */ ++ ++static int ftmac100_remove(struct platform_device *pdev) + { +- struct ftmac100 *priv = netdev_priv(netdev); +- unsigned int phycr; +- int i; +- +- phycr = FTMAC100_PHYCR_PHYAD(phy_id) | +- FTMAC100_PHYCR_REGAD(reg) | +- FTMAC100_PHYCR_MIIRD; +- +- iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR); +- +- for (i = 0; i < 10; i++) { +- phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR); +- +- if ((phycr & FTMAC100_PHYCR_MIIRD) == 0) +- return phycr & FTMAC100_PHYCR_MIIRDATA; +- +- udelay(100); +- } +- +- netdev_err(netdev, "mdio read timed out\n"); ++ struct net_device *dev; ++ struct ftmac100_local *priv; ++ PRINTK("+cleanup_module\n"); ++ ++ dev = platform_get_drvdata(pdev); ++ ++ priv = (struct ftmac100_local *)netdev_priv(dev); ++ if (priv->rx_descs) ++ dma_free_coherent( NULL, sizeof(RX_DESC)*RXDES_NUM, (void*)priv->rx_descs, (dma_addr_t)priv->rx_descs_dma ); ++ if (priv->rx_buf) ++ dma_free_coherent( NULL, RX_BUF_SIZE*RXDES_NUM, (void*)priv->rx_buf, (dma_addr_t)priv->rx_buf_dma ); ++ if (priv->tx_descs) ++ dma_free_coherent( NULL, sizeof(TX_DESC)*TXDES_NUM, (void*)priv->tx_descs, (dma_addr_t)priv->tx_descs_dma ); ++ if (priv->tx_buf) ++ dma_free_coherent( NULL, TX_BUF_SIZE*TXDES_NUM, (void*)priv->tx_buf, (dma_addr_t)priv->tx_buf_dma ); ++ priv->rx_descs = NULL; priv->rx_descs_dma = 0; ++ priv->rx_buf = NULL; priv->rx_buf_dma = 0; ++ priv->tx_descs = NULL; priv->tx_descs_dma = 0; ++ priv->tx_buf = NULL; priv->tx_buf_dma = 0; ++ ++ /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ ++ unregister_netdev(dev); ++ ++ free_irq(dev->irq, dev); ++ //TODO: where is the request_region ? ++ //release_region(devFMAC.base_addr, SMC_IO_EXTENT); ++ free_netdev(dev); + return 0; + } + +-static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg, +- int data) +-{ +- struct ftmac100 *priv = netdev_priv(netdev); +- unsigned int phycr; +- int i; +- +- phycr = FTMAC100_PHYCR_PHYAD(phy_id) | +- FTMAC100_PHYCR_REGAD(reg) | +- FTMAC100_PHYCR_MIIWR; +- +- data = FTMAC100_PHYWDATA_MIIWDATA(data); +- +- iowrite32(data, priv->base + FTMAC100_OFFSET_PHYWDATA); +- iowrite32(phycr, priv->base + FTMAC100_OFFSET_PHYCR); +- +- for (i = 0; i < 10; i++) { +- phycr = ioread32(priv->base + FTMAC100_OFFSET_PHYCR); +- +- if ((phycr & FTMAC100_PHYCR_MIIWR) == 0) +- return; +- +- udelay(100); +- } +- +- netdev_err(netdev, "mdio write timed out\n"); +-} +- +-/****************************************************************************** +- * struct ethtool_ops functions +- *****************************************************************************/ +-static void ftmac100_get_drvinfo(struct net_device *netdev, +- struct ethtool_drvinfo *info) +-{ +- strcpy(info->driver, DRV_NAME); +- strcpy(info->version, DRV_VERSION); +- strcpy(info->bus_info, dev_name(&netdev->dev)); +-} +- +-static int ftmac100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +-{ +- struct ftmac100 *priv = netdev_priv(netdev); +- return mii_ethtool_gset(&priv->mii, cmd); +-} +- +-static int ftmac100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd) +-{ +- struct ftmac100 *priv = netdev_priv(netdev); +- return mii_ethtool_sset(&priv->mii, cmd); +-} +- +-static int ftmac100_nway_reset(struct net_device *netdev) ++static int ftmac100_suspend(struct platform_device *pdev, pm_message_t state) + { +- struct ftmac100 *priv = netdev_priv(netdev); +- return mii_nway_restart(&priv->mii); +-} +- +-static u32 ftmac100_get_link(struct net_device *netdev) +-{ +- struct ftmac100 *priv = netdev_priv(netdev); +- return mii_link_ok(&priv->mii); +-} +- +-static const struct ethtool_ops ftmac100_ethtool_ops = { +- .set_settings = ftmac100_set_settings, +- .get_settings = ftmac100_get_settings, +- .get_drvinfo = ftmac100_get_drvinfo, +- .nway_reset = ftmac100_nway_reset, +- .get_link = ftmac100_get_link, +-}; +- +-/****************************************************************************** +- * interrupt handler +- *****************************************************************************/ +-static irqreturn_t ftmac100_interrupt(int irq, void *dev_id) +-{ +- struct net_device *netdev = dev_id; +- struct ftmac100 *priv = netdev_priv(netdev); +- +- if (likely(netif_running(netdev))) { +- /* Disable interrupts for polling */ +- ftmac100_disable_all_int(priv); +- napi_schedule(&priv->napi); +- } +- +- return IRQ_HANDLED; +-} +- +-/****************************************************************************** +- * struct napi_struct functions +- *****************************************************************************/ +-static int ftmac100_poll(struct napi_struct *napi, int budget) +-{ +- struct ftmac100 *priv = container_of(napi, struct ftmac100, napi); +- struct net_device *netdev = priv->netdev; +- unsigned int status; +- bool completed = true; +- int rx = 0; +- +- status = ioread32(priv->base + FTMAC100_OFFSET_ISR); +- +- if (status & (FTMAC100_INT_RPKT_FINISH | FTMAC100_INT_NORXBUF)) { +- /* +- * FTMAC100_INT_RPKT_FINISH: +- * RX DMA has received packets into RX buffer successfully +- * +- * FTMAC100_INT_NORXBUF: +- * RX buffer unavailable +- */ +- bool retry; +- +- do { +- retry = ftmac100_rx_packet(priv, &rx); +- } while (retry && rx < budget); ++ struct net_device *ndev = platform_get_drvdata(pdev); + +- if (retry && rx == budget) +- completed = false; +- } +- +- if (status & (FTMAC100_INT_XPKT_OK | FTMAC100_INT_XPKT_LOST)) { +- /* +- * FTMAC100_INT_XPKT_OK: +- * packet transmitted to ethernet successfully +- * +- * FTMAC100_INT_XPKT_LOST: +- * packet transmitted to ethernet lost due to late +- * collision or excessive collision +- */ +- ftmac100_tx_complete(priv); +- } +- +- if (status & (FTMAC100_INT_NORXBUF | FTMAC100_INT_RPKT_LOST | +- FTMAC100_INT_AHB_ERR | FTMAC100_INT_PHYSTS_CHG)) { +- if (net_ratelimit()) +- netdev_info(netdev, "[ISR] = 0x%x: %s%s%s%s\n", status, +- status & FTMAC100_INT_NORXBUF ? "NORXBUF " : "", +- status & FTMAC100_INT_RPKT_LOST ? "RPKT_LOST " : "", +- status & FTMAC100_INT_AHB_ERR ? "AHB_ERR " : "", +- status & FTMAC100_INT_PHYSTS_CHG ? "PHYSTS_CHG" : ""); +- +- if (status & FTMAC100_INT_NORXBUF) { +- /* RX buffer unavailable */ +- netdev->stats.rx_over_errors++; +- } +- +- if (status & FTMAC100_INT_RPKT_LOST) { +- /* received packet lost due to RX FIFO full */ +- netdev->stats.rx_fifo_errors++; +- } +- +- if (status & FTMAC100_INT_PHYSTS_CHG) { +- /* PHY link status change */ +- mii_check_link(&priv->mii); ++ if (ndev) { ++ if (netif_running(ndev)) { ++ netif_device_detach(ndev); ++ ftmac100_shutdown(ndev->base_addr); + } + } +- +- if (completed) { +- /* stop polling */ +- napi_complete(napi); +- ftmac100_enable_all_int(priv); +- } +- +- return rx; +-} +- +-/****************************************************************************** +- * struct net_device_ops functions +- *****************************************************************************/ +-static int ftmac100_open(struct net_device *netdev) +-{ +- struct ftmac100 *priv = netdev_priv(netdev); +- int err; +- +- err = ftmac100_alloc_buffers(priv); +- if (err) { +- netdev_err(netdev, "failed to allocate buffers\n"); +- goto err_alloc; +- } +- +- err = request_irq(priv->irq, ftmac100_interrupt, 0, netdev->name, netdev); +- if (err) { +- netdev_err(netdev, "failed to request irq %d\n", priv->irq); +- goto err_irq; +- } +- +- priv->rx_pointer = 0; +- priv->tx_clean_pointer = 0; +- priv->tx_pointer = 0; +- priv->tx_pending = 0; +- +- err = ftmac100_start_hw(priv); +- if (err) +- goto err_hw; +- +- napi_enable(&priv->napi); +- netif_start_queue(netdev); +- +- ftmac100_enable_all_int(priv); +- +- return 0; +- +-err_hw: +- free_irq(priv->irq, netdev); +-err_irq: +- ftmac100_free_buffers(priv); +-err_alloc: +- return err; +-} +- +-static int ftmac100_stop(struct net_device *netdev) +-{ +- struct ftmac100 *priv = netdev_priv(netdev); +- +- ftmac100_disable_all_int(priv); +- netif_stop_queue(netdev); +- napi_disable(&priv->napi); +- ftmac100_stop_hw(priv); +- free_irq(priv->irq, netdev); +- ftmac100_free_buffers(priv); +- + return 0; + } + +-static int ftmac100_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev) ++static int ftmac100_resume(struct platform_device *pdev) + { +- struct ftmac100 *priv = netdev_priv(netdev); +- dma_addr_t map; +- +- if (unlikely(skb->len > MAX_PKT_SIZE)) { +- if (net_ratelimit()) +- netdev_dbg(netdev, "tx packet too big\n"); +- +- netdev->stats.tx_dropped++; +- dev_kfree_skb(skb); +- return NETDEV_TX_OK; +- } ++ struct net_device *ndev = platform_get_drvdata(pdev); + +- map = dma_map_single(priv->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE); +- if (unlikely(dma_mapping_error(priv->dev, map))) { +- /* drop packet */ +- if (net_ratelimit()) +- netdev_err(netdev, "map socket buffer failed\n"); +- +- netdev->stats.tx_dropped++; +- dev_kfree_skb(skb); +- return NETDEV_TX_OK; ++ if (ndev) { ++ if (netif_running(ndev)) { ++ ftmac100_reset(ndev); ++ ftmac100_enable(ndev); ++ netif_device_attach(ndev); ++ } + } +- +- return ftmac100_xmit(priv, skb, map); ++ return 0; + } + +-/* optional */ +-static int ftmac100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +-{ +- struct ftmac100 *priv = netdev_priv(netdev); +- struct mii_ioctl_data *data = if_mii(ifr); +- +- return generic_mii_ioctl(&priv->mii, data, cmd, NULL); ++static void platform_device_release(struct device *dev){ + } + +-static const struct net_device_ops ftmac100_netdev_ops = { +- .ndo_open = ftmac100_open, +- .ndo_stop = ftmac100_stop, +- .ndo_start_xmit = ftmac100_hard_start_xmit, +- .ndo_set_mac_address = eth_mac_addr, +- .ndo_validate_addr = eth_validate_addr, +- .ndo_do_ioctl = ftmac100_do_ioctl, ++static struct platform_driver ftmac100_driver = { ++ .probe = ftmac100_probe, ++ .remove = ftmac100_remove, ++ .suspend = ftmac100_suspend, ++ .resume = ftmac100_resume, ++ .driver = { ++ .name = "ftmac100", ++ }, + }; + +-/****************************************************************************** +- * struct platform_driver functions +- *****************************************************************************/ +-static int ftmac100_probe(struct platform_device *pdev) +-{ +- struct resource *res; +- int irq; +- struct net_device *netdev; +- struct ftmac100 *priv; +- int err; +- +- if (!pdev) +- return -ENODEV; +- +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- if (!res) +- return -ENXIO; +- +- irq = platform_get_irq(pdev, 0); +- if (irq < 0) +- return irq; +- +- /* setup net_device */ +- netdev = alloc_etherdev(sizeof(*priv)); +- if (!netdev) { +- err = -ENOMEM; +- goto err_alloc_etherdev; +- } +- +- SET_NETDEV_DEV(netdev, &pdev->dev); +- SET_ETHTOOL_OPS(netdev, &ftmac100_ethtool_ops); +- netdev->netdev_ops = &ftmac100_netdev_ops; +- +- platform_set_drvdata(pdev, netdev); +- +- /* setup private data */ +- priv = netdev_priv(netdev); +- priv->netdev = netdev; +- priv->dev = &pdev->dev; +- +- spin_lock_init(&priv->tx_lock); +- +- /* initialize NAPI */ +- netif_napi_add(netdev, &priv->napi, ftmac100_poll, 64); +- +- /* map io memory */ +- priv->res = request_mem_region(res->start, resource_size(res), +- dev_name(&pdev->dev)); +- if (!priv->res) { +- dev_err(&pdev->dev, "Could not reserve memory region\n"); +- err = -ENOMEM; +- goto err_req_mem; +- } +- +- priv->base = ioremap(res->start, resource_size(res)); +- if (!priv->base) { +- dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n"); +- err = -EIO; +- goto err_ioremap; +- } +- +- priv->irq = irq; +- +- /* initialize struct mii_if_info */ +- priv->mii.phy_id = 0; +- priv->mii.phy_id_mask = 0x1f; +- priv->mii.reg_num_mask = 0x1f; +- priv->mii.dev = netdev; +- priv->mii.mdio_read = ftmac100_mdio_read; +- priv->mii.mdio_write = ftmac100_mdio_write; +- +- /* register network device */ +- err = register_netdev(netdev); +- if (err) { +- dev_err(&pdev->dev, "Failed to register netdev\n"); +- goto err_register_netdev; +- } +- +- netdev_info(netdev, "irq %d, mapped at %p\n", priv->irq, priv->base); +- +- if (!is_valid_ether_addr(netdev->dev_addr)) { +- eth_hw_addr_random(netdev); +- netdev_info(netdev, "generated random MAC address %pM\n", +- netdev->dev_addr); +- } +- +- return 0; +- +-err_register_netdev: +- iounmap(priv->base); +-err_ioremap: +- release_resource(priv->res); +-err_req_mem: +- netif_napi_del(&priv->napi); +- platform_set_drvdata(pdev, NULL); +- free_netdev(netdev); +-err_alloc_etherdev: +- return err; +-} +- +-static int __exit ftmac100_remove(struct platform_device *pdev) +-{ +- struct net_device *netdev; +- struct ftmac100 *priv; +- +- netdev = platform_get_drvdata(pdev); +- priv = netdev_priv(netdev); +- +- unregister_netdev(netdev); +- +- iounmap(priv->base); +- release_resource(priv->res); +- +- netif_napi_del(&priv->napi); +- platform_set_drvdata(pdev, NULL); +- free_netdev(netdev); +- return 0; +-} ++static struct resource ftmac100_resources_a320[] = { ++ [0] = { ++ .start = MAC_FTMAC100_0_VA_BASE, ++ .end = MAC_FTMAC100_0_VA_LIMIT, ++ .flags = IORESOURCE_IO, ++ }, ++ [1] = { ++ .start = MAC_FTMAC100_0_IRQ, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; + +-static struct platform_driver ftmac100_driver = { +- .probe = ftmac100_probe, +- .remove = __exit_p(ftmac100_remove), +- .driver = { +- .name = DRV_NAME, +- .owner = THIS_MODULE, ++static struct platform_device ftmac100_device_a320 = { ++ .name = "ftmac100", ++ .id = 0, ++ .num_resources = ARRAY_SIZE(ftmac100_resources_a320), ++ .resource = ftmac100_resources_a320, ++ .dev = { ++ .release = platform_device_release, + }, + }; + +-/****************************************************************************** +- * initialization / finalization +- *****************************************************************************/ ++ + static int __init ftmac100_init(void) + { +- pr_info("Loading version " DRV_VERSION " ...\n"); ++ platform_device_register(&ftmac100_device_a320); + return platform_driver_register(&ftmac100_driver); + } + + static void __exit ftmac100_exit(void) + { + platform_driver_unregister(&ftmac100_driver); ++ platform_device_unregister(&ftmac100_device_a320); + } + + module_init(ftmac100_init); + module_exit(ftmac100_exit); +- +-MODULE_AUTHOR("Po-Yu Chuang <ratbert@faraday-tech.com>"); +-MODULE_DESCRIPTION("FTMAC100 driver"); +-MODULE_LICENSE("GPL"); +diff -Nur linux-3.4.110.orig/drivers/net/ethernet/faraday/ftmac100.h linux-3.4.110/drivers/net/ethernet/faraday/ftmac100.h +--- linux-3.4.110.orig/drivers/net/ethernet/faraday/ftmac100.h 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/net/ethernet/faraday/ftmac100.h 2016-04-07 10:20:51.054085357 +0200 +@@ -1,180 +1,267 @@ + /* +- * Faraday FTMAC100 10/100 Ethernet ++ * drivers/net/ftmac100.h + * +- * (C) Copyright 2009-2011 Faraday Technology +- * Po-Yu Chuang <ratbert@faraday-tech.com> ++ * Faraday FTMAC100 Device 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. ++ * Copyright (C) 2005 Faraday Corp. (http://www.faraday-tech.com) ++ * ++ * All Rights Reserved + * +- * 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., 675 Mass Ave, Cambridge, MA 02139, USA. +- */ +- +-#ifndef __FTMAC100_H +-#define __FTMAC100_H +- +-#define FTMAC100_OFFSET_ISR 0x00 +-#define FTMAC100_OFFSET_IMR 0x04 +-#define FTMAC100_OFFSET_MAC_MADR 0x08 +-#define FTMAC100_OFFSET_MAC_LADR 0x0c +-#define FTMAC100_OFFSET_MAHT0 0x10 +-#define FTMAC100_OFFSET_MAHT1 0x14 +-#define FTMAC100_OFFSET_TXPD 0x18 +-#define FTMAC100_OFFSET_RXPD 0x1c +-#define FTMAC100_OFFSET_TXR_BADR 0x20 +-#define FTMAC100_OFFSET_RXR_BADR 0x24 +-#define FTMAC100_OFFSET_ITC 0x28 +-#define FTMAC100_OFFSET_APTC 0x2c +-#define FTMAC100_OFFSET_DBLAC 0x30 +-#define FTMAC100_OFFSET_MACCR 0x88 +-#define FTMAC100_OFFSET_MACSR 0x8c +-#define FTMAC100_OFFSET_PHYCR 0x90 +-#define FTMAC100_OFFSET_PHYWDATA 0x94 +-#define FTMAC100_OFFSET_FCR 0x98 +-#define FTMAC100_OFFSET_BPR 0x9c +-#define FTMAC100_OFFSET_TS 0xc4 +-#define FTMAC100_OFFSET_DMAFIFOS 0xc8 +-#define FTMAC100_OFFSET_TM 0xcc +-#define FTMAC100_OFFSET_TX_MCOL_SCOL 0xd4 +-#define FTMAC100_OFFSET_RPF_AEP 0xd8 +-#define FTMAC100_OFFSET_XM_PG 0xdc +-#define FTMAC100_OFFSET_RUNT_TLCC 0xe0 +-#define FTMAC100_OFFSET_CRCER_FTL 0xe4 +-#define FTMAC100_OFFSET_RLC_RCC 0xe8 +-#define FTMAC100_OFFSET_BROC 0xec +-#define FTMAC100_OFFSET_MULCA 0xf0 +-#define FTMAC100_OFFSET_RP 0xf4 +-#define FTMAC100_OFFSET_XP 0xf8 +- +-/* +- * Interrupt status register & interrupt mask register +- */ +-#define FTMAC100_INT_RPKT_FINISH (1 << 0) +-#define FTMAC100_INT_NORXBUF (1 << 1) +-#define FTMAC100_INT_XPKT_FINISH (1 << 2) +-#define FTMAC100_INT_NOTXBUF (1 << 3) +-#define FTMAC100_INT_XPKT_OK (1 << 4) +-#define FTMAC100_INT_XPKT_LOST (1 << 5) +-#define FTMAC100_INT_RPKT_SAV (1 << 6) +-#define FTMAC100_INT_RPKT_LOST (1 << 7) +-#define FTMAC100_INT_AHB_ERR (1 << 8) +-#define FTMAC100_INT_PHYSTS_CHG (1 << 9) +- +-/* +- * Interrupt timer control register + */ +-#define FTMAC100_ITC_RXINT_CNT(x) (((x) & 0xf) << 0) +-#define FTMAC100_ITC_RXINT_THR(x) (((x) & 0x7) << 4) +-#define FTMAC100_ITC_RXINT_TIME_SEL (1 << 7) +-#define FTMAC100_ITC_TXINT_CNT(x) (((x) & 0xf) << 8) +-#define FTMAC100_ITC_TXINT_THR(x) (((x) & 0x7) << 12) +-#define FTMAC100_ITC_TXINT_TIME_SEL (1 << 15) + +-/* +- * Automatic polling timer control register +- */ +-#define FTMAC100_APTC_RXPOLL_CNT(x) (((x) & 0xf) << 0) +-#define FTMAC100_APTC_RXPOLL_TIME_SEL (1 << 4) +-#define FTMAC100_APTC_TXPOLL_CNT(x) (((x) & 0xf) << 8) +-#define FTMAC100_APTC_TXPOLL_TIME_SEL (1 << 12) ++#ifndef _FTMAC100_H_ ++#define _FTMAC100_H_ + +-/* +- * DMA burst length and arbitration control register +- */ +-#define FTMAC100_DBLAC_INCR4_EN (1 << 0) +-#define FTMAC100_DBLAC_INCR8_EN (1 << 1) +-#define FTMAC100_DBLAC_INCR16_EN (1 << 2) +-#define FTMAC100_DBLAC_RXFIFO_LTHR(x) (((x) & 0x7) << 3) +-#define FTMAC100_DBLAC_RXFIFO_HTHR(x) (((x) & 0x7) << 6) +-#define FTMAC100_DBLAC_RX_THR_EN (1 << 9) ++#define ISR_REG 0x00 // interrups status register ++#define IMR_REG 0x04 // interrupt maks register ++#define MAC_MADR_REG 0x08 // MAC address (Most significant) ++#define MAC_LADR_REG 0x0c // MAC address (Least significant) ++ ++#define MAHT0_REG 0x10 // Multicast Address Hash Table 0 register ++#define MAHT1_REG 0x14 // Multicast Address Hash Table 1 register ++#define TXPD_REG 0x18 // Transmit Poll Demand register ++#define RXPD_REG 0x1c // Receive Poll Demand register ++#define TXR_BADR_REG 0x20 // Transmit Ring Base Address register ++#define RXR_BADR_REG 0x24 // Receive Ring Base Address register ++#define ITC_REG 0x28 // interrupt timer control register ++#define APTC_REG 0x2c // Automatic Polling Timer control register ++#define DBLAC_REG 0x30 // DMA Burst Length and Arbitration control register ++ ++ ++ ++#define MACCR_REG 0x88 // MAC control register ++#define MACSR_REG 0x8c // MAC status register ++#define PHYCR_REG 0x90 // PHY control register ++#define PHYWDATA_REG 0x94 // PHY Write Data register ++#define FCR_REG 0x98 // Flow Control register ++#define BPR_REG 0x9c // back pressure register ++#define WOLCR_REG 0xa0 // Wake-On-Lan control register ++#define WOLSR_REG 0xa4 // Wake-On-Lan status register ++#define WFCRC_REG 0xa8 // Wake-up Frame CRC register ++#define WFBM1_REG 0xb0 // wake-up frame byte mask 1st double word register ++#define WFBM2_REG 0xb4 // wake-up frame byte mask 2nd double word register ++#define WFBM3_REG 0xb8 // wake-up frame byte mask 3rd double word register ++#define WFBM4_REG 0xbc // wake-up frame byte mask 4th double word register ++#define TM_REG 0xcc // test mode register ++ ++#define PHYSTS_CHG_bit (1UL<<9) ++#define AHB_ERR_bit (1UL<<8) ++#define RPKT_LOST_bit (1UL<<7) ++#define RPKT_SAV_bit (1UL<<6) ++#define XPKT_LOST_bit (1UL<<5) ++#define XPKT_OK_bit (1UL<<4) ++#define NOTXBUF_bit (1UL<<3) ++#define XPKT_FINISH_bit (1UL<<2) ++#define NORXBUF_bit (1UL<<1) ++#define RPKT_FINISH_bit (1UL<<0) ++ ++ ++#ifdef __NDS32_EB__ ++typedef struct ++{ ++ unsigned int Reserved2:19; ++ unsigned int TXPOLL_TIME_SEL:1; ++ unsigned int TXPOLL_CNT:4; ++ unsigned int Reserved1:3; ++ unsigned int RXPOLL_TIME_SEL:1; ++ unsigned int RXPOLL_CNT:4; ++}FTMAC100_APTCR_Status; ++#else ++typedef struct ++{ ++ unsigned int RXPOLL_CNT:4; ++ unsigned int RXPOLL_TIME_SEL:1; ++ unsigned int Reserved1:3; ++ unsigned int TXPOLL_CNT:4; ++ unsigned int TXPOLL_TIME_SEL:1; ++ unsigned int Reserved2:19; ++} FTMAC100_APTCR_Status; ++#endif ++ ++#define RX_BROADPKT_bit (1UL<<17) // Receiving broadcast packet ++#define RX_MULTIPKT_bit (1UL<<16) // receiving multicast packet ++#define FULLDUP_bit (1UL<<15) // full duplex ++#define CRC_APD_bit (1UL<<14) // append crc to transmit packet ++#define MDC_SEL_bit (1UL<<13) // set MDC as TX_CK/10 ++#define RCV_ALL_bit (1UL<<12) // not check incoming packet's destination address ++#define RX_FTL_bit (1UL<<11) // Store incoming packet even its length is great than 1518 byte ++#define RX_RUNT_bit (1UL<<10) // Store incoming packet even its length is les than 64 byte ++#define HT_MULTI_EN_bit (1UL<<9) ++#define RCV_EN_bit (1UL<<8) // receiver enable ++#define XMT_EN_bit (1UL<<5) // transmitter enable ++#define CRC_DIS_bit (1UL<<4) ++#define LOOP_EN_bit (1UL<<3) // Internal loop-back ++#define SW_RST_bit (1UL<<2) // software reset/ ++#define RDMA_EN_bit (1UL<<1) // enable DMA receiving channel ++#define XDMA_EN_bit (1UL<<0) // enable DMA transmitting channel ++ ++ ++// -------------------------------------------------------------------- ++// Receive Ring descriptor structure ++// -------------------------------------------------------------------- ++#ifdef __NDS32_EB__ ++typedef struct ++{ ++ // RXDES0 ++ unsigned int RXDMA_OWN:1; // 1 ==> owned by FTMAC100, 0 ==> owned by software ++ unsigned int Reserved3:1; ++ unsigned int FRS:1; ++ unsigned int LRS:1; ++ unsigned int Reserved2:5; ++ unsigned int RX_ODD_NB:1; ++ unsigned int RUNT:1; ++ unsigned int FTL:1; ++ unsigned int CRC_ERR:1; //19 ++ unsigned int RX_ERR:1; //18 ++ unsigned int BROARDCAST:1; //17 ++ unsigned int MULTICAST:1; //16 ++ unsigned int Reserved1:5; //11~15 ++ unsigned int ReceiveFrameLength:11;//0~10 ++ ++ // RXDES1 ++ unsigned int EDOTR:1; ++ unsigned int Reserved:20; ++ unsigned int RXBUF_Size:11; ++ ++ // RXDES2 ++ unsigned int RXBUF_BADR; ++ ++ unsigned int VIR_RXBUF_BADR; // not defined, §ÚÌ®³¨Ó©ñ receive buffer ªº virtual address ++ ++}RX_DESC; ++ ++ ++typedef struct ++{ ++ // TXDES0 ++ unsigned int TXDMA_OWN:1; ++ unsigned int Reserved1:29; ++ unsigned int TXPKT_EXSCOL:1; ++ unsigned int TXPKT_LATECOL:1; ++ ++ // TXDES1 ++ unsigned int EDOTR:1; ++ unsigned int TXIC:1; ++ unsigned int TX2FIC:1; ++ unsigned int FTS:1; ++ unsigned int LTS:1; ++ unsigned int Reserved2:16; ++ unsigned int TXBUF_Size:11; ++ ++ // RXDES2 ++ unsigned int TXBUF_BADR; ++ unsigned int VIR_TXBUF_BADR; ++}TX_DESC; ++#else ++typedef struct ++{ ++ // RXDES0 ++ unsigned int ReceiveFrameLength:11;//0~10 ++ unsigned int Reserved1:5; //11~15 ++ unsigned int MULTICAST:1; //16 ++ unsigned int BROARDCAST:1; //17 ++ unsigned int RX_ERR:1; //18 ++ unsigned int CRC_ERR:1; //19 ++ unsigned int FTL:1; ++ unsigned int RUNT:1; ++ unsigned int RX_ODD_NB:1; ++ unsigned int Reserved2:5; ++ unsigned int LRS:1; ++ unsigned int FRS:1; ++ unsigned int Reserved3:1; ++ unsigned int RXDMA_OWN:1; // 1 ==> owned by FTMAC100, 0 ==> owned by software ++ ++ // RXDES1 ++ unsigned int RXBUF_Size:11; ++ unsigned int Reserved:20; ++ unsigned int EDOTR:1; ++ ++ // RXDES2 ++ unsigned int RXBUF_BADR; ++ ++ unsigned int VIR_RXBUF_BADR; // not defined, §ÚÌ®³¨Ó©ñ receive buffer ªº virtual address ++ ++} RX_DESC; ++ ++ ++typedef struct ++{ ++ // TXDES0 ++ unsigned int TXPKT_LATECOL:1; ++ unsigned int TXPKT_EXSCOL:1; ++ unsigned int Reserved1:29; ++ unsigned int TXDMA_OWN:1; ++ ++ // TXDES1 ++ unsigned int TXBUF_Size:11; ++ unsigned int Reserved2:16; ++ unsigned int LTS:1; ++ unsigned int FTS:1; ++ unsigned int TX2FIC:1; ++ unsigned int TXIC:1; ++ unsigned int EDOTR:1; ++ ++ // RXDES2 ++ unsigned int TXBUF_BADR; ++ unsigned int VIR_TXBUF_BADR; ++} TX_DESC; ++#endif ++ ++// waiting to do: ++#define TXPOLL_CNT 8 ++#define RXPOLL_CNT 0 ++ ++#define OWNBY_SOFTWARE 0 ++#define OWNBY_FTMAC100 1 ++ ++// -------------------------------------------------------------------- ++// driver related definition ++// -------------------------------------------------------------------- ++#define RXDES_NUM 256 // must be 2's power ++#define RX_BUF_SIZE 1536 ++#define TXDES_NUM 64 // must be 2's power ++#define TX_BUF_SIZE 1536 // Luke Lee : Just bigger than 1518 ++ ++ ++struct ftmac100_local ++{ ++ // these are things that the kernel wants me to keep, so users ++ // can find out semi-useless statistics of how well the card is ++ // performing ++ struct net_device_stats stats; ++ ++ // Set to true during the auto-negotiation sequence ++ int autoneg_active; ++ ++ // Address of our PHY port ++ unsigned int phyaddr; ++ ++ // Type of PHY ++ unsigned int phytype; ++ ++ // Last contents of PHY Register 18 ++ unsigned int lastPhy18; ++ ++ spinlock_t lock; ++ ++ volatile RX_DESC *rx_descs; // receive ring base address ++ unsigned int rx_descs_dma; // receive ring physical base address ++ char *rx_buf; // receive buffer cpu address ++ int rx_buf_dma; // receive buffer physical address ++ int rx_idx; // receive descriptor ++ //struct sk_buff *rx_skbuff[RXDES_NUM]; ++ ++ volatile TX_DESC *tx_descs; ++ unsigned int tx_descs_dma; ++ char *tx_buf; ++ int tx_buf_dma; ++ int tx_idx; ++ int old_tx; ++ struct sk_buff *tx_skbuff[RXDES_NUM]; ++ ++ int maccr_val; ++}; + +-/* +- * MAC control register +- */ +-#define FTMAC100_MACCR_XDMA_EN (1 << 0) +-#define FTMAC100_MACCR_RDMA_EN (1 << 1) +-#define FTMAC100_MACCR_SW_RST (1 << 2) +-#define FTMAC100_MACCR_LOOP_EN (1 << 3) +-#define FTMAC100_MACCR_CRC_DIS (1 << 4) +-#define FTMAC100_MACCR_XMT_EN (1 << 5) +-#define FTMAC100_MACCR_ENRX_IN_HALFTX (1 << 6) +-#define FTMAC100_MACCR_RCV_EN (1 << 8) +-#define FTMAC100_MACCR_HT_MULTI_EN (1 << 9) +-#define FTMAC100_MACCR_RX_RUNT (1 << 10) +-#define FTMAC100_MACCR_RX_FTL (1 << 11) +-#define FTMAC100_MACCR_RCV_ALL (1 << 12) +-#define FTMAC100_MACCR_CRC_APD (1 << 14) +-#define FTMAC100_MACCR_FULLDUP (1 << 15) +-#define FTMAC100_MACCR_RX_MULTIPKT (1 << 16) +-#define FTMAC100_MACCR_RX_BROADPKT (1 << 17) +- +-/* +- * PHY control register +- */ +-#define FTMAC100_PHYCR_MIIRDATA 0xffff +-#define FTMAC100_PHYCR_PHYAD(x) (((x) & 0x1f) << 16) +-#define FTMAC100_PHYCR_REGAD(x) (((x) & 0x1f) << 21) +-#define FTMAC100_PHYCR_MIIRD (1 << 26) +-#define FTMAC100_PHYCR_MIIWR (1 << 27) +- +-/* +- * PHY write data register +- */ +-#define FTMAC100_PHYWDATA_MIIWDATA(x) ((x) & 0xffff) +- +-/* +- * Transmit descriptor, aligned to 16 bytes +- */ +-struct ftmac100_txdes { +- unsigned int txdes0; +- unsigned int txdes1; +- unsigned int txdes2; /* TXBUF_BADR */ +- unsigned int txdes3; /* not used by HW */ +-} __attribute__ ((aligned(16))); +- +-#define FTMAC100_TXDES0_TXPKT_LATECOL (1 << 0) +-#define FTMAC100_TXDES0_TXPKT_EXSCOL (1 << 1) +-#define FTMAC100_TXDES0_TXDMA_OWN (1 << 31) +- +-#define FTMAC100_TXDES1_TXBUF_SIZE(x) ((x) & 0x7ff) +-#define FTMAC100_TXDES1_LTS (1 << 27) +-#define FTMAC100_TXDES1_FTS (1 << 28) +-#define FTMAC100_TXDES1_TX2FIC (1 << 29) +-#define FTMAC100_TXDES1_TXIC (1 << 30) +-#define FTMAC100_TXDES1_EDOTR (1 << 31) +- +-/* +- * Receive descriptor, aligned to 16 bytes +- */ +-struct ftmac100_rxdes { +- unsigned int rxdes0; +- unsigned int rxdes1; +- unsigned int rxdes2; /* RXBUF_BADR */ +- unsigned int rxdes3; /* not used by HW */ +-} __attribute__ ((aligned(16))); +- +-#define FTMAC100_RXDES0_RFL 0x7ff +-#define FTMAC100_RXDES0_MULTICAST (1 << 16) +-#define FTMAC100_RXDES0_BROADCAST (1 << 17) +-#define FTMAC100_RXDES0_RX_ERR (1 << 18) +-#define FTMAC100_RXDES0_CRC_ERR (1 << 19) +-#define FTMAC100_RXDES0_FTL (1 << 20) +-#define FTMAC100_RXDES0_RUNT (1 << 21) +-#define FTMAC100_RXDES0_RX_ODD_NB (1 << 22) +-#define FTMAC100_RXDES0_LRS (1 << 28) +-#define FTMAC100_RXDES0_FRS (1 << 29) +-#define FTMAC100_RXDES0_RXDMA_OWN (1 << 31) ++#endif + +-#define FTMAC100_RXDES1_RXBUF_SIZE(x) ((x) & 0x7ff) +-#define FTMAC100_RXDES1_EDORR (1 << 31) + +-#endif /* __FTMAC100_H */ +diff -Nur linux-3.4.110.orig/drivers/net/ethernet/faraday/Kconfig linux-3.4.110/drivers/net/ethernet/faraday/Kconfig +--- linux-3.4.110.orig/drivers/net/ethernet/faraday/Kconfig 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/net/ethernet/faraday/Kconfig 2016-04-07 10:20:51.054085357 +0200 +@@ -5,7 +5,7 @@ + config NET_VENDOR_FARADAY + bool "Faraday devices" + default y +- depends on ARM ++ depends on ARM || NDS32 + ---help--- + If you have a network (Ethernet) card belonging to this class, say Y + and read the Ethernet-HOWTO, available from +@@ -20,7 +20,7 @@ + + config FTMAC100 + tristate "Faraday FTMAC100 10/100 Ethernet support" +- depends on ARM ++ depends on ARM || NDS32 + select NET_CORE + select MII + ---help--- +diff -Nur linux-3.4.110.orig/drivers/pci/Makefile linux-3.4.110/drivers/pci/Makefile +--- linux-3.4.110.orig/drivers/pci/Makefile 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/pci/Makefile 2016-04-07 10:20:51.054085357 +0200 +@@ -49,6 +49,7 @@ + obj-$(CONFIG_MICROBLAZE) += setup-bus.o + obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o + obj-$(CONFIG_SPARC_LEON) += setup-bus.o setup-irq.o ++obj-$(CONFIG_NDS32) += setup-bus.o setup-irq.o + + # + # ACPI Related PCI FW Functions +diff -Nur linux-3.4.110.orig/drivers/rtc/Kconfig linux-3.4.110/drivers/rtc/Kconfig +--- linux-3.4.110.orig/drivers/rtc/Kconfig 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/rtc/Kconfig 2016-04-07 10:20:51.054085357 +0200 +@@ -779,6 +779,16 @@ + This driver can also be built as a module. If so, the module + will be called rtc-ep93xx. + ++config RTC_DRV_FTRTC010 ++ tristate "Faraday Real Time Clock" ++ depends on NDS32 ++ help ++ If you say Y here you will get access to the real time clock ++ built into your AG101 CPU. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called rtc-ftrtc010. ++ + config RTC_DRV_SA1100 + tristate "SA11x0/PXA2xx/PXA910" + depends on ARCH_SA1100 || ARCH_PXA || ARCH_MMP +diff -Nur linux-3.4.110.orig/drivers/rtc/Makefile linux-3.4.110/drivers/rtc/Makefile +--- linux-3.4.110.orig/drivers/rtc/Makefile 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/rtc/Makefile 2016-04-07 10:20:51.054085357 +0200 +@@ -50,6 +50,7 @@ + obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o + obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o + obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o ++obj-$(CONFIG_RTC_DRV_FTRTC010) += rtc-ftrtc010.o + obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o + obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o + obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o +diff -Nur linux-3.4.110.orig/drivers/rtc/rtc-ftrtc010.c linux-3.4.110/drivers/rtc/rtc-ftrtc010.c +--- linux-3.4.110.orig/drivers/rtc/rtc-ftrtc010.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/rtc/rtc-ftrtc010.c 2016-04-07 10:20:51.054085357 +0200 +@@ -0,0 +1,371 @@ ++/* ++ * Faraday RTC Support ++ * ++ * Copyright (C) 2006, 2007, 2008 Paul Mundt ++ * Copyright (C) 2006 Jamie Lenehan ++ * Copyright (C) 2008 Angelo Castello ++ * Copyright (C) 2008 Roy Lee ++ * ++ * Based on the old arch/sh/kernel/cpu/rtc.c by: ++ * ++ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> ++ * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka ++ * ++ * 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. ++ */ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/rtc.h> ++#include <linux/delay.h> ++#include <linux/init.h> ++#include <linux/platform_device.h> ++#include <linux/seq_file.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++ ++#define PCLK ( AHB_CLK_IN / 2) ++ ++#define DRV_NAME "faraday-rtc" ++ ++#define RTC_REG( off) ( *( volatile unsigned long *)( rtc->regbase + ( off))) ++ ++#define RTC_CR RTC_REG( 0x20) /* Control */ ++#define RTC_CR_IE ( 0x1UL << 0) ++#define RTC_CR_IES ( 0x1UL << 1) ++#define RTC_CR_IEM ( 0x1UL << 2) ++#define RTC_CR_IEH ( 0x1UL << 3) ++#define RTC_CR_IED ( 0x1UL << 4) ++#define RTC_CR_ALRM ( 0x1UL << 5) ++#define RTC_CR_LOAD ( 0x1UL << 6) ++ ++#define RTC_RR RTC_REG( 0x1C) /* RTC Record Register */ ++#define RTC_DIV RTC_REG( 0x38) /* RTC Divede Register */ ++#define RTC_REV RTC_REG( 0x3C) /* RTC Divede Register */ ++ ++#define RTC_IR RTC_REG( 0x34) /* RTC interrupt state */ ++#define RTC_IR_IES ( 0x1UL << 0) /* RTC interrupt state */ ++#define RTC_IR_IEM ( 0x1UL << 1) /* RTC interrupt state */ ++#define RTC_IR_IEH ( 0x1UL << 2) /* RTC interrupt state */ ++#define RTC_IR_IED ( 0x1UL << 3) /* RTC interrupt state */ ++#define RTC_IR_ALRM ( 0x1UL << 4) /* RTC interrupt state */ ++ ++#define RTC_SECOND RTC_REG( 0x00) /* RTC sec */ ++#define RTC_MINUTE RTC_REG( 0x04) /* RTC min */ ++#define RTC_HOUR RTC_REG( 0x08) /* RTC hour */ ++#define RTC_DAYS RTC_REG( 0x0C) /* RTC day */ ++ ++#define RTC_ALRM_SECOND RTC_REG( 0x10) /* RTC alarm sec */ ++#define RTC_ALRM_MINUTE RTC_REG( 0x14) /* RTC alarm min */ ++#define RTC_ALRM_HOUR RTC_REG( 0x18) /* RTC alarm hour */ ++ ++#define RTC_WRITE_SECOND RTC_REG( 0x24) /* RTC write port for sec */ ++#define RTC_WRITE_MINUTE RTC_REG( 0x28) /* RTC write port for min */ ++#define RTC_WRITE_HOUR RTC_REG( 0x2C) /* RTC write port for hour */ ++#define RTC_WRITE_DAYS RTC_REG( 0x30) /* RTC write port for day */ ++ ++struct ft_rtc{ ++ ++ void __iomem *regbase; ++ struct resource *res; ++ unsigned int alarm_irq; ++ unsigned int interrupt_irq; ++ struct rtc_device *rtc_dev; ++ spinlock_t lock; /* Protects this structure */ ++}; ++ ++struct ft_rtc rtc_platform_data; ++ ++static irqreturn_t ft_rtc_interrupt( int irq, void *dev_id){ ++ ++ struct ft_rtc *rtc = dev_id; ++ if( RTC_IR & RTC_IR_IES){ ++ ++ RTC_IR &= ~RTC_IR_IES; ++ rtc_update_irq( rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); ++ ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static irqreturn_t ft_rtc_alarm( int irq, void *dev_id){ ++ ++ struct ft_rtc *rtc = dev_id; ++ if( RTC_IR & RTC_IR_ALRM){ ++ ++ RTC_CR &= ~RTC_CR_ALRM; ++ RTC_IR &= ~RTC_IR_ALRM; ++ rtc_update_irq( rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); ++ ++ return IRQ_HANDLED; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static void ft_rtc_release( struct device *dev){ ++ ++ struct ft_rtc *rtc = dev_get_drvdata( dev); ++ ++ RTC_CR &= ~RTC_CR_IES; ++ RTC_CR &= ~RTC_CR_ALRM; ++} ++ ++/* rick add */ ++static int ft_alarm_irq_enable(struct device *dev, unsigned int enabled) ++{ ++// printk("\n\nft_alarm_irq_enable\n\n"); ++ ++ struct ft_rtc *rtc = dev_get_drvdata( dev); ++ spin_lock_irq(&rtc->lock); ++ if (enabled) ++ RTC_CR |= RTC_CR_ALRM; ++ else ++ RTC_CR &= ~RTC_CR_ALRM; ++ spin_unlock_irq(&rtc->lock); ++ return 0; ++} ++ ++static int ft_rtc_read_time( struct device *dev, struct rtc_time *tm){ ++ struct ft_rtc *rtc = dev_get_drvdata( dev); ++ unsigned long time = RTC_DAYS * 86400 + RTC_HOUR * 3600 + RTC_MINUTE * 60 + RTC_SECOND; ++ rtc_time_to_tm( time, tm); ++ if( rtc_valid_tm( tm) < 0) { ++ dev_err( dev, "invalid date\n"); ++ rtc_time_to_tm( 0, tm); ++ } ++ return 0; ++} ++ ++static int ft_rtc_set_time( struct device *dev, struct rtc_time *tm){ ++ ++ struct ft_rtc *rtc = dev_get_drvdata( dev); ++ unsigned long time = 0; ++ ++ rtc_tm_to_time( tm, &time); ++ ++ RTC_WRITE_DAYS = time / 86400; ++ time %= 86400; ++ ++ RTC_WRITE_HOUR = time / 3600; ++ time %= 3600; ++ ++ RTC_WRITE_MINUTE = time / 60; ++ time %= 60; ++ ++ RTC_WRITE_SECOND = time; ++ ++ RTC_CR |= RTC_CR_LOAD; ++ ++ return 0; ++} ++ ++static int ft_rtc_read_alarm( struct device *dev, struct rtc_wkalrm *wkalrm){ ++ ++ struct ft_rtc *rtc = dev_get_drvdata( dev); ++ struct rtc_time *tm = &wkalrm->time; ++ ++ tm->tm_sec = RTC_ALRM_SECOND; ++ tm->tm_min = RTC_ALRM_MINUTE; ++ tm->tm_hour = RTC_ALRM_HOUR; ++ ++ wkalrm->enabled = ( RTC_CR & RTC_CR_ALRM) ? 1 : 0; ++ ++ return 0; ++} ++ ++static int ft_rtc_set_alarm( struct device *dev, struct rtc_wkalrm *wkalrm){ ++ ++ struct ft_rtc *rtc = dev_get_drvdata( dev); ++ struct rtc_time *tm = &wkalrm->time; ++ int err = rtc_valid_tm( tm); ++ if( err < 0){ ++ ++ dev_err( dev, "invalid alarm value\n"); ++ return err; ++ } ++ ++ /* disable alarm interrupt and clear the alarm flag */ ++ RTC_CR &= ~RTC_CR_ALRM; ++ ++ /* set alarm time */ ++ RTC_ALRM_SECOND = tm->tm_sec; ++ RTC_ALRM_MINUTE = tm->tm_min; ++ RTC_ALRM_HOUR = tm->tm_hour; ++ ++ if( wkalrm->enabled) ++ RTC_CR |= RTC_CR_ALRM; ++ ++ return 0; ++} ++ ++/* ++static int ft_rtc_irq_set_state( struct device *dev, int enabled){ ++ struct ft_rtc *rtc = dev_get_drvdata( dev); ++ if( enabled) ++ RTC_CR |= RTC_CR_IES; ++ else ++ RTC_CR &= ~RTC_CR_IES; ++ ++ return 0; ++} ++ ++*/ ++ ++static struct rtc_class_ops ft_rtc_ops = { ++ ++ .release = ft_rtc_release, ++ .alarm_irq_enable = ft_alarm_irq_enable, ++ ++ .read_time = ft_rtc_read_time, ++ .set_time = ft_rtc_set_time, ++ .read_alarm = ft_rtc_read_alarm, ++ .set_alarm = ft_rtc_set_alarm, ++}; ++ ++static int __devinit ft_rtc_probe( struct platform_device *pdev){ ++ ++ struct ft_rtc *rtc = &rtc_platform_data; ++ int ret = -ENOENT; ++ spin_lock_init(&rtc->lock); ++ ++ if( ( rtc->alarm_irq = platform_get_irq( pdev, 0)) < 0) ++ goto err_exit; ++ ++ if( ( rtc->interrupt_irq = platform_get_irq( pdev, 1)) < 0) ++ goto err_exit; ++ ++ if( !( rtc->res = platform_get_resource( pdev, IORESOURCE_MEM, 0))) ++ goto err_exit; ++ ++ if( ( ret = request_irq( rtc->alarm_irq , ft_rtc_alarm, 0, "RTC Alarm : ftrtc010", rtc))) ++ goto err_exit; ++ ++ if( ( ret = request_irq( rtc->interrupt_irq , ft_rtc_interrupt, 0, "RTC Interrupt : ftrtc010", rtc))) ++ goto err_interrupt_irq; ++ ++ ret = -EBUSY; ++ ++ if( !( rtc->res = request_mem_region( rtc->res->start, rtc->res->end - rtc->res->start + 1, pdev->name))) ++ goto err_request_region; ++ ++ ret = -EINVAL; ++ ++ if( !( rtc->regbase = ioremap_nocache( rtc->res->start, rtc->res->end - rtc->res->start + 1))) ++ goto err_ioremap1; ++ ++ ++ //RTC_DIV = ( 0x1UL << 31) | 2; /* AG101 */ ++ RTC_CR |= RTC_CR_IE; ++ platform_set_drvdata( pdev, rtc); ++ device_init_wakeup(&pdev->dev, true); ++ ++ rtc->rtc_dev = rtc_device_register( DRV_NAME, &pdev->dev, &ft_rtc_ops, THIS_MODULE); ++ ++ if( IS_ERR( rtc->rtc_dev)) { ++ ++ ret = PTR_ERR( rtc->rtc_dev); ++ goto err_unmap; ++ } ++ ++ rtc->rtc_dev->max_user_freq = 256; ++ rtc->rtc_dev->irq_freq = 1; ++ return 0; ++ ++err_unmap: ++ iounmap( rtc->regbase); ++err_ioremap1: ++ release_resource( rtc->res); ++err_request_region: ++ free_irq( rtc->interrupt_irq, rtc); ++err_interrupt_irq: ++ free_irq( rtc->alarm_irq, rtc); ++err_exit: ++ return ret; ++} ++ ++static int __devexit ft_rtc_remove( struct platform_device *pdev){ ++ ++ struct ft_rtc *rtc = platform_get_drvdata( pdev); ++ ++ rtc_device_unregister( rtc->rtc_dev); ++ ++ RTC_CR &= ~RTC_CR_ALRM; ++ ++ free_irq( rtc->alarm_irq, rtc); ++ free_irq( rtc->interrupt_irq, rtc); ++ ++ iounmap( rtc->regbase); ++ ++ platform_set_drvdata( pdev, NULL); ++ ++ return 0; ++} ++ ++static void platform_device_release(struct device *dev){ ++} ++ ++static struct resource rtc_resources[] = { ++ { ++ .start = RTC_FTRTC010_PA_BASE, ++ .end = RTC_FTRTC010_PA_LIMIT, ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = RTC_FTRTC010_IRQ0, ++ .end = RTC_FTRTC010_IRQ0, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .start = RTC_FTRTC010_IRQ1, ++ .end = RTC_FTRTC010_IRQ1, ++ .flags = IORESOURCE_IRQ, ++ }, ++}; ++ ++static struct platform_driver ft_rtc_platform_driver = { ++ ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .probe = ft_rtc_probe, ++ .remove = __devexit_p( ft_rtc_remove), ++}; ++ ++static struct platform_device rtc_device = { ++ ++ .name = DRV_NAME, ++ .id = 0, ++ .resource = rtc_resources, ++ .num_resources = ARRAY_SIZE( rtc_resources), ++ .dev = { ++ .platform_data = &rtc_platform_data, ++ .release = platform_device_release, ++ }, ++}; ++ ++static int __init ft_rtc_init( void){ ++ platform_device_register( &rtc_device); ++ return platform_driver_register( &ft_rtc_platform_driver); ++} ++ ++static void __exit ft_rtc_exit( void){ ++ ++ platform_driver_unregister( &ft_rtc_platform_driver); ++ platform_device_unregister( &rtc_device); ++} ++ ++module_init( ft_rtc_init); ++module_exit( ft_rtc_exit); ++ ++MODULE_DESCRIPTION( "SuperH on-chip RTC driver"); ++MODULE_AUTHOR( "Paul Mundt <lethal@linux-sh.org>, " ++ "Jamie Lenehan <lenehan@twibble.org>, " ++ "Angelo Castello <angelo.castello@st.com>, " ++ "Roy Lee <roylee@andestech.com>"); ++MODULE_LICENSE( "GPL"); ++MODULE_ALIAS( "platform:" DRV_NAME); +diff -Nur linux-3.4.110.orig/drivers/tty/serial/8250/8250.c linux-3.4.110/drivers/tty/serial/8250/8250.c +--- linux-3.4.110.orig/drivers/tty/serial/8250/8250.c 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/tty/serial/8250/8250.c 2016-04-07 10:20:51.054085357 +0200 +@@ -570,6 +570,7 @@ + serial_out(up, UART_ICR, value); + } + ++#ifndef CONFIG_NDS32 + static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) + { + unsigned int value; +@@ -581,6 +582,7 @@ + + return value; + } ++#endif + + /* + * FIFO support. +@@ -722,6 +724,7 @@ + return count; + } + ++#ifndef CONFIG_NDS32 + /* + * Read UART ID using the divisor method - set DLL and DLM to zero + * and the revision will be in DLL and device type in DLM. We +@@ -749,7 +752,9 @@ + + return id; + } ++#endif + ++#ifndef CONFIG_NDS32 + /* + * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. + * When this function is called we know it is at least a StarTech +@@ -842,6 +847,7 @@ + else + up->port.type = PORT_16650V2; + } ++#endif + + /* + * We detected a chip without a FIFO. Only two fall into +@@ -865,6 +871,7 @@ + up->port.type = PORT_16450; + } + ++#ifndef CONFIG_NDS32 + static int broken_efr(struct uart_8250_port *up) + { + /* +@@ -877,6 +884,7 @@ + + return 0; + } ++#endif + + static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) + { +@@ -908,7 +916,7 @@ + + up->port.type = PORT_16550A; + up->capabilities |= UART_CAP_FIFO; +- ++#ifndef CONFIG_NDS32 + /* + * Check for presence of the EFR when DLAB is set. + * Only ST16C650V1 UARTs pass this test. +@@ -937,6 +945,7 @@ + autoconfig_has_efr(up); + return; + } ++#endif + + /* + * Check for a National Semiconductor SuperIO chip. +@@ -1156,10 +1165,11 @@ + * We also initialise the EFR (if any) to zero for later. The + * EFR occupies the same register location as the FCR and IIR. + */ ++#ifndef CONFIG_NDS32 + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, 0); + serial_out(up, UART_LCR, 0); +- ++#endif + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = serial_in(up, UART_IIR) >> 6; + +diff -Nur linux-3.4.110.orig/drivers/video/FTLCDC100/faradayfb.h linux-3.4.110/drivers/video/FTLCDC100/faradayfb.h +--- linux-3.4.110.orig/drivers/video/FTLCDC100/faradayfb.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/video/FTLCDC100/faradayfb.h 2016-04-07 10:20:51.058085512 +0200 +@@ -0,0 +1,215 @@ ++#ifndef __FARADAYFB_H ++#define __FARADAYFB_H ++ ++#define FARADAYFB_MODULE_NAME "faradayfb" ++#define DEBUG(enabled, tagged, ...) \ ++ do { \ ++ if (enabled) { \ ++ if (tagged) \ ++ printk("[ %30s() ] ", __func__); \ ++ printk(__VA_ARGS__); \ ++ } \ ++ } while (0) ++ ++#if defined(CONFIG_FFB_MODE_RGB) ++# define DEFAULT_COLOR FFB_MODE_RGB ++#elif defined(CONFIG_FFB_MODE_YUV422) ++# define DEFAULT_COLOR FFB_MODE_YUV422 ++#elif defined(CONFIG_FFB_MODE_YUV420) ++# define DEFAULT_COLOR FFB_MODE_YUV420 ++#endif ++ ++#if defined(CONFIG_FFB_MODE_8BPP) ++# define DEFAULT_BPP FFB_MODE_8BPP ++#elif defined(CONFIG_FFB_MODE_16BPP) ++# define DEFAULT_BPP FFB_MODE_16BPP ++#elif defined(CONFIG_FFB_MODE_24BPP) ++# define DEFAULT_BPP FFB_MODE_24BPP ++#endif ++ ++#define FFB_DEFAULT_MODE (DEFAULT_COLOR | DEFAULT_BPP) ++ ++struct lcd_param { ++ ++ unsigned long value; ++ unsigned long flags; ++}; ++ ++inline struct lcd_param* get_lcd_time(struct lcd_param* array, unsigned long num_array, unsigned long type) ++{ ++ int i; ++ ++ for (i = 0; i < num_array; i++) { ++ ++ struct lcd_param *r = &array[i]; ++ ++ if (r->flags & type & 0xff) ++ return r; ++ } ++ ++ return NULL; ++} ++ ++inline struct lcd_param* get_lcd_ctrl(struct lcd_param* array, unsigned long num_array, unsigned long type) ++{ ++ int i; ++ ++ for (i = 0; i < num_array; i++) { ++ ++ struct lcd_param *r = &array[i]; ++ ++ if ((r->flags & type & 0xff) && (r->flags & type & 0xff00)) ++ return r; ++ } ++ ++ return NULL; ++} ++ ++enum { RGB_8, RGB_16, RGB_24, NR_RGB}; ++ ++struct faradayfb_rgb { ++ ++ struct fb_bitfield red; ++ struct fb_bitfield green; ++ struct fb_bitfield blue; ++ struct fb_bitfield transp; ++}; ++ ++/* This structure describes the machine which we are running on. */ ++struct faradayfb_mach_info { ++ ++ unsigned long num_time0; ++ struct lcd_param * time0; ++ ++ unsigned long num_time1; ++ struct lcd_param * time1; ++ ++ unsigned long num_time2; ++ struct lcd_param * time2; ++ ++ unsigned long num_control; ++ struct lcd_param * control; ++ ++ unsigned long pixclock; ++ ++ unsigned long xres; ++ unsigned long yres; ++ ++ unsigned int max_bpp; ++ unsigned int sync; ++ ++ unsigned int cmap_greyscale:1, ++ cmap_inverse:1, ++ cmap_static:1, ++ unused:29; ++}; ++ ++struct faradayfb_info { ++ ++ struct fb_info *info; ++ struct faradayfb_rgb *rgb[NR_RGB]; ++ ++ unsigned int xres; ++ unsigned int yres; ++ unsigned int max_bpp; ++ ++ /* ++ * These are the addresses we mapped ++ * the framebuffer memory region to. ++ */ ++ dma_addr_t map_dma; ++ unsigned char * map_cpu; ++ unsigned int map_size; ++ ++ unsigned char * screen_cpu; ++ dma_addr_t screen_dma; ++ u32 * palette_cpu; ++ dma_addr_t palette_dma; ++ unsigned int palette_size; ++ ++ unsigned int cmap_inverse:1, ++ cmap_static:1, ++ unused:30; ++ ++ unsigned long time0; ++ unsigned long time1; ++ unsigned long time2; ++ unsigned long control; ++ unsigned long int_mask; ++ unsigned long io_base; ++ ++ unsigned int state; ++ unsigned int task_state; ++ struct semaphore ctrlr_sem; ++ wait_queue_head_t ctrlr_wait; ++ struct work_struct task; ++ ++ unsigned long smode; ++ unsigned long frame420_size; ++}; ++ ++/* ++ * These are the actions for set_ctrlr_state ++ */ ++#define C_DISABLE 0 ++#define C_ENABLE 1 ++#define C_DISABLE_CLKCHANGE 2 ++#define C_ENABLE_CLKCHANGE 3 ++#define C_REENABLE 4 ++#define C_DISABLE_PM 5 ++#define C_ENABLE_PM 6 ++#define C_STARTUP 7 ++ ++#define FARADAY_LCDTIME0_GET_HBP(x) ((((x) >> 24) & 0xFF) + 1) ++#define FARADAY_LCDTIME0_GET_HFP(x) ((((x) >> 16) & 0xFF) + 1) ++#define FARADAY_LCDTIME0_GET_HW(x) ((((x) >> 8) & 0xFF) + 1) ++#define FARADAY_LCDTIME1_GET_VBP(x) ((((x) >> 24) & 0xFF) ) ++#define FARADAY_LCDTIME1_GET_VFP(x) ((((x) >> 16) & 0xFF) ) ++#define FARADAY_LCDTIME1_GET_VW(x) ((((x) >> 8) & 0xFF) + 1) ++ ++#define FARADAY_LCDTIME0_HBP(x) ((((x) - 1) & 0xFF) << 24) ++#define FARADAY_LCDTIME0_HFP(x) ((((x) - 1) & 0xFF) << 16) ++#define FARADAY_LCDTIME0_HW(x) ((((x) - 1) & 0xFF) << 8) ++#define FARADAY_LCDTIME0_PL(x) (((((x) >> 4) - 1) & 0x3F) << 2) ++#define FARADAY_LCDTIME1_VBP(x) ((((x) ) & 0xFF) << 24) ++#define FARADAY_LCDTIME1_VFP(x) ((((x) ) & 0xFF) << 16) ++#define FARADAY_LCDTIME1_VW(x) ((((x) - 1) & 0xFF) << 8) ++#define FARADAY_LCDTIME1_LF(x) ((((x) - 1) & 0x3FF) ) ++ ++#define FFB_MODE_RGB 0x00000001 ++#define FFB_MODE_YUV420 0x00000002 ++#define FFB_MODE_YUV422 0x00000004 ++ ++#define FFB_MODE_8BPP 0x00000100 ++#define FFB_MODE_16BPP 0x00000200 ++#define FFB_MODE_24BPP 0x00000400 ++ ++/* Minimum X and Y resolutions */ ++#define MIN_XRES 64 ++#define MIN_YRES 64 ++ ++typedef struct LCDTag { ++ ++ u32 Timing0; /* 0x00 */ ++ u32 Timing1; /* 0x04 */ ++ u32 Timing2; /* 0x08 */ ++ u32 Timing3; /* 0x0C */ ++ u32 UPBase; /* 0x10 */ ++ u32 LPBase; /* 0x14 */ ++ u32 INTREnable; /* 0x18 */ ++ u32 Control; /* 0x1C */ ++ u32 Status; /* 0x20 */ ++ u32 Interrupt; /* 0x24 */ ++ u32 UPCurr; /* 0x28 */ ++ u32 LPCurr; /* 0x2C */ ++ u32 Reserved1[5]; /* 0x30~0x40 */ ++ u32 GPIO; /* 0x44 */ ++ u32 Reserved2[0x74 - 6]; /* 0x48~0x1FC */ ++ ++ u32 Palette[0x80]; /* 0x200~0x3FC */ ++ u32 TestReg[0x100]; /* 0x400~0x7FC */ ++ ++} LCD_Register; ++ ++#endif /* __FARADAYFB_H */ ++ +diff -Nur linux-3.4.110.orig/drivers/video/FTLCDC100/faradayfb-main.c linux-3.4.110/drivers/video/FTLCDC100/faradayfb-main.c +--- linux-3.4.110.orig/drivers/video/FTLCDC100/faradayfb-main.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/video/FTLCDC100/faradayfb-main.c 2016-04-07 10:20:51.058085512 +0200 +@@ -0,0 +1,911 @@ ++#include <linux/module.h> ++#include <linux/fb.h> ++#include <linux/delay.h> ++#include <linux/device.h> ++#include <linux/dma-mapping.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++ ++#include <asm/uaccess.h> ++#include <asm/atomic.h> ++#include <asm/mach-types.h> ++ ++#include "faradayfb.h" ++#include "lcd-info.c" ++#include "pingpong-module.c" ++ ++static u32 faradayfb_pseudo_palette[32]; ++static inline void faradayfb_lcd_power(struct fb_info *info, int on) ++{ ++ struct faradayfb_info *fbi = info->par; ++ volatile LCD_Register *plcd = (LCD_Register *)fbi->io_base; ++ ++ if (on) ++ fbi->control |= (1UL << 11); ++ else ++ fbi->control &= ~(1UL << 11); ++ ++ plcd->Control = fbi->control; ++} ++ ++static void faradayfb_setup_gpio(struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ volatile LCD_Register *plcd = (LCD_Register *)fbi->io_base; ++ ++ plcd->GPIO = 0x010000; ++} ++ ++static inline void faradayfb_pmu_on(void) ++{ ++ REG32(PMU_FTPMU010_VA_BASE + 0x44) |= 0x00700000; ++} ++ ++static inline void faradayfb_pmu_off(void) ++{ ++ REG32(PMU_FTPMU010_VA_BASE + 0x44) &= ~0x00700000; ++} ++ ++static void faradayfb_enable_controller(struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ volatile LCD_Register *plcd = (LCD_Register *)fbi->io_base; ++ ++ plcd->Timing0 = fbi->time0; ++ plcd->Timing1 = fbi->time1; ++ plcd->Timing2 = fbi->time2; ++ plcd->Control = fbi->control & ~0x01; ++ ++ plcd->UPBase = fbi->screen_dma | fbi->frame420_size; ++ ++ faradayfb_pmu_on(); ++ plcd->Control |= 0x01; ++ ++ DEBUG(0, 1, "Time0 = 0x%08x\n", plcd->Timing0); ++ DEBUG(0, 1, "Time1 = 0x%08x\n", plcd->Timing1); ++ DEBUG(0, 1, "Time2 = 0x%08x\n", plcd->Timing2); ++ DEBUG(0, 1, "Control = 0x%08x\n", plcd->Control); ++ DEBUG(0, 1, "UPBase = 0x%08x\n", plcd->UPBase); ++} ++ ++static void faradayfb_disable_controller(struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ volatile LCD_Register *plcd = (LCD_Register *)fbi->io_base; ++ DECLARE_WAITQUEUE(wait, current); ++ ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ add_wait_queue(&fbi->ctrlr_wait, &wait); ++ ++ fbi->control &= ~0x0001; ++ plcd->Control = fbi->control; ++ faradayfb_pmu_off(); ++ ++ schedule_timeout(20 * HZ / 1000); ++ remove_wait_queue(&fbi->ctrlr_wait, &wait); ++} ++ ++static void faradayfb_enable_int(struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ volatile LCD_Register *plcd = (LCD_Register *)fbi->io_base; ++ ++ plcd->INTREnable = fbi->int_mask; ++} ++ ++static void faradayfb_disable_int(struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ volatile LCD_Register *plcd = (LCD_Register *)fbi->io_base; ++ ++ fbi->int_mask = plcd->INTREnable; ++ plcd->INTREnable = 0; ++ plcd->Status = 0x1e; ++} ++ ++static struct faradayfb_rgb def_rgb_8 = { ++ ++ .red = { .offset = 0, .length = 4 }, ++ .green = { .offset = 0, .length = 4 }, ++ .blue = { .offset = 0, .length = 4 }, ++ .transp = { .offset = 0, .length = 0 }, ++}; ++ ++static struct faradayfb_rgb def_rgb_16 = { ++ ++ .red = { .offset = 11, .length = 5, .msb_right = 0 }, ++ .green = { .offset = 5, .length = 6, .msb_right = 0 }, ++ .blue = { .offset = 0, .length = 5, .msb_right = 0 }, ++ .transp = { .offset = 15, .length = 0, .msb_right = 0 }, ++}; ++ ++static struct faradayfb_rgb def_rgb_24 = { ++ ++ .red = { .offset = 16, .length = 8, .msb_right = 0 }, ++ .green = { .offset = 8, .length = 8, .msb_right = 0 }, ++ .blue = { .offset = 0, .length = 8, .msb_right = 0 }, ++ .transp = { .offset = 0, .length = 0, .msb_right = 0 }, ++}; ++ ++static inline void faradayfb_schedule_work(struct fb_info *info, unsigned int state) ++{ ++ struct faradayfb_info *fbi = info->par; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ /* ++ * We need to handle two requests being made at the same time. ++ * There are two important cases: ++ * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE) ++ * We must perform the unblanking, which will do our REENABLE for us. ++ * 2. When we are blanking, but immediately unblank before we have ++ * blanked. We do the "REENABLE" thing here as well, just to be sure. ++ */ ++ if (fbi->task_state == C_ENABLE && state == C_REENABLE) ++ state = (unsigned int) - 1; ++ ++ if (fbi->task_state == C_DISABLE && state == C_ENABLE) ++ state = C_REENABLE; ++ ++ if (state != (unsigned int) - 1) { ++ ++ fbi->task_state = state; ++ schedule_work(&fbi->task); ++ } ++ ++ local_irq_restore(flags); ++} ++ ++static int faradayfb_setpalettereg(unsigned int regno, unsigned int red, ++ unsigned int green, unsigned int blue, unsigned int trans, ++ struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ ++ if (regno < fbi->palette_size) { ++ ++ fbi->palette_cpu[regno] = ((red >> 0) & (0x1fUL << 11)) | ++ ((green >> 5) & (0x3F << 5)) | ++ ((blue >> 11) & (0x1f << 0)); ++ ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static int faradayfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, ++ unsigned int blue, unsigned int trans, struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ int ret = 1; ++ /* ++ * If inverse mode was selected, invert all the colours ++ * rather than the register number. The register number ++ * is what you poke into the framebuffer to produce the ++ * colour you requested. ++ */ ++ if (fbi->cmap_inverse) { ++ ++ red = 0xffff - red; ++ green = 0xffff - green; ++ blue = 0xffff - blue; ++ } ++ ++ /* ++ * If greyscale is true, then we convert the RGB value ++ * to greyscale no mater what visual we are using. ++ */ ++ if (info->var.grayscale) ++ red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16; ++ ++ switch(info->fix.visual) { ++ ++ case FB_VISUAL_TRUECOLOR: ++ /* ++ * 12 or 16-bit True Colour. We encode the RGB value ++ * according to the RGB bitfield information. ++ */ ++ if (regno < 16) { ++ ++ u32 col; ++ red >>= (16 - info->var.red.length); ++ green >>= (16 - info->var.green.length); ++ blue >>= (16 - info->var.blue.length); ++ col = (red << info->var.red.offset) | ++ (green << info->var.green.offset) | ++ (blue << info->var.blue.offset) ; ++ ++ switch(info->var.bits_per_pixel) { ++ ++ /* is the following code correct?? */ ++ case 16: ++ case 32: ++ ((u32 *)(info->pseudo_palette))[regno] = col; ++ ret=0; ++ break; ++ } ++ } ++ break; ++ ++ case FB_VISUAL_STATIC_PSEUDOCOLOR: ++ case FB_VISUAL_PSEUDOCOLOR: ++ if (fbi->smode == FFB_MODE_RGB) ++ ret = faradayfb_setpalettereg(regno, red, green, blue, trans, info); ++ break; ++ } ++ ++ return ret; ++} ++ ++/* ++ * Round up in the following order: bits_per_pixel, xres, ++ * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, ++ * bitfields, horizontal timing, vertical timing. ++ */ ++static int faradayfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ int rgbidx; ++ ++ var->xres = min(var->xres, (unsigned int)MIN_XRES); ++ var->yres = min(var->yres, (unsigned int)MIN_YRES); ++ var->xres = max(var->xres, fbi->xres); ++ var->yres = max(var->yres, fbi->yres); ++ var->xres_virtual = max(var->xres_virtual, var->xres); ++ var->yres_virtual = max(var->yres_virtual, var->yres); ++ ++ DEBUG(0, 1, "var->bits_per_pixel = %d\n", var->bits_per_pixel); ++ ++ switch (var->bits_per_pixel) { ++ ++ case 1: case 2: case 4: case 8: ++ rgbidx = RGB_8; ++ break; ++ ++ case 16: ++ rgbidx = RGB_16; ++ break; ++ ++ case 32: ++ rgbidx = RGB_24; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ /* ++ * Copy the RGB parameters for this display ++ * from the machine specific parameters. ++ */ ++ var->red = fbi->rgb[ rgbidx]->red; ++ var->green = fbi->rgb[ rgbidx]->green; ++ var->blue = fbi->rgb[ rgbidx]->blue; ++ var->transp = fbi->rgb[ rgbidx]->transp; ++ ++ DEBUG(0, 1, "RGBT length = %d:%d:%d:%d\n", ++ var->red.length, var->green.length, var->blue.length, var->transp.length); ++ ++ DEBUG(0, 1, "RGBT offset = %d:%d:%d:%d\n", ++ var->red.offset, var->green.offset, var->blue.offset, var->transp.offset); ++ ++ DEBUG(0, 1, "Leave\n"); ++ ++ return 0; ++} ++ ++/* ++ * Configures LCD Controller based on entries in var parameter. Settings are ++ * only written to the controller if changes were made. ++ */ ++static int faradayfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ volatile LCD_Register *plcd = (LCD_Register *)fbi->io_base; ++ ++ DEBUG(0, 1, "var: xres=%d hslen=%d lm=%d rm=%d\n", var->xres, var->hsync_len, var->left_margin, var->right_margin); ++ DEBUG(0, 1, "var: yres=%d vslen=%d um=%d bm=%d\n", var->yres, var->vsync_len, var->upper_margin, var->lower_margin); ++ ++ fbi->time0 = FARADAY_LCDTIME0_HFP(var->left_margin) ++ | FARADAY_LCDTIME0_HBP(var->right_margin) ++ | FARADAY_LCDTIME0_HW(var->hsync_len) ++ | FARADAY_LCDTIME0_PL(var->xres); ++ ++ fbi->time1 = FARADAY_LCDTIME1_VBP(var->upper_margin) ++ | FARADAY_LCDTIME1_VFP(var->lower_margin) ++ | FARADAY_LCDTIME1_VW(var->vsync_len) ++ | FARADAY_LCDTIME1_LF(var->yres); ++ ++ if ((plcd->Timing0 != fbi->time0) ++ || (plcd->Timing1 != fbi->time1) ++ || (plcd->Timing2 != fbi->time2) ++ || (plcd->Control != fbi->control)) { ++ ++ faradayfb_schedule_work(info, C_REENABLE); ++ } ++ ++ return 0; ++} ++ ++/* Set the user defined part of the display for the specified console */ ++static int faradayfb_set_par(struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ struct fb_var_screeninfo *var = &info->var; ++ unsigned long palette_mem_size; ++ ++ if (var->bits_per_pixel == 16 || var->bits_per_pixel == 32) ++ info->fix.visual = FB_VISUAL_TRUECOLOR; ++ else if (!fbi->cmap_static) ++ info->fix.visual = FB_VISUAL_PSEUDOCOLOR; ++ else { ++ /* ++ * Some people have weird ideas about wanting static ++ * pseudocolor maps. I suspect their user space ++ * applications are broken. ++ */ ++ info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; ++ } ++ ++ info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8; ++ ++ fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16; ++ ++ palette_mem_size = fbi->palette_size * sizeof(u32); ++ ++ DEBUG(0, 1, "info->fix.line_length = %d\n", info->fix.line_length); ++ DEBUG(0, 1, "palette_mem_size = 0x%08lx\n", (unsigned long) palette_mem_size); ++ ++ fbi->palette_cpu = (u32 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); ++ ++ fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size; ++ ++ /* Set (any) board control register to handle new color depth */ ++ faradayfb_activate_var(var, info); ++ ++ DEBUG(0, 1, "Leave\n"); ++ ++ return 0; ++} ++ ++static irqreturn_t faradayfb_handle_irq(int irq, void *dev_id) ++{ ++#if 0 ++ struct fb_info *info = (struct fb_info*)dev_id; ++ struct faradayfb_info *fbi = info->par; ++ volatile LCD_Register *plcd = (LCD_Register *)fbi->io_base; ++ u32 status = plcd->Interrupt; ++#endif ++ return IRQ_HANDLED; ++} ++ ++/* ++ * This function must be called from task context only, since it will ++ * sleep when disabling the LCD controller, or if we get two contending ++ * processes trying to alter state. ++ */ ++static void set_ctrlr_state(struct fb_info *info, unsigned int state) ++{ ++ struct faradayfb_info *fbi = info->par; ++ unsigned int old_state; ++ ++ down(&fbi->ctrlr_sem); ++ ++ old_state = fbi->state; ++ ++ /* Hack around fbcon initialisation. */ ++ if (old_state == C_STARTUP && state == C_REENABLE) ++ state = C_ENABLE; ++ ++ switch (state) { ++ case C_DISABLE_PM: ++ case C_DISABLE: ++ ++ /* Disable controller */ ++ if (old_state != C_DISABLE) { ++ ++ fbi->state = state; ++ faradayfb_disable_int(info); ++ faradayfb_lcd_power(info, 0); ++ // faradayfb_disable_controller(info); ++ } ++ break; ++ ++ case C_REENABLE: ++ /* ++ * Re-enable the controller only if it was already ++ * enabled. This is so we reprogram the control ++ * registers. ++ */ ++ if (old_state == C_ENABLE) { ++ ++ faradayfb_disable_int(info); ++ faradayfb_lcd_power(info, 0); ++ faradayfb_disable_controller(info); ++ ++ faradayfb_setup_gpio(info); ++ faradayfb_lcd_power(info, 1); ++ faradayfb_enable_controller(info); ++ faradayfb_enable_int(info); ++ } ++ break; ++ ++ case C_ENABLE_PM: ++ /* ++ * Re-enable the controller after PM. This is not ++ * perfect - think about the case where we were doing ++ * a clock change, and we suspended half-way through. ++ */ ++ if (old_state != C_DISABLE_PM) ++ break; ++ /* fall through */ ++ ++ case C_ENABLE: ++ /* ++ * Power up the LCD screen, enable controller, and ++ * turn on the backlight. ++ */ ++ if (old_state != C_ENABLE) { ++ ++ fbi->state = C_ENABLE; ++ faradayfb_setup_gpio(info); ++ faradayfb_lcd_power(info, 1); ++ faradayfb_enable_controller(info); ++ faradayfb_enable_int(info); ++ } ++ break; ++ } ++ up(&fbi->ctrlr_sem); ++} ++ ++/* ++ * Blank the display by setting all palette values to zero. Note, the ++ * 12 and 16 bpp modes don't really use the palette, so this will not ++ * blank the display in all modes. ++ */ ++static int faradayfb_blank(int blank, struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ int i; ++ ++ switch (blank) { ++ case FB_BLANK_POWERDOWN: ++ case FB_BLANK_VSYNC_SUSPEND: ++ case FB_BLANK_HSYNC_SUSPEND: ++ case FB_BLANK_NORMAL: ++ ++ if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR || ++ info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) { ++ ++ for (i = 0; i < fbi->palette_size; i++) ++ faradayfb_setpalettereg(i, 0, 0, 0, 0, info); ++ } ++ ++ faradayfb_schedule_work(info, C_DISABLE); ++ ++ break; ++ ++ case FB_BLANK_UNBLANK: ++ ++ if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR || ++ info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) ++ fb_set_cmap(&info->cmap, info); ++ ++ faradayfb_schedule_work(info, C_ENABLE); ++ ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Our LCD controller task (which is called when we blank or unblank) ++ * via keventd. ++ */ ++static void faradayfb_task(struct work_struct *dummy) ++{ ++ struct faradayfb_info *fbi = container_of(dummy, struct faradayfb_info, task); ++ struct fb_info *info = fbi->info; ++ unsigned int state; ++ ++ state = xchg(&fbi->task_state, -1); ++ set_ctrlr_state(info, state); ++} ++ ++/* Fake monspecs to fill in fbinfo structure */ ++static struct fb_monspecs monspecs = { ++ ++ .hfmin = 30000, ++ .hfmax = 70000, ++ .vfmin = 50, ++ .vfmax = 65, ++}; ++ ++static int ffb_get_mach_param(struct faradayfb_mach_info *inf, struct fb_info *info, unsigned long smode) ++{ ++ struct faradayfb_info *fbi = info->par; ++ struct lcd_param *tparam; ++ unsigned long bpp_mode; ++ ++ if (!(tparam = get_lcd_time(inf->time0, inf->num_time0, smode))) ++ return -1; ++ ++ fbi->time0 = tparam->value; ++ ++ if (!(tparam = get_lcd_time(inf->time1, inf->num_time1, smode))) ++ return -1; ++ ++ fbi->time1 = tparam->value; ++ ++ if (!(tparam = get_lcd_time(inf->time2, inf->num_time2, smode))) ++ return -1; ++ ++ fbi->time2 = tparam->value; ++ ++ switch(info->var.bits_per_pixel) { ++ ++ case 1: case 2: case 4: case 8: ++ bpp_mode = FFB_MODE_8BPP; ++ break; ++ ++ case 16: ++ bpp_mode = FFB_MODE_16BPP; ++ break; ++ ++ case 32: ++ bpp_mode = FFB_MODE_24BPP; ++ break; ++ ++ default: ++ DEBUG(1, 1, "Unsupported BPP, set default BPP to 16\n"); ++ bpp_mode = FFB_MODE_16BPP; ++ break; ++ } ++ ++ if (!(tparam = get_lcd_ctrl(inf->control, inf->num_control, smode | bpp_mode))) ++ return -1; ++ ++ fbi->control = tparam->value; ++ ++ fbi->xres = inf->xres; ++ fbi->yres = inf->yres; ++ ++ return 0; ++} ++ ++static int faradayfb_set_var(struct fb_info *info, struct faradayfb_mach_info *inf, unsigned long type) ++{ ++ struct faradayfb_info *fbi = info->par; ++ unsigned long t_smode = 0; ++ ++ if (!type) ++ t_smode = fbi->smode; ++ else ++ t_smode = type; ++ ++ if (ffb_get_mach_param(inf, info, t_smode)) { ++ ++ DEBUG(1, 1, "Not support mode(%lx)\n", t_smode); ++ return -1; ++ } ++ ++ info->var.xres = fbi->xres; ++ info->var.xres_virtual = fbi->xres; ++ info->var.yres = fbi->yres; ++ info->var.yres_virtual = fbi->yres; ++ ++ info->var.upper_margin = FARADAY_LCDTIME1_GET_VBP(fbi->time1); ++ info->var.lower_margin = FARADAY_LCDTIME1_GET_VFP(fbi->time1); ++ info->var.vsync_len = FARADAY_LCDTIME1_GET_VW(fbi->time1); ++ info->var.left_margin = FARADAY_LCDTIME0_GET_HFP(fbi->time0); ++ info->var.right_margin = FARADAY_LCDTIME0_GET_HBP(fbi->time0); ++ info->var.hsync_len = FARADAY_LCDTIME0_GET_HW(fbi->time0); ++ ++ fbi->int_mask = 0; ++ ++ if (t_smode & FFB_MODE_YUV420) ++ fbi->frame420_size = (((info->var.xres * info->var.yres + 0xffff) & 0xffff0000) >> 16) << 2; ++ else ++ fbi->frame420_size = 0; ++ ++ return 0; ++} ++ ++static struct fb_ops faradayfb_ops = { ++ ++ .owner = THIS_MODULE, ++ .fb_check_var = faradayfb_check_var, ++ .fb_set_par = faradayfb_set_par, ++ .fb_setcolreg = faradayfb_setcolreg, ++ .fb_fillrect = cfb_fillrect, ++ .fb_copyarea = cfb_copyarea, ++ .fb_imageblit = cfb_imageblit, ++ .fb_blank = faradayfb_blank, ++ .fb_mmap = faradayfb_mmap, ++ .fb_ioctl = faradayfb_ioctl, ++}; ++ ++static struct fb_info * __init faradayfb_init_fbinfo(struct device *dev) ++{ ++ struct faradayfb_mach_info *inf; ++ struct fb_info *info; ++ struct faradayfb_info *fbi; ++ ++ if (!(info = framebuffer_alloc(sizeof(struct faradayfb_info), dev))) ++ return NULL; ++ ++ fbi = info->par; ++ fbi->info = info; ++ ++ fbi->io_base = LCD_FTLCDC100_0_VA_BASE; ++ strcpy(info->fix.id, FARADAYFB_MODULE_NAME); ++ ++ info->fix.type = FB_TYPE_PACKED_PIXELS; ++ info->fix.type_aux = 0; ++ info->fix.xpanstep = 0; ++ info->fix.ypanstep = 0; ++ info->fix.ywrapstep = 0; ++ info->fix.accel = FB_ACCEL_NONE; ++ ++ info->var.nonstd = 0; ++ info->var.activate = FB_ACTIVATE_NOW; ++ info->var.height = -1; ++ info->var.width = -1; ++ info->var.accel_flags = 0; ++ info->var.vmode = FB_VMODE_NONINTERLACED; ++ ++ info->fbops = &faradayfb_ops; ++ info->flags = FBINFO_DEFAULT; ++ info->monspecs = monspecs; ++ info->pseudo_palette = &faradayfb_pseudo_palette; ++ ++ fbi->rgb[RGB_8] = &def_rgb_8; ++ fbi->rgb[RGB_16] = &def_rgb_16; ++ fbi->rgb[RGB_24] = &def_rgb_24; ++ ++ inf = (struct faradayfb_mach_info*)dev->platform_data; ++ ++ /* ++ * People just don't seem to get this. We don't support ++ * anything but correct entries now, so panic if someone ++ * does something stupid. ++ */ ++ ++ fbi->xres = inf->xres; ++ fbi->yres = inf->yres; ++ fbi->max_bpp = 32; ++#if defined(CONFIG_FFB_MODE_8BPP) ++ info->var.bits_per_pixel = min((u32)8, inf->max_bpp); ++#elif defined(CONFIG_FFB_MODE_16BPP) ++ info->var.bits_per_pixel = min((u32)16, inf->max_bpp); ++#elif defined(CONFIG_FFB_MODE_24BPP) ++ info->var.bits_per_pixel = min((u32)32, inf->max_bpp); ++ info->var.bits_per_pixel = 32; ++#endif ++ ++ info->var.pixclock = inf->pixclock; ++ info->var.sync = inf->sync; ++ info->var.grayscale = inf->cmap_greyscale; ++ fbi->cmap_inverse = inf->cmap_inverse; ++ fbi->cmap_static = inf->cmap_static; ++ ++ fbi->smode = FFB_DEFAULT_MODE; ++ ++ if (faradayfb_set_var(info, inf, 0)) ++ goto err; ++ ++ fbi->state = C_STARTUP; ++ fbi->task_state = (unsigned char) - 1; ++ info->fix.smem_len = faradayfb_cal_frame_buf_size(fbi); ++ ++ init_waitqueue_head(&fbi->ctrlr_wait); ++ INIT_WORK(&fbi->task, faradayfb_task); ++ init_MUTEX(&fbi->ctrlr_sem); ++ ++ return info; ++err: ++ kfree(fbi); ++ kfree(info); ++ ++ return NULL; ++} ++ ++static int faradayfb_probe(struct platform_device *pdev) ++{ ++ struct fb_info *info; ++ struct faradayfb_info *fbi; ++ int irq; ++ int ret = 0; ++ ++ ret = -ENOMEM; ++ ++ if (!(info = faradayfb_init_fbinfo(&pdev->dev))) { ++ ++ DEBUG(1, 1, "unable to allocate memory for device info\n"); ++ goto err_exit; ++ } ++ ++ fbi = info->par; ++ ++ /* Initialize video memory */ ++ if ((ret = faradayfb_map_video_memory(info)) < 0) ++ goto err_free_mem; ++ ++ ret = -EINVAL; ++ ++ if ((irq = platform_get_irq(pdev, 0)) <= 0) ++ goto err_free_map; ++ ++ if (request_irq(irq, faradayfb_handle_irq, IRQF_DISABLED, "LCD", info)) { ++ ++ DEBUG(1, 1, "request_irq failed: %d\n", ret); ++ goto err_free_map; ++ } ++ ++ /* ++ * This makes sure that our colour bitfield ++ * descriptors are correctly initialised. ++ */ ++ faradayfb_check_var(&info->var, info); ++ faradayfb_set_par(info); ++ ++ dev_set_drvdata(&pdev->dev, info); ++ ++// <============================================ ++ if ((ret = register_framebuffer(info)) < 0) { ++ ++ DEBUG(1, 1, "register_framebuffer failed\n"); ++ goto err_free_irq; ++ } ++// <============================================ ++ ++ faradayfb_clean_screen(info); ++ ++ return 0; ++ ++err_free_irq: ++ dev_set_drvdata(&pdev->dev, NULL); ++ free_irq(irq, info); ++err_free_map: ++ faradayfb_unmap_video_memory(info); ++err_free_mem: ++ kfree(info->par); ++ kfree(info); ++err_exit: ++ return ret; ++} ++ ++/* Called when the device is being detached from the driver */ ++static int faradayfb_remove(struct platform_device *pdev) ++{ ++ struct fb_info *info = platform_get_drvdata(pdev); ++ int irq; ++ ++ set_ctrlr_state(info, C_DISABLE); ++ ++ irq = platform_get_irq(pdev, 0); ++ free_irq(irq, info); ++ ++ unregister_framebuffer(info); ++ faradayfb_unmap_video_memory(info); ++ dev_set_drvdata(&pdev->dev, NULL); ++ kfree(info->par); ++ kfree(info); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++ ++/* suspend and resume support for the lcd controller */ ++static int faradayfb_suspend(struct platform_device *pdev, pm_message_t mesg) ++{ ++ struct fb_info *info = platform_get_drvdata(pdev); ++ ++ // if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) ++ if (mesg.event == PM_EVENT_PRETHAW || mesg.event & PM_EVENT_SLEEP) ++ set_ctrlr_state(info, C_DISABLE_PM); ++ ++ return 0; ++} ++ ++static int faradayfb_resume(struct platform_device *pdev) ++{ ++ struct fb_info *info = platform_get_drvdata(pdev); ++ ++ // need modify ++ // if (level == RESUME_ENABLE) ++ set_ctrlr_state(info, C_ENABLE_PM); ++ ++ return 0; ++} ++ ++#else ++#define faradayfb_suspend NULL ++#define faradayfb_resume NULL ++#endif ++ ++static struct resource faradayfb_resource[] = { ++ ++ { ++ .start = LCD_FTLCDC100_0_PA_BASE, ++ .end = LCD_FTLCDC100_0_PA_LIMIT, ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .start = LCD_FTLCDC100_0_IRQ, ++ .end = LCD_FTLCDC100_0_IRQ, ++ .flags = IORESOURCE_IRQ, ++ } ++}; ++ ++static u64 faradayfb_dmamask = ~(u32)0; ++ ++static struct platform_device faradayfb_device = { ++ ++ .name = "faraday-lcd", ++ .id = -1, ++ .num_resources = ARRAY_SIZE(faradayfb_resource), ++ .resource = faradayfb_resource, ++ .dev = { ++ ++ .platform_data = &ffb_mach_info, ++ .dma_mask = &faradayfb_dmamask, ++ .coherent_dma_mask = 0xffffffff, ++ } ++}; ++ ++static struct platform_driver faradayfb_driver = { ++ .probe = faradayfb_probe, ++ .remove = faradayfb_remove, ++ .suspend = faradayfb_suspend, ++ .resume = faradayfb_resume, ++ .driver = { ++ .name = "faraday-lcd", ++ }, ++}; ++ ++/* ++rick note faraday driver ++*/ ++ ++/* Register both the driver and the device */ ++int __init faradayfb_init(void) ++{ ++ int ret = 0; ++ /* Register the device with LDM */ ++ ++#if 1 ++ if (platform_device_register(&faradayfb_device)) { ++ ++ DEBUG(1, 1, "failed to register faradayfb device\n"); ++ ret = -ENODEV; ++ goto exit; ++ } ++#endif ++ /* Register the driver with LDM */ ++ if (platform_driver_register(&faradayfb_driver)) { ++ ++ DEBUG(1, 1, "failed to register faradayfb driver\n"); ++ platform_device_unregister(&faradayfb_device); ++ ret = -ENODEV; ++ goto exit; ++ } ++exit: ++ return ret; ++} ++ ++static void __exit faradayfb_cleanup(void) ++{ ++ platform_driver_unregister(&faradayfb_driver); ++ platform_device_unregister(&faradayfb_device); ++} ++ ++module_init(faradayfb_init); ++module_exit(faradayfb_cleanup); ++MODULE_DESCRIPTION("Faraday LCD driver"); ++MODULE_AUTHOR("Francis Huang <francish@faraday-tech.com>"); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.4.110.orig/drivers/video/FTLCDC100/Kconfig linux-3.4.110/drivers/video/FTLCDC100/Kconfig +--- linux-3.4.110.orig/drivers/video/FTLCDC100/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/video/FTLCDC100/Kconfig 2016-04-07 10:20:51.058085512 +0200 +@@ -0,0 +1,74 @@ ++config FB_FTLCDC100 ++ tristate "Faraday FTLCDC100 driver" ++ depends on FB && NDS32 ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ ++ choice ++ prompt "Default LCD Panel" ++ depends on FB_FTLCDC100 ++ default PANEL_AUA036QN01 ++ help ++ This option select a default panel setting for the LCD controller ++ ++ config PANEL_AUA036QN01 ++ bool "AU 3.5 inch LCD Panel" ++ ++ config PANEL_CH7013A ++ bool "Chrontel Digital PC to TV Encoder" ++ select I2C ++ select I2C_FARADAY ++ select CH7013A ++ ++ config PANEL_AUA070VW04 ++ bool "AU 7.0 inch LCD Panel" ++ ++ config PANEL_LW500AC9601 ++ bool "CHIMEI 5.0 inch LCD panel" ++ ++ endchoice ++ ++ # config FTLCD_OSD ++ # bool "Enable OSD (On Screen Display)" ++ # depends on FB_FTLCDC100 ++ # default n ++ # ---help--- ++ # This enables access to the OSD (On Screen Display) for Faraday ++ # FTLCDC100 LCD control. Disabling OSD will reduce the size of ++ # the kernel by approximately 6kb. ++ # ++ ++ choice ++ prompt "Default Color Mode" ++ depends on FB_FTLCDC100 ++ default FFB_MODE_RGB ++ help ++ This option select default color mode ++ ++ config FFB_MODE_RGB ++ bool "RGB Mode" ++ config FFB_MODE_YUV422 ++ bool "YUV422 Mode" ++ config FFB_MODE_YUV420 ++ bool "YUV420 Mode" ++ endchoice ++ ++ choice ++ prompt "Default BPP" ++ depends on FB_FTLCDC100 ++ default FFB_MODE_16BPP ++ help ++ This option select default BPP (bits-per-pixel) ++ ++ config FFB_MODE_8BPP ++ depends on FFB_MODE_RGB || FFB_MODE_YUV420 ++ bool "8 bits-per-pixel" ++ config FFB_MODE_16BPP ++ depends on FFB_MODE_RGB || FFB_MODE_YUV422 ++ bool "16 bits-per-pixel" ++ config FFB_MODE_24BPP ++ depends on FFB_MODE_RGB ++ bool "24 bits-per-pixel" ++ endchoice ++ +diff -Nur linux-3.4.110.orig/drivers/video/FTLCDC100/lcd-info.c linux-3.4.110/drivers/video/FTLCDC100/lcd-info.c +--- linux-3.4.110.orig/drivers/video/FTLCDC100/lcd-info.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/video/FTLCDC100/lcd-info.c 2016-04-07 10:20:51.058085512 +0200 +@@ -0,0 +1,264 @@ ++/* ++ * HBP : Horizontal Back Porch ++ * HFP : Horizontal Front Porch ++ * HSPW: Horizontal Sync. Pulse Width ++ * PPL : Pixels-per-line = 16(PPL+1) ++ */ ++#define ENC_PARAM_TIME0(HBP, HFP, HSPW, PPL) \ ++ ((((HBP) - 1) << 24) | \ ++ (((HFP) - 1) << 16) | \ ++ (((HSPW) - 1) << 8 ) | \ ++ ((((PPL) >> 4) - 1) << 2 )) ++ ++/* ++ * HBP : Vertical Back Porch ++ * HFP : Vertical Front Porch ++ * HSPW: Vertical Sync. Pulse Width ++ * LPP : Lines-per-panel = LPP + 1 ++ */ ++#define ENC_PARAM_TIME1(VBP, VFP, VSPW, LPP) \ ++ ((((VBP) ) << 24) | \ ++ (((VFP) ) << 16) | \ ++ (((VSPW) - 1) << 10) | \ ++ (((LPP) - 1) )) ++ ++/* ++ * PRA : Pixel Rate Adaptive ++ * IOE : Invert Panel Output Enable ++ * IPC : Invert Panel Clock (Test Chip Testing) ++ * IHS : Invert Horisontal Sync. ++ * IVS : Invert Versical Sync. ++ * PCD : Panel Clock Divisor ++ */ ++#define ENC_PARAM_TIME2(PRA, IOE, IPC, IHS, IVS, PCD) \ ++ (((PRA) << 15) | \ ++ ((IOE) << 14) | \ ++ ((IPC) << 13) | \ ++ ((IHS) << 12) | \ ++ ((IVS) << 11) | \ ++ (((PCD) - 1) )) ++ ++/* ++ * Enable YCbCr ++ * Enable YCbCr420 ++ * FIFO threadhold ++ * Panel type, 0-6bit, 1-8bit ++ * LcdVComp, when to generate interrupt, 1: start of back_porch ++ * Power Enable ++ * Big Endian Pixel/Byte Ordering ++ * BGR ++ * TFT ++ * LCD bits per pixel ++ * Controller Enable ++ */ ++ ++#define ENC_PARAM_CTRL(ENYUV, ENYUV420, FIFOTH, PTYPE, VCOMP, LCD_ON, ENDIAN, BGR, TFT, BPP, LCD_EN) \ ++ ((ENYUV << 18) | \ ++ (ENYUV420 << 17) | \ ++ (FIFOTH << 16) | \ ++ (PTYPE << 15) | \ ++ (VCOMP << 12) | \ ++ (LCD_ON << 11) | \ ++ (ENDIAN << 9) | \ ++ (BGR << 8) | \ ++ (TFT << 5) | \ ++ (BPP << 1) | \ ++ (LCD_EN)) ++ ++static struct lcd_param control[] = { ++ ++ { ++ .value = ENC_PARAM_CTRL(0, 0, 1, 1, 0x3, 1, 0x0, 1, 1, 0x3, 1), ++ .flags = FFB_MODE_RGB | FFB_MODE_8BPP, ++ }, ++ { ++ .value = ENC_PARAM_CTRL(1, 1, 1, 1, 0x3, 1, 0x0, 0, 1, 0x3, 1), ++ .flags = FFB_MODE_YUV420 | FFB_MODE_8BPP, ++ }, ++ { ++ .value = ENC_PARAM_CTRL(1, 0, 1, 1, 0x3, 1, 0x0, 0, 1, 0x4, 1), ++ .flags = FFB_MODE_YUV422 | FFB_MODE_16BPP, ++ }, ++ { ++ .value = ENC_PARAM_CTRL(0, 0, 1, 1, 0x3, 1, 0x0, 1, 1, 0x4, 1), ++ .flags = FFB_MODE_RGB | FFB_MODE_16BPP, ++ }, ++ { ++ .value = ENC_PARAM_CTRL(0, 0, 1, 1, 0x3, 1, 0x0, 1, 1, 0x5, 1), ++ .flags = FFB_MODE_RGB | FFB_MODE_24BPP, ++ }, ++}; ++ ++#ifdef CONFIG_PANEL_AUA036QN01 ++ ++static struct lcd_param time0[] = { ++ ++ { ++ .value = ENC_PARAM_TIME0(7, 6, 1, 320), ++ .flags = FFB_MODE_RGB | FFB_MODE_YUV420 | FFB_MODE_YUV422, ++ }, ++}; ++ ++static struct lcd_param time1[] = { ++ ++ { ++ .value = ENC_PARAM_TIME1(1, 1, 1, 240), ++ .flags = FFB_MODE_RGB | FFB_MODE_YUV420 | FFB_MODE_YUV422, ++ }, ++}; ++ ++static struct lcd_param time2[] = { ++ ++ { ++ .value = ENC_PARAM_TIME2(0, 0, 1, 1, 1, 0x7), ++ .flags = FFB_MODE_RGB | FFB_MODE_YUV420 | FFB_MODE_YUV422, ++ }, ++}; ++ ++static struct faradayfb_mach_info ffb_mach_info = { ++ ++ .pixclock = 171521, ++ .xres = 320, ++ .yres = 240, ++ .max_bpp = 24, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .num_time0 = ARRAY_SIZE(time0), ++ .time0 = time0, ++ .num_time1 = ARRAY_SIZE(time1), ++ .time1 = time1, ++ .num_time2 = ARRAY_SIZE(time2), ++ .time2 = time2, ++ .num_control = ARRAY_SIZE(control), ++ .control = control, ++}; ++#endif ++ ++#ifdef CONFIG_PANEL_AUA070VW04 ++static struct lcd_param time0[] = { ++ ++ { ++ .value = ENC_PARAM_TIME0(88, 40, 128, 800), ++ .flags = FFB_MODE_RGB | FFB_MODE_YUV420 | FFB_MODE_YUV422, ++ }, ++}; ++ ++static struct lcd_param time1[] = { ++ ++ { ++ .value = ENC_PARAM_TIME1(21, 1, 3, 480), ++ .flags = FFB_MODE_RGB | FFB_MODE_YUV420 | FFB_MODE_YUV422, ++ }, ++}; ++ ++static struct lcd_param time2[] = { ++ ++ { ++ .value = ENC_PARAM_TIME2(0, 1, 1, 1, 1, 0x5), ++ .flags = FFB_MODE_RGB | FFB_MODE_YUV420 | FFB_MODE_YUV422, ++ }, ++}; ++ ++static struct faradayfb_mach_info ffb_mach_info = { ++ ++ .pixclock = 171521, ++ .xres = 800, ++ .yres = 480, ++ .max_bpp = 24, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .num_time0 = ARRAY_SIZE(time0), ++ .time0 = time0, ++ .num_time1 = ARRAY_SIZE(time1), ++ .time1 = time1, ++ .num_time2 = ARRAY_SIZE(time2), ++ .time2 = time2, ++ .num_control = ARRAY_SIZE(control), ++ .control = control, ++}; ++ ++#endif ++ ++#ifdef CONFIG_PANEL_LW500AC9601 ++static struct lcd_param time0[] = { ++ ++ { ++ .value = ENC_PARAM_TIME0(88, 40, 128, 800), ++ .flags = FFB_MODE_RGB | FFB_MODE_YUV420 | FFB_MODE_YUV422, ++ }, ++}; ++ ++static struct lcd_param time1[] = { ++ ++ { ++ .value = ENC_PARAM_TIME1(21, 1, 3, 480), ++ .flags = FFB_MODE_RGB | FFB_MODE_YUV420 | FFB_MODE_YUV422, ++ }, ++}; ++ ++static struct lcd_param time2[] = { ++ ++ { ++ .value = ENC_PARAM_TIME2( 0, 0, 1, 1, 1, 0x3), ++ .flags = FFB_MODE_RGB | FFB_MODE_YUV420 | FFB_MODE_YUV422, ++ }, ++}; ++ ++static struct faradayfb_mach_info ffb_mach_info = { ++ ++ .pixclock = 171521, ++ .xres = 800, ++ .yres = 480, ++ .max_bpp = 24, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .num_time0 = ARRAY_SIZE(time0), ++ .time0 = time0, ++ .num_time1 = ARRAY_SIZE(time1), ++ .time1 = time1, ++ .num_time2 = ARRAY_SIZE(time2), ++ .time2 = time2, ++ .num_control = ARRAY_SIZE(control), ++ .control = control, ++}; ++#endif ++ ++#ifdef CONFIG_CH7013A ++static struct lcd_param time0[] = { ++ ++ { ++ .value = ENC_PARAM_TIME0(42, 10, 96, 640), ++ .flags = FFB_MODE_RGB, ++ }, ++}; ++ ++static struct lcd_param time1[] = { ++ ++ { ++ .value = ENC_PARAM_TIME1(28, 5, 2, 480), ++ .flags = FFB_MODE_RGB, ++ }, ++}; ++static struct lcd_param time2[] = { ++ ++ { ++ .value = ENC_PARAM_TIME2(0, 1, 1, 0, 0, 0x3), ++ .flags = FFB_MODE_RGB, ++ }, ++}; ++ ++static struct faradayfb_mach_info ffb_mach_info = { ++ ++ .pixclock = 37910, ++ .xres = 640, ++ .yres = 480, ++ .max_bpp = 24, ++ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, ++ .num_time0 = ARRAY_SIZE(time0), ++ .time0 = time0, ++ .num_time1 = ARRAY_SIZE(time1), ++ .time1 = time1, ++ .num_time2 = ARRAY_SIZE(time2), ++ .time2 = time2, ++ .num_control = ARRAY_SIZE(control), ++ .control = control, ++}; ++ ++#endif /* CONFIG_CH7013A */ +diff -Nur linux-3.4.110.orig/drivers/video/FTLCDC100/Makefile linux-3.4.110/drivers/video/FTLCDC100/Makefile +--- linux-3.4.110.orig/drivers/video/FTLCDC100/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/video/FTLCDC100/Makefile 2016-04-07 10:20:51.058085512 +0200 +@@ -0,0 +1 @@ ++obj-$(CONFIG_FB_FTLCDC100) += faradayfb-main.o +diff -Nur linux-3.4.110.orig/drivers/video/FTLCDC100/pingpong-module.c linux-3.4.110/drivers/video/FTLCDC100/pingpong-module.c +--- linux-3.4.110.orig/drivers/video/FTLCDC100/pingpong-module.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/video/FTLCDC100/pingpong-module.c 2016-04-07 10:20:51.058085512 +0200 +@@ -0,0 +1,592 @@ ++void *fmem_alloc(size_t size, dma_addr_t *dma_handle, unsigned long flags) ++{ ++ struct page *page; ++ void *cpu_addr = NULL; ++ ++ size = PAGE_ALIGN(size); ++ ++ if (!(page = alloc_pages(GFP_DMA, get_order(size)))) { ++ ++ DEBUG(1, 1, "alloc_pages fail! (requested %#x)", size); ++ goto no_page; ++ } ++ ++ *dma_handle = page_to_phys(page); ++ ++ if ((cpu_addr = __ioremap(*dma_handle, size, flags, 1))) { ++ ++ do { ++ SetPageReserved(page); ++ page++; ++ } while (size -= PAGE_SIZE); ++ } ++ else { ++ __free_pages(page, get_order(size)); ++ DEBUG(1, 1, "__ioremap fail! (phy %#x)", *dma_handle); ++ } ++no_page: ++ return cpu_addr; ++} ++ ++void fmem_free(size_t size, void *cpu_addr, dma_addr_t handle) ++{ ++ struct page *page = pfn_to_page(handle >> PAGE_SHIFT); ++ ++ __iounmap(cpu_addr); ++ size = PAGE_ALIGN(size); ++ ++ do { ++ ClearPageReserved(page); ++ __free_page(page); ++ page++; ++ ++ } while (size -= PAGE_SIZE); ++} ++ ++static int faradayfb_mmap(struct fb_info *info, struct vm_area_struct *vma) ++{ ++ struct faradayfb_info *fbi = info->par; ++ unsigned long off = vma->vm_pgoff << PAGE_SHIFT; ++ int ret = -EINVAL; ++ ++ DEBUG(0, 1, "Enter\n"); ++ ++ if (off < info->fix.smem_len) { ++ ++ off += fbi->screen_dma & PAGE_MASK; ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++ vma->vm_flags |= VM_RESERVED; ++ ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, ++ vma->vm_end - vma->vm_start, vma->vm_page_prot); ++ } ++ else { ++ DEBUG(1, 1, "buffer mapping error !!\n"); ++ } ++ ++ DEBUG(0, 1, "Leave\n"); ++ ++ return ret; ++} ++ ++/* ++ * Allocates the DRAM memory for the frame buffer. This buffer is ++ * remapped into a non-cached, non-buffered, memory region to ++ * allow palette and pixel writes to occur without flushing the ++ * cache. Once this area is remapped, all virtual memory ++ * access to the video memory should occur at the new region. ++ */ ++static int __init faradayfb_map_video_memory(struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ ++ /* ++ * We reserve one page for the palette, plus the size ++ * of the framebuffer. ++ */ ++ fbi->map_size = PAGE_ALIGN(info->fix.smem_len + PAGE_SIZE); ++ ++ fbi->map_cpu = fmem_alloc(fbi->map_size, &fbi->map_dma, pgprot_writecombine(PAGE_KERNEL)); ++ // fbi->map_cpu = dma_alloc_writecombine(fbi->info->dev, fbi->map_size, &fbi->map_dma, GFP_KERNEL); ++ ++ if (fbi->map_cpu) { ++ ++ memset(fbi->map_cpu, 0x1d, fbi->map_size); ++ info->screen_base = fbi->map_cpu + PAGE_SIZE; ++ fbi->screen_dma = fbi->map_dma + PAGE_SIZE; ++ info->fix.smem_start = fbi->screen_dma; ++ } ++ ++ return fbi->map_cpu ? 0 : -ENOMEM; ++} ++ ++static inline void faradayfb_clean_screen(struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ int size = info->var.xres * info->var.yres; ++ ++ if (fbi->smode & FFB_MODE_YUV422) { ++ ++ memset(fbi->map_cpu, 16, size * info->var.bits_per_pixel / 8); ++ } ++ else if (fbi->smode & FFB_MODE_YUV420) { ++ ++ memset(fbi->map_cpu, 16, size); ++ memset(fbi->map_cpu + PAGE_SIZE + ((size + 0xffff) & 0xffff0000), 128, size / 4); ++ memset(fbi->map_cpu + PAGE_SIZE + ((size + 0xffff) & 0xffff0000) * 5 / 4, 128, size / 4); ++ } ++} ++ ++static inline void faradayfb_unmap_video_memory(struct fb_info *info) ++{ ++ struct faradayfb_info *fbi = info->par; ++ fmem_free(fbi->map_size, fbi->map_cpu, fbi->map_dma); ++} ++ ++#define FRAME_SIZE_RGB(xres, yres, mbpp) ((xres) * (yres) * (mbpp) / 8) ++#define FRAME_SIZE_YUV422(xres, yres, mbpp) (((xres) * (yres) * (mbpp) / 8) * 2) ++#define FRAME_SIZE_YUV420(xres, yres, mbpp) (((((xres) * (yres) * (mbpp) / 8) + 0xffff) & 0xffff0000) * 3 / 2) ++ ++static inline u32 faradayfb_cal_frame_buf_size(struct faradayfb_info *fbi) ++{ ++ u32 size_rgb = FRAME_SIZE_RGB(fbi->xres, fbi->yres, fbi->max_bpp); ++ u32 size_yuv422 = FRAME_SIZE_YUV422(fbi->xres, fbi->yres, 8); ++ u32 size_yuv420 = FRAME_SIZE_YUV420(fbi->xres, fbi->yres, 8); ++ ++ return max(size_rgb, max(size_yuv422, size_yuv420)); ++} ++ ++#ifdef CONFIG_FTLCD_OSD ++/************************************ ++ * OSD ++ ***********************************/ ++#define FOSD_SETPOS 0x46e1 ++#define FOSD_SETDIM 0x46e2 ++#define FOSD_SETSCAL 0x46e3 ++#define FLCD_SET_TRANSPARENT 0x46e4 ++#define FLCD_SET_STRING 0x46e5 ++#define FOSD_ON 0x46e6 ++#define FOSD_OFF 0x46e7 ++#define FRREG 0x46e8 ++#define FWREG 0x46e9 ++ ++#define dig_alpha (16 * 10) + (16 * 26) + (16 * 3) ++ ++struct fosd_string { ++ ++ unsigned int Str_row; ++ unsigned int display_mode; ++ unsigned int fg_color; ++ unsigned int bg_color; ++ unsigned char Str_OSD[30]; ++}; ++ ++struct fosd_data { ++ ++ unsigned int HPos; ++ unsigned int VPos; ++ unsigned int HDim; ++ unsigned int VDim; ++ unsigned int transparent_level; ++ unsigned int HScal; ++ unsigned int VScal; ++ struct fosd_string Str_Data[10]; ++}; ++ ++unsigned int OSD_Font[] = { ++ ++ /* 0 */ ++ 0x00, 0x00, 0x00, 0x3e, 0x63, 0x67, 0x6f, 0x7b, ++ 0x73, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, ++ ++ /* 1 */ ++ 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x0c, 0x0c, ++ 0x0c, 0x0c, 0x0c, 0x3f, 0x00, 0x00, 0x00, 0x00, ++ ++ /* 2 */ ++ 0x00, 0x00, 0x00, 0x3e, 0x63, 0x03, 0x06, 0x0c, ++ 0x18, 0x30, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00, ++ ++ /* 3 */ ++ 0x00, 0x00, 0x00, 0x3E, 0x63, 0x03, 0x03, 0x1e, ++ 0x03, 0x03, 0x63, 0x3E, 0x00, 0x00, 0x00, 0x00, ++ ++ /* 4 */ ++ 0x00, 0x00, 0x00, 0x06, 0x0e, 0x1e, 0x36, 0x66, ++ 0x7f, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00, ++ ++ /* 5 */ ++ 0x00, 0x00, 0x00, 0x7f, 0x60, 0x60, 0x60, 0x7e, ++ 0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, ++ ++ /* 6 */ ++ 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7e, ++ 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, ++ ++ /* 7 */ ++ 0x00, 0x00, 0x00, 0x7f, 0x63, 0x03, 0x06, 0x0c, ++ 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, ++ ++ /* 8 */ ++ 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x3e, ++ 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, ++ ++ /* 9 */ ++ 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x3f, ++ 0x03, 0x03, 0x06, 0x3c, 0x00, 0x00, 0x00, 0x00, ++ ++ /* A */ ++ 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63, ++ 0x7f, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, ++ ++ /* B */ ++ 0x00, 0x00, 0x00, 0x7E, 0x33, 0x33, 0x33, 0x3E, ++ 0x33, 0x33, 0x33, 0x7E, 0x00, 0x00, 0x00, 0x00, ++ ++ /* C */ ++ 0x00, 0x00, 0x00, 0x1E, 0x33, 0x61, 0x60, 0x60, ++ 0x60, 0x61, 0x33, 0x1E, 0x00, 0x00, 0x00, 0x00, ++ ++ /* D */ ++ 0x00, 0x00, 0x00, 0x7c, 0x36, 0x33, 0x33, 0x33, ++ 0x33, 0x33, 0x36, 0x7C, 0x00, 0x00, 0x00, 0x00, ++ ++ /* E */ ++ 0x00, 0x00, 0x00, 0x7f, 0x33, 0x31, 0x34, 0x3c, ++ 0x34, 0x31, 0x33, 0x7f, 0x00, 0x00, 0x00, 0x00, ++ ++ /* F */ ++ 0x00, 0x00, 0x00, 0x7f, 0x33, 0x31, 0x34, 0x3c, ++ 0x34, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, ++ ++ /* G */ ++ 0x00, 0x00, 0x00, 0x1E, 0x33, 0x61, 0x60, 0x60, ++ 0x6F, 0x63, 0x36, 0x7C, 0x00, 0x00, 0x00, 0x00, ++ ++ /* H */ ++ 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x64, 0x7f, ++ 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, ++ ++ /* I */ ++ 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, ++ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, ++ ++ /* J */ ++ 0x00, 0x00, 0x00, 0x0f, 0x06, 0x06, 0x06, 0x06, ++ 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, ++ ++ /* K */ ++ 0x00, 0x00, 0x00, 0x73, 0x33, 0x36, 0x36, 0x3c, ++ 0x36, 0x36, 0x33, 0x73, 0x00, 0x00, 0x00, 0x00, ++ ++ /* L */ ++ 0x00, 0x00, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, ++ 0x30, 0x31, 0x33, 0x7f, 0x00, 0x00, 0x00, 0x00, ++ ++ /* M */ ++ 0x00, 0x00, 0x00, 0x63, 0x77, 0x7f, 0x6b, 0x63, ++ 0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, ++ ++ /* N */ ++ 0x00, 0x00, 0x00, 0x63, 0x73, 0x7b, 0x7f, 0x6f, ++ 0x67, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, ++ ++ /* O */ ++ 0x00, 0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x63, ++ 0x63, 0x63, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, ++ ++ /* P */ ++ 0x00, 0x00, 0x00, 0x7e, 0x33, 0x33, 0x33, 0x3e, ++ 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, ++ ++ /* Q */ ++ 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, ++ 0x6b, 0x6f, 0x3e, 0x06, 0x07, 0x00, 0x00, 0x00, ++ ++ /* R */ ++ 0x00, 0x00, 0x00, 0x7e, 0x33, 0x33, 0x33, 0x3e, ++ 0x36, 0x33, 0x33, 0x73, 0x00, 0x00, 0x00, 0x00, ++ ++ /* S */ ++ 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x30, 0x1c, ++ 0x06, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, ++ ++ /* T */ ++ 0x00, 0x00, 0x00, 0xFF, 0x99, 0x18, 0x18, 0x18, ++ 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, ++ ++ /* U */ ++ 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, ++ 0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00, ++ ++ /* V */ ++ 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, ++ 0x63, 0x36, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, ++ ++ /* W */ ++ 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, ++ 0x6b, 0x7f, 0x77, 0x63, 0x00, 0x00, 0x00, 0x00, ++ ++ /* X */ ++ 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x36, 0x1c, ++ 0x36, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, ++ ++ /* Y */ ++ 0x00, 0x00, 0x00, 0x63, 0x63, 0x63, 0x36, 0x1c, ++ 0x1c, 0x1c, 0x1c, 0x3e, 0x00, 0x00, 0x00, 0x00, ++ ++ /* Z */ ++ 0x00, 0x00, 0x00, 0x7f, 0x63, 0x46, 0x0c, 0x18, ++ 0x30, 0x61, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00, ++ ++ /* space */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ ++ /* = */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00, ++ 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ ++ /* , */ ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, ++}; ++ ++void OSD_On(struct faradayfb_info *fbi) ++{ ++ REG32(fbi->io_base + 0x34) &= 0xfffffffe; ++ REG32(fbi->io_base + 0x34) |= 1; ++} ++ ++void OSD_Off(struct faradayfb_info *fbi) ++{ ++ REG32(fbi->io_base + 0x34) &= 0xfffffffe; ++} ++ ++void OSD_Pos(struct faradayfb_info *fbi, int HPos, int VPos) ++{ ++ REG32(fbi->io_base + 0x38) = (HPos << 10) | VPos; ++} ++ ++void OSD_Dim(struct faradayfb_info *fbi, int HDim, int VDim) ++{ ++ REG32(fbi->io_base + 0x34) &= 0x0000001f; ++ REG32(fbi->io_base + 0x34) |= ((HDim << 10) | (VDim << 5)); ++} ++ ++void OSD_transparent(struct faradayfb_info *fbi, int level) ++{ ++ REG32(fbi->io_base + 0x40) &= 0xffffff00; ++ REG32(fbi->io_base + 0x40) |= (level << 6); ++} ++ ++void OSD_fg_color(struct faradayfb_info *fbi, int pal0, int pal1, int pal2, int pal3) ++{ ++ REG32(fbi->io_base + 0x3c) = (pal0) | (pal1 << 8) | (pal2 << 16) | (pal3<< 24); ++} ++ ++void OSD_bg_color(struct faradayfb_info *fbi, int pal1, int pal2, int pal3) ++{ ++ REG32(fbi->io_base + 0x40) &= 0x000000ff; ++ REG32(fbi->io_base + 0x40) |= (pal1 << 8) | (pal2 << 16) | (pal3 << 24); ++} ++ ++void OSD_Scal(struct faradayfb_info *fbi, int HScal, int VScal) ++{ ++ REG32(fbi->io_base + 0x34) &= 0xffffffe1; ++ REG32(fbi->io_base + 0x34) |= (HScal << 3) | (VScal << 1); ++} ++ ++void OSD_putc(struct faradayfb_info *fbi, char c, int position, unsigned int value) ++{ ++ if (c >= '0' && c <= '9') ++ REG32(fbi->io_base + 0xc000 + position * 4) = ((c -'0') << 4) | value; ++ ++ else if (c>= 'A' && c <= 'Z') ++ REG32(fbi->io_base + 0xc000 + position * 4) = ((c - 'A' + 10) << 4) | value; ++ ++ if (c == ' ') ++ REG32(fbi->io_base + 0xc000 + position * 4) = (('Z' - 'A' + 10 + 1) << 4) | value; ++ ++ if (c == '=') ++ REG32(fbi->io_base + 0xc000 + position * 4) = (('Z' - 'A' + 10 + 2) << 4) | value; ++ ++ if (c == ',') ++ REG32(fbi->io_base + 0xc000 + position * 4) = (('Z' - 'A' + 10 + 3) << 4) | value; ++} ++ ++void OSD_puts(struct faradayfb_info *fbi, char *str, int position, unsigned int value) ++{ ++ int i; ++ ++ for (i = 0; i < strlen(str); i++) ++ OSD_putc(fbi, *(str + i), position + i, value); ++} ++ ++void OSD_String(struct faradayfb_info *fbi, int row, int mode, char *str, int fg_color, int bg_color) ++{ ++ int i, j, x, y; ++ unsigned int value = fg_color | bg_color; ++ ++ /* 10 digit & 26 alphabet & ' ' & '=' & ',' */ ++ for (i = 0; i < dig_alpha; i++) { ++ ++ x = 0; ++ y = OSD_Font[i]; ++ ++ for (j = 0; j < 12; j ++) { /* reorder */ ++ if (y & 1) ++ x |= 1; ++ y >>= 1; ++ x <<= 1; ++ } ++ ++ x >>= 1; ++ REG32(fbi->io_base + 0x8000 + i * 4) = x; ++ } ++ ++ OSD_puts(fbi, str, row, value); ++ ++ if (mode == 2) { /* YCbCr */ ++ ++ OSD_fg_color(fbi, 0x57, 0x88, 0x3B, 0xFF); ++ OSD_bg_color(fbi, 0x57, 0x88, 0x3B); ++ } ++ else { ++ OSD_fg_color(fbi, 0x07, 0x38, 0xC0, 0xFF); ++ OSD_bg_color(fbi, 0x07, 0x38, 0xc0); ++ } ++} ++#endif /* CONFIG_FTLCD_OSD */ ++ ++struct andesIO { ++ ++ unsigned long Regaddr; ++ unsigned long Regoffset; ++ unsigned long Regvalue; ++}; ++ ++static int faradayfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) ++{ ++ int ret = 0; ++#ifdef CONFIG_FTLCD_OSD ++ struct faradayfb_info *fbi = info->par; ++ int i; ++ struct fosd_data fosd; ++ ++ struct andesIO IOAccess; ++ unsigned long *Regaccess; ++#endif ++ ++ DEBUG(0, 1, "Enter\n"); ++ ++ switch (cmd) { ++#ifdef CONFIG_FTLCD_OSD ++ case FRREG: ++ ++ if (copy_from_user(&IOAccess, (struct andesIO *)arg, sizeof(struct andesIO))) { ++ ++ ret = -EFAULT; ++ break; ++ } ++ ++ Regaccess = (unsigned long *)(((IOAccess.Regaddr >> 4) | (unsigned long)0xF0000000) + IOAccess.Regoffset); ++ ++ IOAccess.Regvalue = *(Regaccess); ++ ++ if (copy_to_user((struct andesIO *)arg, &IOAccess, sizeof(struct andesIO))) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ break; ++ ++ case FWREG: ++ ++ if (copy_from_user(&IOAccess, (struct andesIO *)arg, sizeof(struct andesIO))) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ Regaccess = (unsigned long *)(((IOAccess.Regaddr >> 4) | (unsigned long)0xF0000000) + IOAccess.Regoffset); ++ *(Regaccess) = IOAccess.Regvalue; ++ ++ break; ++ ++ case FOSD_ON: ++ ++ DEBUG(1, 1, "FOSD_ON:\n"); ++ OSD_On(fbi); ++ break; ++ ++ case FOSD_OFF: ++ ++ DEBUG(1, 1, "FOSD_OFF:\n"); ++ OSD_Off(fbi); ++ break; ++ ++ case FOSD_SETPOS: ++ ++ DEBUG(1, 1, "FOSD_SETPOS:\n"); ++ ++ if (copy_from_user(&fosd, (unsigned int *)arg, 2 * sizeof(unsigned int))) { ++ ++ ret = -EFAULT; ++ break; ++ } ++ ++ OSD_Pos(fbi, fosd.HPos, fosd.VPos); ++ DEBUG(1, 1, "OSD_Pos = %d %d\n", fosd.HPos, fosd.VPos); ++ break; ++ ++ case FOSD_SETDIM: ++ ++ DEBUG(1, 1, "FOSD_SETDIM:\n"); ++ ++ if (copy_from_user(&fosd, (unsigned int *)arg, 4 * sizeof(unsigned int))) { ++ ++ ret = -EFAULT; ++ break; ++ } ++ ++ OSD_Dim(fbi, fosd.HDim, fosd.VDim); ++ DEBUG(1, 1, "OSD_Dim = %d %d\n", fosd.HDim, fosd.VDim); ++ break; ++ ++ case FOSD_SETSCAL: ++ ++ DEBUG(1, 1, "FOSD_SETSCAL:\n"); ++ ++ if (copy_from_user(&fosd, (unsigned int *)arg, 7 * sizeof(unsigned int))) { ++ ret = -EFAULT; ++ break; ++ } ++ ++ OSD_Scal(fbi, fosd.HScal, fosd.VScal); ++ break; ++ ++ case FLCD_SET_TRANSPARENT: ++ ++ DEBUG(1, 1, "FLCD_SET_TRANSPARENT:\n"); ++ ++ if (copy_from_user(&fosd, (unsigned int *)arg, 5 * sizeof(unsigned int))) { ++ ++ ret = -EFAULT; ++ break; ++ } ++ ++ OSD_transparent(fbi, fosd.transparent_level); ++ DEBUG(1, 1, "OSD_transparent = %d\n", fosd.transparent_level); ++ break; ++ ++ case FLCD_SET_STRING: ++ ++ DEBUG(1, 1, "FLCD_SET_STRING:\n"); ++ ++ if (copy_from_user(&fosd, (unsigned int *)arg, sizeof(struct fosd_data))) { ++ ++ ret = -EFAULT; ++ break; ++ } ++ ++ for (i = 0; i < fosd.VDim; i++) ++ ++ OSD_String(fbi, fosd.Str_Data[i].Str_row, ++ fosd.Str_Data[i].display_mode, ++ fosd.Str_Data[i].Str_OSD, ++ fosd.Str_Data[i].fg_color, ++ fosd.Str_Data[i].bg_color); ++ break; ++#endif /* CONFIG_FTLCD_OSD */ ++ ++ default: ++ ++ DEBUG(1, 1, "IOCTL CMD(0x%08u) no define!\n", cmd); ++ ret = -EFAULT; ++ break; ++ } ++ ++ DEBUG(0, 1, "Leave\n"); ++ return ret; ++} ++ +diff -Nur linux-3.4.110.orig/drivers/video/Kconfig linux-3.4.110/drivers/video/Kconfig +--- linux-3.4.110.orig/drivers/video/Kconfig 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/video/Kconfig 2016-04-07 10:20:51.058085512 +0200 +@@ -2166,6 +2166,8 @@ + ---help--- + Say Y here to enable support for PNX4008 RGB Framebuffer + ++source "drivers/video/FTLCDC100/Kconfig" ++ + config FB_IBM_GXT4500 + tristate "Framebuffer support for IBM GXT4500P adaptor" + depends on FB && PPC +diff -Nur linux-3.4.110.orig/drivers/video/Makefile linux-3.4.110/drivers/video/Makefile +--- linux-3.4.110.orig/drivers/video/Makefile 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/video/Makefile 2016-04-07 10:20:51.058085512 +0200 +@@ -143,6 +143,7 @@ + obj-$(CONFIG_FB_CARMINE) += carminefb.o + obj-$(CONFIG_FB_MB862XX) += mb862xx/ + obj-$(CONFIG_FB_MSM) += msm/ ++obj-$(CONFIG_FB_FTLCDC100) += FTLCDC100/ + obj-$(CONFIG_FB_NUC900) += nuc900fb.o + obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o + obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o +diff -Nur linux-3.4.110.orig/drivers/watchdog/ftwdt010_wdt.c linux-3.4.110/drivers/watchdog/ftwdt010_wdt.c +--- linux-3.4.110.orig/drivers/watchdog/ftwdt010_wdt.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/drivers/watchdog/ftwdt010_wdt.c 2016-04-07 10:20:51.058085512 +0200 +@@ -0,0 +1,127 @@ ++/* ++ * Watchdog driver for the FTWDT010 Watch Dog Driver ++ * ++ * (c) Copyright 2004 Faraday Technology Corp. (www.faraday-tech.com) ++ * Based on sa1100_wdt.c by Oleg Drokin <green@crimea.edu> ++ * Based on SoftDog driver by Alan Cox <alan@redhat.com> ++ * ++ * 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. ++ * ++ * 27/11/2004 Initial release ++ */ ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/miscdevice.h> ++#include <linux/watchdog.h> ++#include <linux/delay.h> ++#include <asm/uaccess.h> ++ ++#define DEBUG( str, ...) \ ++ do{ \ ++ if( debug) \ ++ printk( str, ##__VA_ARGS__); \ ++ } while(0) ++ ++#define wdcounter (*( volatile unsigned long *)( WDT_FTWDT010_VA_BASE + 0x00)) ++#define wdload (*( volatile unsigned long *)( WDT_FTWDT010_VA_BASE + 0x04)) ++#define wdrestart (*( volatile unsigned long *)( WDT_FTWDT010_VA_BASE + 0x08)) ++#define wdcr (*( volatile unsigned long *)( WDT_FTWDT010_VA_BASE + 0x0C)) ++#define wdstatus (*( volatile unsigned long *)( WDT_FTWDT010_VA_BASE + 0x10)) ++#define wdclear (*( volatile unsigned long *)( WDT_FTWDT010_VA_BASE + 0x14)) ++#define wdintrcter (*( volatile unsigned long *)( WDT_FTWDT010_VA_BASE + 0x18)) ++ ++#define TIMER_MARGIN 60 /* (secs) Default is 1 minute */ ++#define RESTART_MAGIC 0x5AB9 ++#define PCLK (AHB_CLK_IN / 2) ++ ++static int debug = 0; ++static int timeout = TIMER_MARGIN; /* in seconds */ ++ ++module_param(debug, int, 0); ++module_param(timeout, int, 0); ++ ++static int ftwdt010_dog_open(struct inode *inode, struct file *file){ ++ ++#if 0 ++ /* Allow only one person to hold it open */ ++ if( test_and_set_bit( 1, &ftwdt010_wdt_users)) ++ return -EBUSY; ++ ++ ftwdt010_wdt_users = 1; ++#endif ++ DEBUG("Activating WDT..\n"); ++ ++ wdcr = 0; ++ wdload = PCLK * timeout; ++ wdrestart = RESTART_MAGIC; /* Magic number */ ++ wdcr = 0x03; /* Enable WDT */ ++ ++ return 0; ++} ++ ++static int ftwdt010_dog_release(struct inode *inode, struct file *file){ ++ ++#ifndef CONFIG_WATCHDOG_NOWAYOUT ++ /* ++ * Shut off the timer. ++ * Lock it in if it's a module and we defined ...NOWAYOUT ++ */ ++ wdcr = 0; ++ DEBUG( "Deactivating WDT..\n"); ++#endif ++ return 0; ++} ++ ++static ssize_t ftwdt010_dog_write(struct file *file, const char *data, size_t len, loff_t *ppos){ ++ ++ if(len){ ++ ++ wdrestart = RESTART_MAGIC; ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static struct file_operations ftwdt010_dog_fops = { ++ ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .write = ftwdt010_dog_write, ++ .open = ftwdt010_dog_open, ++ .release = ftwdt010_dog_release, ++}; ++ ++static struct miscdevice ftwdt010_dog_miscdev = { ++ ++ WATCHDOG_MINOR, ++ "FTWDT010 watchdog", ++ &ftwdt010_dog_fops ++}; ++ ++static int __init ftwdt010_dog_init( void){ ++ ++ int ret; ++ ++ ret = misc_register(&ftwdt010_dog_miscdev); ++ ++ if( ret) ++ return ret; ++ ++ DEBUG("FTWDT010 watchdog timer: timer timeout %d sec\n", timeout); ++ ++ return 0; ++} ++ ++static void __exit ftwdt010_dog_exit( void){ ++ ++ misc_deregister(&ftwdt010_dog_miscdev); ++} ++ ++module_init(ftwdt010_dog_init); ++module_exit(ftwdt010_dog_exit); ++MODULE_AUTHOR("Faraday Corp."); ++MODULE_LICENSE("GPL"); +diff -Nur linux-3.4.110.orig/drivers/watchdog/Kconfig linux-3.4.110/drivers/watchdog/Kconfig +--- linux-3.4.110.orig/drivers/watchdog/Kconfig 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/watchdog/Kconfig 2016-04-07 10:20:51.058085512 +0200 +@@ -64,6 +64,12 @@ + To compile this driver as a module, choose M here: the + module will be called softdog. + ++config FTWDT010_WATCHDOG ++ tristate "FTWDT010_WATCHDOG" ++ help ++ Support for Faraday ftwdt010 watchdog. When the watchdog triigers the ++ system will be reset. ++ + config WM831X_WATCHDOG + tristate "WM831x watchdog" + depends on MFD_WM831X +diff -Nur linux-3.4.110.orig/drivers/watchdog/Makefile linux-3.4.110/drivers/watchdog/Makefile +--- linux-3.4.110.orig/drivers/watchdog/Makefile 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/drivers/watchdog/Makefile 2016-04-07 10:20:51.058085512 +0200 +@@ -163,6 +163,7 @@ + obj-$(CONFIG_XEN_WDT) += xen_wdt.o + + # Architecture Independent ++obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o + obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o + obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o + obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o +diff -Nur linux-3.4.110.orig/include/linux/mm.h linux-3.4.110/include/linux/mm.h +--- linux-3.4.110.orig/include/linux/mm.h 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/include/linux/mm.h 2016-04-07 10:20:51.058085512 +0200 +@@ -157,6 +157,7 @@ + #define FAULT_FLAG_ALLOW_RETRY 0x08 /* Retry fault if blocking */ + #define FAULT_FLAG_RETRY_NOWAIT 0x10 /* Don't drop mmap_sem and wait when retrying */ + #define FAULT_FLAG_KILLABLE 0x20 /* The fault task is in SIGKILL killable region */ ++#define FAULT_FLAG_TRIED 0x40 /* second try */ + + /* + * This interface is used by x86 PAT code to identify a pfn mapping that is +diff -Nur linux-3.4.110.orig/include/linux/semaphore.h linux-3.4.110/include/linux/semaphore.h +--- linux-3.4.110.orig/include/linux/semaphore.h 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/include/linux/semaphore.h 2016-04-07 10:20:51.062085666 +0200 +@@ -36,6 +36,9 @@ + lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0); + } + ++#define init_MUTEX(sem) sema_init(sem, 1) ++#define init_MUTEX_LOCKED(sem) sema_init(sem, 0) ++ + extern void down(struct semaphore *sem); + extern int __must_check down_interruptible(struct semaphore *sem); + extern int __must_check down_killable(struct semaphore *sem); +diff -Nur linux-3.4.110.orig/init/Kconfig linux-3.4.110/init/Kconfig +--- linux-3.4.110.orig/init/Kconfig 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/init/Kconfig 2016-04-07 10:20:51.062085666 +0200 +@@ -966,7 +966,7 @@ + + config UID16 + bool "Enable 16-bit UID system calls" if EXPERT +- depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && COMPAT) || UML || (X86_64 && IA32_EMULATION) ++ depends on ARM || BLACKFIN || CRIS || FRV || H8300 || X86_32 || M68K || NDS32 || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && COMPAT) || UML || (X86_64 && IA32_EMULATION) + default y + help + This enables the legacy 16-bit UID syscall wrappers. +diff -Nur linux-3.4.110.orig/kernel/Makefile linux-3.4.110/kernel/Makefile +--- linux-3.4.110.orig/kernel/Makefile 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/kernel/Makefile 2016-04-07 10:20:51.062085666 +0200 +@@ -20,6 +20,7 @@ + CFLAGS_REMOVE_rtmutex-debug.o = -pg + CFLAGS_REMOVE_cgroup-debug.o = -pg + CFLAGS_REMOVE_irq_work.o = -pg ++CFLAGS_REMOVE_kallsyms.o = -pg + endif + + obj-y += sched/ +diff -Nur linux-3.4.110.orig/kernel/trace/Kconfig linux-3.4.110/kernel/trace/Kconfig +--- linux-3.4.110.orig/kernel/trace/Kconfig 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/kernel/trace/Kconfig 2016-04-07 10:20:51.062085666 +0200 +@@ -141,7 +141,7 @@ + config FUNCTION_TRACER + bool "Kernel Function Tracer" + depends on HAVE_FUNCTION_TRACER +- select FRAME_POINTER if !ARM_UNWIND && !PPC && !S390 && !MICROBLAZE ++ select FRAME_POINTER if !ARM_UNWIND && !PPC && !S390 && !MICROBLAZE && !NDS32 + select KALLSYMS + select GENERIC_TRACER + select CONTEXT_SWITCH_TRACER +diff -Nur linux-3.4.110.orig/lib/Kconfig.debug linux-3.4.110/lib/Kconfig.debug +--- linux-3.4.110.orig/lib/Kconfig.debug 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/lib/Kconfig.debug 2016-04-07 10:20:51.062085666 +0200 +@@ -615,7 +615,7 @@ + bool + depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT + select STACKTRACE +- select FRAME_POINTER if !MIPS && !PPC && !ARM_UNWIND && !S390 && !MICROBLAZE ++ select FRAME_POINTER if !MIPS && !PPC && !ARM_UNWIND && !S390 && !MICROBLAZE && !NDS32 + select KALLSYMS + select KALLSYMS_ALL + +@@ -1122,7 +1122,7 @@ + depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT + depends on !X86_64 + select STACKTRACE +- select FRAME_POINTER if !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND ++ select FRAME_POINTER if !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND && !NDS32 + help + Provide stacktrace filter for fault-injection capabilities + +@@ -1132,7 +1132,7 @@ + depends on DEBUG_KERNEL + depends on STACKTRACE_SUPPORT + depends on PROC_FS +- select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND ++ select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND && !NDS32 + select KALLSYMS + select KALLSYMS_ALL + select STACKTRACE +diff -Nur linux-3.4.110.orig/sound/Kconfig linux-3.4.110/sound/Kconfig +--- linux-3.4.110.orig/sound/Kconfig 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/sound/Kconfig 2016-04-07 10:20:51.062085666 +0200 +@@ -93,6 +93,8 @@ + + source "sound/sh/Kconfig" + ++source "sound/nds32/Kconfig" ++ + # the following will depend on the order of config. + # here assuming USB is defined before ALSA + source "sound/usb/Kconfig" +diff -Nur linux-3.4.110.orig/sound/Makefile linux-3.4.110/sound/Makefile +--- linux-3.4.110.orig/sound/Makefile 2015-10-22 03:20:09.000000000 +0200 ++++ linux-3.4.110/sound/Makefile 2016-04-07 10:20:51.062085666 +0200 +@@ -6,7 +6,7 @@ + obj-$(CONFIG_SOUND_PRIME) += oss/ + obj-$(CONFIG_DMASOUND) += oss/ + obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ +- firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ ++ firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ nds32/ + obj-$(CONFIG_SND_AOA) += aoa/ + + # This one must be compilable even if sound is configured out +diff -Nur linux-3.4.110.orig/sound/nds32/FTSSP010_ALSA.c linux-3.4.110/sound/nds32/FTSSP010_ALSA.c +--- linux-3.4.110.orig/sound/nds32/FTSSP010_ALSA.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/sound/nds32/FTSSP010_ALSA.c 2016-04-07 10:20:51.062085666 +0200 +@@ -0,0 +1,2020 @@ ++/* FTSSP010 - UDA1345TS module: ++ * ++ * $log$ ++ * ++ * 2006/02/23: I-Jui Sung: OSS emulation half-duplex ++ * playback/capture at 48K, 44.1K, 8K ++ * with mono/stereo 16bit/8bit ++ * ++ * 2006/02/22: I-Jui Sung: OSS emulation playback at 44.1KHz ++ * 16-bit mono completed. Relying ALSA to ++ * resample ++ * 2009/02/24: dma upgrade checking list: ++ * - ac97 mode playback ................. ok ++ * - ac97 mode capture .................. ok ++ * - i2s mode playback .................. ok ++ * - i2s mode capture ................... ok ++ * - mixer support (snd_ctl_add, ...) ... todo ++ * - debug /proc entry .................. ok ++ */ ++ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <asm/io.h> ++#include <linux/delay.h> ++//#include <asm/spec.h> ++#include <asm/dmad.h> ++#include <linux/dma-mapping.h> ++#include <sound/core.h> ++#include <sound/pcm.h> ++#include <sound/initval.h> ++#include <sound/asound.h> ++#include <linux/i2c.h> ++#include <sound/control.h> ++#include <linux/interrupt.h> ++ ++#include <asm/hardware.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++#include <asm/spec.h> ++ ++#include "FTSSP010_UDA1345TS.h" ++ ++//ADD by river 2011.06.02 ++struct alc5630_data; ++//End ADD by river 2011.06.02 ++ ++void init_hw(unsigned int cardno,unsigned int ac97, struct i2c_client *client); ++ ++#if (!defined(CONFIG_PLATFORM_AHBDMA) && !defined(CONFIG_PLATFORM_APBDMA)) ++#warning needs ahb/apb dma to wrok ++#endif ++ ++/* --------------------------------------------------------------------------- ++ * Define the debug level of FTSSP_DEBUG ++ */ ++#define FTSSP_DEBUG 0 ++#define FTSSP_DEBUG_VERBOSE 0 ++#define FTSSP_PROC_FS 0 ++ ++#undef VVDBG ++#if (FTSSP_DEBUG_VERBOSE) ++#define VVDBG(vvar...) (void)0 ++//#define VVDBG(vvar...) printk(KERN_INFO vvar) ++#else ++#define VVDBG(vvar...) (void)0 ++#endif ++ ++#undef ERR ++#define ERR(vvar...) printk(KERN_ERR vvar) ++ ++#undef INFO ++#define INFO(vvar...) printk(KERN_INFO vvar) ++ ++#if (FTSSP_DEBUG) ++#undef DBG ++#define DBG(vvar...) printk(KERN_INFO vvar) ++#else ++#define DBG(vvar...) (void)0 ++#endif ++ ++#if (FTSSP_DEBUG_VERBOSE) ++#undef VDBG ++#define VDBG(vvar...) printk(KERN_INFO vvar) ++#else ++#define VDBG(vvar...) (void)0 ++#endif ++ ++#ifdef CONFIG_SND_FTSSP010_I2S ++//ADD by river 2011.02.11 ++static struct i2c_client *g_i2c_client; ++ ++////////// ADD by river 2011.01.26 ++// Each client has this additional data ++struct alc5630_data { ++ struct i2c_client *client; ++ struct delayed_work work; ++ unsigned long gpio2_value; ++ struct mutex mtx; ++}; ++ ++static int alc5630_i2c_attach(struct i2c_adapter *adapter); ++static int alc5630_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); ++static int alc5630_i2c_suspend(struct i2c_client *i2c_client, pm_message_t mesg); ++static int alc5630_i2c_resume(struct i2c_client *i2c_client); ++ ++static int alc5630_i2c_remove(struct i2c_client *client); ++static int ftssp_alsa_init(struct i2c_client *client); ++ ++ ++static int i2s_alc5630_read(unsigned int raddr, char *data, struct i2c_client *client) ++{ ++ struct i2c_adapter *adap = client->adapter; ++ struct i2c_msg msg; ++ int ret, i2c_value; ++ ++ //Reading ALC5630 register ++ msg.addr = raddr; ++ msg.flags = (client->flags & I2C_M_TEN) | I2C_M_RD; ++ msg.len = 1; ++ msg.buf = (char *)data; ++ ++ //ret = i2c_transfer(adap, &msg, 1); ++ #ifndef CONFIG_SND_FTSSP010_AC97 ++ ret = i2c_transfer(adap, &msg, 1); ++ #endif ++ ++ if (ret != 0) { ++ printk("i2c read failed\n"); ++ return -1; ++ } ++ else ++ { ++ i2c_value = (data[0]&0xff) << 8 | (data[1]&0xff); ++ return i2c_value; ++ } ++ ++} ++ ++static void i2s_alc5630_write(unsigned int addr, unsigned int data, struct i2c_client *client) ++{ ++ ++ struct i2c_adapter *adap = client->adapter; ++ struct i2c_msg msg; ++ int ret, i2c_value; ++ char buf[3]; ++ ++ //Writing ALC5630 register ++ i2c_value = 0x0; ++ msg.addr = addr; ++ msg.flags = (client->flags & I2C_M_TEN) | ~I2C_M_RD; ++ msg.len = 1; ++ ++ buf[0] = (data >> 8) & 0xff; ++ buf[1] = data & 0xff; ++ msg.buf = (char *)buf; ++ ++ //ret = i2c_transfer(adap, &msg, 1); ++ #ifndef CONFIG_SND_FTSSP010_AC97 ++ ret = i2c_transfer(adap, &msg, 1); ++ #endif ++ ++ if (ret != 0) { ++ printk("i2c write failed\n"); ++ } ++ ++} ++ ++static void i2s_alc5630_read_test(struct i2c_client *client) ++{ ++ char data[3]; ++ //printk(">>>>> : i2s_alc5630_read_test().....\n"); ++ printk("Reg 0x%02x = 0x%08x\n", 0x0, i2s_alc5630_read(0x0, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x02, i2s_alc5630_read(0x02, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x04, i2s_alc5630_read(0x04, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x06, i2s_alc5630_read(0x06, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x08, i2s_alc5630_read(0x08, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x0a, i2s_alc5630_read(0x0a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x0c, i2s_alc5630_read(0x0c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x0e, i2s_alc5630_read(0x0e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x10, i2s_alc5630_read(0x10, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x12, i2s_alc5630_read(0x12, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x14, i2s_alc5630_read(0x14, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x16, i2s_alc5630_read(0x16, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x18, i2s_alc5630_read(0x18, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x1a, i2s_alc5630_read(0x1a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x1c, i2s_alc5630_read(0x1c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x1e, i2s_alc5630_read(0x1e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x20, i2s_alc5630_read(0x20, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x22, i2s_alc5630_read(0x22, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x24, i2s_alc5630_read(0x24, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x26, i2s_alc5630_read(0x26, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x28, i2s_alc5630_read(0x28, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x2a, i2s_alc5630_read(0x2a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x2c, i2s_alc5630_read(0x2c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x2e, i2s_alc5630_read(0x2e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x30, i2s_alc5630_read(0x30, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x32, i2s_alc5630_read(0x32, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x34, i2s_alc5630_read(0x34, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x36, i2s_alc5630_read(0x36, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x38, i2s_alc5630_read(0x38, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x3a, i2s_alc5630_read(0x3a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x3c, i2s_alc5630_read(0x3c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x3e, i2s_alc5630_read(0x3e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x40, i2s_alc5630_read(0x40, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x42, i2s_alc5630_read(0x42, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x44, i2s_alc5630_read(0x44, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x46, i2s_alc5630_read(0x46, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x48, i2s_alc5630_read(0x48, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x4a, i2s_alc5630_read(0x4a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x4c, i2s_alc5630_read(0x4c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x4e, i2s_alc5630_read(0x4e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x50, i2s_alc5630_read(0x50, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x52, i2s_alc5630_read(0x52, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x54, i2s_alc5630_read(0x54, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x56, i2s_alc5630_read(0x56, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x58, i2s_alc5630_read(0x58, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x5a, i2s_alc5630_read(0x5a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x5c, i2s_alc5630_read(0x5c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x5e, i2s_alc5630_read(0x5e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x60, i2s_alc5630_read(0x60, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x62, i2s_alc5630_read(0x62, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x64, i2s_alc5630_read(0x64, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x66, i2s_alc5630_read(0x66, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x68, i2s_alc5630_read(0x68, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x6a, i2s_alc5630_read(0x6a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x6c, i2s_alc5630_read(0x6c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x6e, i2s_alc5630_read(0x6e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x70, i2s_alc5630_read(0x70, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x72, i2s_alc5630_read(0x72, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x74, i2s_alc5630_read(0x74, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x76, i2s_alc5630_read(0x76, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x78, i2s_alc5630_read(0x78, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x7a, i2s_alc5630_read(0x7a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x7c, i2s_alc5630_read(0x7c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x7e, i2s_alc5630_read(0x7e, data,client)); ++ ++} ++ ++static int alc5630_i2c_attach(struct i2c_adapter *adapter){ ++ ++ struct i2c_board_info info; ++ struct i2c_client *client; ++ ++ int ret=0; ++ ++ //i2c_dbg( 1, "alc5630_i2c_attach() is called.\n"); ++ //printk(">>>>>>>>>> (2) alc5630_i2c_attach() is called.\n"); ++ ++ //ret = i2c_probe(adapter, &addr_data, alc5630_detect); ++ memset(&info, 0, sizeof(struct i2c_board_info)); ++ strlcpy(info.type, "alc5630_codec", I2C_NAME_SIZE); ++ //info.addr = 0x3e; ++ info.addr = 0x66; ++ //info.platform_data = node; ++ ++ //client = i2c_new_device(adapter, &info); ++ #ifndef CONFIG_SND_FTSSP010_AC97 ++ client = i2c_new_device(adapter, &info); ++ #endif ++ if (!client) { ++ printk("$$$$$????? : i2c_new_device() failed.....\n"); ++ return -ENODEV; ++ } ++ /* ++ * We know the driver is already loaded, so the device should be ++ * already bound. If not it means binding failed, and then there ++ * is no point in keeping the device instantiated. ++ */ ++ if (!client->driver) { ++ //i2c_unregister_device(client); ++ #ifndef CONFIG_SND_FTSSP010_AC97 ++ i2c_unregister_device(client); ++ #endif ++ return -ENODEV; ++ } ++ ++ /* ++ * Let i2c-core delete that device on driver removal. ++ * This is safe because i2c-core holds the core_lock mutex for us. ++ */ ++ list_add_tail(&client->detected, &client->driver->clients); ++ ++ return ret; ++} ++ ++static irqreturn_t gpio2_irq(int irq, void *dev_id) ++{ ++ ++ struct i2c_client *client = (struct i2c_client *)dev_id; ++ struct alc5630_data *alc5630 = i2c_get_clientdata(client); ++ ++ unsigned long org_mask, org_dir; ++ //printk("@@@@@#####$$$$$!!!!! : gpio2_irq is detected ???....\n"); ++ ++ //Mask GPIO interrupt ++ //REG32(AMIC_VA_BASE + 0x80) = REG32(AMIC_VA_BASE + 0x80) & ~(1 << 13); //GPIO interrupt disable ++ ++ //Dump AMIC contents and ir~ ++ unsigned long ir0,ir1,ir2, ir3, ir4, ir5; ++ unsigned long ir6, ir7, ir8, ir9, ir10; ++ unsigned long ir11, ir12, ir13, ir14, ir15; ++ unsigned long gpio2_value, value; ++ char data[3]; ++ ++ ++ //__asm__ volatile ("setgie.d\n\t"); ++ //REG32(AMIC_VA_BASE + 0x80) = 0; ++ ++ ++ //Get original gpio direction ++ org_dir = REG32(GPIO_VA_BASE + 0x08); ++ ++ //Get original gpio interrupt mask ++ org_mask = REG32(GPIO_VA_BASE + 0x2c); ++ ++ //Mask all gpio interrupt ++ REG32(GPIO_VA_BASE + 0x2c) = 0x0000FFFF; ++ //Clear all gpio interrupt ++ REG32(GPIO_VA_BASE + 0x30) = 0x0000FFFF; ++ ++ //Get gpio pin value ++ REG32(GPIO_VA_BASE + 0x08) = REG32(GPIO_VA_BASE + 0x08) & ~(0x1UL << 2); //Set gpio2 direction => input ++ gpio2_value = (REG32(GPIO_VA_BASE + 0x04) >> 2 & 1); ++ //printk("The gpio2 value is 0x%08x\n",gpio2_value); ++ ++ ++ alc5630->gpio2_value = gpio2_value; ++ schedule_delayed_work(&alc5630->work, 1); ++ ++ /*if (gpio3_value==0x1) { ++ i2s_alc5630_write(0x02, 0x0000, g_i2c_client); ++ i2s_alc5630_write(0x3A, i2s_alc5630_read(0x3A, data,g_i2c_client)|0x0040 , g_i2c_client); ++ printk("External speaker is plugged in... and Try to mute internal speaker......\n"); ++ } ++ else { ++ i2s_alc5630_write(0x02, 0x5F5F, g_i2c_client); ++ i2s_alc5630_write(0x3A, i2s_alc5630_read(0x3A, data,g_i2c_client)|0x0440 , g_i2c_client); ++ printk("External speaker is pulled ... and Try to unmute internal speaker......\n"); ++ }*/ ++ ++ ++ //Set gpio3 pin value to 0 ++ //REG32(GPIO_VA_BASE + 0x08) = REG32(GPIO_VA_BASE + 0x08) | (0x1UL << 3); //Set gpio3 direction => output ++ //value = REG32(GPIO_VA_BASE + 0x00) & ~(0x1UL << 3); ++ //REG32(GPIO_VA_BASE + 0x00) = value; ++ ++ //Get gpio pin value again ++ //REG32(GPIO_VA_BASE + 0x08) = REG32(GPIO_VA_BASE + 0x08) & ~(0x1UL << 3); //Set gpio3 direction => input ++ //gpio3_value = (REG32(GPIO_VA_BASE + 0x04) >> 3 & 1); ++ //printk("The gpio3 value is 0x%08x\n",gpio3_value); ++ ++ //restore original gpio interrupt mask ++ REG32(GPIO_VA_BASE + 0x2c) = org_mask; ++ ++ //restore original gpio direction ++ REG32(GPIO_VA_BASE + 0x08) = org_dir; ++ ++ //unmask GPIO interrupt ++ //REG32(AMIC_VA_BASE + 0x80) = REG32(AMIC_VA_BASE + 0x80) | (1 << 13); //GPIO interrupt enable ++ REG32(AMIC_VA_BASE + 0x84) = REG32(AMIC_VA_BASE + 0x84) | (1 << 13); //Clear GPIO interrupt ++ REG32(GPIO_VA_BASE + 0x30) = 0x0000FFFF; //Clear all gpio interrupt ++ ++ //printk("@@@@@#####$$$$$!!!!! : gpio2_irq() is exited....\n"); ++ ++ return IRQ_HANDLED; ++} ++ ++static void iic_work(struct work_struct *work) ++{ ++ char data[3]; ++ struct alc5630_data *alc5630 = ++ container_of(to_delayed_work(work), struct alc5630_data, work); ++ ++ ++ if (alc5630->gpio2_value==0x0) { ++ //i2s_alc5630_write(0x02, 0x0000, alc5630->client); ++ i2s_alc5630_write(0x02, 0x5F5F, alc5630->client); ++ i2s_alc5630_write(0x3A, (i2s_alc5630_read(0x3A, data,alc5630->client) & 0xFBFF) | 0x0040 , alc5630->client); ++ //printk("External speaker is plugged in... and Try to mute internal speaker......\n"); ++ //i2s_alc5630_read_test(alc5630->client); ++ } ++ else { ++ //i2s_alc5630_write(0x02, 0x5F5F, alc5630->client); ++ i2s_alc5630_write(0x02, 0x0000, alc5630->client); ++ i2s_alc5630_write(0x3A, i2s_alc5630_read(0x3A, data,alc5630->client)|0x0440 , alc5630->client); ++ //printk("External speaker is pulled ... and Try to unmute internal speaker......\n"); ++ //i2s_alc5630_read_test(alc5630->client); ++ } ++ //ftsdc_enable_irq(host, false); ++ ++ ++ //ftsdc_enable_irq(host, true); ++} ++ ++static int alc5630_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ ++ struct alc5630_data *alc5630; ++ struct i2c_adapter *adap = client->adapter; ++ //unsigned char ret1, ret2; ++ struct i2c_msg msg; ++ char rbuf[3], wbuf[3]; ++ int ret, i2c_rvalue, i2c_wvalue; ++ unsigned int gpio2_value; ++ char data[3]; ++ ++ //i2c_dbg( 1, "alc5630_i2c_probe() is called.\n"); ++ //printk(">>>>>>>>>> (3) alc5630_i2c_probe() is called.\n"); ++ ++ alc5630 = kzalloc(sizeof(struct alc5630_data), GFP_KERNEL); ++ ++ if (!alc5630) ++ return -ENOMEM; ++ ++ mutex_init(&alc5630->mtx); ++ client-> flags = 0; ++ alc5630->client = client; ++ i2c_set_clientdata(client, alc5630); ++ ++ //ADD by river 2011.05.18 for GPIO2 interrupt => edge trigger and rising edge ++ REG32(GPIO_VA_BASE + 0x20) = 0x00000000; ++ REG32(GPIO_VA_BASE + 0x2c) = 0x00000000; ++ REG32(GPIO_VA_BASE + 0x2c) = 0x00000000; ++ REG32(GPIO_VA_BASE + 0x30) = 0x0000FFFF; ++ REG32(GPIO_VA_BASE + 0x38) = 0x0000FFFF; ++ REG32(GPIO_VA_BASE + 0x40) = 0x0000FFFF; ++ ++ ++ REG32(GPIO_VA_BASE + 0x08) = REG32(GPIO_VA_BASE + 0x08) & ~(1 << 2); //GPIO2 as input ++ REG32(GPIO_VA_BASE + 0x34) = REG32(GPIO_VA_BASE + 0x34) & ~(1 << 2); //GPIO2 edge trigger ++ //REG32(GPIO_VA_BASE + 0x38) = REG32(GPIO_VA_BASE + 0x38) & ~(1 << 2); //GPIO2 single edge ++ REG32(GPIO_VA_BASE + 0x38) = REG32(GPIO_VA_BASE + 0x38) | (1 << 2); //GPIO2 both edge ++ REG32(GPIO_VA_BASE + 0x3c) = REG32(GPIO_VA_BASE + 0x3c) & ~(1 << 2); //GPIO2 rising edge ++ REG32(GPIO_VA_BASE + 0x20) = REG32(GPIO_VA_BASE + 0x20) | (1 << 2); //GPIO2 pin interrupt enable ++ ++ REG32(AMIC_VA_BASE + 0x20) = REG32(AMIC_VA_BASE + 0x20) | (1 << 13); //Interrupt Trigger Mode (edge trigger) ++ REG32(AMIC_VA_BASE + 0x24) = REG32(AMIC_VA_BASE + 0x24) & ~(1 << 13); //Interrupt Trigger edge(rising edge) ++ REG32(AMIC_VA_BASE + 0x80) = REG32(AMIC_VA_BASE + 0x80) | (1 << 13); //GPIO interrupt enabled ++ //REG32(AMIC_VA_BASE + 0x80) = 0; //GPIO interrupt enabled ++ ++ if (request_irq(GPIO_FTGPIO010_IRQ, gpio2_irq, IRQF_SHARED, "gpio2", client)) { ++ printk("Failed to request GPIO2 interrupt.\n"); ++ goto fail; ++ } ++ ++ //ADD by river 2011.07.11 ++ //REG32(GPIO_VA_BASE + 0x08) = REG32(GPIO_VA_BASE + 0x08) & ~(0x1UL << 3); //Set gpio3 direction => input ++ gpio2_value = (REG32(GPIO_VA_BASE + 0x04) >> 2 & 1); ++ //printk("The gpio2 value is 0x%08x\n",gpio2_value); ++ alc5630->gpio2_value = gpio2_value; ++ ++ if (gpio2_value==0x0) { ++ i2s_alc5630_write(0x02, 0x5F5F, alc5630->client); ++ i2s_alc5630_write(0x3A, (i2s_alc5630_read(0x3A, data,alc5630->client) & 0xFBFF) | 0x0040 , alc5630->client); ++ //printk("@@@@@ alc5630_i2c_probe : External speaker is plugged in... and Try to mute internal speaker......\n"); ++ //i2s_alc5630_read_test(alc5630->client); ++ } ++ else { ++ i2s_alc5630_write(0x02, 0x0000, alc5630->client); ++ i2s_alc5630_write(0x3A, i2s_alc5630_read(0x3A, data,alc5630->client)|0x0440 , alc5630->client); ++ //printk("@@@@@ alc5630_i2c_probe : External speaker is pulled ... and Try to unmute internal speaker......\n"); ++ //i2s_alc5630_read_test(alc5630->client); ++ } ++ ++ //End ADD by river 2011.07.11 ++ ++ //ADD by river 2011.06.02 ++ INIT_DELAYED_WORK(&alc5630->work, iic_work); ++ //End ADD by river 2011.06.02 ++ //End ADD by river 2011.05.18 ++ ++ ftssp_alsa_init(client); ++ ++ return 0; ++ fail: ++ mutex_destroy(&alc5630->mtx); ++ kfree(alc5630); ++ return -EINVAL; ++ ++} ++ ++////////End ADD by river 2011.01.26 ++#endif ++ ++/* --------------------------------------------------------------------------- ++ * Preserved size of memory space for audio DMA ring ++ */ ++#define FTSSP_HW_DMA_SIZE (512 * 1024) ++ ++/* Buffer sizes reported to ALSA layer - AC97 mode */ ++ ++/* ring size, exported to application */ ++#define AC97_HW_BUFFER_BYTES_MAX (42 * 1024) ++/* should not exceed AC97_HW_PERIOD_BYTES_MAX */ ++#define AC97_HW_PERIOD_BYTES_MIN (2 * 1024) ++/* AC97_HW_PERIOD_BYTES_MAX * AC97_HW_PERIODS_MAX <= AC97_HW_BUFFER_SIZE */ ++#define AC97_HW_PERIOD_BYTES_MAX (8 * 1024) ++/* 3 <= AC97_HW_PERIODS_MIN <= AC97_HW_PERIODS_MAX */ ++#define AC97_HW_PERIODS_MIN 3 ++/* AC97_HW_PERIOD_BYTES_MAX * AC97_HW_PERIODS_MAX <= AC97_HW_BUFFER_SIZE */ ++#define AC97_HW_PERIODS_MAX 5 ++ ++/* Driver internal dma buffer size, x2 for S16_LE(16-bits) to AC97 (20-bits), ++ * x6 for sampling rate converion from minimum 8k to AC97 48k. ++ * ++ * Note that AC97 mode cannot do playback and recording simultaneouly. So we ++ * use up all FTSSP_HW_DMA_SIZE of memory. ++ */ ++#define AC97_HW_DMA_SIZE (AC97_HW_BUFFER_BYTES_MAX * 2 * 6) ++ ++/* Buffer sizes reported to ALSA layer - I2S mode */ ++ ++/* ring size, exported to application */ ++#define I2S_HW_BUFFER_BYTES_MAX (256 * 1024) ++/* should not exceed I2S_HW_PERIOD_BYTES_MAX */ ++#define I2S_HW_PERIOD_BYTES_MIN (2 * 1024) ++/* I2S_HW_PERIOD_BYTES_MAX * I2S_HW_PERIODS_MAX <= I2S_HW_BUFFER_SIZE */ ++#define I2S_HW_PERIOD_BYTES_MAX (32 * 1024) ++/* 3 <= I2S_HW_PERIODS_MIN <= I2S_HW_PERIODS_MAX */ ++#define I2S_HW_PERIODS_MIN 3 ++/* I2S_HW_PERIOD_BYTES_MAX * I2S_HW_PERIODS_MAX <= I2S_HW_BUFFER_SIZE */ ++#define I2S_HW_PERIODS_MAX 8 ++ ++/* Page-in size for playback and capture each. Note that I2S mode can do ++ * playback and recording simultaneouly, so this size should be less than or ++ * equal to FTSSP_HW_DMA_SIZE/2 ++ */ ++#define I2S_HW_DMA_SIZE (I2S_HW_BUFFER_BYTES_MAX) ++ ++/* --------------------------------------------------------------------------- ++ * Audio formats ++ */ ++#define AC97_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) ++#define AC97_CODEC_SAMPLE_RATES (SNDRV_PCM_RATE_48000 | \ ++ SNDRV_PCM_RATE_16000 | \ ++ SNDRV_PCM_RATE_8000) ++#define AC97_CODEC_SAMPLE_RATE_MIN (8000) ++#define AC97_CODEC_SAMPLE_RATE_MAX (48000) ++ ++#define I2S_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) ++#define I2S_CODEC_SAMPLE_RATES (SNDRV_PCM_RATE_48000 | \ ++ SNDRV_PCM_RATE_44100 | \ ++ SNDRV_PCM_RATE_32000 | \ ++ SNDRV_PCM_RATE_22050 | \ ++ SNDRV_PCM_RATE_16000 | \ ++ SNDRV_PCM_RATE_11025 | \ ++ SNDRV_PCM_RATE_8000) ++#define I2S_CODEC_SAMPLE_RATE_MIN (8000) ++#define I2S_CODEC_SAMPLE_RATE_MAX (48000) ++ ++ ++/* --------------------------------------------------------------------------- ++ * Configuration ++ */ ++#if (CONFIG_PROC_FS == 0) ++#undef FTSSP_PROC_FS ++#define FTSSP_PROC_FS 0 ++#else ++#if (FTSSP_PROC_FS) ++#include <sound/info.h> ++#endif /* FTSSP_PROC_FS */ ++#endif /* CONFIG_PROC_FS */ ++ ++#define FTSSP_CARD_ID "ftssp010" ++#define FTSSP_DRIVER_NAME "ftssp" ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Faraday Technology Corp."); ++MODULE_DESCRIPTION("FTSSP010 Linux 2.6 Driver"); ++ ++static int cardno = 0; ++//static const unsigned int SSP_FTSSP010_pa_base[SSP_FTSSP010_IRQ_COUNT] = ++// { SSP_FTSSP010_PA_BASE }; ++ ++/* Driver mode */ ++#ifdef CONFIG_SND_FTSSP010_AC97 ++static int ac97 = 1; ++#else ++static int ac97 = 0; ++#endif ++ ++// ---------------------------------------------- ++module_param(cardno, int, 0); ++MODULE_PARM_DESC(cardno, "FTSSP No."); ++ ++module_param(ac97, int, 0); ++MODULE_PARM_DESC(ac97, "AC97 mode"); ++// ---------------------------------------------- ++ ++/* --------------------------------------------------------------------------- ++ * Structures ++ */ ++ ++/* private data for card */ ++typedef struct { ++ struct snd_card *card; ++ struct snd_pcm *pcm; ++ struct snd_pcm_substream *substream_tx; ++ struct snd_pcm_substream *substream_rx; ++#if (FTSSP_PROC_FS) ++ struct snd_info_entry *info_buf_max; ++ struct snd_info_entry *info_period_min; ++ struct snd_info_entry *info_period_max; ++ struct snd_info_entry *info_periods_min; ++ struct snd_info_entry *info_periods_max; ++#endif ++} ftssp_chip; ++ ++/* dma request descriptors */ ++dmad_chreq dma_chreq_tx = { ++ .channel = -1, ++ .drq = NULL, ++}; ++ ++dmad_chreq dma_chreq_rx = { ++ .channel = -1, ++ .drq = NULL, ++}; ++ ++/* Holds ALSA card instance pointers */ ++struct snd_card *ftssp_cards[SSP_FTSSP010_COUNT]; ++ ++/* snd_pcm_hardware */ ++static struct snd_pcm_hardware snd_ftssp_pcm_hw = ++{ ++ .info = SNDRV_PCM_INFO_INTERLEAVED, ++ .formats = I2S_CODEC_FORMATS, ++ .rates = I2S_CODEC_SAMPLE_RATES, ++ .rate_min = I2S_CODEC_SAMPLE_RATE_MIN, ++ .rate_max = I2S_CODEC_SAMPLE_RATE_MAX, ++ .channels_min = 1, ++ .channels_max = 2, ++ .buffer_bytes_max = I2S_HW_BUFFER_BYTES_MAX, ++ .period_bytes_min = I2S_HW_PERIOD_BYTES_MIN, ++ .period_bytes_max = I2S_HW_PERIOD_BYTES_MAX, ++ .periods_min = I2S_HW_PERIODS_MIN, ++ .periods_max = I2S_HW_PERIODS_MAX, ++}; ++ ++/* private data for a substream (playback or capture) */ ++/* function pointer for set up AHBDMA for this substream */ ++typedef void (*start_t)(int cardno, unsigned use_dma); ++typedef void (*pmu_set_clocking_t)(unsigned int); ++typedef void (*ftssp010_config_t)(int cardno, unsigned is_stereo, ++ unsigned speed, int use8bit); ++ ++typedef struct { ++ u32 busy; ++ spinlock_t dma_lock; ++ unsigned dma_area_va; ++ int dma_width; ++ unsigned int tx_period; ++ unsigned int rx_period; ++ ++ start_t start; ++ pmu_set_clocking_t pmu_set_clocking; ++ ftssp010_config_t hw_config; ++} ftssp_substream; ++ ++static ftssp_substream ftssp010_substreams[2] = { ++ /* Playback substream */ ++ { ++ busy : 0, ++ start : ftssp010_start_tx, ++ pmu_set_clocking : pmu_set_i2s_clocking, ++ hw_config : ftssp010_config_tx, ++ }, ++ /* Capture substream */ ++ { ++ busy : 0, ++ start : ftssp010_start_rx, ++ pmu_set_clocking : pmu_set_i2s_clocking, ++ hw_config : ftssp010_config_rx, ++ } ++}; ++ ++/* (AC97 only) Convert 16 bits PCM data in user buffer to/from 20 bits PCM data ++ * (32 bits actaully in dma buffer) for AC97 codec. ++ */ ++static int snd_ftssp_playback_copy(struct snd_pcm_substream *substream, ++ int channel, snd_pcm_uframes_t pos, void *usr_buf, ++ snd_pcm_uframes_t count) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ ftssp_substream *ftssp010_substream = ++ (ftssp_substream *) runtime->private_data; ++ ++ ++ //printk("~~~~~ : snd_ftssp_playback_copy() is invoked....\n"); ++ u32 *dma_va = NULL; ++ u16 *usr_va = usr_buf; ++ int copy_words; ++ int pcm_data; ++ ++ dmad_chreq *dma_chreq; ++ ++ /* frames_to_bytes(runtime, pos + count) * 2(bytes/per pcm) / ++ * 4(bytes per dma unit) */ ++ u32 sw_ptr = (u32)frames_to_bytes(runtime, pos + count) >> 1; ++ ++ switch (runtime->rate) { ++ case 8000: ++ sw_ptr *= 6; ++ ++ dma_va = (unsigned *)(ftssp010_substream->dma_area_va + ++ frames_to_bytes(runtime, pos * 6) * 2); ++ ++ VVDBG("%s: pos(0x%08x) count(0x%08x) next_pos(0x%08x)\n", ++ __func__, (u32)pos, (u32)count, (u32)(pos + count)); ++ VVDBG("%s: va base(0x%08x) range (0x%08x ~ 0x%08x)\n", ++ __func__, (u32)ftssp010_substream->dma_area_va, ++ (u32)dma_va, ++ (u32)dma_va + ++ (u32)2 * frames_to_bytes(runtime, count * 6)); ++ ++ if (runtime->channels == 1) { ++ while (count--) { ++ dma_va[0] = (u32)(*usr_va++) << 4; ++ dma_va[1] = dma_va[2] = dma_va[3] = ++ dma_va[4] = dma_va[5] = dma_va[0]; ++ //memcpy(&dma_va[1], &dma_va[0], 5 * 4 * 1); ++ dma_va += 6; ++ } ++ } else { // assume 2 channels ++ while (count--) { ++ dma_va[0] = (u32)(*usr_va++) << 4; ++ dma_va[1] = (u32)(*usr_va++) << 4; ++ dma_va[2] = dma_va[4] = dma_va[6] = ++ dma_va[8] = dma_va[10] = dma_va[0]; ++ dma_va[3] = dma_va[5] = dma_va[7] = ++ dma_va[9] = dma_va[11] = dma_va[0]; ++ //memcpy(&dma_va[2], &dma_va[0], 5 * 4 * 2); ++ dma_va += 12; ++ } ++ } ++ break; ++ case 16000: ++ sw_ptr *= 3; ++ ++ dma_va = (unsigned *)(ftssp010_substream->dma_area_va + ++ frames_to_bytes(runtime, pos * 3) * 2); ++ ++ VVDBG("%s: pos(0x%08x) count(0x%08x) next_pos(0x%08x)\n", ++ __func__, (u32)pos, (u32)count, (u32)(pos + count)); ++ VVDBG("%s: va base(0x%08x) range (0x%08x ~ 0x%08x)\n", ++ __func__, (u32)ftssp010_substream->dma_area_va, ++ (u32)dma_va, ++ (u32)dma_va + ++ (u32)2 * frames_to_bytes(runtime, count * 3)); ++ ++ if (runtime->channels == 1) { ++ while (count--) { ++ dma_va[0] = (u32)(*usr_va++) << 4; ++ dma_va[1] = dma_va[2] = dma_va[0]; ++ //memcpy(&dma_va[1], &dma_va[0], 2 * 4 * 1); ++ dma_va += 3; ++ } ++ } else { // assume 2 channels ++ while (count--) { ++ dma_va[0] = (u32)(*usr_va++) << 4; ++ dma_va[1] = (u32)(*usr_va++) << 4; ++ dma_va[2] = dma_va[4] = dma_va[0]; ++ dma_va[3] = dma_va[5] = dma_va[1]; ++ //memcpy(&dma_va[2], &dma_va[0], 2 * 4 * 2); ++ dma_va += 6; ++ } ++ } ++ break; ++ case 48000: ++ default: ++ dma_va = (unsigned *)(ftssp010_substream->dma_area_va + ++ frames_to_bytes(runtime, pos) * 2); ++ copy_words = 2 * frames_to_bytes(runtime, count) / sizeof(u32); ++ ++ VVDBG("%s: pos(0x%08x) count(0x%08x) next_pos(0x%08x)\n", ++ __func__, (u32)pos, (u32)count, (u32)(pos + count)); ++ VVDBG("%s: va base(0x%08x) range (0x%08x ~ 0x%08x)\n", ++ __func__, (u32)ftssp010_substream->dma_area_va, ++ (u32)dma_va, ++ (u32)dma_va + (u32)copy_words*4); ++ ++ while (copy_words--) { ++ pcm_data = (*usr_va++); ++ *dma_va++= pcm_data << 4; ++ } ++ break; ++ } ++ ++ dma_chreq = &dma_chreq_tx; ++ ++ if (dmad_update_ring_sw_ptr(dma_chreq, sw_ptr, ++ (runtime->status->state == SNDRV_PCM_STATE_RUNNING) ? 1:0) != 0) ++ { ++ ERR("%s: failed to update sw-pointer!\n", __func__); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int snd_ftssp_capture_copy(struct snd_pcm_substream *substream, ++ int channel, snd_pcm_uframes_t pos, void *usr_buf, ++ snd_pcm_uframes_t count) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ ftssp_substream *ftssp010_substream = ++ (ftssp_substream *) runtime->private_data; ++ ++ //printk("~~~~~ : snd_ftssp_capture_copy() is invoked....\n"); ++ //printk(">>>>>>>>>> : snd_ftssp_capture_copy() for recording....\n"); ++ u32 *dma_va = NULL; ++ u16 *usr_va = usr_buf; ++ ++ switch (runtime->rate) { ++ case 8000: ++ dma_va = (unsigned *)(ftssp010_substream->dma_area_va + ++ frames_to_bytes(runtime, pos * 6) * 2); ++ ++ VVDBG("%s: pos(0x%08x) count(0x%08x) next_pos(0x%08x)\n", ++ __func__, (u32)pos, (u32)count, (u32)(pos + count)); ++ VVDBG("%s: va base(0x%08x) range (0x%08x ~ 0x%08x)\n", ++ __func__, (u32)ftssp010_substream->dma_area_va, ++ (u32)dma_va, ++ (u32)dma_va + ++ (u32)2 * frames_to_bytes(runtime, count * 6)); ++ ++ if (runtime->channels == 1) { ++ while (count--) { ++ *usr_va++ = (u16)(dma_va[0] >> 4); ++ dma_va += 6; ++ } ++ } else { ++ while (count--) { ++ usr_va[0] = (u16)(dma_va[0] >> 4); ++ ++ /* [hw-limit] only slot-3 has valid data in ++ * recording mode -- check TAG_DATA_MONO ++ * defined in "FTSSP010_lib.c". Mask out ++ * one channel to avoid hi-freq noise. ++ */ ++ usr_va[1] = usr_va[0]; ++ usr_va += 2; ++ dma_va += 12; ++ } ++ } ++ break; ++ case 16000: ++ dma_va = (unsigned *)(ftssp010_substream->dma_area_va + ++ frames_to_bytes(runtime, pos * 3) * 2); ++ ++ VVDBG("%s: pos(0x%08x) count(0x%08x) next_pos(0x%08x)\n", ++ __func__, (u32)pos, (u32)count, (u32)(pos + count)); ++ VVDBG("%s: va base(0x%08x) range (0x%08x ~ 0x%08x)\n", ++ __func__, (u32)ftssp010_substream->dma_area_va, ++ (u32)dma_va, ++ (u32)dma_va + ++ (u32)2 * frames_to_bytes(runtime, count * 3)); ++ ++ if (runtime->channels == 1) { ++ while (count--) { ++ *usr_va++ = (u16)(dma_va[0] >> 4); ++ dma_va += 3; ++ } ++ } else { ++ while (count--) { ++ usr_va[0] = (u16)(dma_va[0] >> 4); ++ ++ /* [hw-limit] only slot-3 has valid data in ++ * recording mode -- check TAG_DATA_MONO ++ * defined in "FTSSP010_lib.c". Mask out ++ * one channel to avoid hi-freq noise. ++ */ ++ usr_va[1] = usr_va[0]; ++ usr_va += 2; ++ dma_va += 6; ++ } ++ } ++ break; ++ case 48000: ++ default: ++ dma_va = (unsigned *)(ftssp010_substream->dma_area_va + ++ frames_to_bytes(runtime, pos) * 2); ++ ++ VVDBG("%s: pos(0x%08x) count(0x%08x) next_pos(0x%08x)\n", ++ __func__, (u32)pos, (u32)count, (u32)(pos + count)); ++ VVDBG("%s: va base(0x%08x) range (0x%08x ~ 0x%08x)\n", ++ __func__, (u32)ftssp010_substream->dma_area_va, ++ (u32)dma_va, ++ (u32)dma_va + ++ (u32)2 * frames_to_bytes(runtime, count)); ++ ++ if (runtime->channels == 1) { ++ while (count--) { ++ *usr_va++ = (u16)(*dma_va++ >> 4); ++ } ++ } else { ++ while (count--) { ++ usr_va[0] = (u16)(dma_va[0] >> 4); ++ ++ /* [hw-limit] only slot-3 has valid data in ++ * recording mode -- check TAG_DATA_MONO ++ * defined in "FTSSP010_lib.c". Mask out ++ * one channel to avoid hi-freq noise. ++ */ ++ usr_va[1] = usr_va[0]; ++ usr_va += 2; ++ dma_va += 2; ++ } ++ } ++ break; ++ } ++ ++ return 0; ++} ++ ++/** ++ * These dma callbacks are called in interrupt context. ++ * @data: pointer to the chip-wide structure. ++ * TODO: use stream-specifc data ++ */ ++__attribute__((__unused__)) ++static void ftssp_dma_callback_tx(int ch, u16 int_status, void *data) ++{ ++ ftssp_chip *chip = (ftssp_chip *)data; ++ ++ //printk("~~~~~ : ftssp_dma_callback_tx() is invoked....\n"); ++ if (!ac97) { ++ /* in i2s mode, no indication to driver for user data length. ++ * For simplicity, just go ahead by one period */ ++ ++ struct snd_pcm_runtime *runtime = chip->substream_tx->runtime; ++ ftssp_substream *ftssp010_substream = ++ (ftssp_substream *)runtime->private_data; ++ u32 sw_ptr; ++ u32 tx_period = ftssp010_substream->tx_period + 1; ++ ++ if (tx_period == runtime->periods) ++ sw_ptr = runtime->buffer_size; ++ else ++ sw_ptr = tx_period * runtime->period_size; ++ ++ sw_ptr = (u32)frames_to_bytes(runtime, sw_ptr) >> 1; ++ ++ if (dmad_update_ring_sw_ptr(&dma_chreq_tx, (u32)sw_ptr, 0)) { ++ ERR("%s: failed to update sw-pointer!\n", __func__); ++ } ++ ++ ftssp010_substream->tx_period = tx_period % runtime->periods; ++ } ++ ++ snd_pcm_period_elapsed(chip->substream_tx); ++} ++ ++__attribute__((__unused__)) ++static void ftssp_dma_callback_rx(int ch, u16 int_status, void *data) ++{ ++ ftssp_chip *chip = (ftssp_chip *)data; ++ struct snd_pcm_runtime *runtime = chip->substream_rx->runtime; ++ ftssp_substream *ftssp010_substream = ++ (ftssp_substream *)runtime->private_data; ++ ++ //printk("~~~~~ : ftssp_dma_callback_rx() is invoked....\n"); ++ //printk(">>>>>>>>>> : ftssp_dma_callback_rx() for recording....\n"); ++ ++ u32 sw_ptr; ++ u32 rx_period = ftssp010_substream->rx_period + 1; ++ ++ if (rx_period == runtime->periods) ++ sw_ptr = runtime->buffer_size; ++ else ++ sw_ptr = rx_period * runtime->period_size; ++ ++ if (ac97) { ++ switch (runtime->rate) { ++ case 8000: ++ sw_ptr = sw_ptr * 6; ++ break; ++ case 16000: ++ sw_ptr = sw_ptr * 3; ++ break; ++ case 48000: ++ default: ++ break; ++ } ++ } ++ sw_ptr = (u32)frames_to_bytes(runtime, sw_ptr) >> 1; ++ ++ if (dmad_update_ring_sw_ptr(&dma_chreq_rx, (u32)sw_ptr, 0) != 0) { ++ ERR("%s: failed to update sw-pointer!\n", __func__); ++ } ++ ++ ftssp010_substream->rx_period = rx_period % runtime->periods; ++ ++ snd_pcm_period_elapsed(chip->substream_rx); ++} ++ ++static inline int snd_ftssp_dma_ch_alloc(struct snd_pcm_substream *substream) ++{ ++ dmad_chreq *ch_req __attribute__((__unused__)) = 0; ++ ++ //printk("~~~~~ WATCH : snd_ftssp_dma_ch_alloc() is invoked....\n"); ++#ifdef CONFIG_PLATFORM_APBDMA ++ ++ if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ ch_req = &dma_chreq_tx; ++ ch_req->completion_cb = ftssp_dma_callback_tx; ++ ch_req->apb_req.tx_dir = DMAD_DIR_A0_TO_A1; ++ /*for amerald ac97 ssp2 */ ++ if((inl(PMU_BASE) & AMERALD_MASK) == AMERALD_PRODUCT_ID) ++ { ++ ch_req->apb_req.dev_reqn = APBBR_REQN_I2SAC97TX_AMERALD; ++ } ++ else ++ ch_req->apb_req.dev_reqn = APBBR_REQN_I2SAC97TX; ++ } else { ++ ch_req = &dma_chreq_rx; ++ ch_req->completion_cb = ftssp_dma_callback_rx; ++ ch_req->apb_req.tx_dir = DMAD_DIR_A1_TO_A0; ++ /*for amerald ac97 ssp2 */ ++ if((inl(PMU_BASE) & AMERALD_MASK) == AMERALD_PRODUCT_ID) ++ { ++ ch_req->apb_req.dev_reqn = APBBR_REQN_I2SAC97RX_AMERALD; ++ } ++ else ++ ch_req->apb_req.dev_reqn = APBBR_REQN_I2SAC97RX; ++ } ++ ++ ch_req->controller = DMAD_DMAC_APB_CORE; ++ ch_req->flags = DMAD_FLAGS_RING_MODE; ++ ch_req->ring_base = 0; ++ ch_req->dev_addr = (dma_addr_t)FTSSP010_DATA_PA(cardno); ++ ch_req->periods = 0; ++ ch_req->period_size = 0; ++ ++ if (ac97) { ++ ch_req->apb_req.ring_ctrl = APBBR_ADDRINC_I4X; ++ ch_req->apb_req.ring_reqn = APBBR_REQN_NONE; ++ ch_req->apb_req.dev_ctrl = APBBR_ADDRINC_FIXED; ++ ch_req->apb_req.burst_mode = 0; ++ ch_req->apb_req.data_width = APBBR_DATAWIDTH_4; ++ } else { ++ ch_req->apb_req.ring_ctrl = APBBR_ADDRINC_I2X; ++ ch_req->apb_req.ring_reqn = APBBR_REQN_NONE; ++ ch_req->apb_req.dev_ctrl = APBBR_ADDRINC_FIXED; ++ ch_req->apb_req.burst_mode = 0; ++ ch_req->apb_req.data_width = APBBR_DATAWIDTH_2; ++ } ++ ++ ch_req->completion_data = (void *)snd_pcm_substream_chip(substream); ++ ++ if (dmad_channel_alloc(ch_req) != 0) { ++ ERR("%s: APBDMA channel allocation failed\n",__func__); ++ goto _try_ahb; ++ } ++ ++ DBG("%s: APBDMA channel allocated (ch: %d) ring_mode\n", ++ __func__, ch_req->channel); ++ ++ return 0; ++ ++_try_ahb: ++ ++#endif /* CONFIG_PLATFORM_APBDMA */ ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ ch_req = &dma_chreq_tx; ++ ch_req->completion_cb = ftssp_dma_callback_tx; ++ ch_req->ahb_req.tx_dir = DMAD_DIR_A0_TO_A1; ++ if((inl(PMU_BASE) & AMERALD_MASK) == AMERALD_PRODUCT_ID) ++ { ++ ch_req->ahb_req.dev_reqn = DMAC_REQN_I2SAC97TX_AMERALD; ++ } ++ else ++ ch_req->ahb_req.dev_reqn = DMAC_REQN_I2SAC97TX; ++ } else { ++ ch_req = &dma_chreq_rx; ++ ch_req->completion_cb = ftssp_dma_callback_rx; ++ ch_req->ahb_req.tx_dir = DMAD_DIR_A1_TO_A0; ++ if((inl(PMU_BASE) & AMERALD_MASK) == AMERALD_PRODUCT_ID) ++ { ++ ch_req->ahb_req.dev_reqn = DMAC_REQN_I2SAC97RX_AMERALD; ++ } ++ else ++ ch_req->ahb_req.dev_reqn = DMAC_REQN_I2SAC97RX; ++ } ++ ++ ch_req->controller = DMAD_DMAC_AHB_CORE; ++ ch_req->flags = DMAD_FLAGS_RING_MODE; ++ ch_req->ring_base = 0; ++ ch_req->dev_addr = (dma_addr_t)FTSSP010_DATA_PA(cardno); ++ ch_req->periods = 0; ++ ch_req->period_size = 0; ++ ++ ch_req->ahb_req.sync = 1; ++ ch_req->ahb_req.priority = DMAC_CSR_CHPRI_2; ++ ch_req->ahb_req.hw_handshake = 1; ++ ch_req->ahb_req.burst_size = DMAC_CSR_SIZE_1; ++ ++ if (ac97) { ++ ch_req->ahb_req.ring_width = DMAC_CSR_WIDTH_32; ++ ch_req->ahb_req.ring_ctrl = DMAC_CSR_AD_INC; ++ ch_req->ahb_req.ring_reqn = DMAC_REQN_NONE; ++ ch_req->ahb_req.dev_width = DMAC_CSR_WIDTH_32; ++ ch_req->ahb_req.dev_ctrl = DMAC_CSR_AD_FIX; ++ } else { ++ ch_req->ahb_req.ring_width = DMAC_CSR_WIDTH_16; ++ ch_req->ahb_req.ring_ctrl = DMAC_CSR_AD_INC; ++ ch_req->ahb_req.ring_reqn = DMAC_REQN_NONE; ++ ch_req->ahb_req.dev_width = DMAC_CSR_WIDTH_16; ++ ch_req->ahb_req.dev_ctrl = DMAC_CSR_AD_FIX; ++ } ++ ++ ch_req->completion_data = (void *)snd_pcm_substream_chip(substream); ++ ++ if (dmad_channel_alloc(ch_req) != 0) { ++ ERR("%s: AHBDMA channel allocation failed\n", __func__); ++ goto _err_exit; ++ } ++ ++ DBG("%s: AHBDMA channel allocated (ch: %d) ring_mode\n", ++ __func__, ch_req->channel); ++ ++ return 0; ++ ++_err_exit: ++ ++#endif /* CONFIG_PLATFORM_AHBDMA */ ++ ++ return -ENODEV; ++} ++ ++static inline ftssp_substream *ftssp010_substream_new(int stream_id) ++{ ++ ftssp_substream *s = NULL; ++ ++ //printk("~~~~~ : ftssp010_substream_new() is invoked....\n"); ++ ++ switch (stream_id) { ++ case SNDRV_PCM_STREAM_PLAYBACK: ++ s = &ftssp010_substreams[0]; ++ break; ++ case SNDRV_PCM_STREAM_CAPTURE: ++ s = &ftssp010_substreams[1]; ++ break; ++ default: ++ ERR("%s: wrong stream type (%d)\n", __func__, stream_id); ++ return NULL; ++ } ++ ++ if (s->busy) { ++ ERR("%s: device busy!\n", __func__); ++ return NULL; ++ } ++ s->busy = 1; ++ ++ spin_lock_init(&s->dma_lock); ++ ++ return s; ++} ++ ++static int snd_ftssp_pcm_open(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ int stream_id = substream->pstr->stream; ++ ++ VDBG("%s, %s\n", __func__, ++ (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture"); ++ ++ //printk("~~~~~ : snd_ftssp_pcm_open() is invoked....\n"); ++ ++ /* Both playback and capture share a hardware description */ ++ runtime->hw = snd_ftssp_pcm_hw; ++ ++ /* Allocate & Initialize stream-specific data */ ++ runtime->private_data = ftssp010_substream_new(stream_id); ++ ++ if (runtime->private_data) { ++ //printk("~~~~~ YAYAYA @@@@@ : Calling snd_ftssp_dma_ch_alloc().\n"); ++ return snd_ftssp_dma_ch_alloc(substream); ++ } ++ else ++ return -EBUSY; ++} ++ ++static int snd_ftssp_pcm_close(struct snd_pcm_substream *substream) ++{ ++ int stream_id = substream->pstr->stream; ++ ftssp_substream *ftssp010_substream = ++ (ftssp_substream *)substream->runtime->private_data; ++ ++ VDBG("%s, %s\n", __func__, ++ (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture"); ++ ++ //printk("~~~~~ : snd_ftssp_pcm_close() is invoked....\n"); ++ ++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ++ dmad_channel_free(&dma_chreq_tx); ++ else ++ dmad_channel_free(&dma_chreq_rx); ++ ++ ftssp010_substream->busy = 0; ++ return 0; ++} ++ ++static int snd_ftssp_pcm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *hw_params) ++{ ++ VDBG("%s, %s\n", __func__, ++ (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture"); ++ ++ //printk("~~~~~ : snd_ftssp_pcm_hw_params() is invoked....\n"); ++ ++ if (ac97) ++ return snd_pcm_lib_malloc_pages(substream, AC97_HW_DMA_SIZE); ++ else ++ return snd_pcm_lib_malloc_pages(substream, I2S_HW_DMA_SIZE); ++} ++ ++static int snd_ftssp_pcm_hw_free(struct snd_pcm_substream *substream) ++{ ++ VDBG("%s, %s\n", __func__, ++ (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture"); ++ //printk("~~~~~ : snd_ftssp_pcm_hw_free() is invoked....\n"); ++ ++ if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ dmad_drain_requests(&dma_chreq_tx, 1); ++ else ++ dmad_drain_requests(&dma_chreq_rx, 1); ++ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++/* Prepare FTSSP010 AHBDMA for playback & capture */ ++static int snd_ftssp_pcm_prepare(struct snd_pcm_substream *substream) ++{ ++ ftssp_chip *chip = snd_pcm_substream_chip(substream); ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ ++ //printk("~~~~~ : snd_ftssp_pcm_prepare() is invoked....\n"); ++ //printk("@@@@@ >>>>> : snd_ftssp_pcm_prepare() is called.\n"); ++ ++ ftssp_substream *ftssp010_substream = ++ (ftssp_substream *)runtime->private_data; ++ ++ int stream_id = substream->pstr->stream; ++ dmad_chreq *dma_chreq; ++ unsigned period_size, buffer_size; ++ ++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ++ dma_chreq = &dma_chreq_tx; ++ else ++ dma_chreq = &dma_chreq_rx; ++ ++ period_size = frames_to_bytes(runtime, runtime->period_size); ++ buffer_size = frames_to_bytes(runtime, runtime->buffer_size); ++ ++ if (runtime->format != SNDRV_PCM_FORMAT_S16_LE) ++ return -ENODEV; ++ ++ if (ac97) { ++ switch (runtime->rate) { ++ case 8000: ++ period_size *= 12; ++ buffer_size *= 12; ++ break; ++ case 16000: ++ period_size *= 6; ++ buffer_size *= 6; ++ break; ++ case 48000: ++ default: ++ period_size *= 2; ++ buffer_size *= 2; ++ break; ++ } ++ ++ ftssp010_substream->dma_width = 4; ++ } else { ++ ftssp010_substream->dma_width = 2; ++ } ++ ++ dmad_drain_requests(dma_chreq, 1); ++ ++ dma_chreq->ring_base = (dma_addr_t)runtime->dma_addr; ++ dma_chreq->periods = (dma_addr_t)runtime->periods; ++ if (ac97) { ++ dma_chreq->period_size = (dma_addr_t)(period_size >> 2); ++ dma_chreq->ring_size = (dma_addr_t)(buffer_size >> 2); ++ } else { ++ dma_chreq->period_size = (dma_addr_t)(period_size >> 1); ++ dma_chreq->ring_size = (dma_addr_t)(buffer_size >> 1); ++ } ++ dmad_update_ring(dma_chreq); ++ ++ /* Set PMU, FTSSP010, and DMA */ ++ spin_lock(&ftssp010_substream->dma_lock); ++ ++ /* keep DMA buffer VA for copy() callback */ ++ // todo: support playback/capture simultaneously ++ ftssp010_substream->dma_area_va = (u32)runtime->dma_area; ++ ++ if (ac97) { ++ ftssp010_substream->pmu_set_clocking(48000); ++ ftssp010_substream->hw_config(cardno, ++ runtime->channels > 1 ? 1 : 0, /* 1: stereo, 0: mono */ ++ 48000, ftssp010_substream->dma_width); ++ } else { ++ ++ ftssp010_substream->pmu_set_clocking(runtime->rate); ++ ftssp010_substream->hw_config(cardno, ++ runtime->channels > 1 ? 1 : 0, /* 1: stereo, 0: mono */ ++ runtime->rate, ftssp010_substream->dma_width); ++ } ++ ++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { ++ ftssp010_substream->tx_period = 0; ++ chip->substream_tx = substream; ++ } else { ++ ftssp010_substream->rx_period = 0; ++ chip->substream_rx = substream; ++ } ++ ++ spin_unlock(&ftssp010_substream->dma_lock); ++ ++ VVDBG("%s <<\n", __func__); ++ ++ return 0; ++} ++ ++static inline int snd_ftssp_start_play(ftssp_substream *ftssp010_substream, ++ struct snd_pcm_runtime *runtime) ++{ ++ int err = 0; ++ ++ //printk("~~~~~ : snd_ftssp_start_play() is invoked....\n"); ++ ++ if (ac97) { ++ /* in ac97 mode, user data was fed to dma buffer through ++ * driver-provided copy callback */ ++ err = dmad_kickoff_requests(&dma_chreq_tx); ++ if (err != 0) { ++ ERR("%s: failed to kickoff dma!\n", __func__); ++ return err; ++ } ++ } else { ++ /* in i2s mode, no indication to driver for user data length ++ * (except start threshold). For simplicity at start, just go ++ * ahead by one cycle */ ++ ++ u32 sw_ptr = ++ (u32)frames_to_bytes(runtime, runtime->buffer_size) >>1; ++ ++ err = dmad_update_ring_sw_ptr(&dma_chreq_tx, sw_ptr, 0); ++ if (err != 0) { ++ ERR("%s: failed to update sw-pointer!\n", __func__); ++ return err; ++ } ++ ++ err = dmad_kickoff_requests(&dma_chreq_tx); ++ if (err != 0) { ++ ERR("%s: failed to kickoff dma!\n", __func__); ++ return err; ++ } ++ } ++ ++ ftssp010_substream->start(cardno, 1); ++ ++ //ADD by river 2011.03.08 ++ //i2s_alc5630_write(0x02, 0x0000, g_i2c_client); ++ //i2s_alc5630_write(0x04, 0x0000, g_i2c_client); ++ //i2s_alc5630_write(0x0c, 0x1010, g_i2c_client); ++ //i2s_alc5630_write(0x10, 0xff03, g_i2c_client); ++ //End ADD by river 2011.03.08 ++ ++ return 0; ++} ++ ++static inline int snd_ftssp_start_record(ftssp_substream *ftssp010_substream, ++ struct snd_pcm_runtime *runtime) ++{ ++ int err = 0; ++ ++ //printk("~~~~~ : snd_ftssp_start_record() is invoked....\n"); ++ ++ u32 sw_ptr = (u32)frames_to_bytes(runtime, runtime->buffer_size); ++ ++ if (ac97) { ++ switch (runtime->rate) { ++ case 8000: ++ sw_ptr = (sw_ptr * 3); ++ break; ++ case 16000: ++ sw_ptr = (sw_ptr * 3) >> 1; ++ break; ++ case 48000: ++ default: ++ sw_ptr = sw_ptr >> 1; ++ break; ++ } ++ } else { ++ ++ //printk(">>>>>>>>>> : snd_ftssp_start_record() for recording....\n"); ++ sw_ptr = sw_ptr >> 1; ++ } ++ ++ err = dmad_update_ring_sw_ptr(&dma_chreq_rx, sw_ptr, 0); ++ if (err != 0) { ++ ERR("%s: failed to update sw-pointer!\n", __func__); ++ return err; ++ } ++ ++ err = dmad_kickoff_requests(&dma_chreq_rx); ++ if (err != 0) { ++ ERR("%s: failed to kickoff dma!\n", __func__); ++ return err; ++ } ++ ++ ftssp010_substream->start(cardno, 1); ++ ++ return 0; ++} ++ ++/* Triggers AHBDMA for playback & capture */ ++static int snd_ftssp_pcm_trigger(struct snd_pcm_substream * substream, int cmd) ++{ ++ ftssp_substream *ftssp010_substream = ++ (ftssp_substream *)substream->runtime->private_data; ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ int err = 0; ++ int stream_id = substream->pstr->stream; ++ ++ //printk("~~~~~ : snd_ftssp_pcm_trigger() is invoked....\n"); ++ ++ /* note local interrupts are already disabled in the midlevel code */ ++ spin_lock(&ftssp010_substream->dma_lock); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ ++ VDBG("%s: SNDRV_PCM_TRIGGER_START state(0x%08x)\n", ++ __func__, (u32)runtime->status->state); ++ ++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { ++ err = snd_ftssp_start_play(ftssp010_substream, runtime); ++ } else { ++ err = snd_ftssp_start_record(ftssp010_substream, ++ runtime); ++ } ++ break; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ ++ VDBG("%s: SNDRV_PCM_TRIGGER_STOP state(0x%08x)\n", ++ __func__, (u32)substream->runtime->status->state); ++ ++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { ++ ftssp010_stop_tx(cardno); ++ dmad_drain_requests(&dma_chreq_tx, 1); ++ } else { ++ ftssp010_stop_rx(cardno); ++ dmad_drain_requests(&dma_chreq_rx, 1); ++ } ++ break; ++ default: ++ err = -EINVAL; ++ break; ++ } ++ ++ spin_unlock(&ftssp010_substream->dma_lock); ++ return err; ++} ++ ++// pcm middle-layer call this function within irq (snd_pcm_period_elapsed) or ++// with local irq disabled (snd_pcm_lib_write1) ++static snd_pcm_uframes_t snd_ftssp_pcm_pointer( ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ u32 hw_ptr; ++ snd_pcm_uframes_t ret; ++ int stream_id = substream->pstr->stream; ++ ++ //printk("~~~~~ : snd_ftssp_pcm_pointer() is invoked....\n"); ++ ++ ++ /* Fetch DMA pointer, with spin lock */ ++ //spin_lock_irqsave(&ftssp010_substream->dma_lock, flags); ++ ++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { ++ hw_ptr = dmad_probe_ring_hw_ptr(&dma_chreq_tx); ++ } else { ++ hw_ptr = dmad_probe_ring_hw_ptr(&dma_chreq_rx); ++ } ++ ++ //spin_unlock_irqrestore(&ftssp010_substream->dma_lock, flags); ++ ++ if (ac97) { ++ ret = bytes_to_frames(runtime, hw_ptr << 1); ++ ++ switch (runtime->rate) { ++ case 8000: ++ ret = ret / 6; ++ break; ++ case 16000: ++ ret = ret / 3; ++ break; ++ case 48000: ++ default: ++ break; ++ } ++ } else { ++ ret = bytes_to_frames(runtime, hw_ptr << 1); ++ } ++ ++ ++ VVDBG("%s: hw_ptr(0x%08x) ret(0x%08x)\n", ++ (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ? "p" : "c", ++ (u32)hw_ptr, (u32)ret); ++ ++ /* ALSA requires return value 0 <= ret < buffer_size */ ++ if (ret >= runtime->buffer_size) ++ return 0; ++ return ret; ++} ++ ++/* For FTSSP010 driver, operations are shared among playback & capture */ ++static struct snd_pcm_ops snd_ftssp_playback_ops = { ++ .open = snd_ftssp_pcm_open, ++ .close = snd_ftssp_pcm_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = snd_ftssp_pcm_hw_params, ++ .hw_free = snd_ftssp_pcm_hw_free, ++ .prepare = snd_ftssp_pcm_prepare, ++ .trigger = snd_ftssp_pcm_trigger, ++ .pointer = snd_ftssp_pcm_pointer, ++ .copy = NULL, ++}; ++ ++static struct snd_pcm_ops snd_ftssp_capture_ops = { ++ .open = snd_ftssp_pcm_open, ++ .close = snd_ftssp_pcm_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = snd_ftssp_pcm_hw_params, ++ .hw_free = snd_ftssp_pcm_hw_free, ++ .prepare = snd_ftssp_pcm_prepare, ++ .trigger = snd_ftssp_pcm_trigger, ++ .pointer = snd_ftssp_pcm_pointer, ++ .copy = NULL, ++}; ++ ++/* ALSA PCM constructor */ ++static int snd_ftssp_new_pcm(ftssp_chip *chip) ++{ ++ struct snd_pcm *pcm; ++ int err; ++ ++ //printk("~~~~~ : snd_ftssp_new_pcm() is invoked....\n"); ++ ++ /* PCM device #0 with 1 playback and 1 capture */ ++ if ((err = snd_pcm_new(chip->card, "ftssp_pcm", 0, 1, 1, &pcm)) < 0) ++ return err; ++ ++ pcm->private_data = chip; ++ strcpy(pcm->name, "ftssp_pcm device"); ++ chip->pcm = pcm; ++ ++ /* set operators for playback and capture*/ ++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, ++ &snd_ftssp_playback_ops); ++ ++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, ++ &snd_ftssp_capture_ops); ++ ++ /* Pre-allocate buffer, as suggested by ALSA driver document */ ++ // todo: support playback/capture simultaneously ++ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, ++ NULL, FTSSP_HW_DMA_SIZE, FTSSP_HW_DMA_SIZE); ++ ++ /* Force half-duplex (on A320D, or AC97 mode) */ ++ if (ac97) ++ pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX; ++ ++ return 0; ++} ++ ++#if (FTSSP_PROC_FS) ++static void snd_ftssp_buf_max_read(struct snd_info_entry *entry, ++ struct snd_info_buffer *buffer) ++{ ++ snd_iprintf(buffer, "%d\n", snd_ftssp_pcm_hw.buffer_bytes_max); ++} ++ ++static void snd_ftssp_buf_max_write(struct snd_info_entry *entry, ++ struct snd_info_buffer *buffer) ++{ ++ char tmp[128]; ++ char *ptr_e; ++ u32 val; ++ ++ if (buffer->size == 0) ++ return; ++ ++ memset(tmp, 0, 128); ++ snd_info_get_str(tmp, buffer->buffer, 127); ++ ++ val = simple_strtoul(tmp, &ptr_e, 10); ++ if (*ptr_e == 'k') ++ val *= 1024; ++ else if (*ptr_e == 'm') ++ val *= 1024 * 1024; ++ ++ if (ac97) { ++ if (val > AC97_HW_BUFFER_BYTES_MAX) ++ val = AC97_HW_BUFFER_BYTES_MAX; ++ } else { ++ if (val > I2S_HW_BUFFER_BYTES_MAX) ++ val = I2S_HW_BUFFER_BYTES_MAX; ++ } ++ ++ snd_ftssp_pcm_hw.buffer_bytes_max = (size_t)val; ++} ++ ++static void snd_ftssp_period_min_read(struct snd_info_entry *entry, ++ struct snd_info_buffer *buffer) ++{ ++ snd_iprintf(buffer, "%d\n", snd_ftssp_pcm_hw.period_bytes_min); ++} ++ ++static void snd_ftssp_period_min_write(struct snd_info_entry *entry, ++ struct snd_info_buffer *buffer) ++{ ++ char tmp[128]; ++ char *ptr_e; ++ u32 val; ++ ++ if (buffer->size == 0) ++ return; ++ ++ memset(tmp, 0, 128); ++ snd_info_get_str(tmp, buffer->buffer, 127); ++ ++ val = simple_strtoul(tmp, &ptr_e, 10); ++ if (*ptr_e == 'k') ++ val *= 1024; ++ else if (*ptr_e == 'm') ++ val *= 1024 * 1024; ++ ++ snd_ftssp_pcm_hw.period_bytes_min = (size_t)val; ++ ++ if ((val * snd_ftssp_pcm_hw.periods_max) > ++ snd_ftssp_pcm_hw.buffer_bytes_max) { ++ INFO("\nWarning: period_bytes(%d) * periods(%d) exceeds " ++ "hw_buffer_size(%d).\n", ++ snd_ftssp_pcm_hw.period_bytes_min, ++ snd_ftssp_pcm_hw.periods_max, ++ snd_ftssp_pcm_hw.buffer_bytes_max); ++ INFO(" Unexpected access violation may occur!\n"); ++ } ++} ++ ++static void snd_ftssp_period_max_read(struct snd_info_entry *entry, ++ struct snd_info_buffer *buffer) ++{ ++ snd_iprintf(buffer, "%d\n", snd_ftssp_pcm_hw.period_bytes_max); ++} ++ ++static void snd_ftssp_period_max_write(struct snd_info_entry *entry, ++ struct snd_info_buffer *buffer) ++{ ++ char tmp[128]; ++ char *ptr_e; ++ u32 val; ++ ++ if (buffer->size == 0) ++ return; ++ ++ memset(tmp, 0, 128); ++ snd_info_get_str(tmp, buffer->buffer, 127); ++ ++ val = simple_strtoul(tmp, &ptr_e, 10); ++ if (*ptr_e == 'k') ++ val *= 1024; ++ else if (*ptr_e == 'm') ++ val *= 1024 * 1024; ++ ++ snd_ftssp_pcm_hw.period_bytes_max = (size_t)val; ++ ++ if ((val * snd_ftssp_pcm_hw.periods_max) > ++ snd_ftssp_pcm_hw.buffer_bytes_max) { ++ INFO("\nWarning: period_bytes(%d) * periods(%d) exceeds " ++ "hw_buffer_size(%d).\n", ++ snd_ftssp_pcm_hw.period_bytes_max, ++ snd_ftssp_pcm_hw.periods_max, ++ snd_ftssp_pcm_hw.buffer_bytes_max); ++ INFO(" Unexpected access violation may occur!\n"); ++ } ++} ++ ++static void snd_ftssp_periods_min_read(struct snd_info_entry *entry, ++ struct snd_info_buffer *buffer) ++{ ++ snd_iprintf(buffer, "%d\n", snd_ftssp_pcm_hw.periods_min); ++} ++ ++static void snd_ftssp_periods_min_write(struct snd_info_entry *entry, ++ struct snd_info_buffer *buffer) ++{ ++ char tmp[128]; ++ char *ptr_e; ++ u32 val; ++ ++ if (buffer->size == 0) ++ return; ++ ++ memset(tmp, 0, 128); ++ snd_info_get_str(tmp, buffer->buffer, 127); ++ ++ val = simple_strtoul(tmp, &ptr_e, 10); ++ if (*ptr_e == 'k') ++ val *= 1024; ++ else if (*ptr_e == 'm') ++ val *= 1024 * 1024; ++ ++ snd_ftssp_pcm_hw.periods_min = (size_t)val; ++ ++ if ((val * snd_ftssp_pcm_hw.period_bytes_max) > ++ snd_ftssp_pcm_hw.buffer_bytes_max) { ++ INFO("\nWarning: period_bytes(%d) * periods(%d) exceeds " ++ "hw_buffer_size(%d).\n", ++ snd_ftssp_pcm_hw.period_bytes_max, ++ snd_ftssp_pcm_hw.periods_min, ++ snd_ftssp_pcm_hw.buffer_bytes_max); ++ INFO(" Unexpected access violation may occur!\n"); ++ } ++} ++ ++static void snd_ftssp_periods_max_read(struct snd_info_entry *entry, ++ struct snd_info_buffer *buffer) ++{ ++ snd_iprintf(buffer, "%d\n", snd_ftssp_pcm_hw.periods_max); ++} ++ ++static void snd_ftssp_periods_max_write(struct snd_info_entry *entry, ++ struct snd_info_buffer *buffer) ++{ ++ char tmp[128]; ++ char *ptr_e; ++ u32 val; ++ ++ if (buffer->size == 0) ++ return; ++ ++ memset(tmp, 0, 128); ++ snd_info_get_str(tmp, buffer->buffer, 127); ++ ++ val = simple_strtoul(tmp, &ptr_e, 10); ++ if (*ptr_e == 'k') ++ val *= 1024; ++ else if (*ptr_e == 'm') ++ val *= 1024 * 1024; ++ ++ snd_ftssp_pcm_hw.periods_max = (size_t)val; ++ ++ if ((val * snd_ftssp_pcm_hw.period_bytes_max) > ++ snd_ftssp_pcm_hw.buffer_bytes_max) { ++ INFO("\nWarning: period_bytes(%d) * periods(%d) exceeds " ++ "hw_buffer_size(%d).\n", ++ snd_ftssp_pcm_hw.period_bytes_max, ++ snd_ftssp_pcm_hw.periods_max, ++ snd_ftssp_pcm_hw.buffer_bytes_max); ++ INFO(" Unexpected access violation may occur!\n"); ++ } ++} ++#endif //FTSSP_PROC_FS ++ ++static inline void ftssp_ac97_init(void) ++{ ++ //driver_name = AC97_DRIVER_NAME; ++ //codec_info = AC97_CODEC_NAME; ++ ++ /* Change codec-dependent callbacks to AC97 */ ++ ftssp010_substreams[0].pmu_set_clocking = pmu_set_ac97_clocking; ++ ftssp010_substreams[0].hw_config = ftssp010_config_ac97_play; ++ ftssp010_substreams[1].pmu_set_clocking = pmu_set_ac97_clocking; ++ ftssp010_substreams[1].hw_config = ftssp010_config_ac97_rec; ++ ++ snd_ftssp_playback_ops.copy = snd_ftssp_playback_copy; ++ snd_ftssp_capture_ops.copy = snd_ftssp_capture_copy; ++ ++ snd_ftssp_pcm_hw.rates = AC97_CODEC_SAMPLE_RATES; ++ snd_ftssp_pcm_hw.rate_min = AC97_CODEC_SAMPLE_RATE_MIN; ++ snd_ftssp_pcm_hw.rate_max = AC97_CODEC_SAMPLE_RATE_MAX; ++ snd_ftssp_pcm_hw.formats = AC97_CODEC_FORMATS; ++ snd_ftssp_pcm_hw.buffer_bytes_max = AC97_HW_BUFFER_BYTES_MAX; ++ snd_ftssp_pcm_hw.period_bytes_min = AC97_HW_PERIOD_BYTES_MIN; ++ snd_ftssp_pcm_hw.period_bytes_max = AC97_HW_PERIOD_BYTES_MAX; ++ snd_ftssp_pcm_hw.periods_min = AC97_HW_PERIODS_MIN; ++ snd_ftssp_pcm_hw.periods_max = AC97_HW_PERIODS_MAX; ++} ++ ++static int ftssp_alsa_init(struct i2c_client *client) ++{ ++ ftssp_chip *chip; ++ int err; ++ ++ //ADD by river 2011.03.08 ++ //g_i2c_client = client; ++ //End ADD by river 2011.03.08 ++ //printk(">>>>>>>>> (4) ftssp_alsa_init().\n"); ++ init_hw(cardno, ac97, client); ++ ++ if (ac97) ++ ftssp_ac97_init(); ++ ++ DBG("%s: FTSSP010 #%d (Physical Addr=0x%08X), mode: %s\n", ++ __func__, ++ cardno, SSP_FTSSP010_pa_base[cardno], ++ ac97 ? "ac97" : "i2s"); ++ ++ err = snd_card_create(cardno, FTSSP_CARD_ID, THIS_MODULE, ++ sizeof(ftssp_chip), &ftssp_cards[cardno]); ++ if (err < 0) ++ return err; ++ ++ if (ac97) { ++ sprintf(ftssp_cards[cardno]->driver, FTSSP_DRIVER_NAME); ++ sprintf(ftssp_cards[cardno]->shortname, ++ FTSSP_DRIVER_NAME "_ac97"); ++ sprintf(ftssp_cards[cardno]->longname, ++ FTSSP_DRIVER_NAME "_ac97 controller"); ++ } else { ++ sprintf(ftssp_cards[cardno]->driver, FTSSP_DRIVER_NAME); ++ sprintf(ftssp_cards[cardno]->shortname, ++ FTSSP_DRIVER_NAME "_i2s"); ++ sprintf(ftssp_cards[cardno]->longname, ++ FTSSP_DRIVER_NAME "_i2s controller"); ++ } ++ ++ // PCM ++ chip = (ftssp_chip *)(ftssp_cards[cardno]->private_data); ++ chip->card = ftssp_cards[cardno]; ++ ++ if ((err = snd_ftssp_new_pcm(chip))) { ++ ERR("%s, Can't new PCM devices\n",__func__); ++ return -ENODEV; ++ } ++ ++#if (FTSSP_PROC_FS) ++ // new a proc entries subordinate to card->proc_root for debugging ++ // /proc/card#/buf_max ++ snd_card_proc_new(chip->card, "buf_max", &chip->info_buf_max); ++ if (chip->info_buf_max) { ++ chip->info_buf_max->c.text.read = snd_ftssp_buf_max_read; ++ chip->info_buf_max->c.text.write = snd_ftssp_buf_max_write; ++ } ++ // /proc/card#/period_min ++ snd_card_proc_new(chip->card, "period_size_min", ++ &chip->info_period_min); ++ if (chip->info_period_min) { ++ chip->info_period_min->c.text.read = snd_ftssp_period_min_read; ++ chip->info_period_min->c.text.write = ++ snd_ftssp_period_min_write; ++ } ++ // /proc/card#/period_max ++ snd_card_proc_new(chip->card, "period_size_max", ++ &chip->info_period_max); ++ if (chip->info_period_max) { ++ chip->info_period_max->c.text.read = snd_ftssp_period_max_read; ++ chip->info_period_max->c.text.write = ++ snd_ftssp_period_max_write; ++ } ++ // /proc/card#/periods_min ++ snd_card_proc_new(chip->card, "periods_min", &chip->info_periods_min); ++ if (chip->info_periods_min) { ++ chip->info_periods_min->c.text.read = ++ snd_ftssp_periods_min_read; ++ chip->info_periods_min->c.text.write = ++ snd_ftssp_periods_min_write; ++ } ++ // /proc/card#/periods_max ++ snd_card_proc_new(chip->card, "periods_max", &chip->info_periods_max); ++ if (chip->info_periods_max) { ++ chip->info_periods_max->c.text.read = ++ snd_ftssp_periods_max_read; ++ chip->info_periods_max->c.text.write = ++ snd_ftssp_periods_max_write; ++ } ++#endif ++ ++ // Register the card to ALSA ++ if ((err = snd_card_register(chip->card)) == 0) { ++ INFO("%s card registered!\n", FTSSP_CARD_ID); ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SND_FTSSP010_I2S ++//ADD by river 2011.01.26 ++static int alc5630_i2c_remove(struct i2c_client *client) ++{ ++ struct alc5630_data *alc5630 = i2c_get_clientdata(client); ++ ++ // power down codec chip ++ //tas_write_reg(tas, TAS_REG_ACR, 1, &tmp); ++ ++ mutex_destroy(&alc5630->mtx); ++ kfree(alc5630); ++ return 0; ++} ++ ++static const struct i2c_device_id alc5630_i2c_id[] = { ++ { "alc5630_codec", 0 }, ++ { } ++}; ++ ++// This is the driver that will be inserted ++static struct i2c_driver alc5630_driver = { ++ .driver = { ++ .name = "alc5630_codec", ++ .owner = THIS_MODULE, ++ }, ++ .attach_adapter = alc5630_i2c_attach, ++ .probe = alc5630_i2c_probe, ++ .remove = alc5630_i2c_remove, ++ .suspend = alc5630_i2c_suspend, ++ .resume = alc5630_i2c_resume, ++ .id_table = alc5630_i2c_id, ++}; ++ ++static int alc5630_i2c_suspend(struct i2c_client *i2c_client, pm_message_t mesg) ++{ ++ //printk("@@@@@ TRACE by river 2011.05.10 : alc5630_i2c_suspend() is invoked.\n"); ++ ++ //i2c_del_driver(&alc5630_driver); ++ //#ifndef CONFIG_SND_FTSSP010_AC97 ++ // i2c_del_driver(&alc5630_driver); ++ //#endif ++ //printk("@@@@@ TRACE by river 2011.05.10 : alc5630_i2c_suspend() -2 is invoked.\n"); ++ dmad_channel_free(&dma_chreq_tx); ++ dmad_channel_free(&dma_chreq_rx); ++ //printk("@@@@@ TRACE by river 2011.05.10 : alc5630_i2c_suspend() -3 is invoked.\n"); ++ //snd_card_free(ftssp_cards[cardno]); ++ ++ return 0; ++ ++} ++ ++static int alc5630_i2c_resume(struct i2c_client *i2c_client) ++{ ++ ++ //printk("@@@@@ TRACE by river 2011.05.10 : alc5630_i2c_resume() is invoked.\n"); ++ //#ifdef CONFIG_SND_FTSSP010_AC97 ++ // ftssp_alsa_init(NULL); ++ //#else ++ // return i2c_add_driver(&alc5630_driver); ++ //#endif ++ ++ return 0; ++ ++} ++#endif ++ ++static __init int ftssp_alsa_i2c_i2s_init(void) ++{ ++ ++ //printk(">>>>>>>>>> (1) ftssp_alsa_i2c_i2s_init().\n"); ++ //return i2c_add_driver(&alc5630_driver); ++ #ifdef CONFIG_SND_FTSSP010_AC97 ++ return ftssp_alsa_init(NULL); ++ #else ++ return i2c_add_driver(&alc5630_driver); ++ #endif ++} ++//End ADD by river 2011.01.26 ++ ++static __exit void ftssp_alsa_i2c_i2s_exit(void) ++{ ++ DBG("%s, cleaning up\n",__func__); ++ ++ //i2c_del_driver(&alc5630_driver); ++ #ifndef CONFIG_SND_FTSSP010_AC97 ++ i2c_del_driver(&alc5630_driver); ++ #endif ++ ++ dmad_channel_free(&dma_chreq_tx); ++ dmad_channel_free(&dma_chreq_rx); ++ ++ snd_card_free(ftssp_cards[cardno]); ++} ++ ++/*static __exit void ftssp_alsa_exit(void) ++{ ++ DBG("%s, cleaning up\n",__func__); ++ ++ dmad_channel_free(&dma_chreq_tx); ++ dmad_channel_free(&dma_chreq_rx); ++ ++ snd_card_free(ftssp_cards[cardno]); ++}*/ ++ ++//MOD by river 2011.01.26 ++//module_init(ftssp_alsa_init); ++//module_exit(ftssp_alsa_exit); ++module_init(ftssp_alsa_i2c_i2s_init); ++module_exit(ftssp_alsa_i2c_i2s_exit); ++//End MOD by river 2011.01.26 +diff -Nur linux-3.4.110.orig/sound/nds32/FTSSP010_HDA.c linux-3.4.110/sound/nds32/FTSSP010_HDA.c +--- linux-3.4.110.orig/sound/nds32/FTSSP010_HDA.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/sound/nds32/FTSSP010_HDA.c 2016-04-07 10:20:51.062085666 +0200 +@@ -0,0 +1,745 @@ ++/* FTSSP010 - UDA1345TS module: ++ * ++ * $log$ ++ * ++ * 2006/02/23: I-Jui Sung: OSS emulation half-duplex ++ * playback/capture at 48K, 44.1K, 8K ++ * with mono/stereo 16bit/8bit ++ * ++ * 2006/02/22: I-Jui Sung: OSS emulation playback at 44.1KHz ++ * 16-bit mono completed. Relying ALSA to ++ * resample ++ * 2009/02/24: dma upgrade checking list: ++ * - ac97 mode playback ................. ok ++ * - ac97 mode capture .................. ok ++ * - i2s mode playback .................. ok ++ * - i2s mode capture ................... ok ++ * - mixer support (snd_ctl_add, ...) ... todo ++ * - debug /proc entry .................. ok ++ */ ++ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <asm/io.h> ++#include <linux/delay.h> ++#include <asm/spec.h> ++#include <asm/dmad.h> ++#include <linux/dma-mapping.h> ++#include <sound/core.h> ++#include <sound/pcm.h> ++#include <sound/initval.h> ++#include <sound/asound.h> ++#include <sound/control.h> ++#include "FTSSP010_HDA.h" ++void init_hw(unsigned int cardno); ++ ++#if (!defined(CONFIG_PLATFORM_AHBDMA) && !defined(CONFIG_PLATFORM_APBDMA)) ++#warning needs ahb/apb dma to wrok ++#endif ++ ++/* --------------------------------------------------------------------------- ++ * Define the debug level of FTSSP_DEBUG ++ */ ++#define FTSSP_DEBUG 0 ++#define FTSSP_DEBUG_VERBOSE 0 ++#define FTSSP_PROC_FS 1 ++ ++#undef VVDBG ++#if (FTSSP_DEBUG_VERBOSE) ++//#define VVDBG(vvar...) (void)0 ++#define VVDBG(vvar...) printk(KERN_INFO vvar) ++#else ++#define VVDBG(vvar...) (void)0 ++#endif ++ ++#undef ERR ++#define ERR(vvar...) printk(KERN_ERR vvar) ++ ++#undef INFO ++#define INFO(vvar...) printk(KERN_INFO vvar) ++ ++#if (FTSSP_DEBUG) ++#undef DBG ++#define DBG(vvar...) printk(KERN_INFO vvar) ++#else ++#define DBG(vvar...) (void)0 ++#endif ++ ++#if (FTSSP_DEBUG_VERBOSE) ++#undef VDBG ++#define VDBG(vvar...) printk(KERN_INFO vvar) ++#else ++#define VDBG(vvar...) (void)0 ++#endif ++ ++/* --------------------------------------------------------------------------- ++ * Preserved size of memory space for audio DMA ring ++ */ ++#define FTSSP_HW_DMA_SIZE (512 * 1024) ++ ++ ++/* HDA HW configuration*/ ++/* ring size, exported to application */ ++#define HDA_HW_BUFFER_BYTES_MAX (256 * 1024) ++#define HDA_HW_PERIOD_BYTES_MIN (2 * 1024) ++#define HDA_HW_PERIOD_BYTES_MAX (32 * 1024) ++#define HDA_HW_PERIODS_MIN 3 ++#define HDA_HW_PERIODS_MAX 8 ++ ++#define HDA_HW_DMA_SIZE (HDA_HW_BUFFER_BYTES_MAX) ++ ++ ++/* --------------------------------------------------------------------------- ++ * Audio formats ++ */ ++ ++/* HDA formats */ ++#define HDA_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) ++#define HDA_CODEC_SAMPLE_RATES (SNDRV_PCM_RATE_192000 | \ ++ SNDRV_PCM_RATE_176400| \ ++ SNDRV_PCM_RATE_96000 | \ ++ SNDRV_PCM_RATE_88200 | \ ++ SNDRV_PCM_RATE_48000 | \ ++ SNDRV_PCM_RATE_44100 | \ ++ SNDRV_PCM_RATE_32000 | \ ++ SNDRV_PCM_RATE_22050 | \ ++ SNDRV_PCM_RATE_16000 | \ ++ SNDRV_PCM_RATE_11025 | \ ++ SNDRV_PCM_RATE_8000) ++#define HDA_CODEC_SAMPLE_RATE_MIN (8000) ++#define HDA_CODEC_SAMPLE_RATE_MAX (192000) ++ ++/* --------------------------------------------------------------------------- ++ * Configuration ++ */ ++#if (CONFIG_PROC_FS == 0) ++#undef FTSSP_PROC_FS ++#define FTSSP_PROC_FS 0 ++#else ++#if (FTSSP_PROC_FS) ++#include <sound/info.h> ++#endif /* FTSSP_PROC_FS */ ++#endif /* CONFIG_PROC_FS */ ++ ++#define FTSSP_CARD_ID "ftssp010" ++#define FTSSP_DRIVER_NAME "ftssp" ++ ++MODULE_LICENSE("Faraday License"); ++MODULE_AUTHOR("Faraday Technology Corp."); ++MODULE_DESCRIPTION("FTSSP010 Linux 2.6 Driver"); ++ ++static int cardno = 0; ++static const unsigned int SSP_FTSSP010_pa_base[SSP_FTSSP010_IRQ_COUNT] = ++ { SSP_FTSSP010_PA_BASE }; ++ ++/* Driver mode */ ++ ++// ---------------------------------------------- ++module_param(cardno, int, 0); ++MODULE_PARM_DESC(cardno, "FTSSP No."); ++ ++// ---------------------------------------------- ++ ++/* --------------------------------------------------------------------------- ++ * Structures ++ */ ++ ++/* private data for card */ ++typedef struct { ++ struct snd_card *card; ++ struct snd_pcm *pcm; ++ struct snd_pcm_substream *substream_tx; ++ struct snd_pcm_substream *substream_rx; ++} ftssp_chip; ++ ++/* dma request descriptors */ ++dmad_chreq dma_chreq_tx = { ++ .channel = -1, ++ .drq = NULL, ++}; ++ ++dmad_chreq dma_chreq_rx = { ++ .channel = -1, ++ .drq = NULL, ++}; ++ ++/* Holds ALSA card instance pointers */ ++struct snd_card *ftssp_cards[SSP_FTSSP010_COUNT]; ++ ++/* snd_pcm_hardware */ ++static struct snd_pcm_hardware snd_ftssp_pcm_hw = ++{ ++ .info = SNDRV_PCM_INFO_INTERLEAVED, ++ .formats = HDA_CODEC_FORMATS, ++ .rates = HDA_CODEC_SAMPLE_RATES, ++ .rate_min = HDA_CODEC_SAMPLE_RATE_MIN, ++ .rate_max = HDA_CODEC_SAMPLE_RATE_MAX, ++ .channels_min = 1, ++ .channels_max = 2, ++ .buffer_bytes_max = HDA_HW_BUFFER_BYTES_MAX, ++ .period_bytes_min = HDA_HW_PERIOD_BYTES_MIN, ++ .period_bytes_max = HDA_HW_PERIOD_BYTES_MAX, ++ .periods_min = HDA_HW_PERIODS_MIN, ++ .periods_max = HDA_HW_PERIODS_MAX, ++}; ++ ++/* private data for a substream (playback or capture) */ ++/* function pointer for set up AHBDMA for this substream */ ++typedef void (*start_t)(int cardno, unsigned use_dma); ++typedef void (*ftssp010_config_t)(int cardno, unsigned is_stereo, ++ unsigned speed, int use8bit); ++ ++typedef struct { ++ u32 busy; ++ spinlock_t dma_lock; ++ unsigned dma_area_va; ++ int dma_width; ++ unsigned int tx_period; ++ unsigned int rx_period; ++ ++ start_t start; ++ ftssp010_config_t hw_config; ++} ftssp_substream; ++ ++static ftssp_substream ftssp010_substreams[2] = { ++ /* Playback substream */ ++ { ++ busy : 0, ++ hw_config : ftssp010_config_hda_play, ++ }, ++ /* Capture substream */ ++ { ++ busy : 0, ++ hw_config : ftssp010_config_hda_rec, ++ } ++}; ++ ++ ++/** ++ * These dma callbacks are called in interrupt context. ++ * @data: pointer to the chip-wide structure. ++ * TODO: use stream-specifc data ++ */ ++__attribute__((__unused__)) ++static void ftssp_dma_callback_tx(int ch, u16 int_status, void *data) ++{ ++ ftssp_chip *chip = (ftssp_chip *)data; ++ struct snd_pcm_runtime *runtime = chip->substream_tx->runtime; ++ ftssp_substream *ftssp010_substream = ++ (ftssp_substream *)runtime->private_data; ++ u32 sw_ptr; ++ u32 tx_period = ftssp010_substream->tx_period + 1; ++ ++ if (tx_period == runtime->periods) ++ sw_ptr = runtime->buffer_size; ++ else ++ sw_ptr = tx_period * runtime->period_size; ++ ++ sw_ptr = (u32)frames_to_bytes(runtime, sw_ptr) >> 1; ++ ++ if (dmad_update_ring_sw_ptr(&dma_chreq_tx, (u32)sw_ptr, 0)) { ++ ERR("%s: failed to update sw-pointer!\n", __func__); ++ } ++ ++ ftssp010_substream->tx_period = tx_period % runtime->periods; ++ snd_pcm_period_elapsed(chip->substream_tx); ++} ++ ++__attribute__((__unused__)) ++static void ftssp_dma_callback_rx(int ch, u16 int_status, void *data) ++{ ++ ftssp_chip *chip = (ftssp_chip *)data; ++ struct snd_pcm_runtime *runtime = chip->substream_rx->runtime; ++ ftssp_substream *ftssp010_substream = ++ (ftssp_substream *)runtime->private_data; ++ u32 sw_ptr; ++ u32 rx_period = ftssp010_substream->rx_period + 1; ++ ++ if (rx_period == runtime->periods) ++ sw_ptr = runtime->buffer_size; ++ else ++ sw_ptr = rx_period * runtime->period_size; ++ sw_ptr = (u32)frames_to_bytes(runtime, sw_ptr) >> 1; ++ ++ if (dmad_update_ring_sw_ptr(&dma_chreq_rx, (u32)sw_ptr, 0) != 0) { ++ ERR("%s: failed to update sw-pointer!\n", __func__); ++ } ++ ++ ftssp010_substream->rx_period = rx_period % runtime->periods; ++ ++ snd_pcm_period_elapsed(chip->substream_rx); ++} ++ ++static inline int snd_ftssp_dma_ch_alloc(struct snd_pcm_substream *substream) ++{ ++ dmad_chreq *ch_req __attribute__((__unused__)) = 0; ++ ++#ifdef CONFIG_PLATFORM_APBDMA ++ ++ if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ ch_req = &dma_chreq_tx; ++ ch_req->completion_cb = ftssp_dma_callback_tx; ++ ch_req->apb_req.tx_dir = DMAD_DIR_A0_TO_A1; ++ ch_req->apb_req.dev_reqn = APBBR_REQN_I2SAC97TX; ++ } else { ++ ch_req = &dma_chreq_rx; ++ ch_req->completion_cb = ftssp_dma_callback_rx; ++ ch_req->apb_req.tx_dir = DMAD_DIR_A1_TO_A0; ++ ch_req->apb_req.dev_reqn = APBBR_REQN_I2SAC97RX; ++ } ++ ++ ch_req->controller = DMAD_DMAC_APB_CORE; ++ ch_req->flags = DMAD_FLAGS_RING_MODE; ++ ch_req->ring_base = 0; ++ ch_req->dev_addr = (dma_addr_t)FTSSP010_DATA_PA(cardno); ++ ch_req->periods = 0; ++ ch_req->period_size = 0; ++ ++ ch_req->apb_req.ring_ctrl = APBBR_ADDRINC_I2X; ++ ch_req->apb_req.ring_reqn = APBBR_REQN_NONE; ++ ch_req->apb_req.dev_ctrl = APBBR_ADDRINC_FIXED; ++ ch_req->apb_req.burst_mode = 0; ++ ch_req->apb_req.data_width = APBBR_DATAWIDTH_2; ++ ch_req->completion_data = (void *)snd_pcm_substream_chip(substream); ++ ++ ch_req->completion_data = (void *)snd_pcm_substream_chip(substream); ++ ++ if (dmad_channel_alloc(ch_req) != 0) { ++ ERR("%s: APBDMA channel allocation failed\n",__func__); ++ goto _try_ahb; ++ } ++ ++ DBG("%s: APBDMA channel allocated (ch: %d) ring_mode\n", ++ __func__, ch_req->channel); ++ ++ return 0; ++ ++_try_ahb: ++ ++#endif /* CONFIG_PLATFORM_APBDMA */ ++ ++#ifdef CONFIG_PLATFORM_AHBDMA ++ ++ if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ ch_req = &dma_chreq_tx; ++ ch_req->completion_cb = ftssp_dma_callback_tx; ++ ch_req->ahb_req.tx_dir = DMAD_DIR_A0_TO_A1; ++ ch_req->ahb_req.dev_reqn = DMAC_REQN_I2SAC97TX; ++ } else { ++ ch_req = &dma_chreq_rx; ++ ch_req->completion_cb = ftssp_dma_callback_rx; ++ ch_req->ahb_req.tx_dir = DMAD_DIR_A1_TO_A0; ++ ch_req->ahb_req.dev_reqn = DMAC_REQN_I2SAC97RX; ++ } ++ ++ ch_req->controller = DMAD_DMAC_AHB_CORE; ++ ch_req->flags = DMAD_FLAGS_RING_MODE; ++ ch_req->ring_base = 0; ++ ch_req->dev_addr = (dma_addr_t)FTSSP010_DATA_PA(cardno); ++ ch_req->periods = 0; ++ ch_req->period_size = 0; ++ ++ ch_req->ahb_req.sync = 1; ++ ch_req->ahb_req.priority = DMAC_CSR_CHPRI_2; ++ ch_req->ahb_req.hw_handshake = 1; ++ ch_req->ahb_req.burst_size = DMAC_CSR_SIZE_1; ++ ++ ch_req->ahb_req.ring_width = DMAC_CSR_WIDTH_32; ++ ch_req->ahb_req.ring_ctrl = DMAC_CSR_AD_INC; ++ ch_req->ahb_req.ring_reqn = DMAC_REQN_NONE; ++ ch_req->ahb_req.dev_width = DMAC_CSR_WIDTH_32; ++ ch_req->ahb_req.dev_ctrl = DMAC_CSR_AD_FIX; ++ ++ ch_req->completion_data = (void *)snd_pcm_substream_chip(substream); ++ ++ if (dmad_channel_alloc(ch_req) != 0) { ++ ERR("%s: AHBDMA channel allocation failed\n", __func__); ++ goto _err_exit; ++ } ++ ++ DBG("%s: AHBDMA channel allocated (ch: %d) ring_mode\n", ++ __func__, ch_req->channel); ++ ++ return 0; ++ ++_err_exit: ++ ++#endif /* CONFIG_PLATFORM_AHBDMA */ ++ ++ return -ENODEV; ++} ++ ++static inline ftssp_substream *ftssp010_substream_new(int stream_id) ++{ ++ ftssp_substream *s = NULL; ++ ++ switch (stream_id) { ++ case SNDRV_PCM_STREAM_PLAYBACK: ++ s = &ftssp010_substreams[0]; ++ break; ++ case SNDRV_PCM_STREAM_CAPTURE: ++ s = &ftssp010_substreams[1]; ++ break; ++ default: ++ ERR("%s: wrong stream type (%d)\n", __func__, stream_id); ++ return NULL; ++ } ++ ++ if (s->busy) { ++ ERR("%s: device busy!\n", __func__); ++ return NULL; ++ } ++ s->busy = 1; ++ ++ spin_lock_init(&s->dma_lock); ++ ++ return s; ++} ++ ++static int snd_ftssp_pcm_open(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ int stream_id = substream->pstr->stream; ++ ++ VDBG("%s, %s\n", __func__, ++ (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture"); ++ ++ /* Both playback and capture share a hardware description */ ++ runtime->hw = snd_ftssp_pcm_hw; ++ ++ /* Allocate & Initialize stream-specific data */ ++ runtime->private_data = ftssp010_substream_new(stream_id); ++ ++ if (runtime->private_data) ++ return snd_ftssp_dma_ch_alloc(substream); ++ else ++ return -EBUSY; ++} ++ ++static int snd_ftssp_pcm_close(struct snd_pcm_substream *substream) ++{ ++ int stream_id = substream->pstr->stream; ++ ftssp_substream *ftssp010_substream = ++ (ftssp_substream *)substream->runtime->private_data; ++ ++ VDBG("%s, %s\n", __func__, ++ (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture"); ++ ++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ++ dmad_channel_free(&dma_chreq_tx); ++ else ++ dmad_channel_free(&dma_chreq_rx); ++ ++ ftssp010_substream->busy = 0; ++ return 0; ++} ++ ++static int snd_ftssp_pcm_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *hw_params) ++{ ++ VDBG("%s, %s\n", __func__, ++ (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture"); ++ ++ return snd_pcm_lib_malloc_pages(substream, HDA_HW_DMA_SIZE); ++} ++ ++static int snd_ftssp_pcm_hw_free(struct snd_pcm_substream *substream) ++{ ++ VDBG("%s, %s\n", __func__, ++ (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) ? ++ "playback" : "capture"); ++ ++ if (substream->pstr->stream == SNDRV_PCM_STREAM_PLAYBACK) ++ dmad_drain_requests(&dma_chreq_tx, 1); ++ else ++ dmad_drain_requests(&dma_chreq_rx, 1); ++ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++/* Prepare FTSSP010 AHBDMA for playback & capture */ ++static int snd_ftssp_pcm_prepare(struct snd_pcm_substream *substream) ++{ ++ ftssp_chip *chip = snd_pcm_substream_chip(substream); ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ ++ ftssp_substream *ftssp010_substream = ++ (ftssp_substream *)runtime->private_data; ++ ++ int stream_id = substream->pstr->stream; ++ dmad_chreq *dma_chreq; ++ unsigned period_size, buffer_size; ++ VVDBG("%s before spin_lock<<\n", __func__); ++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ++ dma_chreq = &dma_chreq_tx; ++ else ++ dma_chreq = &dma_chreq_rx; ++ ++ period_size = frames_to_bytes(runtime, runtime->period_size); ++ buffer_size = frames_to_bytes(runtime, runtime->buffer_size); ++ ++ if (runtime->format != SNDRV_PCM_FORMAT_S16_LE) ++ return -ENODEV; ++ ++ ftssp010_substream->dma_width = 4; ++ ++ dmad_drain_requests(dma_chreq, 1); ++ ++ dma_chreq->ring_base = (dma_addr_t)runtime->dma_addr; ++ dma_chreq->periods = (dma_addr_t)runtime->periods; ++ dma_chreq->period_size = (dma_addr_t)(period_size >> 1); ++ dma_chreq->ring_size = (dma_addr_t)(buffer_size >> 1); ++ dmad_update_ring(dma_chreq); ++ ++ /* Set PMU, FTSSP010, and DMA */ ++ spin_lock(&ftssp010_substream->dma_lock); ++ ++ /* keep DMA buffer VA for copy() callback */ ++ // todo: support playback/capture simultaneously ++ ftssp010_substream->dma_area_va = (u32)runtime->dma_area; ++ VVDBG("%s before hw_config<<\n", __func__); ++ ftssp010_substream->hw_config(cardno, ++ runtime->channels > 1 ? 1 : 0, /* 1: stereo, 0: mono */ ++ runtime->rate, ftssp010_substream->dma_width); ++ VVDBG("%s after hw_config<<\n", __func__); ++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { ++ ftssp010_substream->tx_period = 0; ++ chip->substream_tx = substream; ++ } else { ++ ftssp010_substream->rx_period = 0; ++ chip->substream_rx = substream; ++ } ++ ++ spin_unlock(&ftssp010_substream->dma_lock); ++ VVDBG("%s after spin_unlock <<\n", __func__); ++ ++ return 0; ++} ++ ++static inline int snd_ftssp_start_play(ftssp_substream *ftssp010_substream, ++ struct snd_pcm_runtime *runtime) ++{ ++ int err = 0; ++ u32 sw_ptr = ++ (u32)frames_to_bytes(runtime, runtime->buffer_size) >> 1; ++ ++ err = dmad_update_ring_sw_ptr(&dma_chreq_tx, sw_ptr, 0); ++ if (err != 0) { ++ ERR("%s: failed to update sw-pointer!\n", __func__); ++ return err; ++ } ++ err = dmad_kickoff_requests(&dma_chreq_tx); ++ if (err != 0) { ++ ERR("%s: failed to kickoff dma!\n", __func__); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static inline int snd_ftssp_start_record(ftssp_substream *ftssp010_substream, ++ struct snd_pcm_runtime *runtime) ++{ ++ int err = 0; ++ u32 sw_ptr = (u32)frames_to_bytes(runtime, runtime->buffer_size); ++ ++ sw_ptr = sw_ptr >> 1; ++ printk(">>>>>>>>>> : snd_ftssp_start_record() for recording....\n"); ++ err = dmad_update_ring_sw_ptr(&dma_chreq_rx, sw_ptr, 0); ++ if (err != 0) { ++ ERR("%s: failed to update sw-pointer!\n", __func__); ++ return err; ++ } ++ ++ err = dmad_kickoff_requests(&dma_chreq_rx); ++ if (err != 0) { ++ ERR("%s: failed to kickoff dma!\n", __func__); ++ return err; ++ } ++ ++ ++ return 0; ++} ++ ++/* Triggers AHBDMA for playback & capture */ ++static int snd_ftssp_pcm_trigger(struct snd_pcm_substream * substream, int cmd) ++{ ++ ftssp_substream *ftssp010_substream = ++ (ftssp_substream *)substream->runtime->private_data; ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ int err = 0; ++ int stream_id = substream->pstr->stream; ++ ++ /* note local interrupts are already disabled in the midlevel code */ ++ spin_lock(&ftssp010_substream->dma_lock); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ ++ VDBG("%s: SNDRV_PCM_TRIGGER_START state(0x%08x)\n", ++ __func__, (u32)runtime->status->state); ++ ++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { ++ err = snd_ftssp_start_play(ftssp010_substream, runtime); ++ } else { ++ err = snd_ftssp_start_record(ftssp010_substream, ++ runtime); ++ } ++ break; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ ++ VDBG("%s: SNDRV_PCM_TRIGGER_STOP state(0x%08x)\n", ++ __func__, (u32)substream->runtime->status->state); ++ ++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { ++ ftssp010_stop_tx(cardno); ++ dmad_drain_requests(&dma_chreq_tx, 1); ++ } else { ++ ftssp010_stop_rx(cardno); ++ dmad_drain_requests(&dma_chreq_rx, 1); ++ } ++ break; ++ default: ++ err = -EINVAL; ++ break; ++ } ++ ++ spin_unlock(&ftssp010_substream->dma_lock); ++ return err; ++} ++ ++// pcm middle-layer call this function within irq (snd_pcm_period_elapsed) or ++// with local irq disabled (snd_pcm_lib_write1) ++static snd_pcm_uframes_t snd_ftssp_pcm_pointer( ++ struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ u32 hw_ptr; ++ snd_pcm_uframes_t ret; ++ int stream_id = substream->pstr->stream; ++ ++ /* Fetch DMA pointer, with spin lock */ ++ //spin_lock_irqsave(&ftssp010_substream->dma_lock, flags); ++ ++ if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { ++ hw_ptr = dmad_probe_ring_hw_ptr(&dma_chreq_tx); ++ } else { ++ hw_ptr = dmad_probe_ring_hw_ptr(&dma_chreq_rx); ++ } ++ ret = bytes_to_frames(runtime, hw_ptr << 1); ++ //spin_unlock_irqrestore(&ftssp010_substream->dma_lock, flags); ++ VVDBG("%s: hw_ptr(0x%08x) ret(0x%08x)\n", ++ (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ? "p" : "c", ++ (u32)hw_ptr, (u32)ret); ++ ++ /* ALSA requires return value 0 <= ret < buffer_size */ ++ if (ret >= runtime->buffer_size) ++ return 0; ++ return ret; ++} ++ ++/* For FTSSP010 driver, operations are shared among playback & capture */ ++static struct snd_pcm_ops snd_ftssp_playback_ops = { ++ .open = snd_ftssp_pcm_open, ++ .close = snd_ftssp_pcm_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = snd_ftssp_pcm_hw_params, ++ .hw_free = snd_ftssp_pcm_hw_free, ++ .prepare = snd_ftssp_pcm_prepare, ++ .trigger = snd_ftssp_pcm_trigger, ++ .pointer = snd_ftssp_pcm_pointer, ++ .copy = NULL, ++}; ++ ++static struct snd_pcm_ops snd_ftssp_capture_ops = { ++ .open = snd_ftssp_pcm_open, ++ .close = snd_ftssp_pcm_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = snd_ftssp_pcm_hw_params, ++ .hw_free = snd_ftssp_pcm_hw_free, ++ .prepare = snd_ftssp_pcm_prepare, ++ .trigger = snd_ftssp_pcm_trigger, ++ .pointer = snd_ftssp_pcm_pointer, ++ .copy = NULL, ++}; ++ ++/* ALSA PCM constructor */ ++static int snd_ftssp_new_pcm(ftssp_chip *chip) ++{ ++ struct snd_pcm *pcm; ++ int err; ++ ++ /* PCM device #0 with 1 playback and 1 capture */ ++ if ((err = snd_pcm_new(chip->card, "ftssp_pcm", 0, 1, 1, &pcm)) < 0) ++ return err; ++ ++ pcm->private_data = chip; ++ strcpy(pcm->name, "ftssp_pcm device"); ++ chip->pcm = pcm; ++ ++ /* set operators for playback and capture*/ ++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, ++ &snd_ftssp_playback_ops); ++ ++ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, ++ &snd_ftssp_capture_ops); ++ ++ /* Pre-allocate buffer, as suggested by ALSA driver document */ ++ // todo: support playback/capture simultaneously ++ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, ++ NULL, FTSSP_HW_DMA_SIZE, FTSSP_HW_DMA_SIZE); ++ ++ return 0; ++} ++ ++static __init int ftssp_alsa_init(void) ++{ ++ ftssp_chip *chip; ++ int err; ++ init_hw(cardno); ++ INFO("After init_hw!\n"); ++ err = snd_card_create(cardno, FTSSP_CARD_ID, THIS_MODULE, ++ sizeof(ftssp_chip), &ftssp_cards[cardno]); ++ INFO("After snd_card_create!\n"); ++ if (err < 0) ++ return err; ++ sprintf(ftssp_cards[cardno]->driver, FTSSP_DRIVER_NAME); ++ sprintf(ftssp_cards[cardno]->shortname, ++ FTSSP_DRIVER_NAME "_HDA"); ++ sprintf(ftssp_cards[cardno]->longname, ++ FTSSP_DRIVER_NAME "_HDA controller"); ++ /* PCM */ ++ chip = (ftssp_chip *)(ftssp_cards[cardno]->private_data); ++ chip->card = ftssp_cards[cardno]; ++ ++ if ((err = snd_ftssp_new_pcm(chip))) { ++ ERR("%s, Can't new PCM devices\n",__func__); ++ return -ENODEV; ++ } ++ ++ ++ /* Register the card to ALSA */ ++ if ((err = snd_card_register(chip->card)) == 0) { ++ INFO("%s card registered!\n", FTSSP_CARD_ID); ++ } ++ ++ return 0; ++} ++ ++static __exit void ftssp_alsa_exit(void) ++{ ++ DBG("%s, cleaning up\n",__func__); ++ ++ dmad_channel_free(&dma_chreq_tx); ++ dmad_channel_free(&dma_chreq_rx); ++ ++ snd_card_free(ftssp_cards[cardno]); ++} ++ ++module_init(ftssp_alsa_init); ++module_exit(ftssp_alsa_exit); +diff -Nur linux-3.4.110.orig/sound/nds32/FTSSP010_HDA.h linux-3.4.110/sound/nds32/FTSSP010_HDA.h +--- linux-3.4.110.orig/sound/nds32/FTSSP010_HDA.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/sound/nds32/FTSSP010_HDA.h 2016-04-07 10:20:51.062085666 +0200 +@@ -0,0 +1,34 @@ ++/* FTSSP010 - HDA supporting library header */ ++/* ++ * ++ * $log$ ++ * ++ */ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <asm/io.h> ++#include <linux/delay.h> ++#include <asm/spec.h> ++#include <linux/dma-mapping.h> ++ ++ ++#define FTSSP010_DATA(x) (SSP_FTSSP010_va_base[(x)]+0x18) ++#define FTSSP010_DATA_PA(x) (SSP_FTSSP010_pa_base[(x)]+0x18) ++ ++ ++/* Returns FTSSP010 status */ ++extern void ftssp010_set_int_control(int cardno, unsigned val); ++extern int ftssp010_get_status(int cardno); ++extern unsigned ftssp010_get_int_status(int cardno); ++/* Polls FIFO full register */ ++extern int ftssp010_tx_fifo_not_full(int cardno); ++ ++/* Configure FTSSP010 to a given sampling rate and channel number */ ++extern void ftssp010_config_hda_play(int cardno, unsigned is_stereo, unsigned speed, int use8bit); ++ ++extern void ftssp010_config_hda_rec(int cardno, unsigned is_stereo, unsigned speed, int use8bit); ++ ++extern void ftssp010_stop_tx(int cardno); ++extern void ftssp010_stop_rx(int cardno); ++ ++ +diff -Nur linux-3.4.110.orig/sound/nds32/FTSSP010_HDA_lib.c linux-3.4.110/sound/nds32/FTSSP010_HDA_lib.c +--- linux-3.4.110.orig/sound/nds32/FTSSP010_HDA_lib.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/sound/nds32/FTSSP010_HDA_lib.c 2016-04-07 10:20:51.062085666 +0200 +@@ -0,0 +1,477 @@ ++/* FTSSP010 - UDA1345TS module ++ * ++ * $log$ ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <asm/io.h> ++#include <linux/delay.h> ++#include <asm/spec.h> ++#include <asm/dmad.h> ++#include <linux/dma-mapping.h> ++#include "hda.h" ++ ++#if 0 ++MODULE_LICENSE("Faraday License"); ++MODULE_AUTHOR("Faraday Technology Corp."); ++MODULE_DESCRIPTION("FTSSP010 - UDA1345TS Linux 2.6 Library"); ++#endif ++#undef ERR ++#define ERR(vvar...) printk(KERN_ERR vvar) ++#define DBG(vvar...) printk(KERN_INFO vvar) ++ ++#define SSP_TXFCLR 0x8 ++#define SSP_RXFCLR 0x4 ++#define SSP_RFIEN 0x4 ++#define SSP_TFIEN 0x8 ++#define SSP_SSPEN 0x1 ++#define SSP_TXDOE 0x2 ++#define SSP_RXDMAEN 0x10 ++#define SSP_TXDMAEN 0x20 ++#define SSP_RFURIEN 0x1 ++#define SSP_TFURIEN 0x2 ++#define HDA_STRNUM_RX 1 ++#define HDA_STRNUM_TX 2 ++#define HDA_CHANUM 0 ++#define HDA_CRST_MASK 0x20 ++/* Initialize FTSSP010 to output to UDA1345TS via I2S */ ++#define FTSSP010_CONTROL0(x) (SSP_FTSSP010_va_base[(x)]+0x0) ++#define FTSSP010_CONTROL0_OPM_STEREO 0xC ++#define FTSSP010_CONTROL0_OPM_MONO 0x8 ++ ++#define FTSSP010_CONTROL1(x) (SSP_FTSSP010_va_base[(x)]+0x4) ++#define FTSSP010_CONTROL2(x) (SSP_FTSSP010_va_base[(x)]+0x8) ++ ++#define FTSSP010_INT_CONTROL(x) (SSP_FTSSP010_va_base[(x)]+0x10) ++#define FTSSP010_STATUS(x) (SSP_FTSSP010_va_base[(x)]+0xC) ++#define FTSSP010_INT_STATUS(x) (SSP_FTSSP010_va_base[(x)]+0x14) ++#define FTSSP010_DATA(x) (SSP_FTSSP010_va_base[(x)]+0x18) ++#define FTSSP010_INFO(x) (SSP_FTSSP010_va_base[(x)]+0x1C) ++#define FTSSP010_AC_COMMAND(x) (SSP_FTSSP010_va_base[(x)]+0x28) ++#define FTSSP010_IRSPR(x) (SSP_FTSSP010_va_base[(x)]+0x2C) ++#define FTSSP010_ICMDST(x) (SSP_FTSSP010_va_base[(x)]+0x30) ++#define HDA_REG_OSDC(x) (SSP_FTSSP010_va_base[(x)]+0x50) ++#define HDA_REG_ISDC(x) (SSP_FTSSP010_va_base[(x)]+0x54) ++ ++static const unsigned int SSP_FTSSP010_va_base[SSP_FTSSP010_IRQ_COUNT] = { SSP_FTSSP010_VA_BASE }; ++static const unsigned int SSP_FTSSP010_pa_base[SSP_FTSSP010_IRQ_COUNT] = { SSP_FTSSP010_PA_BASE }; ++ ++void SetSSP_Enable(int cardno, int enable) ++{ ++ volatile unsigned int ctrl = 0; ++ ++ ctrl = inl(FTSSP010_CONTROL2(cardno)); ++ if(enable) ++ ctrl |= SSP_SSPEN + SSP_TXDOE; ++ else ++ ctrl &= ~(SSP_SSPEN + SSP_TXDOE); ++ ++ outl(ctrl, FTSSP010_CONTROL2(cardno)); ++} ++void SetSSP_Enable_rx(int cardno, int enable) ++{ ++ volatile unsigned int ctrl = 0; ++ ++ ctrl = inl(FTSSP010_CONTROL2(cardno)); ++ if(enable) ++ ctrl |= SSP_SSPEN ; ++ else ++ ctrl &= ~(SSP_SSPEN); ++ ++ outl(ctrl, FTSSP010_CONTROL2(cardno)); ++} ++ ++void SetSSP_FIFO_Threshold(int cardno, unsigned int trans_len,unsigned int rec_len) ++{ ++ volatile unsigned int ctrl = 0; ++ ctrl = inl(FTSSP010_INT_CONTROL(cardno)); ++ ++ ctrl &= ~0x0000FF00; ++ ctrl |= ((trans_len << 12) + (rec_len << 8)) & 0x0000FF00; ++ ++ outl(ctrl, FTSSP010_INT_CONTROL(cardno)); ++} ++void SetSSP_IntMask(int cardno,int Mask) ++{ ++ volatile unsigned int ctrl = 0; ++ ctrl = inl(FTSSP010_INT_CONTROL(cardno)); ++ ctrl &= ~0x3F; ++ ctrl |= Mask; ++ outw(ctrl, FTSSP010_INT_CONTROL(cardno)); ++} ++void SetSSP_TXFIFO(int cardno, unsigned int threshold,unsigned int underrun) ++{ ++ volatile unsigned int data = 0; ++ ++ data = inl(FTSSP010_INT_CONTROL(cardno)); ++ ++ if (threshold) ++ data |= SSP_TFIEN; ++ else ++ data &= ~SSP_TFIEN; //Howard@2007-4-13 ++ ++ if (underrun) ++ data |= SSP_TFURIEN; ++ else ++ data &= ~SSP_TFURIEN; //Howard@2007-4-13 ++ ++ outl(data, FTSSP010_INT_CONTROL(cardno)); ++} ++void SetSSP_RXFIFO(int cardno,unsigned int threshold,unsigned int underrun) ++{ ++ volatile unsigned int data = 0; ++ ++ data = inl(FTSSP010_INT_CONTROL(cardno)); ++ ++ if (threshold) ++ data |= SSP_RFIEN; ++ else ++ data &= ~SSP_RFIEN; //Howard@2007-4-13 ++ ++ if (underrun) ++ data |= SSP_RFURIEN; ++ else ++ data &= ~SSP_RFURIEN; //Howard@2007-4-13 ++ ++ outl(data, FTSSP010_INT_CONTROL(cardno)); ++} ++void SetSSP_DMA(int cardno, unsigned int trans,unsigned int rec) ++{ ++ volatile unsigned int data = 0; ++ ++ data = inl(FTSSP010_INT_CONTROL(cardno)); ++ ++ if (trans) ++ data |= SSP_TXDMAEN; ++ else ++ data &= ~SSP_TXDMAEN; ++ ++ if (rec) ++ data |= SSP_RXDMAEN; ++ else ++ data &= ~SSP_RXDMAEN; ++ ++ outl(data, FTSSP010_INT_CONTROL(cardno)); ++} ++void SSPClearTxFIFO(int cardno) ++{ ++ volatile unsigned int data = 0; ++ ++ data = inl(FTSSP010_CONTROL2(cardno)); ++ data |= SSP_TXFCLR; ++ outl(data, FTSSP010_CONTROL2(cardno)); ++} ++ ++ ++void SSPClearRxFIFO(int cardno) ++{ ++ volatile unsigned int data = 0; ++ ++ data = inl(FTSSP010_CONTROL2(cardno)); ++ data |= SSP_RXFCLR; ++ outl(data, FTSSP010_CONTROL2(cardno)); ++} ++ ++void ftssp010_set_int_control(int cardno, unsigned val) ++{ ++ outl(val, FTSSP010_INT_CONTROL(cardno)); ++} ++ ++unsigned ftssp010_get_int_status(int cardno) ++{ ++ return (inl(FTSSP010_INT_STATUS(cardno))); ++} ++ ++int ftssp010_get_status(int cardno) ++{ ++ return (inl(FTSSP010_STATUS(cardno))); ++} ++ ++int ftssp010_tx_fifo_not_full(int cardno) ++{ ++ return (inl(FTSSP010_STATUS(cardno))&0x2)==0x2; ++} ++ ++int ftssp010_tx_fifo_vaild_entries(int cardno) ++{ ++ return (inl(FTSSP010_STATUS(cardno))>>12) & 0x1f; ++} ++ ++/* Configure FTSSP010 to a given sampling rate and channel number ++ * for HDA mode in playback mode ++ */ ++void init_hw(unsigned int cardno) ++{ ++ /* Step 1: Set HDA Mode & HDA Format */ ++ outl(HDA_MODE | 0x4000, FTSSP010_CONTROL0(cardno)); /* set FTSSP010 to HDA mode */ ++ mdelay(50); ++ outl(HDA_CRST_CLR | (5 << HDA_RST_FCNT_OFS), FTSSP010_CONTROL2(cardno)); /* Cold Reset AC-Link */ ++ mdelay(50); ++ while((inl(FTSSP010_CONTROL2(cardno)) & HDA_CRST_MASK) != HDA_CRST_CLR); ++ SetSSP_IntMask(cardno, 0); ++ ++} ++void SSPClearFIFO(int cardno, unsigned int tx, unsigned int rx) ++{ ++ unsigned int data; ++ ++ if (tx == 1) { ++ //clear TX ++ data = inl(FTSSP010_CONTROL2(cardno)); ++ //data = REG32(SSP_REG_CTRL2); ++ data |= SSP_TXFCLR; ++ outl(data, FTSSP010_CONTROL2(cardno)); ++ //REG32(SSP_REG_CTRL2) = data; ++ } ++ ++ if (rx == 1) { ++ //clear RX ++ data = inl(FTSSP010_CONTROL2(cardno)); ++ //data = REG32(SSP_REG_CTRL2); ++ data |= SSP_RXFCLR; ++ //REG32(SSP_REG_CTRL2) = data; ++ outl(data, FTSSP010_CONTROL2(cardno)); ++ } ++} ++void hda_cmd_rsp(int cardno, unsigned int node_num, unsigned int verb_num, unsigned int func_num) ++{ ++ //unsigned int HDA_REG_ICMDST; ++ volatile unsigned int hda_cmd = HDA_COD_DEVADDR | (node_num << 20) | (verb_num << 8) | func_num; ++ //Wait CMD Bus Not Busy ++ while((inl(FTSSP010_ICMDST(cardno)) & HDA_ICB_MASK) != 0); ++ //Write CMD into ICW ++ outl(hda_cmd, FTSSP010_AC_COMMAND(cardno)); ++ mdelay(50); ++ //Wait new resp is latched into IRR ++ while((inl(FTSSP010_ICMDST(cardno)) & HDA_IRV_MASK) == 0); ++ //Get Resp From IRR & Compare with Expected Resp ++ //clear IRV ++ outl(inl(FTSSP010_ICMDST(cardno)) | (1 << HDA_IRV_OFFSET), FTSSP010_ICMDST(cardno)); ++ mdelay(50); ++} ++void hda_cmdrsp_proc(int cardno, unsigned int node_num, unsigned int issue_cmd, unsigned int expect_rsp) ++{ ++ unsigned int hda_cmd = HDA_COD_DEVADDR | node_num | issue_cmd; ++ unsigned int HDA_REG_ICMDST; ++ //Wait CMD Bus Not Busy ++ while((inl(FTSSP010_ICMDST(cardno)) & HDA_ICB_MASK) != 0); ++ ++ //Write CMD into ICW ++ //REG32(HDA_REG_ICMDW) = hda_cmd; ++ outl(hda_cmd, FTSSP010_AC_COMMAND(cardno)); ++ mdelay(50); ++ //Wait new resp is latched into IRR ++ while((inl(FTSSP010_ICMDST(cardno)) & HDA_IRV_MASK) == 0); ++ //Get Resp From IRR & Compare with Expected Resp ++ if (inl(FTSSP010_IRSPR(cardno)) != expect_rsp) { ++ ERR("%s: unexpected rsp!",__func__); ++ } ++ else { ++ //clear IRV ++ outl(inl(FTSSP010_ICMDST(cardno)) | (1 << HDA_IRV_OFFSET), FTSSP010_ICMDST(cardno)); ++ } ++} ++unsigned int hda_covfmt_setup(unsigned int type, unsigned int base, unsigned int mult, unsigned int div, unsigned int bits, unsigned int chnum) ++{ ++ unsigned int hda_fmt = type << HDA_FMT_TYPE_OFS | ++ base << HDA_FMT_BASE_OFS | ++ mult << HDA_FMT_MULT_OFS | ++ div << HDA_FMT_DIV_OFS | ++ bits << HDA_FMT_BITS_OFS | ++ chnum << HDA_FMT_CHNUM_OFS; ++ return hda_fmt; ++} ++unsigned int hda_covstr_setup(unsigned int stream, unsigned int channel) ++{ ++ unsigned int hda_str = stream << HDA_STR_STR_OFS | ++ channel << HDA_STR_CHA_OFS ; ++ return hda_str; ++} ++unsigned int hda_converter_setup(int cardno, unsigned int mode, unsigned int type, unsigned int base, unsigned mult, unsigned int div, unsigned int bits, unsigned int chnum, unsigned int stream, unsigned int channel) ++{ ++ unsigned int hda_fmt = 0; ++ unsigned int hda_str = 0; ++ unsigned int exp_rsp = 0; ++ unsigned int node_num = 0; ++ ++ if (mode == HDA_OUT_STR) { ++ node_num = HDA_OUTCOV_NODE; ++ } ++ else { ++ node_num = HDA_INCOV_NODE; ++ } ++ //a: Set Converter Format to Converter ++ hda_fmt = hda_covfmt_setup(type, base, mult, div, bits, chnum); ++ exp_rsp = HDA_RESP_ZERO_VAL; ++ hda_cmdrsp_proc(cardno, node_num, (HDA_CMD_SETCVTFMT | hda_fmt), exp_rsp); ++ //b: Get Converter Format from Converter ++ exp_rsp = hda_fmt; ++ hda_cmdrsp_proc(cardno, node_num, HDA_CMD_GETCVTFMT, exp_rsp); ++ //c: Set Converter Stream to Converter ++ hda_str = hda_covstr_setup(stream, channel); ++ exp_rsp = HDA_RESP_ZERO_VAL; ++ hda_cmdrsp_proc(cardno, node_num, (HDA_CMD_SETCVTSTR | hda_str), exp_rsp); ++ //d: Get Converter Stream from Converter ++ exp_rsp = hda_str; ++ hda_cmdrsp_proc(cardno, node_num, HDA_CMD_GETCVTSTR, exp_rsp); ++ ++ return hda_fmt; ++} ++void hda_iosdc_setup(int cardno, unsigned int io_sel, unsigned int ctrl, unsigned int stream_num, unsigned int hda_fmt) ++{ ++ unsigned int hda_reg_base = (io_sel == 1)? HDA_REG_OSDC(cardno) : HDA_REG_ISDC(cardno); ++ if (ctrl == 1) {//run ++ outl((stream_num << HDA_SDC_STNUM_OFFSET) | hda_fmt, hda_reg_base); ++ outl((inl(hda_reg_base) | (1 << HDA_SDC_SRUN_OFFSET)),hda_reg_base); ++ } ++ ++} ++static void _ftssp010_config_hda(int cardno, unsigned is_stereo, unsigned speed, int is_rec) ++{ ++ unsigned int hda_fmt = 0; ++ unsigned int div = 0,mult = 0, base = 0; ++ switch (speed) { ++ case 44100: ++ base = 1; ++ div = 0; ++ break; ++ case 48000: ++ div = 0; ++ break; ++ case 96000: ++ mult = 1; ++ break; ++ case 192000: ++ mult = 3; ++ break; ++ } ++ ++ if (is_rec) { /* Recording */ ++ /* ------------------------------------------------ */ ++ /* Codec initialization */ ++ /* ------------------------------------------------ */ ++ /* Step 3: Codec Evaluation */ ++ /* root_node -> node 1(Audio Func Group) */ ++ /* -> node 2(Output Converter) */ ++ /* -> node 3(Input Converter) */ ++ /* ------------------------------------------------ */ ++ //input ++ hda_cmd_rsp(cardno, 0x1a, 0x707, 0x20); //pin complex => input enable, port-c LINE1 ++ hda_cmd_rsp(cardno, 0x08, 0x3f0, 0x3f);//pin amp => max LINE ADC amplifier gain ++ hda_cmd_rsp(cardno, 0x1a, 0x3f0, 0x00);//pin complex => no mute ++ hda_cmd_rsp(cardno, 0x23, 0x3f2, 0x3f);//pin complex => no mute ++ /* ------------------------------ */ ++ /* Step 4: Output Converter Setup */ ++ /* ------------------------------ */ ++ /* Set Converter Format & Stream to Node 2(Output Converter) */ ++ /* type = PCM, base = 48K, mult = xN, div = /M, bits = 8~32bits/sample, chnum = 1 */ ++ /* stream = 1, lowest channel = 0 */ ++ ++ hda_fmt = hda_converter_setup(cardno, HDA_IN_STR, //MODE ++ 0, base, mult, div, 1, 1, //FORMAT ++ HDA_STRNUM_RX, HDA_CHANUM); //STREAM ++ /* ---------------------------- */ ++ /* Step 5: Enable Output Stream */ ++ /* ---------------------------- */ ++ hda_iosdc_setup(cardno, HDA_IN_STR, HDA_STR_RUN, HDA_STRNUM_RX, hda_fmt); ++ SetSSP_Enable_rx(cardno, 1); ++ SetSSP_RXFIFO(cardno, 0, 0); ++ SetSSP_TXFIFO(cardno, 0, 0); ++ SetSSP_FIFO_Threshold(cardno,12,12); ++ SetSSP_DMA(cardno, 0, 1); ++ ++ SSPClearTxFIFO(cardno); ++ SSPClearRxFIFO(cardno); ++ ++ //SetSSP_Enable_rx(cardno, 0); ++ ++ } else { /* Playback */ ++ /* ------------------------------------------------ */ ++ /* Codec initialization */ ++ /* ------------------------------------------------ */ ++ /* Step 3: Codec Evaluation */ ++ /* root_node -> node 1(Audio Func Group) */ ++ /* -> node 2(Output Converter) */ ++ /* -> node 3(Input Converter) */ ++ /* ------------------------------------------------ */ ++ //DBG("%s before_cmd_rsp<<",__func__); ++ hda_cmd_rsp(cardno, 0x14, 0x707, 0x40);//pin complex => output ++ //DBG("%s after hda_cmd_rsp<<pin complex => output>>",__func__); ++ hda_cmd_rsp(cardno, 0x0c, 0x3f0, 0x3f);//pin amp => 0x3f ++ hda_cmd_rsp(cardno, 0x14, 0x3f0, 0x00);//pin complex => no mute ++ //DBG("%s after hda_cmd_rsp",__func__); ++ //msleep_interruptible(10); ++ /* ------------------------------ */ ++ /* Step 4: Output Converter Setup */ ++ /* ------------------------------ */ ++ /* Set Converter Format & Stream to Node 2(Output Converter) */ ++ /* type = PCM, base = 48K, mult = xN, div = /M, bits = 8~32bits/sample, chnum = 1 */ ++ /* stream = 1, lowest channel = 0 */ ++ hda_fmt = hda_converter_setup(cardno, HDA_OUT_STR, //MODE ++ 0, base, mult, div, 1, 1, //FORMAT ++ HDA_STRNUM_TX, HDA_CHANUM); //STREAM ++ //DBG("%s after hda_converter_setup",__func__); ++ /* ---------------------------- */ ++ /* Step 5: Enable Output Stream */ ++ /* ---------------------------- */ ++ hda_iosdc_setup(cardno, HDA_OUT_STR, HDA_STR_RUN, HDA_STRNUM_TX, hda_fmt); ++ SetSSP_Enable(cardno, 1); ++ SetSSP_RXFIFO(cardno, 0, 0); ++ SetSSP_TXFIFO(cardno, 0, 0); ++ //outl(0xC, FTSSP010_CONTROL2(cardno)); /* Disable FTSSP010, clear RX/TX Fifo. */ ++ SetSSP_FIFO_Threshold(cardno,12,12); ++ SetSSP_DMA(cardno,1,0); ++ ++ SSPClearTxFIFO(cardno); ++ SSPClearRxFIFO(cardno); ++ } ++ ++ while(inl(FTSSP010_INT_STATUS(cardno))&0x3); ++} ++/* for HDA */ ++void ftssp010_config_hda_play(int cardno, unsigned is_stereo, unsigned speed, int use8bit) ++{ ++ _ftssp010_config_hda(cardno, is_stereo, speed, 0); ++} ++ ++void ftssp010_config_hda_rec(int cardno, unsigned is_stereo, unsigned speed, int use8bit) ++{ ++ _ftssp010_config_hda(cardno, is_stereo, speed, 1); ++} ++ ++ ++ ++void ftssp010_stop_tx(int cardno) ++{ ++ unsigned int hda_reg_base = HDA_REG_OSDC(cardno); ++ SetSSP_Enable(cardno,0); ++ SetSSP_DMA(cardno,0,0); ++ ++ /* turn off output node */ ++ hda_cmd_rsp(cardno,0x14, 0x707, 0); //pin complex => input enable, port-c LINE1 ++ hda_cmd_rsp(cardno,0x0c, 0x3f0, 0x80); //pin amp => max LINE ADC amplifier gain ++ hda_cmd_rsp(cardno,0x14, 0x3f0, 0x80); //pin complex => no mute ++ ++ outl(0, hda_reg_base); ++ SSPClearFIFO(cardno, 1, 0); ++ //outl(inl(FTSSP010_INT_CONTROL(cardno)) & (~0x22), FTSSP010_INT_CONTROL(cardno)); ++} ++ ++void ftssp010_stop_rx(int cardno) ++{ ++ unsigned int hda_reg_base = HDA_REG_ISDC(cardno); ++ SetSSP_Enable_rx(cardno, 0); ++ SetSSP_DMA(cardno, 0, 0); ++ ++ /* turn off output node */ ++ hda_cmd_rsp(cardno,0x1a, 0x707, 0); //pin complex => input enable, port-c LINE1 ++ hda_cmd_rsp(cardno,0x08, 0x3f0, 0x80);//pin amp => LINE ADC amplifier gain ++ hda_cmd_rsp(cardno,0x1a, 0x3f0, 0x80);//pin complex => mute ++ hda_cmd_rsp(cardno,0x23, 0x3f2, 0x80);//pin complex => no mute ++ ++ outl(0, hda_reg_base); ++ SSPClearFIFO(cardno, 0, 1); ++ //outl(inl(FTSSP010_INT_CONTROL(cardno)) & (~0x11), FTSSP010_INT_CONTROL(cardno)); ++} ++ +diff -Nur linux-3.4.110.orig/sound/nds32/FTSSP010_lib.c linux-3.4.110/sound/nds32/FTSSP010_lib.c +--- linux-3.4.110.orig/sound/nds32/FTSSP010_lib.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/sound/nds32/FTSSP010_lib.c 2016-04-07 10:20:51.062085666 +0200 +@@ -0,0 +1,795 @@ ++/* FTSSP010 - UDA1345TS module ++ * ++ * $log$ ++ */ ++ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <asm/io.h> ++#include <linux/delay.h> ++#include <linux/i2c.h> ++#include <asm/spec.h> ++#include <asm/dmad.h> ++#include <linux/dma-mapping.h> ++#include "FTSSP010_UDA1345TS.h" ++ ++#if 0 ++MODULE_LICENSE("Faraday License"); ++MODULE_AUTHOR("Faraday Technology Corp."); ++MODULE_DESCRIPTION("FTSSP010 - UDA1345TS Linux 2.6 Library"); ++#endif ++ ++#define PMU_PDLLCR1 (PMU_FTPMU010_VA_BASE+0x34) ++#define PMU_MFPSR (PMU_FTPMU010_VA_BASE+0x28) ++#define PMU_I2SAC97_REQACKCFG (PMU_FTPMU010_VA_BASE+0xbc) ++#define PMU_C4 (PMU_FTPMU010_VA_BASE+0xc4) ++ ++#define SSPCLK_TO_SCLKDIV(sspclk_div2,bps) ((sspclk_div2)/(bps)-1) ++ ++// Each client has this additional data ++struct alc5630_data { ++ struct i2c_client *client; ++ struct delayed_work work; ++ unsigned long gpio2_value; ++ struct mutex mtx; ++}; ++ ++//ADD by river 2011.01.26 ++static int i2s_alc5630_read(unsigned int raddr, char *data, struct i2c_client *client) ++{ ++#ifndef CONFIG_SND_FTSSP010_AC97 ++ struct i2c_adapter *adap = client->adapter; ++ int ret; ++#endif ++ struct i2c_msg msg; ++ int i2c_value; ++ ++ //Reading ALC5630 register ++ msg.addr = raddr; ++ msg.flags = (client->flags & I2C_M_TEN) | I2C_M_RD; ++ msg.len = 1; ++ msg.buf = (char *)data; ++ ++ //ret = i2c_transfer(adap, &msg, 1); ++#ifndef CONFIG_SND_FTSSP010_AC97 ++ ret = i2c_transfer(adap, &msg, 1); ++ if (ret != 0) { ++ printk("i2c read failed\n"); ++ return -1; ++ } ++ else ++#endif ++ { ++ i2c_value = (data[0]&0xff) << 8 | (data[1]&0xff); ++ return i2c_value; ++ } ++} ++ ++static void i2s_alc5630_write(unsigned int raddr, unsigned int data, struct i2c_client *client) ++{ ++#ifndef CONFIG_SND_FTSSP010_AC97 ++ struct i2c_adapter *adap = client->adapter; ++ int ret; ++#endif ++ struct i2c_msg msg; ++ char buf[3]; ++ ++ //Writing ALC5630 register ++ msg.addr = raddr; ++ msg.flags = (client->flags & I2C_M_TEN) | ~I2C_M_RD; ++ msg.len = 1; ++ ++ buf[0] = (data >> 8) & 0xff; ++ buf[1] = data & 0xff; ++ msg.buf = (char *)buf; ++ ++ //ret = i2c_transfer(adap, &msg, 1); ++#ifndef CONFIG_SND_FTSSP010_AC97 ++ ret = i2c_transfer(adap, &msg, 1); ++ if (ret != 0) ++ { ++ printk("i2c write failed\n"); ++ } ++#endif ++} ++ ++/* ++static void i2s_alc5630_master_stereo_mode(struct i2c_client *client) ++{ ++ //printk(">>>>>>>>> (7) i2s_alc5630_master_stereo_mode() is called.\n"); ++ i2s_alc5630_write(0x02, 0x5f5f, client); ++ mdelay(50); ++ i2s_alc5630_write(0x04, 0x5f5f, client); ++ mdelay(50); ++ i2s_alc5630_write(0x26, 0x000f, client); ++ mdelay(50); ++ i2s_alc5630_write(0x34, 0x0000, client); // codec master mode ++ //i2s_alc5630_write(0x34, 0x8000, client); // codec slave mode ++ mdelay(50); ++ i2s_alc5630_write(0x3a, 0x0801, client); ++ mdelay(50); ++ i2s_alc5630_write(0x3c, 0xffff, client); ++ mdelay(50); ++ i2s_alc5630_write(0x3e, 0xffff, client); ++ mdelay(50); ++ i2s_alc5630_write(0x60, 0x3075, client); // codec master mode. divider. ++ mdelay(50); ++ i2s_alc5630_write(0x62, 0x1010, client); // codec master mode. divider. ++ ++} ++*/ ++ ++/* ++static void i2s_alc5630_read_test(struct i2c_client *client) ++{ ++ char data[3]; ++ printk(">>>>> : i2s_alc5630_read_test().....\n"); ++ printk("Reg 0x%02x = 0x%08x\n", 0x0, i2s_alc5630_read(0x0, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x02, i2s_alc5630_read(0x02, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x04, i2s_alc5630_read(0x04, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x06, i2s_alc5630_read(0x06, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x08, i2s_alc5630_read(0x08, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x0a, i2s_alc5630_read(0x0a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x0c, i2s_alc5630_read(0x0c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x0e, i2s_alc5630_read(0x0e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x10, i2s_alc5630_read(0x10, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x12, i2s_alc5630_read(0x12, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x14, i2s_alc5630_read(0x14, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x16, i2s_alc5630_read(0x16, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x18, i2s_alc5630_read(0x18, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x1a, i2s_alc5630_read(0x1a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x1c, i2s_alc5630_read(0x1c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x1e, i2s_alc5630_read(0x1e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x20, i2s_alc5630_read(0x20, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x22, i2s_alc5630_read(0x22, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x24, i2s_alc5630_read(0x24, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x26, i2s_alc5630_read(0x26, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x28, i2s_alc5630_read(0x28, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x2a, i2s_alc5630_read(0x2a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x2c, i2s_alc5630_read(0x2c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x2e, i2s_alc5630_read(0x2e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x30, i2s_alc5630_read(0x30, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x32, i2s_alc5630_read(0x32, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x34, i2s_alc5630_read(0x34, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x36, i2s_alc5630_read(0x36, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x38, i2s_alc5630_read(0x38, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x3a, i2s_alc5630_read(0x3a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x3c, i2s_alc5630_read(0x3c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x3e, i2s_alc5630_read(0x3e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x40, i2s_alc5630_read(0x40, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x42, i2s_alc5630_read(0x42, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x44, i2s_alc5630_read(0x44, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x46, i2s_alc5630_read(0x46, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x48, i2s_alc5630_read(0x48, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x4a, i2s_alc5630_read(0x4a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x4c, i2s_alc5630_read(0x4c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x4e, i2s_alc5630_read(0x4e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x50, i2s_alc5630_read(0x50, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x52, i2s_alc5630_read(0x52, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x54, i2s_alc5630_read(0x54, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x56, i2s_alc5630_read(0x56, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x58, i2s_alc5630_read(0x58, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x5a, i2s_alc5630_read(0x5a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x5c, i2s_alc5630_read(0x5c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x5e, i2s_alc5630_read(0x5e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x60, i2s_alc5630_read(0x60, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x62, i2s_alc5630_read(0x62, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x64, i2s_alc5630_read(0x64, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x66, i2s_alc5630_read(0x66, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x68, i2s_alc5630_read(0x68, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x6a, i2s_alc5630_read(0x6a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x6c, i2s_alc5630_read(0x6c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x6e, i2s_alc5630_read(0x6e, data,client)); ++ ++ printk("Reg 0x%02x = 0x%08x\n", 0x70, i2s_alc5630_read(0x70, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x72, i2s_alc5630_read(0x72, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x74, i2s_alc5630_read(0x74, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x76, i2s_alc5630_read(0x76, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x78, i2s_alc5630_read(0x78, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x7a, i2s_alc5630_read(0x7a, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x7c, i2s_alc5630_read(0x7c, data,client)); ++ printk("Reg 0x%02x = 0x%08x\n", 0x7e, i2s_alc5630_read(0x7e, data,client)); ++ ++} ++*/ ++ ++static void i2s_al5630_slave_stereo_mode(struct i2c_client *client) ++{ ++ ++ ++ i2s_alc5630_write(0x34, 0x8000, client); // codec slave mode ++ i2s_alc5630_write(0x0c, 0x1010, client); ++ i2s_alc5630_write(0x10, 0xee03, client); ++ i2s_alc5630_write(0x1c, 0x0748, client); ++ //i2s_alc5630_write(0x02, 0x8080, client); ++ //i2s_alc5630_write(0x04, 0x8888, client); ++ i2s_alc5630_write(0x62, 0x0000, client); ++ ++} ++ ++//End ADD by river 2011.01.26 ++ ++ ++/* Drive PMU to generate I2S main clocking signal. Also configures PMU to set correct DMA REQ/ACK pair */ ++void pmu_set_i2s_clocking(unsigned int speed) ++{ ++ unsigned int pmu_pdllcr1; /* PLL/DLL Control Register 1 */ ++ /* Configure PMU to generate I2S main clock */ ++ #ifdef CONFIG_PLAT_AG101 ++ pmu_pdllcr1 = inl(PMU_PDLLCR1)&0xfff0ffff; /* Bit 19-16 are relevent */ ++ #endif ++ ++ switch (speed) { ++ case 8000: ++ pmu_pdllcr1 |= 0x00000000; /* 2.048MHz x2 */ ++ break; ++ case 11025: ++ pmu_pdllcr1 |= 0x00010000; /* 2.8224MHz x2 */ ++ break; ++ case 16000: ++ pmu_pdllcr1 |= 0x00020000; /* 4.096MHz x2 */ ++ break; ++ case 22050: ++ pmu_pdllcr1 |= 0x00030000; /* 5.6448MHz x2 */ ++ break; ++ case 32000: ++ pmu_pdllcr1 |= 0x00040000; /* 8.192MHz x2 */ ++ break; ++ case 44100: ++ pmu_pdllcr1 |= 0x00050000; /* 11.2896Mhz x2 */ ++ break; ++ case 48000: ++ pmu_pdllcr1 |= 0x00060000; /* 12.2880MHz x2 */ ++ break; ++ default: ++ printk("%s: Unknown i2s speed %d\n",__func__,speed); ++ }; ++ ++ #ifdef CONFIG_PLAT_AG101 ++ outl(pmu_pdllcr1, PMU_PDLLCR1); ++ /* Configure PMU to select I2S output (instead of AC97) */ ++ outl(inl(PMU_MFPSR)&(~(1<<3)), PMU_MFPSR); /* clear bit 3 of MFPSR*/ ++ #endif ++} ++ ++/* Drive PMU to generate AC97 main clocking signal. Also configures PMU to set correct DMA REQ/ACK pair */ ++void pmu_set_ac97_clocking(unsigned int speed) ++{ ++ /* Configure PMU to select AC97 output (instead of I2S) */ ++ /* Set GPIO[26] to AC97 clock, use 49.152MHz main clock (AC97 CLK1) */ ++ //outl(inl(PMU_MFPSR)|((1<<13)|(1<<3)), PMU_MFPSR); /* Set bit 13 & 3 of MFPSR*/ ++ #ifndef CONFIG_PLAT_AG102 ++ outl(inl(PMU_MFPSR)|((1<<13)|(1<<3)), PMU_MFPSR); /* Set bit 13 & 3 of MFPSR*/ ++ #endif ++} ++ ++/* Programs PMU to set I2S/AC97 DMA Channel, ch=0-7 */ ++void pmu_set_i2s_dma_channel(unsigned ch) ++{ ++ #ifdef CONFIG_PLAT_AG101 ++ ch&=0x7; ++ //outl((inl(PMU_I2SAC97_REQACKCFG)&(~0x7))|ch, PMU_I2SAC97_REQACKCFG); ++ outl(0xa, PMU_I2SAC97_REQACKCFG); ++ outl(0xb, PMU_C4); ++ #endif ++} ++ ++/* Initialize FTSSP010 to output to UDA1345TS via I2S */ ++#define FTSSP010_CONTROL0(x) (SSP_FTSSP010_va_base[(x)]+0x0) ++#define FTSSP010_CONTROL0_OPM_STEREO 0xC ++#define FTSSP010_CONTROL0_OPM_MONO 0x8 ++ ++#define FTSSP010_CONTROL1(x) (SSP_FTSSP010_va_base[(x)]+0x4) ++#define FTSSP010_CONTROL2(x) (SSP_FTSSP010_va_base[(x)]+0x8) ++ ++#define FTSSP010_INT_CONTROL(x) (SSP_FTSSP010_va_base[(x)]+0x10) ++#define FTSSP010_STATUS(x) (SSP_FTSSP010_va_base[(x)]+0xC) ++#define FTSSP010_INT_STATUS(x) (SSP_FTSSP010_va_base[(x)]+0x14) ++#define FTSSP010_DATA(x) (SSP_FTSSP010_va_base[(x)]+0x18) ++#define FTSSP010_INFO(x) (SSP_FTSSP010_va_base[(x)]+0x1C) ++ ++//static const unsigned int SSP_FTSSP010_va_base[SSP_FTSSP010_IRQ_COUNT] = { SSP_FTSSP010_VA_BASE }; ++//static const unsigned int SSP_FTSSP010_pa_base[SSP_FTSSP010_IRQ_COUNT] = { SSP_FTSSP010_PA_BASE }; ++ ++//ADD by river 2011.02.11 ++static struct i2c_client *g_i2c_client; ++ ++ ++#define FTSSP010_ACLINK_SLOT_VALID(x) (SSP_FTSSP010_va_base[(x)]+0x20) ++ ++void ftssp010_set_int_control(int cardno, unsigned val) ++{ ++ outl(val, FTSSP010_INT_CONTROL(cardno)); ++} ++ ++unsigned ftssp010_get_int_status(int cardno) ++{ ++ return (inl(FTSSP010_INT_STATUS(cardno))); ++} ++ ++int ftssp010_get_status(int cardno) ++{ ++ return (inl(FTSSP010_STATUS(cardno))); ++} ++ ++int ftssp010_tx_fifo_not_full(int cardno) ++{ ++ return (inl(FTSSP010_STATUS(cardno))&0x2)==0x2; ++} ++ ++int ftssp010_tx_fifo_vaild_entries(int cardno) ++{ ++ return (inl(FTSSP010_STATUS(cardno))>>12) & 0x1f; ++} ++ ++#include "FTSSP010_W83972D.h" ++ ++// AC97 codec tags ++#define TAG_COMMAND 0xe000 ++#define TAG_DATA 0x9800 /* Slot 3/4 */ ++#define TAG_DATA_MONO 0x9000 /* Slot 3 */ ++//#define TAG_DATA_LINE_IN 0x9000 /* Slot 3 */ ++ ++void ftssp010_ac97_write_codec_start(unsigned int cardno) ++{ ++ outl(0x0, FTSSP010_INT_CONTROL(cardno));/*Disable interrupts & DMA req */ ++ outl(0xC, FTSSP010_CONTROL2(cardno)); /* Disable FTSSP010, clear RX/TX Fifo. */ ++ outl(TAG_COMMAND, FTSSP010_ACLINK_SLOT_VALID(cardno)); ++} ++ ++void ftssp010_ac97_write_codec(unsigned int cardno,unsigned int reg,unsigned int data) ++{ ++ outl(reg << 12, FTSSP010_DATA(cardno)); ++ mdelay(50); ++ outl(data << 4, FTSSP010_DATA(cardno)); ++ mdelay(50); ++} ++ ++void ftssp010_ac97_write_codec_commit(unsigned int cardno) ++{ ++ while((inl(FTSSP010_CONTROL2(cardno))&0x1)==0) { ++ outl(0x3 , FTSSP010_CONTROL2(cardno)); /* SSPEN + TXDOE */ ++ } ++ while(ftssp010_tx_fifo_vaild_entries(cardno)) ++ ; ++ /* Wait for frame completion */ ++ while((inl(FTSSP010_INT_STATUS(cardno))&0x10)==0) ++ ; ++ outl(0x0, FTSSP010_CONTROL2(cardno)); ++} ++ ++/* Configure FTSSP010 to a given sampling rate and channel number ++ * for AC97 mode in playback mode ++ */ ++void init_hw(unsigned int cardno,unsigned int ac97, struct i2c_client *client) ++{ ++ ++ //printk(">>>>>>>>>> (5) init_hw() is called.\n"); ++ g_i2c_client = client; ++ ++ if(ac97) ++ { ++ //pmu_set_ac97_clocking(48000); ++ #ifndef CONFIG_PLAT_AG102 ++ pmu_set_ac97_clocking(48000); ++ #endif ++ outl(0x400c, FTSSP010_CONTROL0(cardno)); /* set FTSSP010 to AC97 mode */ ++ mdelay(50); ++ outl(0xc400, FTSSP010_INT_CONTROL(cardno)); ++ mdelay(50); ++ outl(0x20, FTSSP010_CONTROL2(cardno)); /* Cold Reset AC-Link */ ++ mdelay(50); ++ while(inl(FTSSP010_CONTROL2(cardno))) ++ mdelay(50); ++ outl(0x40, FTSSP010_CONTROL2(cardno)); /* Reset AC-Link */ ++ mdelay(1500); ++ } ++ else ++ { ++ ++ //printk(">>>>>>>>> (6) I2S mode selected....YAYAYA......\n"); ++ #ifdef CONFIG_PLAT_AG101 ++ outl(inl(PMU_MFPSR)&(~(1<<3)), PMU_MFPSR); /* clear bit 3 of MFPSR*/ ++ outl(0xa, PMU_I2SAC97_REQACKCFG); ++ outl(0xb, PMU_C4); ++ #endif ++ ++ //MOD by river 2011.01.26 ++ //i2s_alc5630_master_stereo_mode(client); ++ i2s_al5630_slave_stereo_mode(client); ++ //ssp_slave_stereo_mode(); ++ //End MOD by river 2011.01.26 ++ outl(0x311c, FTSSP010_CONTROL0(cardno)); /* I2S Master */ ++ outl(0, FTSSP010_CONTROL1(cardno)); /* I2S Master */ ++ outl(0xc400, FTSSP010_INT_CONTROL(cardno)); /* I2S Master */ ++ outl(0x40, FTSSP010_CONTROL2(cardno)); /* Reset AC-Link */ ++ ++ //i2s_alc5630_read_test(client); ++ } ++} ++static void _ftssp010_config_ac97(int cardno, unsigned is_stereo, unsigned speed, int is_rec) ++{ ++ /* Codec initialization */ ++ ftssp010_ac97_write_codec_start(cardno); ++ ftssp010_ac97_write_codec(cardno, W83972D_RESET, 0); ++ ftssp010_ac97_write_codec_commit(cardno); ++ ++ msleep_interruptible(10); ++ ftssp010_ac97_write_codec_start(cardno); ++ ++ if (is_rec) { /* Recording */ ++ /* Mute output */ ++ //ftssp010_ac97_write_codec(cardno, W83972D_STEREO_OUTPUT_CONTROL, 0x8000); ++ /* Mute PCM */ ++ //ftssp010_ac97_write_codec(cardno, W83972D_PCM_OUTPUT_CONTROL, 0x8000); ++ ++ /* Register 0x10, Line-In/Mic Gain */ ++ ftssp010_ac97_write_codec(cardno, W83972D_LINE_IN_VOLUME, 0x808); ++ //ftssp010_ac97_write_codec(cardno, W83972D_AUX_INPUT_CONTROL, 0x808); ++ ftssp010_ac97_write_codec(cardno, W83972D_MIC_VOLUME, 0x8); ++ /* FIXME: REC from line-in only */ ++ ++ /* Register 0x1A, Record Select=StereoMix */ ++ ftssp010_ac97_write_codec(cardno, W83972D_RECORD_SELECT, 0x505 /*404*/); ++ /* Register 0x1C, Record Gain=0db */ ++ ftssp010_ac97_write_codec(cardno, W83972D_RECORD_GAIN, 0x808); ++ ftssp010_ac97_write_codec(cardno, W83972D_RECORD_GAIN_MIC, 0x8); ++ } else { /* Playback */ ++ /* Register 0x10, Mute Line-In/Mic Gain */ ++ ftssp010_ac97_write_codec(cardno, W83972D_LINE_IN_VOLUME, 0x8000); ++ ftssp010_ac97_write_codec(cardno, W83972D_MIC_VOLUME, 0x8000); ++ ++ /* Register 0x1A, Mute Record Gains */ ++ ftssp010_ac97_write_codec(cardno, W83972D_RECORD_GAIN, 0x8000); ++ ftssp010_ac97_write_codec(cardno, W83972D_RECORD_GAIN_MIC, 0x8000); ++ ++ /* Output */ ++ ftssp010_ac97_write_codec(cardno, W83972D_STEREO_OUTPUT_CONTROL, 0); ++ ftssp010_ac97_write_codec(cardno, W83972D_PCM_OUTPUT_CONTROL, 0x808); ++ } ++ ++#if 0 ++ ftssp010_ac97_write_codec(cardno, W83972D_EXT_AUDIO_CONTROL, 0x1); ++ ftssp010_ac97_write_codec(cardno, W83972D_DAC_SAMPLE_RATE_CONTROL, speed); ++#endif ++ ++ ftssp010_ac97_write_codec_commit(cardno); ++ msleep_interruptible(10); ++ ++ /* Start data transfer */ ++// if(is_rec) { ++// outl(TAG_DATA_LINE_IN, FTSSP010_ACLINK_SLOT_VALID(cardno)); ++// } else { ++ if(is_stereo) ++ outl(TAG_DATA, FTSSP010_ACLINK_SLOT_VALID(cardno)); ++ else ++ outl(TAG_DATA_MONO, FTSSP010_ACLINK_SLOT_VALID(cardno)); ++// } ++ while(inl(FTSSP010_INT_STATUS(cardno))&0x3); ++// msleep_interruptible(10); ++} ++ ++void ftssp010_config_ac97_play(int cardno, unsigned is_stereo, unsigned speed, int use8bit) ++{ ++ _ftssp010_config_ac97(cardno, is_stereo, speed, 0); ++} ++ ++void ftssp010_config_ac97_rec(int cardno, unsigned is_stereo, unsigned speed, int use8bit) ++{ ++ _ftssp010_config_ac97(cardno, is_stereo, speed, 1); ++} ++/* ++ * Configure FTSSP010 to a given sampling rate and channel number ++ * for I2S mode ++ */ ++void ftssp010_config(int cardno, unsigned is_stereo, unsigned speed, int width, int is_rec) ++{ ++ int use8bit = (width == 1 ? 1 : 0); ++ unsigned opm, bps = 2 * (use8bit ? 8 : 16); /* bits per 1 second audio data. */ ++ unsigned fpclkdiv = 0; ++ ++ //ADD by river 2011.06.02 ++ struct alc5630_data *alc5630; ++ char data[3]; ++ opm = is_stereo ? FTSSP010_CONTROL0_OPM_STEREO : FTSSP010_CONTROL0_OPM_MONO; ++ //MOD by river 2011.01.27 ++ outl(0x3100 | opm, FTSSP010_CONTROL0(cardno)); /* I2S Master */ ++ //End MOD by river 2011.01.27 ++ ++#if 0 ++ printk("%s: use %dHz %d-bit %s \n",__func__, ++ speed, ++ use8bit?8:16, ++ is_stereo?"stereo":"mono" ++ ); ++#endif ++ ++ /* configures CONTROL1 to use suitable clock divider. ++ the I2S clock is generated from PMU. */ ++ bps *= speed; ++ switch(speed) { ++ case 8000: /* SCLK : 256KHZ */ ++ i2s_alc5630_write(0x44, 0x3ea0, g_i2c_client); //? ++ i2s_alc5630_write(0x60, 0x3174, g_i2c_client); ++ i2s_alc5630_write(0x62, 0x1010, g_i2c_client); ++ //i2s_alc5630_write(0x44, 0x6a0, g_i2c_client); //? ++ //i2s_alc5630_write(0x60, 0x3174, g_i2c_client); ++ //i2s_alc5630_write(0x62, 0x1010, g_i2c_client); ++ fpclkdiv = 0xBB; ++ ++ //fpclkdiv=SSPCLK_TO_SCLKDIV(2048000, bps); ++ break; ++ case 11025: /* SCLK : 352.8KHZ */ ++ i2s_alc5630_write(0x44, 0x3ea0, g_i2c_client); //? ++ i2s_alc5630_write(0x60, 0x3174, g_i2c_client); ++ i2s_alc5630_write(0x62, 0x1010, g_i2c_client); ++ fpclkdiv = 0x88; ++ //fpclkdiv=SSPCLK_TO_SCLKDIV(2822400, bps); ++ break; ++ case 16000: /* SCLK : 512KHZ */ ++ i2s_alc5630_write(0x44, 0x3ea0, g_i2c_client); //? ++ i2s_alc5630_write(0x60, 0x3174, g_i2c_client); ++ i2s_alc5630_write(0x62, 0x1010, g_i2c_client); ++ fpclkdiv = 0x5f; ++ //fpclkdiv=SSPCLK_TO_SCLKDIV(4096000, bps); ++ break; ++ case 22050: /* SCLK : 705.6KHZ */ ++ i2s_alc5630_write(0x44, 0x3ea0, g_i2c_client); ++ i2s_alc5630_write(0x60, 0x3174, g_i2c_client); ++ i2s_alc5630_write(0x62, 0x1010, g_i2c_client); ++ fpclkdiv = 0x45; ++ //fpclkdiv=SSPCLK_TO_SCLKDIV(5644800, bps); ++ break; ++ case 24000: /* SCLK : 768KHZ */ ++ i2s_alc5630_write(0x44, 0x3ea0, g_i2c_client); ++ i2s_alc5630_write(0x60, 0x3174, g_i2c_client); ++ i2s_alc5630_write(0x62, 0x1010, g_i2c_client); ++ fpclkdiv = 0x3e; ++ //fpclkdiv=SSPCLK_TO_SCLKDIV(5644800, bps); ++ break; ++ case 32000: /* SCLK : 1024KHZ */ ++ i2s_alc5630_write(0x44, 0x3ea0, g_i2c_client); ++ i2s_alc5630_write(0x60, 0x3174, g_i2c_client); ++ i2s_alc5630_write(0x62, 0x1010, g_i2c_client); ++ //fpclkdiv = 0x2e; ++ fpclkdiv = 0x2f; ++ //fpclkdiv=SSPCLK_TO_SCLKDIV(8192000, bps); ++ break; ++ case 44100: /* SCLK : 1.4112 MHZ */ /* 96 MHZ */ ++ i2s_alc5630_write(0x44, 0x3ea0, g_i2c_client); ++ i2s_alc5630_write(0x60, 0x3174, g_i2c_client); ++ i2s_alc5630_write(0x62, 0x1010, g_i2c_client); ++ fpclkdiv = 0x22; ++ //fpclkdiv=SSPCLK_TO_SCLKDIV(11289600, bps); ++ break; ++ case 48000: /* SCLK : 1.536 MHZ */ ++ i2s_alc5630_write(0x44, 0x3ea0, g_i2c_client); ++ i2s_alc5630_write(0x60, 0x3174, g_i2c_client); ++ i2s_alc5630_write(0x62, 0x1010, g_i2c_client); ++ fpclkdiv = 0x1f; ++ //fpclkdiv=SSPCLK_TO_SCLKDIV(12288000, bps); ++ ++ break; ++ default: ++ printk("%s: unsupported speed %d\n", __func__,speed); ++ return; ++ }; ++ ++ ++ if(!use8bit) { ++ outl(0xf0000|fpclkdiv, FTSSP010_CONTROL1(cardno)); /* 16bits */ ++ //outl(0xf0000|0x10, FTSSP010_CONTROL1(cardno)); /* 16bits */ ++ //outl(0xf0000|0x22, FTSSP010_CONTROL1(cardno)); /* 16bits */ ++ } else { ++ outl(0x70000|fpclkdiv, FTSSP010_CONTROL1(cardno)); /* 8bits */ ++ } ++ ++ //printk("#####$$$$$ : bps = %d\n", bps); ++ //printk("#####$$$$$ : speed = %d\n", speed); ++ //printk("#####$$$$$ : fpclkdiv = 0x%08x\n", fpclkdiv); ++ //printk("#####$$$$$ : FTSSP010_CONTROL1(cardno) = 0x%08x\n", inl(FTSSP010_CONTROL1(cardno))); ++ ++ if(is_rec) ++ outl(inl(FTSSP010_INT_CONTROL(cardno))&(~0x0f15), FTSSP010_INT_CONTROL(cardno)); /* Disable all interrupts */ ++ else ++ outl(inl(FTSSP010_INT_CONTROL(cardno))&(~0xf02a) , FTSSP010_INT_CONTROL(cardno)); /* Disable all interrupts */ ++ ++ outl(0xc, FTSSP010_CONTROL2(cardno)); /* clear FIFOs */ ++ ++ //ADD by river 2011.06.02 ++ alc5630 = i2c_get_clientdata(g_i2c_client); ++ //End ++ ++ if(is_rec) { ++ printk("ftssp010_config() for I2S mode in record.\n"); ++ //ADD by river 2011.03.21 ++ //TEST by river 2011.03.22 for recording => workable ++ //i2s_alc5630_write(0x0e, 0x8888, g_i2c_client); ++ i2s_alc5630_write(0x0e, 0x0808, g_i2c_client); ++ i2s_alc5630_write(0x10, 0xee03, g_i2c_client); ++ i2s_alc5630_write(0x22, 0x0500, g_i2c_client); ++ i2s_alc5630_write(0x1c, 0x0748, g_i2c_client); ++ i2s_alc5630_write(0x14, 0x1f1f, g_i2c_client); ++ i2s_alc5630_write(0x12, 0xdfdf, g_i2c_client); ++ ++ i2s_alc5630_write(0x26, 0x000f, g_i2c_client); ++ i2s_alc5630_write(0x3a, 0xffff, g_i2c_client); ++ i2s_alc5630_write(0x3c, 0xffff, g_i2c_client); ++ //i2s_alc5630_write(0x3e, 0xffff, g_i2c_client); ++ i2s_alc5630_write(0x3e, 0x80cf, g_i2c_client); ++ ++ i2s_alc5630_write(0x44, 0x3ea0, g_i2c_client); ++ i2s_alc5630_write(0x42, 0x2000, g_i2c_client); ++ i2s_alc5630_write(0x40, 0x8c0a, g_i2c_client); ++ ++ //i2s_alc5630_write(0x02, 0x0000, g_i2c_client); ++ i2s_alc5630_write(0x02, 0x8080, g_i2c_client); ++ i2s_alc5630_write(0x04, 0x0000, g_i2c_client); ++ //End TEST by river 2011.03.22 ++ ++ //printk("ftssp010_config() for I2S mode (Recording) ===> Dump register.\n"); ++ //i2s_alc5630_read_test(g_i2c_client); ++ ++ } ++ else { ++ //printk("ftssp010_config() for I2S mode in playback.\n"); ++ //ADD by river 2011.03.24 for record and playback case ++ i2s_alc5630_write(0x0e, 0x0808, g_i2c_client); ++ i2s_alc5630_write(0x12, 0xcbcb, g_i2c_client); ++ i2s_alc5630_write(0x14, 0x7f7f, g_i2c_client); ++ i2s_alc5630_write(0x22, 0x0000, g_i2c_client); ++ i2s_alc5630_write(0x3e, 0x8000, g_i2c_client); ++ i2s_alc5630_write(0x40, 0x0c0a, g_i2c_client); ++ i2s_alc5630_write(0x42, 0x0000, g_i2c_client); ++ //End ADD by river 2011.03.24 for record and playback case ++ ++ //TEST by river 2011.03.23 ++ i2s_alc5630_write(0x26, 0x0000, g_i2c_client); ++ i2s_alc5630_write(0x3c, 0x2000, g_i2c_client); ++ i2s_alc5630_write(0x3a, 0x0002, g_i2c_client); ++ i2s_alc5630_write(0x3c, 0xa330, g_i2c_client); ++ i2s_alc5630_write(0x3a, 0xc843, g_i2c_client); ++ //End TEST by river 2011.03.23 ++ ++ //ADD by river 2011.03.23 for HP Out De-pop ++ i2s_alc5630_write(0x3A, i2s_alc5630_read(0x3A, data,g_i2c_client)|0x0002 , g_i2c_client); ++ i2s_alc5630_write(0x04, i2s_alc5630_read(0x04, data,g_i2c_client)|0x8080 , g_i2c_client); ++ i2s_alc5630_write(0x3A, i2s_alc5630_read(0x3A, data,g_i2c_client)|0x0040 , g_i2c_client); ++ i2s_alc5630_write(0x3c, i2s_alc5630_read(0x3C, data,g_i2c_client)|0x2000 , g_i2c_client); ++ i2s_alc5630_write(0x3E, i2s_alc5630_read(0x3E, data,g_i2c_client)|0xfC00 , g_i2c_client); ++ i2s_alc5630_write(0x5E, i2s_alc5630_read(0x5E, data,g_i2c_client)|0x0100 , g_i2c_client); ++ mdelay(500); ++ i2s_alc5630_write(0x3A, i2s_alc5630_read(0x3A, data,g_i2c_client)|0x0200 , g_i2c_client); ++ i2s_alc5630_write(0x3A, i2s_alc5630_read(0x3A, data,g_i2c_client)|0x0100 , g_i2c_client); ++ i2s_alc5630_write(0x5E, i2s_alc5630_read(0x5E, data,g_i2c_client)& 0xfeff ,g_i2c_client); ++ //End ADD by river 2011.03.23 for HP Out De-pop ++ ++ ++ //TEST by river 2011.03.22 ++ i2s_alc5630_write(0x1c, 0x0748, g_i2c_client); ++ //End TEST by river 2011.03.22 ++ ++ ++ //TEST by river 2011.03.16 ++ //i2s_alc5630_write(0x02, 0x8080, g_i2c_client); ++ i2s_alc5630_write(0x26, 0x000f, g_i2c_client); ++ //End TEST by river 2011.03.16 ++ ++ //ADD by river 2011.03.23 ++ if (alc5630->gpio2_value==0x0) ++ i2s_alc5630_write(0x3A, (i2s_alc5630_read(0x3A, data,g_i2c_client) & 0xFBFF)|0x0040 , g_i2c_client); ++ else ++ i2s_alc5630_write(0x3A, i2s_alc5630_read(0x3A, data,g_i2c_client)|0x0440 , g_i2c_client); ++ ++ ++ i2s_alc5630_write(0x5E, i2s_alc5630_read(0x5E, data,g_i2c_client)|0x0020 , g_i2c_client); ++ i2s_alc5630_write(0x5E, i2s_alc5630_read(0x5E, data,g_i2c_client)|0x00c0 , g_i2c_client); ++ i2s_alc5630_write(0x04, i2s_alc5630_read(0x04, data,g_i2c_client)& 0x7f7f , g_i2c_client); ++ mdelay(30); ++ ++ if (alc5630->gpio2_value==0x0) { ++ //printk(">>>>>>>>>>>> Turn off internal speaker.....\n"); ++ i2s_alc5630_write(0x02, 0x5F5F, g_i2c_client); ++ //i2s_alc5630_write(0x02, 0x0000, g_i2c_client); ++ } ++ else { ++ //printk(">>>>>>>>>>>> Turn on internal speaker.....\n"); ++ i2s_alc5630_write(0x02, 0x0000, g_i2c_client); ++ //i2s_alc5630_write(0x02, 0x5F5F, g_i2c_client); ++ } ++ //End ADD by river 2011.03.23 ++ ++ ++ //printk("ftssp010_config() for I2S mode (Playback) ===> Dump register.\n"); ++ //i2s_alc5630_read_test(g_i2c_client); ++ } ++ ++#if 0 ++ /* Stuff TX fifo */ ++ while(ftssp010_tx_fifo_not_full(cardno)) { ++ outl(0x0, FTSSP010_DATA(cardno)); ++ } ++#endif ++} ++ ++void ftssp010_config_tx(int cardno, unsigned is_stereo, unsigned speed, int width) ++{ ++ return ftssp010_config(cardno, is_stereo, speed, width, 0); ++} ++ ++void ftssp010_config_rx(int cardno, unsigned is_stereo, unsigned speed, int width) ++{ ++ return ftssp010_config(cardno, is_stereo, speed, width, 1); ++} ++ ++/* Configures FTSSP010 to start TX. If use_dma being nonzero, ++ * FTSSP010 will use hardware handshake for DMA */ ++void ftssp010_start_tx(int cardno, unsigned use_dma) ++{ ++ unsigned bogus=0x800*3; ++ if(use_dma) { ++ /* Enable H/W DMA Request and set TX DMA threshold to 12*/ ++// outl(0xC022, FTSSP010_INT_CONTROL(cardno)); ++ outl(inl(FTSSP010_INT_CONTROL(cardno)) | 0xc422, FTSSP010_INT_CONTROL(cardno)); ++#if 0 ++ printk("%s: enable DMA request\n", __func__); ++#endif ++ } ++// outl(0x3, FTSSP010_CONTROL2(cardno)); ++ outl(inl(FTSSP010_CONTROL2(cardno)) | 0x3, FTSSP010_CONTROL2(cardno)); ++// printk("%s\n",__func__); ++// printk("int_control 0x%x\n",inl(FTSSP010_INT_CONTROL(cardno))); ++// printk("control2 0x%x\n",inl(FTSSP010_CONTROL2(cardno))); ++ if(!use_dma) { ++ while(bogus>0) { ++ while(!ftssp010_tx_fifo_not_full(cardno)) ++ udelay(50); ++ outl(0, FTSSP010_DATA(cardno)); ++ bogus--; ++ } ++ } ++} ++ ++/* Configures FTSSP010 to start RX. If use_dma being nonzero, ++ * FTSSP010 will use hardware handshake for DMA */ ++void ftssp010_start_rx(int cardno, unsigned use_dma) ++{ ++ if(use_dma) { ++ /* Enable H/W DMA Request and set RX DMA threshold to 2*/ ++// outl(0x0111, FTSSP010_INT_CONTROL(cardno)); ++ outl(inl(FTSSP010_INT_CONTROL(cardno)) | 0xc411, FTSSP010_INT_CONTROL(cardno)); ++#if 0 ++ printk("%s: enable DMA request\n", __func__); ++#endif ++ } ++// outl(0x3, FTSSP010_CONTROL2(cardno)); ++ outl(inl(FTSSP010_CONTROL2(cardno)) | 0x3, FTSSP010_CONTROL2(cardno)); ++// printk("%s\n",__func__); ++// printk("int_control 0x%x\n",inl(FTSSP010_INT_CONTROL(cardno))); ++// printk("control2 0x%x\n",inl(FTSSP010_CONTROL2(cardno))); ++} ++ ++void ftssp010_stop_tx(int cardno) ++{ ++// outl(0, FTSSP010_CONTROL2(cardno)); ++ outl(inl(FTSSP010_INT_CONTROL(cardno)) & (~0x22), FTSSP010_INT_CONTROL(cardno)); ++// printk("%s\n",__func__); ++// printk("int_control 0x%x\n",inl(FTSSP010_INT_CONTROL(cardno))); ++// printk("control2 0x%x\n",inl(FTSSP010_CONTROL2(cardno))); ++} ++ ++void ftssp010_stop_rx(int cardno) ++{ ++ //outl(0, FTSSP010_CONTROL2(cardno)); ++ outl(inl(FTSSP010_INT_CONTROL(cardno)) & (~0x11), FTSSP010_INT_CONTROL(cardno)); ++ //printk("%s\n",__func__); ++ //printk("int_control 0x%x\n",inl(FTSSP010_INT_CONTROL(cardno))); ++ //printk("control2 0x%x\n",inl(FTSSP010_CONTROL2(cardno))); ++} ++ +diff -Nur linux-3.4.110.orig/sound/nds32/FTSSP010_UDA1345TS.h linux-3.4.110/sound/nds32/FTSSP010_UDA1345TS.h +--- linux-3.4.110.orig/sound/nds32/FTSSP010_UDA1345TS.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/sound/nds32/FTSSP010_UDA1345TS.h 2016-04-07 10:20:51.066085821 +0200 +@@ -0,0 +1,81 @@ ++/* FTSSP010 - UDA1345TS supporting library header */ ++/* ++ * ++ * $log$ ++ * ++ */ ++#include <linux/init.h> ++#include <linux/module.h> ++#include <asm/io.h> ++#include <linux/delay.h> ++#include <asm/spec.h> ++#include <linux/dma-mapping.h> ++ ++/* Programming sequence: ++ * Suppose your playback format is 44.1KHz, 16 bit stereo ++ * PIO mode: ++ * pmu_set_i2s_clocking(44100); ++ * ftssp010_config(1, 44100, 0); ++ * ftssp010_start_tx(0); ++ * while(ftssp010_tx_fifo_not_full()) { ++ * Poke_your_PCM_data_to_FTSSP_data_port ++ * ++ * DMA mode: ++ * pmu_set_i2s_clocking(44100); ++ * ftssp010_config(1, 44100); ++ * <setup DMA controller, acquire DMA channel> ++ * pmu_set_i2s_dma_channel(ch); ++ * ftssp010_start_tx(1); ++ * <wait DMA to complete..> ++ * ftssp010_stop_tx(); ++ */ ++#define FTSSP010_DATA(x) (SSP_FTSSP010_va_base[(x)]+0x18) ++#define FTSSP010_DATA_PA(x) (SSP_FTSSP010_pa_base[(x)]+0x18) ++ ++/* Initialize FTSSP010 to output to UDA1345TS via I2S */ ++#define FTSSP010_CONTROL0(x) (SSP_FTSSP010_va_base[(x)]+0x0) ++#define FTSSP010_CONTROL0_OPM_STEREO 0xC ++#define FTSSP010_CONTROL0_OPM_MONO 0x8 ++ ++#define FTSSP010_CONTROL1(x) (SSP_FTSSP010_va_base[(x)]+0x4) ++#define FTSSP010_CONTROL2(x) (SSP_FTSSP010_va_base[(x)]+0x8) ++ ++#define FTSSP010_INT_CONTROL(x) (SSP_FTSSP010_va_base[(x)]+0x10) ++#define FTSSP010_STATUS(x) (SSP_FTSSP010_va_base[(x)]+0xC) ++#define FTSSP010_INT_STATUS(x) (SSP_FTSSP010_va_base[(x)]+0x14) ++#define FTSSP010_DATA(x) (SSP_FTSSP010_va_base[(x)]+0x18) ++#define FTSSP010_INFO(x) (SSP_FTSSP010_va_base[(x)]+0x1C) ++ ++static const unsigned int SSP_FTSSP010_va_base[SSP_FTSSP010_IRQ_COUNT] = { SSP_FTSSP010_VA_BASE }; ++static const unsigned int SSP_FTSSP010_pa_base[SSP_FTSSP010_IRQ_COUNT] = { SSP_FTSSP010_PA_BASE }; ++ ++/* Drive PMU to generate I2S main clocking signal. Also configures PMU to set correct DMA REQ/ACK pair */ ++extern void pmu_set_i2s_clocking(unsigned int speed); ++/* Programs PMU to set I2S/AC97 DMA Channel, ch=0-7 */ ++extern void pmu_set_i2s_dma_channel(unsigned ch); ++ ++/* Drive PMU to generate AC97 main clocking signal. Also configures PMU to set correct DMA REQ/ACK pair */ ++extern void pmu_set_ac97_clocking(unsigned int speed); ++ ++/* Returns FTSSP010 status */ ++extern void ftssp010_set_int_control(int cardno, unsigned val); ++extern int ftssp010_get_status(int cardno); ++extern unsigned ftssp010_get_int_status(int cardno); ++/* Polls FIFO full register */ ++extern int ftssp010_tx_fifo_not_full(int cardno); ++/* Configure FTSSP010 to a given sampling rate and channel number */ ++extern void ftssp010_config_tx(int cardno, unsigned is_stereo, unsigned speed, int use8bit); ++extern void ftssp010_config_rx(int cardno, unsigned is_stereo, unsigned speed, int use8bit); ++ ++/* Configure FTSSP010 to a given sampling rate and channel number */ ++extern void ftssp010_config_ac97_play(int cardno, unsigned is_stereo, unsigned speed, int use8bit); ++ ++extern void ftssp010_config_ac97_rec(int cardno, unsigned is_stereo, unsigned speed, int use8bit); ++ ++/* Initialize FTSSP010 to output to UDA1345TS via I2S */ ++extern void ftssp010_start_tx(int cardno, unsigned use_dma); ++extern void ftssp010_start_rx(int cardno, unsigned use_dma); ++extern void ftssp010_stop_tx(int cardno); ++extern void ftssp010_stop_rx(int cardno); ++ ++ +diff -Nur linux-3.4.110.orig/sound/nds32/FTSSP010_W83972D.h linux-3.4.110/sound/nds32/FTSSP010_W83972D.h +--- linux-3.4.110.orig/sound/nds32/FTSSP010_W83972D.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/sound/nds32/FTSSP010_W83972D.h 2016-04-07 10:20:51.066085821 +0200 +@@ -0,0 +1,17 @@ ++/* AC97 Codec related */ ++ ++ ++/* Register Index for Winbond W83972D AC97 Codec */ ++#define W83972D_RESET 0x0 ++#define W83972D_STEREO_OUTPUT_CONTROL 0x2 ++#define W83972D_MIC_VOLUME 0xE ++#define W83972D_LINE_IN_VOLUME 0x10 ++#define W83972D_AUX_INPUT_CONTROL 0x16 ++#define W83972D_PCM_OUTPUT_CONTROL 0x18 ++#define W83972D_RECORD_SELECT 0x1A ++#define W83972D_RECORD_GAIN 0x1C ++#define W83972D_RECORD_GAIN_MIC 0x1E ++#define W83972D_EXT_AUDIO_CONTROL 0x2A ++#define W83972D_DAC_SAMPLE_RATE_CONTROL 0x2C ++#define W83972D_VER1 0x7C ++#define W83972D_VER2 0x7E +diff -Nur linux-3.4.110.orig/sound/nds32/hda.h linux-3.4.110/sound/nds32/hda.h +--- linux-3.4.110.orig/sound/nds32/hda.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/sound/nds32/hda.h 2016-04-07 10:20:51.066085821 +0200 +@@ -0,0 +1,106 @@ ++// HDA Mode definition ++ #define HDA_MODE 0x80000000 ++ ++ // HDA CTRL definition ++ #define HDA_CRST_SET 0x00 ++ #define HDA_CRST_CLR 0x20 ++ #define HDA_CRST_MASK 0x20 ++ #define HDA_RST_FCNT_OFS 8 ++ ++ // HDA LNKST definition ++ #define HDA_COD_ALIVE 0x20000000 ++ ++ // HDA INTC definition ++ #define HDA_INTC_USOLEN 0x40000 ++ #define HDA_INTC_SDIWEN 0x20000 ++ #define HDA_INTC_CRINTE 0x10000 ++ ++ // HDA INTST definition ++ #define HDA_INTST_USOLEN 0x80 ++ #define HDA_INTST_SDIWEN 0x40 ++ #define HDA_INTST_CRINTE 0x20 ++ ++ // HDA ICMDST mask & offset ++ #define HDA_IRRADD_MASK 0xf0 ++ #define HDA_IRRUNSOL_MASK 0x08 ++ #define HDA_IRV_MASK 0x02 ++ #define HDA_ICB_MASK 0x01 ++ #define HDA_IRRADD_OFFSET 4 ++ #define HDA_IRRUNSOL_OFFSET 3 ++ #define HDA_IRV_OFFSET 1 ++ #define HDA_ICB_OFFSET 0 ++ //HDA OSDC/ISDC bit offset ++ #define HDA_SDC_STNUM_OFFSET 28 ++ #define HDA_SDC_SRUN_OFFSET 15 ++ #define HDA_SDC_BASE_OFFSET 14 ++ #define HDA_SDC_MULT_OFFSET 11 ++ #define HDA_SDC_DIV_OFFSET 8 ++ #define HDA_SDC_BITS_OFFSET 4 ++ #define HDA_SDC_CHAN_OFFSET 0 ++ ++ // HDA Codec CMD ++ #define HDA_COD_DEVADDR 0x00000000 ++ #define HDA_ROOT_NODE 0x00000000 ++ #define HDA_AUDIO_NODE 0x00100000 ++ #define HDA_OUTCOV_NODE 0x00200000 ++ //#define HDA_INCOV_NODE 0x0FF00000 ++ #define HDA_INCOV_NODE 0x00800000 //kane, for real CODEC node mapping ++ #define HDA_CMD_FGRST 0x0007FF00 ++ #define HDA_CMD_GETVID 0x000F0000 ++ #define HDA_CMD_SUBNCNT 0x000F0004 ++ #define HDA_CMD_FGTYPE 0x000F0005 ++ #define HDA_CMD_AUDIOWCAP 0x000F0009 ++ #define HDA_CMD_SETCVTSTR 0x00070600 ++ #define HDA_CMD_GETCVTSTR 0x000F0600 ++ #define HDA_CMD_SETCVTFMT 0x00020000 ++ #define HDA_CMD_GETCVTFMT 0x000A0000 ++ #define HDA_CMD_SETPROCST 0x00070300 ++ #define HDA_CMD_TRIGUNSOL 0x00070400 ++ //HDA Codec Resp ++ #define HDA_RESP_ZERO_VAL 0x00000000 ++ #define HDA_RESP_EXP_VID 0x10ec0888 ++ #define HDA_RSP_NODNUM_MSK 0xff0000 ++ #define HDA_RSP_NODCNT_MSK 0x0000ff ++ #define HDA_RSP_NODNUM_OFS 16 ++ #define HDA_RSP_NODCNT_OFS 0 ++ #define HDA_RSP_FGNTYPE_MSK 0xff ++ #define HDA_RSP_FGNUSCAP_MSK 0x100 ++ #define HDA_RSP_FGNTYPE_OFS 0 ++ #define HDA_RSP_FGNUSCAP_OFS 8 ++ #define HDA_RSP_AWCTYPE_MSK 0xf00000 ++ #define HDA_RSP_AWCUSCAP_MSK 0x000080 ++ #define HDA_RSP_AWCSTE_MSK 0x000001 ++ #define HDA_RSP_AWCTYPE_OFS 20 ++ #define HDA_RSP_AWCUSCAP_OFS 7 ++ #define HDA_RSP_AWCSTE_OFS 0 ++ #define HDA_RSP_CVTCHA_MSK 0x00 ++ #define HDA_RSP_CVTSTR_MSK 0xf0 ++ #define HDA_RSP_FMTTYPE_MSK 0x8000 ++ #define HDA_RSP_FMTBASE_MSK 0x4000 ++ #define HDA_RSP_FMTMULT_MSK 0x3800 ++ #define HDA_RSP_FMTDIV_MSK 0x0700 ++ #define HDA_RSP_FMTBITS_MSK 0x0070 ++ #define HDA_RSP_FMTCHNUM_MSK 0x000f ++ //HDA Func Group definition ++ #define HDA_FG_AUDIO 0x1 ++ // HDA Audio Widiget definition ++ #define HDA_AWC_INPUT 0x1 ++ #define HDA_AWC_OUTPUT 0x0 ++ #define HDA_AWC_MONO 0x0 ++ #define HDA_AWC_STEREO 0x1 ++ // HDA Converter Format definition ++ #define HDA_FMT_TYPE_OFS 15 ++ #define HDA_FMT_BASE_OFS 14 ++ #define HDA_FMT_MULT_OFS 11 ++ #define HDA_FMT_DIV_OFS 8 ++ #define HDA_FMT_BITS_OFS 4 ++ #define HDA_FMT_CHNUM_OFS 0 ++ // HDA Coverter Stream definition ++ #define HDA_STR_STR_OFS 4 ++ #define HDA_STR_CHA_OFS 0 ++ // HDA IOSDC definition ++ #define HDA_IN_STR 0 ++ #define HDA_OUT_STR 1 ++ #define HDA_STR_STOP 0 ++ #define HDA_STR_RUN 1 ++ +diff -Nur linux-3.4.110.orig/sound/nds32/Kconfig linux-3.4.110/sound/nds32/Kconfig +--- linux-3.4.110.orig/sound/nds32/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/sound/nds32/Kconfig 2016-04-07 10:20:51.066085821 +0200 +@@ -0,0 +1,22 @@ ++menu "ALSA NDS32 devices" ++ depends on SND!=n && NDS32 ++ ++config SND_FTSSP010 ++ tristate "Faraday FTSSP010 audio Driver" ++ depends on SND && NDS32 ++ select SND_PCM ++# select SND_AC97_CODEC ++ ++choice ++ prompt "AC97/I2S/HDA selection" ++ depends on SND_FTSSP010 ++ default SND_FTSSP010_AC97 ++config SND_FTSSP010_AC97 ++ bool "AC97" ++config SND_FTSSP010_I2S ++ bool "I2S" ++config SND_FTSSP010_HDA ++ bool "HDA" ++endchoice ++endmenu ++ +diff -Nur linux-3.4.110.orig/sound/nds32/Makefile linux-3.4.110/sound/nds32/Makefile +--- linux-3.4.110.orig/sound/nds32/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/sound/nds32/Makefile 2016-04-07 10:20:51.066085821 +0200 +@@ -0,0 +1,10 @@ ++ifeq ($(CONFIG_SND_FTSSP010_AC97),y) ++snd-ftssp010-objs := FTSSP010_ALSA.o FTSSP010_lib.o ++endif ++ifeq ($(CONFIG_SND_FTSSP010_I2S),y) ++snd-ftssp010-objs := FTSSP010_ALSA.o FTSSP010_lib.o ++endif ++ifeq ($(CONFIG_SND_FTSSP010_HDA),y) ++snd-ftssp010-objs := FTSSP010_HDA.o FTSSP010_HDA_lib.o ++endif ++obj-$(CONFIG_SND_FTSSP010) += snd-ftssp010.o |