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 + * Made generic by Deepak Saxena + * + * 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 +#include +#include +#include +#include +#include +#include + +#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 , Deepak Saxena "); +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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 +#include +#include + +#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 +#else /* CONFIG_SMP*/ + + + +#define ATOMIC_INIT(i) { (i) } + +#ifdef __KERNEL__ + +#include + +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 +#include + +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 +#include + +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 + +#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 + +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 +#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 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +#include + +/* + * Ext2 is defined to use little-endian byte ordering. + */ +#include + +#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 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 + +#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 +#else +#include +#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 + +#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 + +#include + +/* + * 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 , 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 + +#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 + +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 + +#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 +#include + +#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 + +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 + +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 + +#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 + +#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 + +/***************************************************************************** + * 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 /* need struct page */ +#include + +#include + +/* + * 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 +#include + +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 + +#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 + +#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 +#include +#include + +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 + +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 + +#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 +#include +#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 +#include + +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 + +#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 +#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 +#include +#include + +typedef struct { + unsigned int __softirq_pending; +} ____cacheline_aligned irq_cpustat_t; + +#include /* 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 + +#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 +#include +#include + +/* + * 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 + * 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 + +#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 + +#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 +#include +#include +#include +#include + + +/* + * 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 +#include + +#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 +#include + +#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 + +#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 +#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 + +#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 +#include +#include + +#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 +#include +#include + +#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 +#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 + +#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 + +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 + +/* + * 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 +#ifndef __FARADAY_PLATFORM_INDEPENDENT_MEMORY_HEADER__ +#define __FARADAY_PLATFORM_INDEPENDENT_MEMORY_HEADER__ + +#include + +#ifndef __ASSEMBLY__ +#include +#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 + +#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 + +#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 + +#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 + +#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 +#include +#include + +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 + +#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 +#include + +#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 +#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 +#include + +#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 + * 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 + +#include /* 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 + +#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 +#include +#include + +/* + * 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 +#include + +#include +#include +#include +#ifndef __ASSEMBLY__ +#include +#endif + +#ifdef CONFIG_CACHE_L2 +#include +#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 +#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 + +/* + * 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 + +#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 + +#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 +#include +#include +#include +#include + +#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 + +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 + +#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 + +#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 +#include +#include + +#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 + +#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 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 + +#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 + +/* 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 + +#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 +#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 +#include +#include + +#ifndef CONFIG_SMP +# error " 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 + +#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 +#ifdef CONFIG_PLAT_AG102 +#include +#else +#include +#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 /* Manual defined spec */ + +/* + * Platform independent specification + */ + +#define NR_IRQS PLATFORM_INTERRUPTS + +#ifndef TIMER_CLK_IN +#error Missing platform dependent symbol TIMER_CLK_IN in 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 + +#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 + +#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 +#include + +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 + +/* + * 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 +#include + 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 +#include + +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 */ +#define N_R3964 9 /* Reserved for Simatic R3964 module */ +#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ +#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 +#include + + +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 + +#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 +#include +#include + +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 + +#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 + +#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 + +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 + +/* + * 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 +#include +#include +#include +#include +#include + +#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 +#include +#include + +/* + * 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 + +#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 +#include +/* 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 +#include + +#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 + +#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 , + , , + and the SMP-HOWTO available at + . + + 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 + , 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=[,][,] 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 +#include +#include +#include +#include +#include + +/* + * 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 +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include + +#include +#include +#include + +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 + * + * 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 . + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +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: + * + * [,][,] + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include + + .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 +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +/* + * $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 +#include +#include +#include +#include +#include +#include +#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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +# 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 +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include + +/* + * 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 +#include +#include +#include + +#include + +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 +#include + +#include + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// ============================================================================ +// 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 Kernel + * Probes initial implementation ( includes contributions from + * Rusty Russell). + * 2004-July Suparna Bhattacharya added jumper probes + * interface to access function arguments. + * 2004-Oct Jim Keniston and Prasanna S Panchamukhi + * adapted for x86_64 from i386. + * 2005-Mar Roland McGrath + * Fixed to handle %rip-relative addressing mode correctly. + * 2005-May Hien Nguyen , Jim Keniston + * and Prasanna S Panchamukhi + * added function-return probes. + * 2005-May Rusty Lynch + * Added function return probes functionality + * 2006-Feb Masami Hiramatsu added + * kprobe-booster and kretprobe-booster for i386. + * 2007-Dec Masami Hiramatsu added kprobe-booster + * and kretprobe-booster for x86-64 + * 2007-Dec Masami Hiramatsu , Arjan van de Ven + * and Jim Keniston + * unified x86 kprobes code. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include + +#include + +#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 +#include +#endif + +//#include +//#include + +#ifdef __cplusplus +extern "C" +{ +#else +#include +#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 +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * 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 + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 + + .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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + */ +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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 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 + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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 +#include +#include +#include +#include + +#include +#include + +/* + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#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 +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 +#include +#include +#include + +#define LOAD_OFFSET (PAGE_OFFSET - PHYS_OFFSET) +#include + +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 +#include + + .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, + * 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 +#include + +#include +#include +#include +#include + +#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, + * 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 +#include +#include +#include +#include +#include + +/* + * 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 + + .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 +#include +#include +#include + + +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 + +/* + void *memcpy(void *dst, const void *src, int n); + + dst: $r0 + src: $r1 + n : $r2 + ret: $r0 - pointer to the memory area dst. +*/ + +#include + + .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 + +/* + 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 +#include + +/* + 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 +#include + + .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 +#include +#include +#include + + .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 +#include + +/* + * 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 +#include +#include + + +/* + * 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 +#include +#include + + .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 +#include + + .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 +#include +#include + + .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 +#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 +#include + +#include +#include +#include +#include + +#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 +#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 +#include +#include + +/* + * 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 +#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 +#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 +#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 +#include +#include + +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include + +/* + * 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 +#include + +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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#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 + +/* + * 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 + * 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 +#include +#include +#include + +/* + * 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 +#include +#include + +#define COLOUR_ALIGN(addr,pgoff) \ + ((((addr)+REALSHMLBA-1)&~(REALSHMLBA-1)) + \ + (((pgoff)<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 +#include +#include +#include + +#include +#include +#include +#include + +#include +#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 +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_CACHE_L2 +#include +#endif +#include + +#include +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 +//#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 +#include +#include +#include +#include + +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 +#include +#include +#include + +#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 + */ + +#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 +#include +#include +#include +#include +#include +#include + +#include "op_impl.h" + +#ifdef CONFIG_PLAT_AG102 +#include +#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 +#include +#include + +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_AUTO_SYS_CLK +#include +#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 +#include +#include + +#include +#include +#include +#include +#include + +#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 + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +extern void ag101_cpu_sleep(void); +extern void ag101_cpu_resume(void); +extern void ag101_cpu_resume2(void); + +#include +/* + * 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 + * + * 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 +#include +#include +#include + + .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 +#include +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include + +#include +#include +#include +#include +#include +#include +#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 +#else +#include +#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)< +#include +#include + +#include + +#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 +#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)<> (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< + * + * 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 +#include +#include +#include +#include +/* + * the following include file is for testing device node + */ +#include +#include +#include +/*************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcu.h" +#include "gmac.h" + +#ifdef CONFIG_PLAT_AG102 +#include +#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 +#include + +//#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 +.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 +#include +#include +#include + +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include + +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include + +#include +#include +#include + +#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 + +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 +#include +#include +#include + +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +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 +#include +#include + +#include +#include +#include + +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +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_defconfig] [--bootm] [--ramdisk=]" + 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 +#include +#include +#include +#include +#include +#include +#include /* HDIO_GETGEO */ +#include +#include +#include /* invalidate_bdev */ +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include /* HDIO_GETGEO */ +#include +#include +#include /* invalidate_bdev */ +#include +#include +#include +#include +#include +#include +#include + +#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 +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 +#include */ /* 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 +#include +#include +#include +#include + +#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 +#include +#include +#include + +#include +#include "cpe_ts.h" + + +#include + +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 + * 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 -#include -#include +#include #include +#include + +#include +#include /* printk() */ +#include /* kmalloc() */ +#include /* error codes */ +#include /* size_t */ #include -#include -#include -#include -#include + +#include #include +#include /* struct device, and other headers */ +#include /* eth_type_trans */ +#include /* struct iphdr */ +#include /* struct tcphdr */ +#include + +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // dma_clean_range +#include #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; irx_descs[i].RXDMA_OWN = OWNBY_FTMAC100; // owned by FTMAC100 + } + priv->rx_idx = 0; + + for (i=0; itx_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<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; irx_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; itx_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, "" ); + 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<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 "); -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 + * 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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 , " + "Jamie Lenehan , " + "Angelo Castello , " + "Roy Lee "); +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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 "); +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 + * Based on SoftDog driver by Alan Cox + * + * 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 +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#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 +#include +#include +#include +#include +#include + + +#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 +#include +#include +#include +#include +#include +#include +#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< 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 +#include +#include +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include + +/* 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); + * + * pmu_set_i2s_dma_channel(ch); + * ftssp010_start_tx(1); + * + * 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