move new files out from platform support patch
authorImre Kaloz <kaloz@openwrt.org>
Mon, 22 Feb 2010 13:54:47 +0000 (13:54 +0000)
committerImre Kaloz <kaloz@openwrt.org>
Mon, 22 Feb 2010 13:54:47 +0000 (13:54 +0000)
SVN-Revision: 19815

279 files changed:
target/linux/ubicom32/files/arch/ubicom32/Kconfig [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/Kconfig.debug [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/Makefile [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/crypto/Makefile [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/crypto/aes_ubicom32.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_des.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_ubicom32.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_ubicom32.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/crypto/des_check_key.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/crypto/des_ubicom32.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/crypto/md5_ubicom32.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/crypto/md5_ubicom32_asm.S [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/crypto/sha1_ubicom32.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/crypto/sha1_ubicom32_asm.S [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/.gitignore [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/Kbuild [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/a.out.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/atomic.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/audio.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/audionode.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/auxvec.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/bitops.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/board.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/bootargs.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/bootinfo.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/bug.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/bugs.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/byteorder.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/cache.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/cachectl.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/cacheflush.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/checksum.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/cpu.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/cputime.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/current.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/delay.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/device.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/devtree.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/div64.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/dma-mapping.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/dma.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/elf.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/emergency-restart.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/entry.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/errno.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/fb.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/fcntl.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/flat.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/fpu.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ftrace.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/futex.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/gpio.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/hardirq.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/hw_irq.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/io.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ioctl.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ioctls.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ip5000-asm.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ip5000.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ipcbuf.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/irq.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/irq_regs.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/irqflags.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/kdebug.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/kmap_types.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ldsr.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/linkage.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/local.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/machdep.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/mc146818rtc.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/memory_map.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/mman.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/mmu.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/mmu_context.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/module.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/msgbuf.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/mutex.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/namei.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm-alloc.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm_size.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm_text.lds.inc [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/page.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/page_offset.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/param.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/pci.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/pcm_tio.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/percpu.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/pgalloc.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/pgtable.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/plio.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/poll.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/posix_types.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/processor.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/profilesample.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ptrace.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/range-protect-asm.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/range-protect.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/resource.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ring_tio.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/scatterlist.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/sd_tio.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/sections.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/segment.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/semaphore-helper.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/semaphore.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/sembuf.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/setup.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/shmbuf.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/shmparam.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/sigcontext.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/siginfo.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/signal.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/smp.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/socket.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/sockios.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/spinlock.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/spinlock_types.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/stacktrace.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/stat.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/statfs.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/string.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/swab.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/switch-dev.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/system.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/termbits.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/termios.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/thread-asm.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/thread.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/thread_info.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/timex.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/tlb.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/tlbflush.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/topology.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/traps.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/types.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/uaccess.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/uart_tio.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubi32-cs4384.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubi32-pcm.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-common-asm.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-common.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-spi-gpio.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-tio.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32bl.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32fb.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32hid.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32input.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32input_i2c.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32lcd.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32lcdpower.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32ring.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32sd.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32suart.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/ucontext.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/unaligned.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/unistd.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/user.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/vdc_tio.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/vga.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/include/asm/xor.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/Makefile [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/asm-offsets.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/devtree.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/dma.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/flat.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/head.S [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/init_task.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/ldsr.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/module.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/os_node.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/process.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/processor.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/ptrace.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/semaphore.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/setup.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/signal.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/smp.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/stacktrace.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/sys_ubicom32.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/syscalltable.S [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/thread.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/time.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/timer_broadcast.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/timer_device.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/timer_tick.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/topology.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/traps.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/uaccess.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_context_switch.S [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_ksyms.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_syscall.S [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/unaligned_trap.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/kernel/vmlinux.lds.S [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/lib/Makefile [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/lib/checksum.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/lib/delay.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/lib/mem_ubicom32.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/Kconfig.switch [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/Makefile [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/audio.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/board.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/bootargs.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/cachectl.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/common.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/io.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/pci.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/plio.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/profile.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/profile.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/profpkt.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/ring_tio.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-bcm539x-reg.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-bcm539x.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-core.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-core.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/ubi32-gpio.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32hid.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input_i2c.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/usb.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/usb_tio.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/usb_tio.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-common/vdc_tio.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/Kconfig [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/Makefile [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5160dev.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5160rgw.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5170dpf.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/Kconfig [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/Makefile [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7145dpf.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160bringup.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160dpf.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160rgw.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500av.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500iap.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500media.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500module.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500wspkr.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mm/Makefile [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mm/fault.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mm/init.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mm/kmap.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mm/memory.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/mm/ocm-alloc.c [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/oprofile/Makefile [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/oprofile/ipProf.h [new file with mode: 0644]
target/linux/ubicom32/files/arch/ubicom32/oprofile/profile.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/char/hw_random/ubicom32-rng.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/mmc/host/ubicom32sd.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/mtd/devices/nand-spi-er.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/mtd/devices/ubi32-m25p80.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/mtd/devices/ubi32-nand-spi-er.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/net/ubi32-eth.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/net/ubi32-eth.h [new file with mode: 0644]
target/linux/ubicom32/files/drivers/serial/ubi32_mailbox.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/serial/ubi32_serdes.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/serial/ubi32_uarttio.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/spi/spi_ubicom32_gpio.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/uio/uio_ubicom32ring.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/usb/musb/ubi32_usb.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/video/backlight/ubicom32bl.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcd.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcd.h [new file with mode: 0644]
target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcdpower.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/video/ubicom32fb.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/video/ubicom32plio80.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/video/ubicom32vfb.c [new file with mode: 0644]
target/linux/ubicom32/files/drivers/watchdog/ubi32_wdt.c [new file with mode: 0644]
target/linux/ubicom32/files/sound/ubicom32/Kconfig [new file with mode: 0644]
target/linux/ubicom32/files/sound/ubicom32/Makefile [new file with mode: 0644]
target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4350.c [new file with mode: 0644]
target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4384.c [new file with mode: 0644]
target/linux/ubicom32/files/sound/ubicom32/ubi32-generic-capture.c [new file with mode: 0644]
target/linux/ubicom32/files/sound/ubicom32/ubi32-generic.c [new file with mode: 0644]
target/linux/ubicom32/files/sound/ubicom32/ubi32-pcm.c [new file with mode: 0644]
target/linux/ubicom32/files/sound/ubicom32/ubi32.h [new file with mode: 0644]
target/linux/ubicom32/patches-2.6.30/100-ubicom32_support.patch

diff --git a/target/linux/ubicom32/files/arch/ubicom32/Kconfig b/target/linux/ubicom32/files/arch/ubicom32/Kconfig
new file mode 100644 (file)
index 0000000..acc6116
--- /dev/null
@@ -0,0 +1,403 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+mainmenu "uClinux/ubicom32 (w/o MMU) Kernel Configuration"
+
+config UBICOM32
+       bool
+       select HAVE_OPROFILE
+       default y
+
+config RAMKERNEL
+       bool
+       default y
+
+config CPU_BIG_ENDIAN
+       bool
+       default y
+
+config FORCE_MAX_ZONEORDER
+       int
+       default "14"
+
+config HAVE_CLK
+       bool
+       default y
+
+config MMU
+       bool
+       default n
+
+config FPU
+       bool
+       default n
+
+config ZONE_DMA
+       bool
+       default y
+
+config RWSEM_GENERIC_SPINLOCK
+       bool
+       default y
+
+config RWSEM_XCHGADD_ALGORITHM
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U32
+       bool
+       default n
+
+config ARCH_HAS_ILOG2_U64
+       bool
+       default n
+
+config GENERIC_FIND_NEXT_BIT
+       bool
+       default y
+
+config GENERIC_GPIO
+       bool
+       default y
+
+config GPIOLIB
+       bool
+       default y
+
+config GENERIC_HWEIGHT
+       bool
+       default y
+
+config GENERIC_HARDIRQS
+       bool
+       default y
+
+config STACKTRACE_SUPPORT
+       bool
+       default y
+
+config LOCKDEP_SUPPORT
+       bool
+       default y
+
+config GENERIC_CALIBRATE_DELAY
+       bool
+       default y
+
+config GENERIC_TIME
+       bool
+       default y
+
+config TIME_LOW_RES
+       bool
+       default y
+
+config GENERIC_CLOCKEVENTS
+       bool
+       default y
+
+config GENERIC_CLOCKEVENTS_BROADCAST
+       bool
+       depends on GENERIC_CLOCKEVENTS
+       default y if SMP && !LOCAL_TIMERS
+
+config NO_IOPORT
+       def_bool y
+
+config ARCH_SUPPORTS_AOUT
+       def_bool y
+
+config IRQ_PER_CPU
+       bool
+       default y
+
+config SCHED_NO_NO_OMIT_FRAME_POINTER
+       bool
+       default y
+
+config UBICOM32_PLIO
+       bool
+       default n
+
+menu "Processor type and features"
+
+comment "Processor type will be selected by Board"
+
+config UBICOM32_V3
+       bool
+       help
+         Ubicom IP5xxx series processor support.
+
+config UBICOM32_V4
+       bool
+       help
+         Ubicom IP7xxx series processor support.
+
+comment "Board"
+choice
+       prompt "Board type"
+       help
+               Select your board.
+
+config NOBOARD
+       bool "No board selected"
+       help
+               Default. Don't select any board specific config. Will not build unless you change!
+
+# Add your boards here
+source "arch/ubicom32/mach-ip5k/Kconfig"
+source "arch/ubicom32/mach-ip7k/Kconfig"
+
+endchoice
+
+comment "Kernel Options"
+config SMP
+       bool "Symmetric multi-processing support"
+       select USE_GENERIC_SMP_HELPERS
+       default n
+       help
+         Enables multithreading support.  Enabling SMP support increases
+         the size of system data structures.  SMP support can have either
+         positive or negative impact on performance depending on workloads.
+
+         If you do not know what to do here, say N.
+config OLD_40400010_SYSTEM_CALL
+       bool "Provide old system call interface at 0x40400010"
+       default y
+       help
+         Provides the old system call interface, does not affect the
+         new system_call interface.
+
+config NR_CPUS
+       int "Number of configured CPUs"
+       range 2 32
+       default 2
+       depends on SMP
+       help
+               Upper bound on the number of CPUs. Space is reserved
+               at compile time for this many CPUs.
+
+config LOCAL_TIMERS
+       bool "Use local timer interrupts"
+       depends on SMP
+       default y
+       help
+         Enable support for local timers on SMP platforms, rather then the
+         legacy IPI broadcast method.  Local timers allows the system
+         accounting to be spread across the timer interval, preventing a
+         "thundering herd" at every timer tick.  A physical timer is allocated
+         per cpu.
+
+config TIMER_EXTRA_ALLOC
+       int "Number of additional physical timer events to create"
+       depends on GENERIC_CLOCKEVENTS
+       default 0
+       help
+               The Ubicom32 processor has a number of event timers that can be wrapped
+               in Linux clock event structures (assuming that the timers are not being
+               used for another purpose).  Based on the value of LOCAL_TIMERS, either
+               2 timers will be used or a timer will be used for every CPU.  This value
+               allows the programmer to select additional timers over that amount.
+
+config IRQSTACKS
+       bool "Create separate stacks for interrupt handling"
+       default n
+       help
+               Selecting this causes interrupts to be created on a separate
+               stack instead of nesting the interrupts on the kernel stack.
+
+config IRQSTACKS_USEOCM
+       bool "Use OCM for interrupt stacks"
+       default n
+       depends on IRQSTACKS
+       help
+               Selecting this cause the interrupt stacks to be placed in OCM
+               reducing cache misses at the expense of using the OCM for servicing
+               interrupts.
+
+menu "OCM Instruction Heap"
+
+config OCM_MODULES_RESERVATION
+       int "OCM Instruction heap reservation. 0-192 kB"
+       range 0 192
+       default "0"
+       help
+         The minimum amount of OCM memory to reserve for kernel loadable module
+         code. If you are not using this memory it cannot be used for anything
+         else. Leave it as 0 if you have prebuilt modules that are compiled with
+         OCM support.
+
+config OCM_MODULES_MAY_CONSUME_REMAINING_CODESPACE
+       bool "Give all unused ocm code space to the ocm instruction heap."
+       default n
+       help
+         Allow the OCM instruction heap allocation to consume any remaining
+         unused OCM code space.  The result of this is that you will not have
+         and deterministic results, but you will not have any waste either.
+
+config OCM_MODULES_FALLBACK_TO_DDR
+       bool "Loadable Modules requiring OCM may fallback to use DDR."
+       default n
+       help
+         If a module cannot get the OCM code it requires allow DDR to
+         be used instead.
+endmenu
+
+config HZ
+       int "Frequency of 'jiffies' (for polling)"
+       default 1000
+       help
+               100 is common for embedded systems, but 1000 allows
+               you to do more drivers without actually having
+               interrupts working properly.
+
+comment "RAM configuration"
+
+config MIN_RAMSIZE
+       hex "Minimum Size of RAM (in bytes)"
+       range 0x01000000 0x08000000
+       default "0x02000000"
+       help
+               Define the minimum acceptable size of the system
+               RAM. Must be at least 16MB (0x01000000)
+
+comment "Build options"
+config LINKER_RELAXATION
+       bool "Linker Relaxation"
+       default y
+       help
+         Turns on linker relaxation that will produce smaller
+         faster code. Increases link time.
+
+comment "Driver options"
+menu "PCI Bus"
+config PCI
+       bool "PCI bus"
+       default true
+       help
+         Enable/Disable PCI bus
+       source "drivers/pci/Kconfig"
+
+
+config PCI_DEV0_IDSEL
+       hex "slot 0 address"
+       depends on PCI
+       default "0x01000000"
+       help
+         Slot 0 address.  This address should correspond to the address line
+         which the IDSEL bit for this slot is connected to.
+
+config PCI_DEV1_IDSEL
+       hex "slot 1 address"
+       depends on PCI
+       default "0x02000000"
+       help
+         Slot 1 address.  This address should correspond to the address line
+         which the IDSEL bit for this slot is connected to.
+endmenu
+# End PCI
+
+menu "Input devices"
+config UBICOM_INPUT
+       bool "Ubicom polled GPIO input driver"
+       select INPUT
+       select INPUT_POLLDEV
+       help
+               Polling input driver, much like the GPIO input driver, except that it doesn't
+               rely on interrupts.  It will report events via the input subsystem.
+       default n
+
+config UBICOM_INPUT_I2C
+       bool "Ubicom polled GPIO input driver over I2C"
+       select INPUT
+       select INPUT_POLLDEV
+       help
+               Polling input driver, much like the PCA953x driver, it can support a variety of
+               different I2C I/O expanders.  This device polls the I2C I/O expander for events
+               and reports them via the input subsystem.
+       default n
+endmenu
+# Input devices
+
+source "arch/ubicom32/mach-common/Kconfig.switch"
+
+menu "Misc devices"
+config UBICOM_HID
+       bool "Ubicom HID driver"
+       select INPUT
+       select INPUT_POLLDEV
+       select LCD_CLASS_DEVICE
+       help
+               Driver for HID chip found on some Ubicom reference designs.  This chip handles
+               PWM, button input, and IR remote control.  It registers as an input device and
+               a backlight device.
+       default n
+endmenu
+# Misc devices
+
+config CMDLINE_BOOL
+       bool "Built-in kernel command line"
+       default n
+       help
+         Allow for specifying boot arguments to the kernel at
+         build time.  On some systems (e.g. embedded ones), it is
+         necessary or convenient to provide some or all of the
+         kernel boot arguments with the kernel itself (that is,
+         to not rely on the boot loader to provide them.)
+
+         To compile command line arguments into the kernel,
+         set this option to 'Y', then fill in the
+         the boot arguments in CONFIG_CMDLINE.
+
+         Systems with fully functional boot loaders (i.e. non-embedded)
+         should leave this option set to 'N'.
+
+config CMDLINE
+       string "Built-in kernel command string"
+       depends on CMDLINE_BOOL
+       default ""
+       help
+         Enter arguments here that should be compiled into the kernel
+         image and used at boot time.  If the boot loader provides a
+         command line at boot time, it is appended to this string to
+         form the full kernel command line, when the system boots.
+
+         However, you can use the CONFIG_CMDLINE_OVERRIDE option to
+         change this behavior.
+
+         In most cases, the command line (whether built-in or provided
+         by the boot loader) should specify the device for the root
+         file system.
+
+config CMDLINE_OVERRIDE
+       bool "Built-in command line overrides boot loader arguments"
+       default n
+       depends on CMDLINE_BOOL
+       help
+         Set this option to 'Y' to have the kernel ignore the boot loader
+         command line, and use ONLY the built-in command line.
+
+         This is used to work around broken boot loaders.  This should
+         be set to 'N' under normal conditions.
+
+endmenu
+# End Processor type and features
+
+source "arch/ubicom32/Kconfig.debug"
+
+menu "Executable file formats"
+source "fs/Kconfig.binfmt"
+endmenu
+
+source "init/Kconfig"
+source "kernel/Kconfig.preempt"
+source "kernel/time/Kconfig"
+source "mm/Kconfig"
+source "net/Kconfig"
+source "drivers/Kconfig"
+source "fs/Kconfig"
+source "security/Kconfig"
+source "crypto/Kconfig"
+source "lib/Kconfig"
diff --git a/target/linux/ubicom32/files/arch/ubicom32/Kconfig.debug b/target/linux/ubicom32/files/arch/ubicom32/Kconfig.debug
new file mode 100644 (file)
index 0000000..330c758
--- /dev/null
@@ -0,0 +1,129 @@
+menu "Kernel hacking"
+
+config TRACE_IRQFLAGS_SUPPORT
+       def_bool y
+
+config DEBUG_VERBOSE
+        bool "Verbose fault messages"
+        default y
+        select PRINTK
+        help
+          When a program crashes due to an exception, or the kernel detects
+          an internal error, the kernel can print a not so brief message
+          explaining what the problem was. This debugging information is
+          useful to developers and kernel hackers when tracking down problems,
+          but mostly meaningless to other people. This is always helpful for
+          debugging but serves no purpose on a production system.
+          Most people should say N here.
+
+config PROTECT_KERNEL
+       default y
+       bool 'Enable Kernel range register Protection'
+       help
+         Adds code to enable/disable range registers to protect static
+         kernel code/data from userspace.  Currently the ranges covered
+         do no protect kernel loadable modules or dynamically allocated
+         kernel data.
+
+config NO_KERNEL_MSG
+       bool "Suppress Kernel BUG Messages"
+       help
+         Do not output any debug BUG messages within the kernel.
+
+config EARLY_PRINTK
+       bool "Use the driver that you selected as console also for early printk (to debug kernel bootup)."
+       default n
+       help
+         If you want to use the serdes driver (console=ttyUS0) for
+         early printk, you must also supply an additional kernel boot
+         parameter like this:
+
+               serdes=ioportaddr,irq,clockrate,baud
+
+         For an IP7160RGW eval board, you could use this:
+
+               serdes=0x2004000,61,250000000,57600
+
+         which will let you see early printk output at 57600 baud.
+
+config STOP_ON_TRAP
+       bool "Enable stopping at the LDSR for all traps"
+       default n
+       help
+       Cause the LDSR to stop all threads whenever a trap is about to be serviced
+
+config STOP_ON_BUG
+       bool "Enable stopping on failed BUG_ON()"
+       default n
+       help
+       Cause all BUG_ON failures to stop all threads
+
+config DEBUG_IRQMEASURE
+       bool "Enable IRQ handler measurements"
+       default n
+       help
+       When enabled each IRQ's min/avg/max times will be printed.  If the handler
+       re-enables interrupt, the times will show the full time including to service
+       nested interrupts.  See /proc/irq_measurements.
+
+config DEBUG_PCIMEASURE
+       bool "Enable PCI transaction measurements"
+       default n
+       help
+       When enabled the system will measure the min/avg/max timer for each PCI transactions.
+       See /proc/pci_measurements.
+
+config ACCESS_OK_CHECKS_ENABLED
+       bool "Enable user space access checks"
+       default n
+       help
+       Enabling this check causes the kernel to verify that addresses passed
+       to the kernel by the user space code are within the processes
+       address space.  On a no-mmu system, this is done by examining the
+       processes memory data structures (adversly affecting performance) but
+       ensuring that a process does not ask the kernel to violate another
+       processes address space.  Sadly, the kernel uses access_ok() for
+       address that are in the kernel which results in a large volume of
+       false positives.
+
+choice
+       prompt "Unaligned Access Support"
+       default UNALIGNED_ACCESS_ENABLED
+       help
+               Kernel / Userspace unaligned access handling.
+
+config  UNALIGNED_ACCESS_ENABLED
+       bool "Kernel and Userspace"
+       help
+
+config  UNALIGNED_ACCESS_USERSPACE_ONLY
+       bool "Userspace Only"
+       help
+
+config  UNALIGNED_ACCESS_DISABLED
+       bool "Disabled"
+       help
+
+endchoice
+
+config DEBUG_STACKOVERFLOW
+       bool "Check for stack overflows"
+       default n
+       depends on DEBUG_KERNEL
+       help
+         This option will cause messages to be printed if free kernel stack space
+         drops below a certain limit (THREAD_SIZE /8).
+
+config DEBUG_STACK_USAGE
+       bool "Stack utilization instrumentation"
+       default n
+       depends on DEBUG_KERNEL
+       help
+         Enables the display of the minimum amount of free kernel stack which each
+         task has ever had available in the sysrq-T and sysrq-P debug output.
+
+         This option will slow down process creation somewhat.
+
+source "lib/Kconfig.debug"
+
+endmenu
diff --git a/target/linux/ubicom32/files/arch/ubicom32/Makefile b/target/linux/ubicom32/files/arch/ubicom32/Makefile
new file mode 100644 (file)
index 0000000..c5712d8
--- /dev/null
@@ -0,0 +1,104 @@
+#
+# arch/ubicom32/Makefile
+#      <TODO: Replace with short file description>
+#
+# (C) Copyright 2009, Ubicom, Inc.
+#
+# This file is part of the Ubicom32 Linux Kernel Port.
+#
+# The Ubicom32 Linux Kernel Port 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.
+#
+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+# see <http://www.gnu.org/licenses/>.
+#
+# Ubicom32 implementation derived from (with many thanks):
+#   arch/m68knommu
+#   arch/blackfin
+#   arch/parisc
+#
+
+KBUILD_DEFCONFIG :=
+
+# setup the machine name and machine dependent settings
+machine-$(CONFIG_UBICOM32_V3)  := ip5k
+machine-$(CONFIG_UBICOM32_V4)  := ip7k
+MACHINE := $(machine-y)
+export MACHINE
+
+model-$(CONFIG_RAMKERNEL)      := ram
+model-$(CONFIG_ROMKERNEL)      := rom
+MODEL := $(model-y)
+export MODEL
+
+CPUCLASS := $(cpuclass-y)
+
+export CPUCLASS
+
+#
+# We want the core kernel built using the fastcall ABI but modules need
+# to be built using the slower calling convention because they could be
+# loaded out of range for fast calls.
+#
+CFLAGS_KERNEL    += -mfastcall
+CFLAGS_MODULE    += -mno-fastcall
+
+#
+# Some CFLAG additions based on specific CPU type.
+#
+cflags-$(CONFIG_UBICOM32_V3)           := -march=ubicom32v3 -DIP5000
+cflags-$(CONFIG_UBICOM32_V4)           := -march=ubicom32v4 -DIP7000
+
+ldflags-$(CONFIG_LINKER_RELAXATION)    := --relax
+LDFLAGS_vmlinux := $(ldflags-y)
+
+GCCLIBDIR := $(dir $(shell $(CC) $(cflags-y) -print-libgcc-file-name))
+GCC_LIBS := $(GCCLIBDIR)/libgcc.a
+
+KBUILD_CFLAGS += $(cflags-y) -ffunction-sections
+KBUILD_AFLAGS += $(cflags-y)
+
+KBUILD_CFLAGS += -D__linux__ -Dlinux
+KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\"
+
+# include any machine specific directory
+ifneq ($(machine-y),)
+core-y += arch/$(ARCH)/mach-$(MACHINE)/
+endif
+
+head-y := arch/$(ARCH)/kernel/head.o
+
+core-y += arch/$(ARCH)/kernel/ \
+          arch/$(ARCH)/mm/ \
+          arch/$(ARCH)/crypto/ \
+          arch/$(ARCH)/mach-common/
+
+drivers-$(CONFIG_OPROFILE)     += arch/ubicom32/oprofile/
+
+libs-y += arch/$(ARCH)/lib/
+libs-y += $(GCC_LIBS)
+
+archclean:
+
+# make sure developer has selected a valid board
+ifeq ($(CONFIG_NOBOARD),y)
+# $(error have to select a valid board file $(CONFIG_NOBOARD), please run kernel config again)
+_all: config_board_error
+endif
+
+config_board_error:
+       @echo "*************************************************"
+       @echo "You have not selected a proper board."
+       @echo "Please run menuconfig (or config) against your"
+       @echo "kernel and choose your board under Processor"
+       @echo "options"
+       @echo "*************************************************"
+       @exit 1
diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/Makefile b/target/linux/ubicom32/files/arch/ubicom32/crypto/Makefile
new file mode 100644 (file)
index 0000000..2d8e586
--- /dev/null
@@ -0,0 +1,36 @@
+#
+# arch/ubicom32/crypto/Makefile
+#      <TODO: Replace with short file description>
+#
+# (C) Copyright 2009, Ubicom, Inc.
+#
+# This file is part of the Ubicom32 Linux Kernel Port.
+#
+# The Ubicom32 Linux Kernel Port 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.
+#
+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+# see <http://www.gnu.org/licenses/>.
+#
+# Ubicom32 implementation derived from (with many thanks):
+#   arch/m68knommu
+#   arch/blackfin
+#   arch/parisc
+#
+obj-$(CONFIG_CRYPTO_UBICOM32) += crypto_ubicom32.o
+obj-$(CONFIG_CRYPTO_AES_UBICOM32) += aes_ubicom32.o
+obj-$(CONFIG_CRYPTO_DES_UBICOM32) += des.o
+obj-$(CONFIG_CRYPTO_MD5_UBICOM32) += md5.o
+obj-$(CONFIG_CRYPTO_SHA1_UBICOM32) += sha1.o
+
+des-y := des_ubicom32.o des_check_key.o
+md5-y := md5_ubicom32.o md5_ubicom32_asm.o
+sha1-y := sha1_ubicom32.o
diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/aes_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/crypto/aes_ubicom32.c
new file mode 100644 (file)
index 0000000..f0b9f86
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * arch/ubicom32/crypto/aes_ubicom32.c
+ *   Ubicom32 implementation of the AES Cipher Algorithm.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include "crypto_ubicom32.h"
+#include <asm/linkage.h>
+
+struct ubicom32_aes_ctx {
+       u8 key[AES_MAX_KEY_SIZE];
+       u32 ctrl;
+       int key_len;
+};
+
+static inline void aes_hw_set_key(const u8 *key, u8 key_len)
+{
+       /*
+        * switch case has more overhead than 4 move.4 instructions, so just copy 256 bits
+        */
+       SEC_SET_KEY_256(key);
+}
+
+static inline void aes_hw_set_iv(const u8 *iv)
+{
+       SEC_SET_IV_4W(iv);
+}
+
+static inline void aes_hw_cipher(u8 *out, const u8 *in)
+{
+       SEC_SET_INPUT_4W(in);
+
+       asm volatile (
+       "       ; start AES by writing 0x40(SECURITY_BASE)      \n\t"
+       "       move.4 0x40(%0), #0x01                          \n\t"
+       "       pipe_flush 0                                    \n\t"
+       "                                                       \n\t"
+       "       ; wait for the module to calculate the output   \n\t"
+       "       btst 0x04(%0), #0                               \n\t"
+       "       jmpne.f .-4                                     \n\t"
+               :
+               : "a" (SEC_BASE)
+               : "cc"
+       );
+
+       SEC_GET_OUTPUT_4W(out);
+}
+
+static int __ocm_text aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+                      unsigned int key_len)
+{
+       struct ubicom32_aes_ctx *uctx = crypto_tfm_ctx(tfm);
+
+       uctx->key_len = key_len;
+       memcpy(uctx->key, in_key, key_len);
+
+       /*
+        * leave out HASH_ALG (none = 0), CBC (no = 0), DIR (unknown) yet
+        */
+       switch (uctx->key_len) {
+       case 16:
+               uctx->ctrl = SEC_KEY_128_BITS | SEC_ALG_AES;
+               break;
+       case 24:
+               uctx->ctrl = SEC_KEY_192_BITS | SEC_ALG_AES;
+               break;
+       case 32:
+               uctx->ctrl = SEC_KEY_256_BITS | SEC_ALG_AES;
+               break;
+       }
+
+       return 0;
+}
+
+static inline void aes_cipher(struct crypto_tfm *tfm, u8 *out, const u8 *in, u32 extra_flags)
+{
+       const struct ubicom32_aes_ctx *uctx = crypto_tfm_ctx(tfm);
+
+       hw_crypto_lock();
+       hw_crypto_check();
+       hw_crypto_set_ctrl(uctx->ctrl | extra_flags);
+
+       aes_hw_set_key(uctx->key, uctx->key_len);
+       aes_hw_cipher(out, in);
+
+       hw_crypto_unlock();
+}
+
+static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+       aes_cipher(tfm, out, in, SEC_DIR_ENCRYPT);
+}
+
+static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+       aes_cipher(tfm, out, in, SEC_DIR_DECRYPT);
+}
+
+static struct crypto_alg aes_alg = {
+       .cra_name               =       "aes",
+       .cra_driver_name        =       "aes-ubicom32",
+       .cra_priority           =       CRYPTO_UBICOM32_PRIORITY,
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       AES_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct ubicom32_aes_ctx),
+       .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(aes_alg.cra_list),
+       .cra_u                  =       {
+               .cipher = {
+                       .cia_min_keysize        =       AES_MIN_KEY_SIZE,
+                       .cia_max_keysize        =       AES_MAX_KEY_SIZE,
+                       .cia_setkey             =       aes_set_key,
+                       .cia_encrypt            =       aes_encrypt,
+                       .cia_decrypt            =       aes_decrypt,
+               }
+       }
+};
+
+static void __ocm_text ecb_aes_crypt_loop(u8 *out, u8 *in, unsigned int n)
+{
+       while (likely(n)) {
+               aes_hw_cipher(out, in);
+               out += AES_BLOCK_SIZE;
+               in += AES_BLOCK_SIZE;
+               n -= AES_BLOCK_SIZE;
+       }
+}
+
+static int __ocm_text ecb_aes_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                        struct scatterlist *src, unsigned int nbytes, u32 extra_flags)
+{
+       const struct ubicom32_aes_ctx *uctx = crypto_blkcipher_ctx(desc->tfm);
+       int ret;
+
+       struct blkcipher_walk walk;
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       ret = blkcipher_walk_virt(desc, &walk);
+        if (ret) {
+                return ret;
+        }
+
+       hw_crypto_lock();
+       hw_crypto_check();
+
+        hw_crypto_set_ctrl(uctx->ctrl | extra_flags);
+        aes_hw_set_key(uctx->key, uctx->key_len);
+
+       while (likely((nbytes = walk.nbytes))) {
+               /* only use complete blocks */
+               unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
+               u8 *out = walk.dst.virt.addr;
+               u8 *in = walk.src.virt.addr;
+
+               /* finish n/16 blocks */
+               ecb_aes_crypt_loop(out, in, n);
+
+               nbytes &= AES_BLOCK_SIZE - 1;
+               ret = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       hw_crypto_unlock();
+       return ret;
+}
+
+static int ecb_aes_encrypt(struct blkcipher_desc *desc,
+                          struct scatterlist *dst, struct scatterlist *src,
+                          unsigned int nbytes)
+{
+       return ecb_aes_crypt(desc, dst, src, nbytes, SEC_DIR_ENCRYPT);
+}
+
+static int ecb_aes_decrypt(struct blkcipher_desc *desc,
+                          struct scatterlist *dst, struct scatterlist *src,
+                          unsigned int nbytes)
+{
+       return ecb_aes_crypt(desc, dst, src, nbytes, SEC_DIR_DECRYPT);
+}
+
+static struct crypto_alg ecb_aes_alg = {
+       .cra_name               =       "ecb(aes)",
+       .cra_driver_name        =       "ecb-aes-ubicom32",
+       .cra_priority           =       CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
+       .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          =       AES_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct ubicom32_aes_ctx),
+       .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
+       .cra_type               =       &crypto_blkcipher_type,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(ecb_aes_alg.cra_list),
+       .cra_u                  =       {
+               .blkcipher = {
+                       .min_keysize            =       AES_MIN_KEY_SIZE,
+                       .max_keysize            =       AES_MAX_KEY_SIZE,
+                       .setkey                 =       aes_set_key,
+                       .encrypt                =       ecb_aes_encrypt,
+                       .decrypt                =       ecb_aes_decrypt,
+               }
+       }
+};
+
+#if CRYPTO_UBICOM32_LOOP_ASM
+void __ocm_text cbc_aes_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
+{
+       asm volatile (
+       "; set init. iv 4w                      \n\t"
+       "       move.4 0x50(%0), 0x0(%3)        \n\t"
+       "       move.4 0x54(%0), 0x4(%3)        \n\t"
+       "       move.4 0x58(%0), 0x8(%3)        \n\t"
+       "       move.4 0x5c(%0), 0xc(%3)        \n\t"
+       "                                       \n\t"
+       "; we know n > 0, so we can always      \n\t"
+       "; load the first block                 \n\t"
+       "; set input 4w                         \n\t"
+       "       move.4 0x30(%0), 0x0(%2)        \n\t"
+       "       move.4 0x34(%0), 0x4(%2)        \n\t"
+       "       move.4 0x38(%0), 0x8(%2)        \n\t"
+       "       move.4 0x3c(%0), 0xc(%2)        \n\t"
+       "                                       \n\t"
+       "; kickoff hw                           \n\t"
+       "       move.4 0x40(%0), %2             \n\t"
+       "                                       \n\t"
+       "; update n & flush                     \n\t"
+       "       add.4 %4, #-16, %4              \n\t"
+       "       pipe_flush 0                    \n\t"
+       "                                       \n\t"
+       "; while (n):  work on 2nd block        \n\t"
+       " 1:    lsl.4 d15, %4, #0x0             \n\t"
+       "       jmpeq.f 5f                      \n\t"
+       "                                       \n\t"
+       "; set input 4w (2nd)                   \n\t"
+       "       move.4 0x30(%0), 0x10(%2)       \n\t"
+       "       move.4 0x34(%0), 0x14(%2)       \n\t"
+       "       move.4 0x38(%0), 0x18(%2)       \n\t"
+       "       move.4 0x3c(%0), 0x1c(%2)       \n\t"
+       "                                       \n\t"
+       "; update n/in asap while waiting       \n\t"
+       "       add.4 %4, #-16, %4              \n\t"
+       "       move.4 d15, 16(%2)++            \n\t"
+       "                                       \n\t"
+       "; wait for the previous output         \n\t"
+       "       btst 0x04(%0), #0               \n\t"
+       "       jmpne.f -4                      \n\t"
+       "                                       \n\t"
+       "; read previous output                 \n\t"
+       "       move.4 0x0(%1), 0x50(%0)        \n\t"
+       "       move.4 0x4(%1), 0x54(%0)        \n\t"
+       "       move.4 0x8(%1), 0x58(%0)        \n\t"
+       "       move.4 0xc(%1), 0x5c(%0)        \n\t"
+       "                                       \n\t"
+       "; kick off hw for 2nd input            \n\t"
+       "       move.4 0x40(%0), %2             \n\t"
+       "                                       \n\t"
+       "; update out asap                      \n\t"
+       "       move.4 d15, 16(%1)++            \n\t"
+       "                                       \n\t"
+       "; go back to loop                      \n\t"
+       "       jmpt 1b                         \n\t"
+       "                                       \n\t"
+       "; wait for last output                 \n\t"
+       " 5:    btst 0x04(%0), #0               \n\t"
+        "       jmpne.f -4                      \n\t"
+        "                                       \n\t"
+       "; read last output                     \n\t"
+       "       move.4 0x0(%1), 0x50(%0)        \n\t"
+       "       move.4 0x4(%1), 0x54(%0)        \n\t"
+       "       move.4 0x8(%1), 0x58(%0)        \n\t"
+       "       move.4 0xc(%1), 0x5c(%0)        \n\t"
+        "                                       \n\t"
+       "; copy out iv                          \n\t"
+       "       move.4 0x0(%3), 0x50(%0)        \n\t"
+       "       move.4 0x4(%3), 0x54(%0)        \n\t"
+       "       move.4 0x8(%3), 0x58(%0)        \n\t"
+       "       move.4 0xc(%3), 0x5c(%0)        \n\t"
+        "                                       \n\t"
+               :
+               : "a" (SEC_BASE), "a" (out), "a" (in), "a" (iv), "d" (n)
+               : "d15", "cc"
+       );
+}
+
+#else
+
+static void __ocm_text cbc_aes_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
+{
+       aes_hw_set_iv(iv);
+       while (likely(n)) {
+               aes_hw_cipher(out, in);
+               out += AES_BLOCK_SIZE;
+               in += AES_BLOCK_SIZE;
+               n -= AES_BLOCK_SIZE;
+       }
+       SEC_COPY_4W(iv, out - AES_BLOCK_SIZE);
+}
+
+#endif
+
+static void __ocm_text cbc_aes_decrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
+{
+        while (likely(n)) {
+                aes_hw_set_iv(iv);
+               SEC_COPY_4W(iv, in);
+                aes_hw_cipher(out, in);
+                out += AES_BLOCK_SIZE;
+                in += AES_BLOCK_SIZE;
+                n -= AES_BLOCK_SIZE;
+        }
+}
+
+static int __ocm_text cbc_aes_crypt(struct blkcipher_desc *desc,
+                           struct scatterlist *dst, struct scatterlist *src,
+                           unsigned int nbytes, u32 extra_flags)
+{
+       struct ubicom32_aes_ctx *uctx = crypto_blkcipher_ctx(desc->tfm);
+       int ret;
+
+        struct blkcipher_walk walk;
+        blkcipher_walk_init(&walk, dst, src, nbytes);
+       ret = blkcipher_walk_virt(desc, &walk);
+       if (unlikely(ret)) {
+               return ret;
+       }
+
+        hw_crypto_lock();
+       hw_crypto_check();
+
+        hw_crypto_set_ctrl(uctx->ctrl | extra_flags);
+        aes_hw_set_key(uctx->key, uctx->key_len);
+
+       while (likely((nbytes = walk.nbytes))) {
+                /* only use complete blocks */
+                unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
+               if (likely(n)) {
+                       u8 *out = walk.dst.virt.addr;
+                       u8 *in = walk.src.virt.addr;
+
+                       if (extra_flags & SEC_DIR_ENCRYPT) {
+                               cbc_aes_encrypt_loop(out, in, walk.iv, n);
+                       } else {
+                               cbc_aes_decrypt_loop(out, in, walk.iv, n);
+                       }
+               }
+
+               nbytes &= AES_BLOCK_SIZE - 1;
+                ret = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+       hw_crypto_unlock();
+
+       return ret;
+}
+
+static int __ocm_text cbc_aes_encrypt(struct blkcipher_desc *desc,
+                          struct scatterlist *dst, struct scatterlist *src,
+                          unsigned int nbytes)
+{
+       return cbc_aes_crypt(desc, dst, src, nbytes, SEC_DIR_ENCRYPT | SEC_CBC_SET);
+}
+
+static int __ocm_text cbc_aes_decrypt(struct blkcipher_desc *desc,
+                          struct scatterlist *dst, struct scatterlist *src,
+                          unsigned int nbytes)
+{
+       return cbc_aes_crypt(desc, dst, src, nbytes, SEC_DIR_DECRYPT | SEC_CBC_SET);
+}
+
+static struct crypto_alg cbc_aes_alg = {
+       .cra_name               =       "cbc(aes)",
+       .cra_driver_name        =       "cbc-aes-ubicom32",
+       .cra_priority           =       CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
+       .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          =       AES_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct ubicom32_aes_ctx),
+       .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
+       .cra_type               =       &crypto_blkcipher_type,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(cbc_aes_alg.cra_list),
+       .cra_u                  =       {
+               .blkcipher = {
+                       .min_keysize            =       AES_MIN_KEY_SIZE,
+                       .max_keysize            =       AES_MAX_KEY_SIZE,
+                       .ivsize                 =       AES_BLOCK_SIZE,
+                       .setkey                 =       aes_set_key,
+                       .encrypt                =       cbc_aes_encrypt,
+                       .decrypt                =       cbc_aes_decrypt,
+               }
+       }
+};
+
+static int __init aes_init(void)
+{
+       int ret;
+
+       hw_crypto_init();
+
+       ret = crypto_register_alg(&aes_alg);
+       if (ret)
+               goto aes_err;
+
+       ret = crypto_register_alg(&ecb_aes_alg);
+       if (ret)
+               goto ecb_aes_err;
+
+       ret = crypto_register_alg(&cbc_aes_alg);
+       if (ret)
+               goto cbc_aes_err;
+
+out:
+       return ret;
+
+cbc_aes_err:
+       crypto_unregister_alg(&ecb_aes_alg);
+ecb_aes_err:
+       crypto_unregister_alg(&aes_alg);
+aes_err:
+       goto out;
+}
+
+static void __exit aes_fini(void)
+{
+       crypto_unregister_alg(&cbc_aes_alg);
+       crypto_unregister_alg(&ecb_aes_alg);
+       crypto_unregister_alg(&aes_alg);
+}
+
+module_init(aes_init);
+module_exit(aes_fini);
+
+MODULE_ALIAS("aes");
+
+MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_des.h b/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_des.h
new file mode 100644 (file)
index 0000000..3fc0ac3
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * arch/ubicom32/crypto/crypto_des.h
+ *   Function for checking keys for the DES and Triple DES Encryption
+ *   algorithms.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef __CRYPTO_DES_H__
+#define __CRYPTO_DES_H__
+
+extern int crypto_des_check_key(const u8*, unsigned int, u32*);
+
+#endif /* __CRYPTO_DES_H__ */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_ubicom32.c
new file mode 100644 (file)
index 0000000..237ebbd
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * arch/ubicom32/crypto/crypto_ubicom32.c
+ *   Generic code to support ubicom32 hardware crypto accelerator
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include "crypto_ubicom32.h"
+
+spinlock_t crypto_ubicom32_lock;
+bool crypto_ubicom32_inited = false;
+volatile bool crypto_ubicom32_on = false;
+volatile unsigned long crypto_ubicom32_last_use;
+
+struct timer_list crypto_ubicom32_ps_timer;
+void crypto_ubicom32_ps_check(unsigned long data)
+{
+       unsigned long idle_time = msecs_to_jiffies(HW_CRYPTO_PS_MAX_IDLE_MS);
+
+       BUG_ON(!crypto_ubicom32_on);
+
+       if (((jiffies - crypto_ubicom32_last_use) > idle_time) && spin_trylock_bh(&crypto_ubicom32_lock)) {
+                hw_crypto_turn_off();
+                spin_unlock_bh(&crypto_ubicom32_lock);
+               return;
+       }
+
+       /* keep monitoring */
+       hw_crypto_ps_start();
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_ubicom32.h b/target/linux/ubicom32/files/arch/ubicom32/crypto/crypto_ubicom32.h
new file mode 100644 (file)
index 0000000..e754c19
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * arch/ubicom32/crypto/crypto_ubicom32.h
+ *   Support for Ubicom32 cryptographic instructions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _CRYPTO_ARCH_UBICOM32_CRYPT_H
+#define _CRYPTO_ARCH_UBICOM32_CRYPT_H
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/ip5000.h>
+
+#define CRYPTO_UBICOM32_LOOP_ASM 1
+#define CRYPTO_UBICOM32_ALIGNMENT 4
+#define SEC_ALIGNED(p) (((u32)p & 3) == 0)
+
+#define SEC_BASE               SECURITY_BASE
+#define SEC_KEY_OFFSET         SECURITY_KEY_VALUE(0)
+#define SEC_INPUT_OFFSET       SECURITY_KEY_IN(0)
+#define SEC_OUTPUT_OFFSET      SECURITY_KEY_OUT(0)
+#define SEC_HASH_OFFSET                SECURITY_KEY_HASH(0)
+
+#define SEC_KEY_128_BITS       SECURITY_CTRL_KEY_SIZE(0)
+#define SEC_KEY_192_BITS       SECURITY_CTRL_KEY_SIZE(1)
+#define SEC_KEY_256_BITS       SECURITY_CTRL_KEY_SIZE(2)
+
+#define SEC_HASH_NONE          SECURITY_CTRL_HASH_ALG_NONE
+#define SEC_HASH_MD5           SECURITY_CTRL_HASH_ALG_MD5
+#define SEC_HASH_SHA1          SECURITY_CTRL_HASH_ALG_SHA1
+
+#define SEC_CBC_SET            SECURITY_CTRL_CBC
+#define SEC_CBC_NONE           0
+
+#define SEC_ALG_AES            SECURITY_CTRL_CIPHER_ALG_AES
+#define SEC_ALG_NONE           SECURITY_CTRL_CIPHER_ALG_NONE
+#define SEC_ALG_DES            SECURITY_CTRL_CIPHER_ALG_DES
+#define SEC_ALG_3DES           SECURITY_CTRL_CIPHER_ALG_3DES
+
+#define SEC_DIR_ENCRYPT                SECURITY_CTRL_ENCIPHER
+#define SEC_DIR_DECRYPT                0
+
+#define CRYPTO_UBICOM32_PRIORITY 300
+#define CRYPTO_UBICOM32_COMPOSITE_PRIORITY 400
+
+#define HW_CRYPTO_PS_MAX_IDLE_MS 100    /* idle time (ms) before shuting down sm */
+
+extern spinlock_t crypto_ubicom32_lock;
+extern bool crypto_ubicom32_inited;
+extern volatile bool crypto_ubicom32_on;
+extern volatile unsigned long crypto_ubicom32_last_use;
+extern struct timer_list crypto_ubicom32_ps_timer;
+extern void crypto_ubicom32_ps_check(unsigned long data);
+
+#define SEC_COPY_2W(t, s)                              \
+       asm volatile (                                  \
+       "       move.4 0(%0), 0(%1)             \n\t"   \
+       "       move.4 4(%0), 4(%1)             \n\t"   \
+                                                       \
+               :                                       \
+               : "a" (t), "a" (s)                      \
+       )
+
+#define SEC_COPY_4W(t, s)                              \
+       asm volatile (                                  \
+       "       move.4 0(%0), 0(%1)             \n\t"   \
+       "       move.4 4(%0), 4(%1)             \n\t"   \
+       "       move.4 8(%0), 8(%1)             \n\t"   \
+       "       move.4 12(%0), 12(%1)           \n\t"   \
+               :                                       \
+               : "a" (t), "a" (s)                      \
+       )
+
+#define SEC_COPY_5W(t, s)                              \
+       asm volatile (                                  \
+       "       move.4 0(%0), 0(%1)             \n\t"   \
+       "       move.4 4(%0), 4(%1)             \n\t"   \
+       "       move.4 8(%0), 8(%1)             \n\t"   \
+       "       move.4 12(%0), 12(%1)           \n\t"   \
+       "       move.4 16(%0), 16(%1)           \n\t"   \
+               :                                       \
+               : "a" (t), "a" (s)                      \
+       )
+
+#define SEC_SET_KEY_2W(x)                              \
+       asm volatile (                                  \
+       "       ; write key to Security Keyblock \n\t"  \
+       "       move.4 0x10(%0), 0(%1)          \n\t"   \
+       "       move.4 0x14(%0), 4(%1)          \n\t"   \
+               :                                       \
+               : "a" (SECURITY_BASE), "a" (x)          \
+       )
+
+#define SEC_SET_KEY_4W(x) \
+       asm volatile ( \
+       "       ; write key to Security Keyblock \n\t"  \
+       "       move.4 0x10(%0), 0(%1)          \n\t"   \
+       "       move.4 0x14(%0), 4(%1)          \n\t"   \
+       "       move.4 0x18(%0), 8(%1)          \n\t"   \
+       "       move.4 0x1c(%0), 12(%1)         \n\t"   \
+               :                                       \
+               : "a"(SECURITY_BASE), "a"(x)            \
+       )
+
+#define SEC_SET_KEY_6W(x)                              \
+       asm volatile (                                  \
+       "       ; write key to Security Keyblock \n\t"  \
+       "       move.4 0x10(%0), 0(%1)          \n\t"   \
+       "       move.4 0x14(%0), 4(%1)          \n\t"   \
+       "       move.4 0x18(%0), 8(%1)          \n\t"   \
+       "       move.4 0x1c(%0), 12(%1)         \n\t"   \
+       "       move.4 0x20(%0), 16(%1)         \n\t"   \
+       "       move.4 0x24(%0), 20(%1)         \n\t"   \
+               :                                       \
+               : "a" (SECURITY_BASE), "a" (x)          \
+       )
+
+#define SEC_SET_KEY_8W(x)                              \
+       asm volatile (                                  \
+       "       ; write key to Security Keyblock \n\t"  \
+       "       move.4 0x10(%0), 0(%1)          \n\t"   \
+       "       move.4 0x14(%0), 4(%1)          \n\t"   \
+       "       move.4 0x18(%0), 8(%1)          \n\t"   \
+       "       move.4 0x1c(%0), 12(%1)         \n\t"   \
+       "       move.4 0x20(%0), 16(%1)         \n\t"   \
+       "       move.4 0x24(%0), 20(%1)         \n\t"   \
+       "       move.4 0x28(%0), 24(%1)         \n\t"   \
+       "       move.4 0x2c(%0), 28(%1)         \n\t"   \
+               :                                       \
+               : "a" (SECURITY_BASE), "a" (x)          \
+       )
+
+#define SEC_SET_KEY_64(k)      SEC_SET_KEY_2W(k)
+#define SEC_SET_KEY_128(k)     SEC_SET_KEY_4W(k)
+#define SEC_SET_KEY_192(k)     SEC_SET_KEY_6W(k)
+#define SEC_SET_KEY_256(k)     SEC_SET_KEY_8W(k)
+
+#define DES_SET_KEY(x)                 SEC_SET_KEY_64(x)
+#define DES3_SET_KEY(x)        SEC_SET_KEY_192(x)
+
+#define SEC_SET_INPUT_2W(x)                            \
+       asm volatile (                                  \
+       "       ; write key to Security Keyblock \n\t"  \
+       "       move.4 0x30(%0), 0(%1)          \n\t"   \
+       "       move.4 0x34(%0), 4(%1)          \n\t"   \
+               :                                       \
+               : "a" (SECURITY_BASE), "a" (x)          \
+       )
+
+#define SEC_GET_OUTPUT_2W(x)                           \
+       asm volatile (                                  \
+       "       ; write key to Security Keyblock \n\t"  \
+       "       move.4 0(%1), 0x50(%0)          \n\t"   \
+       "       move.4 4(%1), 0x54(%0)          \n\t"   \
+               :                                       \
+               : "a" (SECURITY_BASE), "a" (x)          \
+       )
+
+#define SEC_SET_INPUT_4W(x) \
+       asm volatile ( \
+       "       ; write key to Security Keyblock \n\t"  \
+       "       move.4 0x30(%0), 0(%1)          \n\t"   \
+       "       move.4 0x34(%0), 4(%1)          \n\t"   \
+       "       move.4 0x38(%0), 8(%1)          \n\t"   \
+       "       move.4 0x3c(%0), 12(%1)         \n\t"   \
+               :                                       \
+               : "a" (SECURITY_BASE), "a" (x)          \
+       )
+
+#define SEC_GET_OUTPUT_4W(x)                           \
+       asm volatile (                                  \
+       "       ; read output from Security Keyblock \n\t" \
+       "       move.4 0(%1), 0x50(%0)          \n\t"   \
+       "       move.4 4(%1), 0x54(%0)          \n\t"   \
+       "       move.4 8(%1), 0x58(%0)          \n\t"   \
+       "       move.4 12(%1), 0x5c(%0)         \n\t"   \
+               :                                       \
+               : "a" (SECURITY_BASE), "a" (x)          \
+       )
+
+#define SEC_SET_IV_4W(x)                               \
+       asm volatile (                                  \
+       "       ; write IV to Security Keyblock  \n\t"  \
+       "       move.4 0x50(%0), 0(%1)          \n\t"   \
+       "       move.4 0x54(%0), 4(%1)          \n\t"   \
+       "       move.4 0x58(%0), 8(%1)          \n\t"   \
+       "       move.4 0x5c(%0), 12(%1)         \n\t"   \
+               :                                       \
+               : "a" (SECURITY_BASE), "a" (x)          \
+       )
+
+#define SEC_PIPE_FLUSH() asm volatile ( " pipe_flush 0 \n\t" )
+
+static inline void hw_crypto_set_ctrl(uint32_t c)
+{
+       asm volatile (
+       "       move.4  0(%0), %1               \n\t"
+               :
+               : "a" (SECURITY_BASE + SECURITY_CTRL), "d" (c)
+       );
+}
+
+static inline void hw_crypto_ps_start(void)
+{
+       crypto_ubicom32_ps_timer.expires = jiffies + msecs_to_jiffies(HW_CRYPTO_PS_MAX_IDLE_MS >> 1);
+       add_timer(&crypto_ubicom32_ps_timer);
+}
+
+static inline void hw_crypto_turn_on(void)
+{
+       asm volatile (
+       "       moveai  A4, %0                  \n\t"
+       "       bset    0x0(A4), 0x0(A4), %1    \n\t"
+       "       cycles 11                       \n\t"
+               :
+               : "i" (OCP_BASE >> 7), "i" (GEN_CLK_PLL_SECURITY_BIT_NO)
+               : "a4", "cc"
+       );
+       crypto_ubicom32_on = true;
+}
+
+static inline void hw_crypto_turn_off(void)
+{
+       asm volatile (
+       "       moveai  A4, %0                  \n\t"
+       "       bclr    0x0(A4), 0x0(A4), %1    \n\t"
+               :
+               : "i" (OCP_BASE >> 7), "i" (GEN_CLK_PLL_SECURITY_BIT_NO)
+               : "a4", "cc"
+       );
+       crypto_ubicom32_on = false;
+}
+
+/*
+ * hw_crypto_check
+ *     Most probably hw crypto is called in clusters and it makes no sense to turn it off
+ *     and on and waster 13 cycles every time.
+ */
+static inline void hw_crypto_check(void)
+{
+       if (likely(crypto_ubicom32_on)) {
+               return;
+       }
+       crypto_ubicom32_last_use = jiffies;
+       hw_crypto_turn_on();
+       hw_crypto_ps_start();
+}
+
+/*
+ * hw_crypto_ps_init
+ *     Init power save timer
+ */
+static inline void hw_crypto_ps_init(void)
+{
+       init_timer_deferrable(&crypto_ubicom32_ps_timer);
+       crypto_ubicom32_ps_timer.function = crypto_ubicom32_ps_check;
+       crypto_ubicom32_ps_timer.data = 0;
+}
+
+/*
+ * hw_crypto_init()
+ *      Initialize OCP security module lock and disables its clock.
+ */
+static inline void hw_crypto_init(void)
+{
+       if (!crypto_ubicom32_inited) {
+               crypto_ubicom32_inited = true;
+               spin_lock_init(&crypto_ubicom32_lock);
+               hw_crypto_ps_init();
+               hw_crypto_turn_off();
+       }
+}
+
+/*
+ * hw_crypto_lock()
+ *      Locks the OCP security module and enables its clock.
+ */
+static inline void hw_crypto_lock(void)
+{
+       spin_lock_bh(&crypto_ubicom32_lock);
+}
+
+/*
+ * hw_crypto_unlock()
+ *      Unlocks the OCP security module and disables its clock.
+ */
+static inline void hw_crypto_unlock(void)
+{
+       crypto_ubicom32_last_use = jiffies;
+       spin_unlock_bh(&crypto_ubicom32_lock);
+}
+
+#define CONFIG_CRYPTO_UBICOM32_DEBUG 1
+
+#ifdef CONFIG_CRYPTO_UBICOM32_DEBUG
+static inline void hex_dump(void *buf, int b_size, const char *msg)
+{
+       u8 *b = (u8 *)buf;
+       int i;
+       if (msg) {
+               printk("%s:\t", msg);
+       }
+
+       for (i=0; i < b_size; i++) {
+               printk("%02x ", b[i]);
+               if ((i & 3) == 3) {
+                       printk(" ");
+               }
+               if ((i & 31) == 31) {
+                       printk("\n");
+               }
+       }
+       printk("\n");
+}
+#define UBICOM32_SEC_DUMP(a, b, c) hex_dump(a, b, c)
+#else
+#define UBICOM32_SEC_DUMP(a, b, c)
+#endif
+
+#endif /* _CRYPTO_ARCH_UBICOM32_CRYPT_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/des_check_key.c b/target/linux/ubicom32/files/arch/ubicom32/crypto/des_check_key.c
new file mode 100644 (file)
index 0000000..162e524
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * arch/ubicom32/crypto/des_check_key.c
+ *   Ubicom32 architecture function for checking keys for the DES and
+ *   Tripple DES Encryption algorithms.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * Originally released as descore by Dana L. How <how@isl.stanford.edu>.
+ * Modified by Raimar Falke <rf13@inf.tu-dresden.de> for the Linux-Kernel.
+ * Derived from Cryptoapi and Nettle implementations, adapted for in-place
+ * scatterlist interface.  Changed LGPL to GPL per section 3 of the LGPL.
+ *
+ * s390 Version:
+ *   Copyright IBM Corp. 2003
+ *   Author(s): Thomas Spatzier
+ *             Jan Glauber (jan.glauber@de.ibm.com)
+ *
+ * Derived from "crypto/des.c"
+ *   Copyright (c) 1992 Dana L. How.
+ *   Copyright (c) Raimar Falke <rf13@inf.tu-dresden.de>
+ *   Copyright (c) Gisle Sflensminde <gisle@ii.uib.no>
+ *   Copyright (C) 2001 Niels Mvller.
+ *   Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/crypto.h>
+#include "crypto_des.h"
+
+#define ROR(d,c,o)     ((d) = (d) >> (c) | (d) << (o))
+
+static const u8 parity[] = {
+       8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3,
+       0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
+       0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
+       8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
+       0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
+       8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
+       8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
+       4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8,
+};
+
+/*
+ * RFC2451: Weak key checks SHOULD be performed.
+ */
+int
+crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags)
+{
+       u32 n, w;
+
+       n  = parity[key[0]]; n <<= 4;
+       n |= parity[key[1]]; n <<= 4;
+       n |= parity[key[2]]; n <<= 4;
+       n |= parity[key[3]]; n <<= 4;
+       n |= parity[key[4]]; n <<= 4;
+       n |= parity[key[5]]; n <<= 4;
+       n |= parity[key[6]]; n <<= 4;
+       n |= parity[key[7]];
+       w = 0x88888888L;
+
+       if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY)
+           && !((n - (w >> 3)) & w)) {  /* 1 in 10^10 keys passes this test */
+               if (n < 0x41415151) {
+                       if (n < 0x31312121) {
+                               if (n < 0x14141515) {
+                                       /* 01 01 01 01 01 01 01 01 */
+                                       if (n == 0x11111111) goto weak;
+                                       /* 01 1F 01 1F 01 0E 01 0E */
+                                       if (n == 0x13131212) goto weak;
+                               } else {
+                                       /* 01 E0 01 E0 01 F1 01 F1 */
+                                       if (n == 0x14141515) goto weak;
+                                       /* 01 FE 01 FE 01 FE 01 FE */
+                                       if (n == 0x16161616) goto weak;
+                               }
+                       } else {
+                               if (n < 0x34342525) {
+                                       /* 1F 01 1F 01 0E 01 0E 01 */
+                                       if (n == 0x31312121) goto weak;
+                                       /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */
+                                       if (n == 0x33332222) goto weak;
+                               } else {
+                                       /* 1F E0 1F E0 0E F1 0E F1 */
+                                       if (n == 0x34342525) goto weak;
+                                       /* 1F FE 1F FE 0E FE 0E FE */
+                                       if (n == 0x36362626) goto weak;
+                               }
+                       }
+               } else {
+                       if (n < 0x61616161) {
+                               if (n < 0x44445555) {
+                                       /* E0 01 E0 01 F1 01 F1 01 */
+                                       if (n == 0x41415151) goto weak;
+                                       /* E0 1F E0 1F F1 0E F1 0E */
+                                       if (n == 0x43435252) goto weak;
+                               } else {
+                                       /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */
+                                       if (n == 0x44445555) goto weak;
+                                       /* E0 FE E0 FE F1 FE F1 FE */
+                                       if (n == 0x46465656) goto weak;
+                               }
+                       } else {
+                               if (n < 0x64646565) {
+                                       /* FE 01 FE 01 FE 01 FE 01 */
+                                       if (n == 0x61616161) goto weak;
+                                       /* FE 1F FE 1F FE 0E FE 0E */
+                                       if (n == 0x63636262) goto weak;
+                               } else {
+                                       /* FE E0 FE E0 FE F1 FE F1 */
+                                       if (n == 0x64646565) goto weak;
+                                       /* FE FE FE FE FE FE FE FE */
+                                       if (n == 0x66666666) goto weak;
+                               }
+                       }
+               }
+       }
+       return 0;
+weak:
+       *flags |= CRYPTO_TFM_RES_WEAK_KEY;
+       return -EINVAL;
+}
+
+EXPORT_SYMBOL(crypto_des_check_key);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Key Check function for DES &  DES3 Cipher Algorithms");
diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/des_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/crypto/des_ubicom32.c
new file mode 100644 (file)
index 0000000..14e5fb2
--- /dev/null
@@ -0,0 +1,761 @@
+/*
+ * arch/ubicom32/crypto/des_ubicom32.c
+ *   Ubicom32 implementation of the DES Cipher Algorithm.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <crypto/algapi.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include "crypto_ubicom32.h"
+extern int crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags);
+
+#define DES_BLOCK_SIZE 8
+#define DES_KEY_SIZE 8
+
+#define DES3_192_KEY_SIZE      (3 * DES_KEY_SIZE)
+#define DES3_192_BLOCK_SIZE    DES_BLOCK_SIZE
+
+#define DES3_SUB_KEY(key, i)   (((u8 *)key) + (i * DES_KEY_SIZE))
+
+enum des_ops {
+       DES_ENCRYPT,
+       DES_DECRYPT,
+
+       DES3_EDE_ENCRYPT,
+       DES3_EDE_DECRYPT,
+
+#ifdef DES3_EEE
+       DES3_EEE_ENCRYPT,
+       DES3_EEE_DECRYPT,
+#endif
+};
+
+struct ubicom32_des_ctx {
+       u8 key[3 * DES_KEY_SIZE];
+       u32 ctrl;
+       int key_len;
+};
+
+static inline void des_hw_set_key(const u8 *key, u8 key_len)
+{
+       /*
+        * HW 3DES is not tested yet, use DES just as ipOS
+        */
+       DES_SET_KEY(key);
+}
+
+static inline void des_hw_cipher(u8 *out, const u8 *in)
+{
+       SEC_SET_INPUT_2W(in);
+
+       asm volatile (
+       "       ; start DES by writing 0x38(SECURITY_BASE)      \n\t"
+       "       move.4 0x38(%0), #0x01                          \n\t"
+       "       pipe_flush 0                                    \n\t"
+       "                                                       \n\t"
+       "       ; wait for the module to calculate the output   \n\t"
+       "       btst 0x04(%0), #0                               \n\t"
+       "       jmpne.f .-4                                     \n\t"
+               :
+               : "a" (SEC_BASE)
+               : "cc"
+       );
+
+       SEC_GET_OUTPUT_2W(out);
+}
+
+
+static void inline des3_hw_ede_encrypt(u8 *keys, u8 *out, const u8 *in)
+{
+       hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
+       des_hw_set_key(DES3_SUB_KEY(keys, 0), DES_KEY_SIZE);
+       des_hw_cipher(out, in);
+
+       hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
+       des_hw_set_key(DES3_SUB_KEY(keys, 1), DES_KEY_SIZE);
+       des_hw_cipher(out, out);
+
+       hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
+       des_hw_set_key(DES3_SUB_KEY(keys, 2), DES_KEY_SIZE);
+       des_hw_cipher(out, out);
+}
+
+static void inline des3_hw_ede_decrypt(u8 *keys, u8 *out, const u8 *in)
+{
+       hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
+       des_hw_set_key(DES3_SUB_KEY(keys, 2), DES_KEY_SIZE);
+       des_hw_cipher(out, in);
+
+       hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
+       des_hw_set_key(DES3_SUB_KEY(keys, 1), DES_KEY_SIZE);
+       des_hw_cipher(out, out);
+
+       hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
+       des_hw_set_key(DES3_SUB_KEY(keys, 0), DES_KEY_SIZE);
+       des_hw_cipher(out, out);
+}
+
+#ifdef DES3_EEE
+static void inline des3_hw_eee_encrypt(u8 *keys, u8 *out, const u8 *in)
+{
+       hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
+       des_hw_set_key(DES3_SUB_KEY(keys, 0), 2);
+       des_hw_cipher(out, in);
+
+       hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
+       des_hw_set_key(DES3_SUB_KEY(keys, 1), 2);
+       des_hw_cipher(out, out);
+
+       hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
+       des_hw_set_key(DES3_SUB_KEY(keys, 2), 2);
+       des_hw_cipher(out, out);
+}
+
+static void inline des3_hw_eee_decrypt(u8 *keys, u8 *out, const u8 *in)
+{
+       hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
+       des_hw_set_key(DES3_SUB_KEY(keys, 2), 2);
+       des_hw_cipher(out, in);
+
+       hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
+       des_hw_set_key(DES3_SUB_KEY(keys, 1), 2);
+       des_hw_cipher(out, out);
+
+       hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
+       des_hw_set_key(DES3_SUB_KEY(keys, 0), 2);
+       des_hw_cipher(out, out);
+}
+#endif
+
+static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
+                     unsigned int keylen)
+{
+       struct ubicom32_des_ctx *dctx = crypto_tfm_ctx(tfm);
+       u32 *flags = &tfm->crt_flags;
+       int ret;
+
+       /* test if key is valid (not a weak key) */
+       ret = crypto_des_check_key(key, keylen, flags);
+       if (ret == 0) {
+               memcpy(dctx->key, key, keylen);
+               dctx->key_len = keylen;
+               //dctx->ctrl = (keylen == DES_KEY_SIZE) ? SEC_ALG_DES : SEC_ALG_3DES
+               /* 2DES and 3DES are both implemented with DES hw function */
+               dctx->ctrl = SEC_ALG_DES;
+       }
+       return ret;
+}
+
+static inline void des_cipher_1b(struct crypto_tfm *tfm, u8 *out, const u8 *in, u32 extra_flags)
+{
+       const struct ubicom32_des_ctx *uctx = crypto_tfm_ctx(tfm);
+
+       hw_crypto_lock();
+       hw_crypto_check();
+       hw_crypto_set_ctrl(uctx->ctrl | extra_flags);
+
+       des_hw_set_key(uctx->key, uctx->key_len);
+       des_hw_cipher(out, in);
+
+       hw_crypto_unlock();
+}
+
+static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+       des_cipher_1b(tfm, out, in, SEC_DIR_ENCRYPT);
+}
+
+static void des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
+{
+       des_cipher_1b(tfm, out, in, SEC_DIR_DECRYPT);
+}
+
+static struct crypto_alg des_alg = {
+       .cra_name               =       "des",
+       .cra_driver_name        =       "des-ubicom32",
+       .cra_priority           =       CRYPTO_UBICOM32_PRIORITY,
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       DES_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct ubicom32_des_ctx),
+       .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
+       .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(des_alg.cra_list),
+       .cra_u                  = {
+               .cipher = {
+                       .cia_min_keysize        =       DES_KEY_SIZE,
+                       .cia_max_keysize        =       DES_KEY_SIZE,
+                       .cia_setkey             =       des_setkey,
+                       .cia_encrypt            =       des_encrypt,
+                       .cia_decrypt            =       des_decrypt,
+               }
+       }
+};
+
+static void ecb_des_ciper_loop(u8 *out, u8 *in, unsigned int n)
+{
+       while (likely(n)) {
+               des_hw_cipher(out, in);
+               out += DES_BLOCK_SIZE;
+               in += DES_BLOCK_SIZE;
+               n -= DES_BLOCK_SIZE;
+       }
+}
+
+static void ecb_des3_ede_encrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n)
+{
+       while (likely(n)) {
+               des3_hw_ede_encrypt(keys, out, in);
+
+               out += DES_BLOCK_SIZE;
+               in += DES_BLOCK_SIZE;
+               n -= DES_BLOCK_SIZE;
+       }
+}
+
+static void ecb_des3_ede_decrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n)
+{
+       while (likely(n)) {
+               des3_hw_ede_decrypt(keys, out, in);
+
+               out += DES_BLOCK_SIZE;
+               in += DES_BLOCK_SIZE;
+               n -= DES_BLOCK_SIZE;
+       }
+}
+
+#ifdef DES3_EEE
+static void ecb_des3_eee_encrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n)
+{
+       while (likely(n)) {
+               des3_hw_eee_encrypt(keys, out, in);
+
+               out += DES_BLOCK_SIZE;
+               in += DES_BLOCK_SIZE;
+               n -= DES_BLOCK_SIZE;
+       }
+}
+
+static void ecb_des3_eee_decrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n)
+{
+       while (likely(n)) {
+               des3_hw_eee_decrypt(keys, out, in);
+
+               out += DES_BLOCK_SIZE;
+               in += DES_BLOCK_SIZE;
+               n -= DES_BLOCK_SIZE;
+       }
+}
+#endif
+
+static inline void ecb_des_cipher_n(struct ubicom32_des_ctx *uctx, enum des_ops op, u8 *out, u8 *in, unsigned int n)
+{
+       switch (op) {
+       case DES_ENCRYPT:
+       case DES_DECRYPT:
+               /* set the right algo, direction and key once */
+               hw_crypto_set_ctrl(SEC_ALG_DES | (op == DES_ENCRYPT ? SEC_DIR_ENCRYPT : 0));
+               des_hw_set_key(uctx->key, uctx->key_len);
+               ecb_des_ciper_loop(out, in, n);
+               break;
+
+       case DES3_EDE_ENCRYPT:
+               ecb_des3_ede_encrypt_loop(uctx->key, out, in, n);
+               break;
+
+       case DES3_EDE_DECRYPT:
+               ecb_des3_ede_decrypt_loop(uctx->key, out, in, n);
+               break;
+
+#ifdef DES3_EEE
+       case DES3_EEE_ENCRYPT:
+               ecb_des3_eee_encrypt_loop(uctx->key, out, in, n);
+               break;
+
+       case DES3_EEE_DECRYPT:
+               ecb_des3_eee_decrypt_loop(uctx->key, out, in, n);
+               break;
+#endif
+       }
+}
+
+static inline void des_xor_2w(u32 *data, u32 *iv)
+{
+       data[0] ^= iv[0];
+       data[1] ^= iv[1];
+}
+
+static void cbc_des_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
+{
+       while (likely(n)) {
+               des_xor_2w((u32 *)in, (u32 *)iv);
+               des_hw_cipher(out, in);
+               SEC_COPY_2W(iv, out);
+               out += DES_BLOCK_SIZE;
+               in += DES_BLOCK_SIZE;
+               n -= DES_BLOCK_SIZE;
+       }
+}
+
+static void cbc_des_decrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
+{
+       u8 next_iv[DES_BLOCK_SIZE];
+       while (likely(n)) {
+               SEC_COPY_2W(next_iv, in);
+               des_hw_cipher(out, in);
+               des_xor_2w((u32 *)out, (u32 *)iv);
+               SEC_COPY_2W(iv, next_iv);
+
+               out += DES_BLOCK_SIZE;
+               in += DES_BLOCK_SIZE;
+               n -= DES_BLOCK_SIZE;
+       }
+}
+
+static void cbc_des3_ede_encrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n)
+{
+       while (likely(n)) {
+               des_xor_2w((u32 *)in, (u32 *)iv);
+               des3_hw_ede_encrypt(keys, out, in);
+               SEC_COPY_2W(iv, out);
+
+               out += DES_BLOCK_SIZE;
+               in += DES_BLOCK_SIZE;
+               n -= DES_BLOCK_SIZE;
+       }
+}
+
+static void cbc_des3_ede_decrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n)
+{
+       u8 next_iv[DES_BLOCK_SIZE];
+       while (likely(n)) {
+               SEC_COPY_2W(next_iv, in);
+               des3_hw_ede_decrypt(keys, out, in);
+               des_xor_2w((u32 *)out, (u32 *)iv);
+               SEC_COPY_2W(iv, next_iv);
+
+               out += DES_BLOCK_SIZE;
+               in += DES_BLOCK_SIZE;
+               n -= DES_BLOCK_SIZE;
+       }
+}
+
+#ifdef DES3_EEE
+static void cbc_des3_eee_encrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n)
+{
+       while (likely(n)) {
+               des_xor_2w((u32 *)in, (u32 *)iv);
+               des3_hw_eee_encrypt(keys, out, in);
+               SEC_COPY_2W(iv, out);
+
+               out += DES_BLOCK_SIZE;
+               in += DES_BLOCK_SIZE;
+               n -= DES_BLOCK_SIZE;
+       }
+}
+
+static void cbc_des3_eee_decrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n)
+{
+       u8 next_iv[DES_BLOCK_SIZE];
+       while (likely(n)) {
+               SEC_COPY_2W(next_iv, in);
+               des3_hw_eee_decrypt(keys, out, in);
+               des_xor_2w((u32 *)out, (u32 *)iv);
+               SEC_COPY_2W(iv, next_iv);
+
+               out += DES_BLOCK_SIZE;
+               in += DES_BLOCK_SIZE;
+               n -= DES_BLOCK_SIZE;
+       }
+}
+#endif
+
+static inline void cbc_des_cipher_n(struct ubicom32_des_ctx *uctx, enum des_ops op, u8 *out, u8 *in, u8 *iv, unsigned int n)
+{
+       switch (op) {
+       case DES_ENCRYPT:
+               hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
+               des_hw_set_key(uctx->key, uctx->key_len);
+               cbc_des_encrypt_loop(out, in, iv, n);
+               break;
+
+       case DES_DECRYPT:
+               /* set the right algo, direction and key once */
+               hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
+               des_hw_set_key(uctx->key, uctx->key_len);
+               cbc_des_decrypt_loop(out, in, iv, n);
+               break;
+
+       case DES3_EDE_ENCRYPT:
+               cbc_des3_ede_encrypt_loop(uctx->key, out, in, iv, n);
+               break;
+
+       case DES3_EDE_DECRYPT:
+               cbc_des3_ede_decrypt_loop(uctx->key, out, in, iv, n);
+               break;
+
+#ifdef DES3_EEE
+       case DES3_EEE_ENCRYPT:
+               cbc_des3_eee_encrypt_loop(uctx->key, out, in, iv, n);
+               break;
+
+       case DES3_EEE_DECRYPT:
+               cbc_des3_eee_decrypt_loop(uctx->key, out, in, iv, n);
+               break;
+#endif
+       }
+}
+
+static int des_cipher(struct blkcipher_desc *desc, struct scatterlist *dst,
+                     struct scatterlist *src, unsigned int nbytes, u32 extra_flags, enum des_ops op)
+{
+       struct ubicom32_des_ctx *uctx = crypto_blkcipher_ctx(desc->tfm);
+       int ret;
+
+       struct blkcipher_walk walk;
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       ret = blkcipher_walk_virt(desc, &walk);
+       if (ret) {
+               return ret;
+       }
+
+       hw_crypto_lock();
+       hw_crypto_check();
+
+       while ((nbytes = walk.nbytes)) {
+               /* only use complete blocks */
+               unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1);
+               u8 *out = walk.dst.virt.addr;
+               u8 *in = walk.src.virt.addr;
+
+               /* finish n/16 blocks */
+               if (extra_flags & SEC_CBC_SET) {
+                       cbc_des_cipher_n(uctx, op, out, in, walk.iv, n);
+               } else {
+                       ecb_des_cipher_n(uctx, op, out, in, n);
+               }
+
+               nbytes &= DES_BLOCK_SIZE - 1;
+               ret = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       hw_crypto_unlock();
+       return ret;
+}
+
+static int ecb_des_encrypt(struct blkcipher_desc *desc,
+                          struct scatterlist *dst, struct scatterlist *src,
+                          unsigned int nbytes)
+{
+       return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES_ENCRYPT);
+}
+
+static int ecb_des_decrypt(struct blkcipher_desc *desc,
+                          struct scatterlist *dst, struct scatterlist *src,
+                          unsigned int nbytes)
+{
+       return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES_DECRYPT);
+}
+
+static struct crypto_alg ecb_des_alg = {
+       .cra_name               =       "ecb(des)",
+       .cra_driver_name        =       "ecb-des-ubicom32",
+       .cra_priority           =       CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
+       .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          =       DES_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct ubicom32_des_ctx),
+       .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
+       .cra_type               =       &crypto_blkcipher_type,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(ecb_des_alg.cra_list),
+       .cra_u                  = {
+               .blkcipher = {
+                       .min_keysize            =       DES_KEY_SIZE,
+                       .max_keysize            =       DES_KEY_SIZE,
+                       .setkey                 =       des_setkey,
+                       .encrypt                =       ecb_des_encrypt,
+                       .decrypt                =       ecb_des_decrypt,
+               }
+       }
+};
+
+static int cbc_des_encrypt(struct blkcipher_desc *desc,
+                          struct scatterlist *dst, struct scatterlist *src,
+                          unsigned int nbytes)
+{
+       return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES_ENCRYPT);
+}
+
+static int cbc_des_decrypt(struct blkcipher_desc *desc,
+                          struct scatterlist *dst, struct scatterlist *src,
+                          unsigned int nbytes)
+{
+       return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES_DECRYPT);
+}
+
+static struct crypto_alg cbc_des_alg = {
+       .cra_name               =       "cbc(des)",
+       .cra_driver_name        =       "cbc-des-ubicom32",
+       .cra_priority           =       CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
+       .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          =       DES_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct ubicom32_des_ctx),
+       .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
+       .cra_type               =       &crypto_blkcipher_type,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(cbc_des_alg.cra_list),
+       .cra_u                  = {
+               .blkcipher = {
+                       .min_keysize            =       DES_KEY_SIZE,
+                       .max_keysize            =       DES_KEY_SIZE,
+                       .ivsize                 =       DES_BLOCK_SIZE,
+                       .setkey                 =       des_setkey,
+                       .encrypt                =       cbc_des_encrypt,
+                       .decrypt                =       cbc_des_decrypt,
+               }
+       }
+};
+
+/*
+ * RFC2451:
+ *
+ *   For DES-EDE3, there is no known need to reject weak or
+ *   complementation keys.  Any weakness is obviated by the use of
+ *   multiple keys.
+ *
+ *   However, if the first two or last two independent 64-bit keys are
+ *   equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the
+ *   same as DES.  Implementers MUST reject keys that exhibit this
+ *   property.
+ *
+ */
+static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
+                          unsigned int keylen)
+{
+       int i, ret;
+       struct ubicom32_des_ctx *dctx = crypto_tfm_ctx(tfm);
+       const u8 *temp_key = key;
+       u32 *flags = &tfm->crt_flags;
+
+       if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
+           memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2],
+                  DES_KEY_SIZE))) {
+
+               *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
+               return -EINVAL;
+       }
+       for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) {
+               ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
+               if (ret < 0)
+                       return ret;
+       }
+       memcpy(dctx->key, key, keylen);
+       dctx->ctrl = SEC_ALG_DES;       //hw 3DES not working yet
+       dctx->key_len = keylen;
+       return 0;
+}
+
+static void des3_192_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       struct ubicom32_des_ctx *uctx = crypto_tfm_ctx(tfm);
+
+       hw_crypto_lock();
+       hw_crypto_check();
+
+       des3_hw_ede_encrypt(uctx->key, dst, src);
+
+       hw_crypto_unlock();
+}
+
+static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+{
+       struct ubicom32_des_ctx *uctx = crypto_tfm_ctx(tfm);
+
+       hw_crypto_lock();
+       hw_crypto_check();
+
+       des3_hw_ede_decrypt(uctx->key, dst, src);
+
+       hw_crypto_unlock();
+}
+
+static struct crypto_alg des3_192_alg = {
+       .cra_name               =       "des3_ede",
+       .cra_driver_name        =       "des3_ede-ubicom32",
+       .cra_priority           =       CRYPTO_UBICOM32_PRIORITY,
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       DES3_192_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct ubicom32_des_ctx),
+       .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(des3_192_alg.cra_list),
+       .cra_u                  = {
+               .cipher = {
+                       .cia_min_keysize        =       DES3_192_KEY_SIZE,
+                       .cia_max_keysize        =       DES3_192_KEY_SIZE,
+                       .cia_setkey             =       des3_192_setkey,
+                       .cia_encrypt            =       des3_192_encrypt,
+                       .cia_decrypt            =       des3_192_decrypt,
+               }
+       }
+};
+
+static int ecb_des3_192_encrypt(struct blkcipher_desc *desc,
+                               struct scatterlist *dst,
+                               struct scatterlist *src, unsigned int nbytes)
+{
+       return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES3_EDE_ENCRYPT);
+}
+
+static int ecb_des3_192_decrypt(struct blkcipher_desc *desc,
+                               struct scatterlist *dst,
+                               struct scatterlist *src, unsigned int nbytes)
+{
+       return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES3_EDE_DECRYPT);
+}
+
+static struct crypto_alg ecb_des3_192_alg = {
+       .cra_name               =       "ecb(des3_ede)",
+       .cra_driver_name        =       "ecb-des3_ede-ubicom32",
+       .cra_priority           =       CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
+       .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          =       DES3_192_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct ubicom32_des_ctx),
+       .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
+       .cra_type               =       &crypto_blkcipher_type,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(
+                                               ecb_des3_192_alg.cra_list),
+       .cra_u                  = {
+               .blkcipher = {
+                       .min_keysize            =       DES3_192_KEY_SIZE,
+                       .max_keysize            =       DES3_192_KEY_SIZE,
+                       .setkey                 =       des3_192_setkey,
+                       .encrypt                =       ecb_des3_192_encrypt,
+                       .decrypt                =       ecb_des3_192_decrypt,
+               }
+       }
+};
+
+static int cbc_des3_192_encrypt(struct blkcipher_desc *desc,
+                               struct scatterlist *dst,
+                               struct scatterlist *src, unsigned int nbytes)
+{
+       return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES3_EDE_ENCRYPT);
+}
+
+static int cbc_des3_192_decrypt(struct blkcipher_desc *desc,
+                               struct scatterlist *dst,
+                               struct scatterlist *src, unsigned int nbytes)
+{
+       return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES3_EDE_DECRYPT);
+}
+
+static struct crypto_alg cbc_des3_192_alg = {
+       .cra_name               =       "cbc(des3_ede)",
+       .cra_driver_name        =       "cbc-des3_ede-ubicom32",
+       .cra_priority           =       CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
+       .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          =       DES3_192_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct ubicom32_des_ctx),
+       .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
+       .cra_type               =       &crypto_blkcipher_type,
+       .cra_module             =       THIS_MODULE,
+       .cra_list               =       LIST_HEAD_INIT(
+                                               cbc_des3_192_alg.cra_list),
+       .cra_u                  = {
+               .blkcipher = {
+                       .min_keysize            =       DES3_192_KEY_SIZE,
+                       .max_keysize            =       DES3_192_KEY_SIZE,
+                       .ivsize                 =       DES3_192_BLOCK_SIZE,
+                       .setkey                 =       des3_192_setkey,
+                       .encrypt                =       cbc_des3_192_encrypt,
+                       .decrypt                =       cbc_des3_192_decrypt,
+               }
+       }
+};
+
+static int init(void)
+{
+       int ret = 0;
+
+       hw_crypto_init();
+
+       ret = crypto_register_alg(&des_alg);
+       if (ret)
+               goto des_err;
+       ret = crypto_register_alg(&ecb_des_alg);
+       if (ret)
+               goto ecb_des_err;
+       ret = crypto_register_alg(&cbc_des_alg);
+       if (ret)
+               goto cbc_des_err;
+
+       ret = crypto_register_alg(&des3_192_alg);
+       if (ret)
+               goto des3_192_err;
+       ret = crypto_register_alg(&ecb_des3_192_alg);
+       if (ret)
+               goto ecb_des3_192_err;
+       ret = crypto_register_alg(&cbc_des3_192_alg);
+       if (ret)
+               goto cbc_des3_192_err;
+
+out:
+       return ret;
+
+cbc_des3_192_err:
+       crypto_unregister_alg(&ecb_des3_192_alg);
+ecb_des3_192_err:
+       crypto_unregister_alg(&des3_192_alg);
+des3_192_err:
+       crypto_unregister_alg(&cbc_des_alg);
+cbc_des_err:
+       crypto_unregister_alg(&ecb_des_alg);
+ecb_des_err:
+       crypto_unregister_alg(&des_alg);
+des_err:
+       goto out;
+}
+
+static void __exit fini(void)
+{
+       crypto_unregister_alg(&cbc_des3_192_alg);
+       crypto_unregister_alg(&ecb_des3_192_alg);
+       crypto_unregister_alg(&des3_192_alg);
+       crypto_unregister_alg(&cbc_des_alg);
+       crypto_unregister_alg(&ecb_des_alg);
+       crypto_unregister_alg(&des_alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_ALIAS("des");
+MODULE_ALIAS("des3_ede");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms");
diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/md5_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/crypto/md5_ubicom32.c
new file mode 100644 (file)
index 0000000..1f2b978
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * arch/ubicom32/crypto/md5_ubicom32.c
+ *   Ubicom32 implementation of the MD5 Secure Hash Algorithm
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+
+#include "crypto_ubicom32.h"
+
+#define MD5_DIGEST_SIZE        16
+#define MD5_BLOCK_SIZE 64
+#define MD5_HASH_WORDS 4
+
+extern void _md5_ip5k_init_digest(u32_t *digest);
+extern void _md5_ip5k_transform(u32_t *data_input);
+extern void _md5_ip5k_get_digest(u32_t *digest);
+
+struct ubicom32_md5_ctx {
+       u64 count;              /* message length */
+       u32 state[MD5_HASH_WORDS];
+       u8 buf[2 * MD5_BLOCK_SIZE];
+};
+
+static void md5_init(struct crypto_tfm *tfm)
+{
+       struct ubicom32_md5_ctx *mctx = crypto_tfm_ctx(tfm);
+       mctx->state[0] = 0x01234567;
+       mctx->state[1] = 0x89abcdef;
+       mctx->state[2] = 0xfedcba98;
+       mctx->state[3] = 0x76543210;
+
+       mctx->count = 0;
+}
+
+static inline void _md5_process(u32 *digest, const u8 *data)
+{
+       _md5_ip5k_transform((u32 *)data);
+}
+
+static void md5_update(struct crypto_tfm *tfm, const u8 *data,
+                       unsigned int len)
+{
+       struct ubicom32_md5_ctx *mctx = crypto_tfm_ctx(tfm);
+       int index, clen;
+
+       /* how much is already in the buffer? */
+       index = mctx->count & 0x3f;
+
+       mctx->count += len;
+
+       if (index + len < MD5_BLOCK_SIZE) {
+               goto store_only;
+       }
+
+       hw_crypto_lock();
+       hw_crypto_check();
+
+       /* init digest set ctrl register too */
+       _md5_ip5k_init_digest(mctx->state);
+
+       if (unlikely(index == 0 && SEC_ALIGNED(data))) {
+fast_process:
+               while (len >= MD5_BLOCK_SIZE) {
+                       _md5_process(mctx->state, data);
+                       data += MD5_BLOCK_SIZE;
+                       len -= MD5_BLOCK_SIZE;
+               }
+               goto store;
+       }
+
+       /* process one stored block */
+       if (index) {
+               clen = MD5_BLOCK_SIZE - index;
+               memcpy(mctx->buf + index, data, clen);
+               _md5_process(mctx->state, mctx->buf);
+               data += clen;
+               len -= clen;
+               index = 0;
+       }
+
+       if (likely(SEC_ALIGNED(data))) {
+               goto fast_process;
+       }
+
+       /* process as many blocks as possible */
+       while (len >= MD5_BLOCK_SIZE) {
+               memcpy(mctx->buf, data, MD5_BLOCK_SIZE);
+               _md5_process(mctx->state, mctx->buf);
+               data += MD5_BLOCK_SIZE;
+               len -= MD5_BLOCK_SIZE;
+       }
+
+store:
+       _md5_ip5k_get_digest(mctx->state);
+       hw_crypto_unlock();
+
+store_only:
+       /* anything left? */
+       if (len)
+               memcpy(mctx->buf + index , data, len);
+}
+
+/* Add padding and return the message digest. */
+static void md5_final(struct crypto_tfm *tfm, u8 *out)
+{
+       struct ubicom32_md5_ctx *mctx = crypto_tfm_ctx(tfm);
+       u32 bits[2];
+       unsigned int index, end;
+
+       /* must perform manual padding */
+       index = mctx->count & 0x3f;
+       end =  (index < 56) ? MD5_BLOCK_SIZE : (2 * MD5_BLOCK_SIZE);
+
+       /* start pad with 1 */
+       mctx->buf[index] = 0x80;
+
+       /* pad with zeros */
+       index++;
+       memset(mctx->buf + index, 0x00, end - index - 8);
+
+       /* append message length */
+       bits[0] = mctx->count << 3;
+       bits[1] = mctx->count >> 29;
+       __cpu_to_le32s(bits);
+       __cpu_to_le32s(bits + 1);
+
+       memcpy(mctx->buf + end - 8, &bits, sizeof(bits));
+
+       /* force to use the mctx->buf and ignore the partial buf */
+       mctx->count = mctx->count & ~0x3f;
+       md5_update(tfm, mctx->buf, end);
+
+       /* copy digest to out */
+       memcpy(out, mctx->state, MD5_DIGEST_SIZE);
+
+       /* wipe context */
+       memset(mctx, 0, sizeof *mctx);
+}
+
+static struct crypto_alg alg = {
+       .cra_name       =       "md5",
+       .cra_driver_name=       "md5-ubicom32",
+       .cra_priority   =       CRYPTO_UBICOM32_PRIORITY,
+       .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
+       .cra_blocksize  =       MD5_BLOCK_SIZE,
+       .cra_ctxsize    =       sizeof(struct ubicom32_md5_ctx),
+       .cra_module     =       THIS_MODULE,
+       .cra_list       =       LIST_HEAD_INIT(alg.cra_list),
+       .cra_u = {
+               .digest = {
+                       .dia_digestsize =       MD5_DIGEST_SIZE,
+                       .dia_init       =       md5_init,
+                       .dia_update     =       md5_update,
+                       .dia_final      =       md5_final,
+               }
+       }
+};
+
+static int __init init(void)
+{
+       hw_crypto_init();
+       return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+       crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_ALIAS("md5");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MD5 Secure Hash Algorithm");
diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/md5_ubicom32_asm.S b/target/linux/ubicom32/files/arch/ubicom32/crypto/md5_ubicom32_asm.S
new file mode 100644 (file)
index 0000000..963a357
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * arch/ubicom32/crypto/md5_ubicom32_asm.S
+ *     MD5 (Message Digest 5) support for Ubicom32 v3 architecture
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#define __ASM__
+#include <asm/ip5000.h>
+
+#ifndef RP
+#define RP A5
+#endif
+
+;*****************************************************************************************
+; The function prototypes
+;*****************************************************************************************
+; void md5_ip5k_init(void)
+; void md5_ip5k_transform(u32_t *data_input)
+; void md5_get_digest(u32_t *digest)
+
+;*****************************************************************************************
+; Inputs
+;*****************************************************************************************;
+; data_input is the pointer to the block of data over which the digest will be calculated.
+;      It should be word aligned.
+;
+; digest is the pointer to the block of data into which the digest (the output) will be written.
+;      It should be word aligned.
+;
+
+;*****************************************************************************************
+; Outputs
+;*****************************************************************************************
+; None
+
+;*****************************************************************************************
+; An: Address Registers
+;*****************************************************************************************
+#define an_digest A3
+#define an_data_input A3
+#define an_security_block A4
+
+;*****************************************************************************************
+; Hash Constants
+;*****************************************************************************************
+#define HASH_MD5_IN0 0x01234567
+#define HASH_MD5_IN1 0x89abcdef
+#define HASH_MD5_IN2 0xfedcba98
+#define HASH_MD5_IN3 0x76543210
+
+#define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2
+#define HASH_SECURITY_BLOCK_CONTROL_INIT_MD5 ((1 << 4) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION)
+
+;*****************************************************************************************
+; Hash related defines
+;*****************************************************************************************
+#define hash_control 0x00(an_security_block)
+#define hash_control_low 0x02(an_security_block)
+#define hash_status 0x04(an_security_block)
+
+#define hash_input_0 0x30(an_security_block)
+#define hash_input_1 0x34(an_security_block)
+#define hash_input_2 0x38(an_security_block)
+#define hash_input_3 0x3c(an_security_block)
+#define hash_input_4 0x40(an_security_block)
+
+#define hash_output_0 0x70(an_security_block)
+#define hash_output_0_low 0x72(an_security_block)
+#define hash_output_1 0x74(an_security_block)
+#define hash_output_1_low 0x76(an_security_block)
+#define hash_output_2 0x78(an_security_block)
+#define hash_output_2_low 0x7a(an_security_block)
+#define hash_output_3 0x7c(an_security_block)
+#define hash_output_3_low 0x7e(an_security_block)
+
+;*****************************************************************************************
+; Assembly macros
+;*****************************************************************************************
+       ; C compiler reserves RP (A5) for return address during subroutine call.
+       ; Use RP to return to caller
+.macro call_return_macro
+       calli   RP, 0(RP)
+.endm
+
+#if 0
+;*****************************************************************************************
+;      void md5_ip5k_init(void)
+;              initialize the output registers of the hash module
+;
+       ;.section .text.md5_ip5k_init,"ax",@progbits
+       .section .text
+       .global _md5_ip5k_init
+       .func md5_ip5k_init, _md5_ip5k_init
+
+_md5_ip5k_init:
+       moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
+
+       movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5)
+       movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5)
+
+       movei hash_output_0, #%hi(HASH_MD5_IN0)
+       movei hash_output_0_low, #%lo(HASH_MD5_IN0)
+
+       movei hash_output_1, #%hi(HASH_MD5_IN1)
+       movei hash_output_1_low, #%lo(HASH_MD5_IN1)
+
+       movei hash_output_2, #%hi(HASH_MD5_IN2)
+       movei hash_output_2_low, #%lo(HASH_MD5_IN2)
+
+       movei hash_output_3, #%hi(HASH_MD5_IN3)
+       movei hash_output_3_low, #%lo(HASH_MD5_IN3)
+
+       call_return_macro
+       .endfunc
+#endif
+
+;*****************************************************************************************
+;      void md5_ip5k_init_digest(u32_t *hash_input)
+;              initialize the output registers of the hash module
+
+       ;.section .text.md5_ip5k_init_digest,"ax",@progbits
+       .section .text
+       .global _md5_ip5k_init_digest
+       .func md5_ip5k_init_digest, _md5_ip5k_init_digest
+
+_md5_ip5k_init_digest:
+       movea an_data_input, D0
+
+       moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
+
+       movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5)
+       movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5)
+
+       move.4 hash_output_0, (an_data_input)4++
+       move.4 hash_output_1, (an_data_input)4++
+       move.4 hash_output_2, (an_data_input)4++
+       move.4 hash_output_3, (an_data_input)4++
+
+       call_return_macro
+       .endfunc
+
+;*****************************************************************************************
+;      void md5_ip5k_transform(u32_t *data_input)
+;              performs intermediate transformation step for the hash calculation
+;
+       ;.sect .text.md5_ip5k_transform,"ax",@progbits
+       .section .text
+       .global _md5_ip5k_transform
+       .func md5_ip5k_transform, _md5_ip5k_transform
+
+_md5_ip5k_transform:
+       movea an_data_input, D0
+
+       moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
+
+       ; Write the first 128bits (16 bytes)
+       move.4 hash_input_0, (an_data_input)4++
+       move.4 hash_input_1, (an_data_input)4++
+       move.4 hash_input_2, (an_data_input)4++
+       move.4 hash_input_3, (an_data_input)4++
+       move.4 hash_input_4, D0
+
+       move.4 hash_input_0, (an_data_input)4++
+       move.4 hash_input_1, (an_data_input)4++
+       move.4 hash_input_2, (an_data_input)4++
+       move.4 hash_input_3, (an_data_input)4++
+       move.4 hash_input_4, D0
+
+       move.4 hash_input_0, (an_data_input)4++
+       move.4 hash_input_1, (an_data_input)4++
+       move.4 hash_input_2, (an_data_input)4++
+       move.4 hash_input_3, (an_data_input)4++
+       move.4 hash_input_4, D0
+
+       move.4 hash_input_0, (an_data_input)4++
+       move.4 hash_input_1, (an_data_input)4++
+       move.4 hash_input_2, (an_data_input)4++
+       move.4 hash_input_3, (an_data_input)4++
+       move.4 hash_input_4, D0
+
+       pipe_flush 0
+
+md5_ip5k_transform_wait:
+       ; wait for the module to calculate the output hash
+       btst hash_status, #0
+       jmpne.f md5_ip5k_transform_wait
+
+       call_return_macro
+       .endfunc
+
+;*****************************************************************************************
+;      void md5_ip5k_get_digest(u32_t *digest)
+;              Return the hash of the input data
+;
+       ;.sect .text.md5_get_digest,"ax",@progbits
+       .section .text
+       .global _md5_ip5k_get_digest
+       .func md5_ip5k_get_digest, _md5_ip5k_get_digest
+
+_md5_ip5k_get_digest:
+       movea an_digest, D0
+
+       moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
+
+       ; we have finished
+       move.4 0(an_digest), hash_output_0
+       move.4 4(an_digest), hash_output_1
+       move.4 8(an_digest), hash_output_2
+       move.4 12(an_digest), hash_output_3
+
+       call_return_macro
+       .endfunc
diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/sha1_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/crypto/sha1_ubicom32.c
new file mode 100644 (file)
index 0000000..2d0c870
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * arch/ubicom32/crypto/sha1_ubicom32.c
+ *   Ubicom32 implementation of the SHA1 Secure Hash Algorithm.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <crypto/sha.h>
+#include <asm/linkage.h>
+
+#include "crypto_ubicom32.h"
+#define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2
+#define HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1 ((1 << 5) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION)
+
+struct ubicom32_sha1_ctx {
+       u64 count;              /* message length */
+       u32 state[5];
+       u8 buf[2 * SHA1_BLOCK_SIZE];
+};
+
+static inline void sha1_clear_2ws(u8 *buf, int wc)
+{
+       asm volatile (
+       "1:     move.4  (%0)4++, #0             \n\t"
+       "       move.4  (%0)4++, #0             \n\t"
+       "       sub.4   %1, #2, %1              \n\t"
+       "       jmple.f 1b                      \n\t"
+               :
+               : "a" (buf), "d" (wc)
+               : "cc"
+       );
+}
+
+/* only wipe out count, state, and 1st half of buf - 9 bytes at most */
+#define sha1_wipe_out(sctx) sha1_clear_2ws((u8 *)sctx, 2 + 5 + 16 - 2)
+
+static inline void sha1_init_digest(u32 *digest)
+{
+       hw_crypto_set_ctrl(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1);
+       asm volatile (
+       "       ; move digests to hash_output regs      \n\t"
+       "       move.4  0x70(%0), 0x0(%1)               \n\t"
+       "       move.4  0x74(%0), 0x4(%1)               \n\t"
+       "       move.4  0x78(%0), 0x8(%1)               \n\t"
+       "       move.4  0x7c(%0), 0xc(%1)               \n\t"
+       "       move.4  0x80(%0), 0x10(%1)              \n\t"
+               :
+               : "a" (SEC_BASE), "a" (digest)
+       );
+}
+
+static inline void sha1_transform_feed(const u8 *in)
+{
+       asm volatile (
+       "       ; write the 1st 16 bytes        \n\t"
+       "       move.4  0x30(%0), 0x0(%1)       \n\t"
+       "       move.4  0x34(%0), 0x4(%1)       \n\t"
+       "       move.4  0x38(%0), 0x8(%1)       \n\t"
+       "       move.4  0x3c(%0), 0xc(%1)       \n\t"
+       "       move.4  0x40(%0), %1            \n\t"
+       "       ; write the 2nd 16 bytes        \n\t"
+       "       move.4  0x30(%0), 0x10(%1)      \n\t"
+       "       move.4  0x34(%0), 0x14(%1)      \n\t"
+       "       move.4  0x38(%0), 0x18(%1)      \n\t"
+       "       move.4  0x3c(%0), 0x1c(%1)      \n\t"
+       "       move.4  0x40(%0), %1            \n\t"
+       "       ; write the 3rd 16 bytes        \n\t"
+       "       move.4  0x30(%0), 0x20(%1)      \n\t"
+       "       move.4  0x34(%0), 0x24(%1)      \n\t"
+       "       move.4  0x38(%0), 0x28(%1)      \n\t"
+       "       move.4  0x3c(%0), 0x2c(%1)      \n\t"
+       "       move.4  0x40(%0), %1            \n\t"
+       "       ; write the 4th 16 bytes        \n\t"
+       "       move.4  0x30(%0), 0x30(%1)      \n\t"
+       "       move.4  0x34(%0), 0x34(%1)      \n\t"
+       "       move.4  0x38(%0), 0x38(%1)      \n\t"
+       "       move.4  0x3c(%0), 0x3c(%1)      \n\t"
+       "       move.4  0x40(%0), %1            \n\t"
+       "       pipe_flush 0                    \n\t"
+               :
+               : "a"(SEC_BASE), "a"(in)
+       );
+}
+
+static inline void sha1_transform_wait(void)
+{
+       asm volatile (
+       "       btst    0x04(%0), #0            \n\t"
+       "       jmpne.f -4                      \n\t"
+               :
+               : "a"(SEC_BASE)
+               : "cc"
+       );
+}
+
+static inline void sha1_output_digest(u32 *digest)
+{
+       asm volatile (
+       "       move.4  0x0(%1), 0x70(%0)               \n\t"
+       "       move.4  0x4(%1), 0x74(%0)               \n\t"
+       "       move.4  0x8(%1), 0x78(%0)               \n\t"
+       "       move.4  0xc(%1), 0x7c(%0)               \n\t"
+       "       move.4  0x10(%1), 0x80(%0)              \n\t"
+               :
+               : "a" (SEC_BASE), "a" (digest)
+       );
+}
+
+static __ocm_text void sha1_init(struct crypto_tfm *tfm)
+{
+       struct ubicom32_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+
+       sctx->state[0] = SHA1_H0;
+       sctx->state[1] = SHA1_H1;
+       sctx->state[2] = SHA1_H2;
+       sctx->state[3] = SHA1_H3;
+       sctx->state[4] = SHA1_H4;
+       sctx->count = 0;
+}
+
+static void __ocm_text sha1_update(struct crypto_tfm *tfm, const u8 *data,
+                       unsigned int len)
+{
+       struct ubicom32_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+       int index, clen;
+
+       /* how much is already in the buffer? */
+       index = sctx->count & 0x3f;
+
+       sctx->count += len;
+
+       if (index + len < SHA1_BLOCK_SIZE) {
+               goto store_only;
+       }
+
+       hw_crypto_lock();
+       hw_crypto_check();
+
+       /* init digest set ctrl register too */
+       sha1_init_digest(sctx->state);
+
+       if (unlikely(index == 0 && SEC_ALIGNED(data))) {
+fast_process:
+#if CRYPTO_UBICOM32_LOOP_ASM
+               if (likely(len >= SHA1_BLOCK_SIZE)) {
+                       register unsigned int cnt = len >> 6;   // loop = len / 64;
+                       sha1_transform_feed(data);
+                       data += SHA1_BLOCK_SIZE;
+
+                       /* cnt is pre-decremented in the loop */
+                       asm volatile (
+                       "; while (--loop):  work on 2nd block   \n\t"
+                       "1:     add.4   %2, #-1, %2             \n\t"
+                       "       jmpeq.f 5f                      \n\t"
+                       "                                       \n\t"
+                       "       ; write the 1st 16 bytes        \n\t"
+                       "       move.4  0x30(%1), (%0)4++       \n\t"
+                       "       move.4  0x34(%1), (%0)4++       \n\t"
+                       "       move.4  0x38(%1), (%0)4++       \n\t"
+                       "       move.4  0x3c(%1), (%0)4++       \n\t"
+                       "       ; can not kick off hw before it \n\t"
+                       "       ; is done with the prev block   \n\t"
+                       "                                       \n\t"
+                       "       btst    0x04(%1), #0            \n\t"
+                       "       jmpne.f -4                      \n\t"
+                       "                                       \n\t"
+                       "       ; tell hw to load 1st 16 bytes  \n\t"
+                       "       move.4  0x40(%1), %2            \n\t"
+                       "                                       \n\t"
+                       "       ; write the 2nd 16 bytes        \n\t"
+                       "       move.4  0x30(%1), (%0)4++       \n\t"
+                       "       move.4  0x34(%1), (%0)4++       \n\t"
+                       "       move.4  0x38(%1), (%0)4++       \n\t"
+                       "       move.4  0x3c(%1), (%0)4++       \n\t"
+                       "       move.4  0x40(%1), %2            \n\t"
+                       "                                       \n\t"
+                       "       ; write the 3rd 16 bytes        \n\t"
+                       "       move.4  0x30(%1), (%0)4++       \n\t"
+                       "       move.4  0x34(%1), (%0)4++       \n\t"
+                       "       move.4  0x38(%1), (%0)4++       \n\t"
+                       "       move.4  0x3c(%1), (%0)4++       \n\t"
+                       "       move.4  0x40(%1), %2            \n\t"
+                       "                                       \n\t"
+                       "       ; write the 4th 16 bytes        \n\t"
+                       "       move.4  0x30(%1), (%0)4++       \n\t"
+                       "       move.4  0x34(%1), (%0)4++       \n\t"
+                       "       move.4  0x38(%1), (%0)4++       \n\t"
+                       "       move.4  0x3c(%1), (%0)4++       \n\t"
+                       "       move.4  0x40(%1), %2            \n\t"
+                       "                                       \n\t"
+                       "; no need flush, enough insts          \n\t"
+                       "; before next hw wait                  \n\t"
+                       "                                       \n\t"
+                       "; go back to loop                      \n\t"
+                       "       jmpt 1b                         \n\t"
+                       "                                       \n\t"
+                       "; wait hw for last block               \n\t"
+                       "5:     btst 0x04(%1), #0               \n\t"
+                       "       jmpne.f -4                      \n\t"
+                       "                                       \n\t"
+                               : "+a" (data)
+                               : "a"( SEC_BASE), "d" (cnt)
+                               : "cc"
+                       );
+
+                       len = len & (64 - 1);
+               }
+#else
+               while (likely(len >= SHA1_BLOCK_SIZE)) {
+                       sha1_transform_feed(data);
+                       data += SHA1_BLOCK_SIZE;
+                       len -= SHA1_BLOCK_SIZE;
+                       sha1_transform_wait();
+               }
+#endif
+               goto store;
+       }
+
+       /* process one stored block */
+       if (index) {
+               clen = SHA1_BLOCK_SIZE - index;
+               memcpy(sctx->buf + index, data, clen);
+               sha1_transform_feed(sctx->buf);
+               data += clen;
+               len -= clen;
+               index = 0;
+               sha1_transform_wait();
+       }
+
+       if (likely(SEC_ALIGNED(data))) {
+               goto fast_process;
+       }
+
+       /* process as many blocks as possible */
+       if (likely(len >= SHA1_BLOCK_SIZE)) {
+               memcpy(sctx->buf, data, SHA1_BLOCK_SIZE);
+               do {
+                       sha1_transform_feed(sctx->buf);
+                       data += SHA1_BLOCK_SIZE;
+                       len -= SHA1_BLOCK_SIZE;
+                       if (likely(len >= SHA1_BLOCK_SIZE)) {
+                               memcpy(sctx->buf, data, SHA1_BLOCK_SIZE);
+                               sha1_transform_wait();
+                               continue;
+                       }
+                       /* it is the last block */
+                       sha1_transform_wait();
+                       break;
+               } while (1);
+       }
+
+store:
+       sha1_output_digest(sctx->state);
+       hw_crypto_unlock();
+
+store_only:
+       /* anything left? */
+       if (len)
+               memcpy(sctx->buf + index , data, len);
+}
+
+/* Add padding and return the message digest. */
+static void __ocm_text sha1_final(struct crypto_tfm *tfm, u8 *out)
+{
+       struct ubicom32_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
+       u64 bits;
+       unsigned int index, end;
+
+       /* must perform manual padding */
+       index = sctx->count & 0x3f;
+       end =  (index < 56) ? SHA1_BLOCK_SIZE : (2 * SHA1_BLOCK_SIZE);
+
+       /* start pad with 1 */
+       sctx->buf[index] = 0x80;
+
+       /* pad with zeros */
+       index++;
+       memset(sctx->buf + index, 0x00, end - index - 8);
+
+       /* append message length */
+       bits = sctx->count << 3 ;
+       SEC_COPY_2W(sctx->buf + end - 8, &bits);
+
+       /* force to use the sctx->buf and ignore the partial buf */
+       sctx->count = sctx->count & ~0x3f;
+       sha1_update(tfm, sctx->buf, end);
+
+       /* copy digest to out */
+       SEC_COPY_5W(out, sctx->state);
+
+       /* wipe context */
+       sha1_wipe_out(sctx);
+}
+
+static struct crypto_alg alg = {
+       .cra_name       =       "sha1",
+       .cra_driver_name=       "sha1-ubicom32",
+       .cra_priority   =       CRYPTO_UBICOM32_PRIORITY,
+       .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
+       .cra_blocksize  =       SHA1_BLOCK_SIZE,
+       .cra_ctxsize    =       sizeof(struct ubicom32_sha1_ctx),
+       .cra_module     =       THIS_MODULE,
+       .cra_list       =       LIST_HEAD_INIT(alg.cra_list),
+       .cra_u    = {
+               .digest = {
+                       .dia_digestsize =       SHA1_DIGEST_SIZE,
+                       .dia_init       =       sha1_init,
+                       .dia_update     =       sha1_update,
+                       .dia_final      =       sha1_final,
+               }
+       }
+};
+
+static int __init init(void)
+{
+       hw_crypto_init();
+       return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+       crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_ALIAS("sha1");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm");
diff --git a/target/linux/ubicom32/files/arch/ubicom32/crypto/sha1_ubicom32_asm.S b/target/linux/ubicom32/files/arch/ubicom32/crypto/sha1_ubicom32_asm.S
new file mode 100644 (file)
index 0000000..f610b7e
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * arch/ubicom32/crypto/sha1_ubicom32_asm.S
+ *     SHA1 hash support for Ubicom32 architecture V3.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#define __ASM__
+#include <asm/ip5000.h>
+
+#ifndef RP
+#define RP A5
+#endif
+
+;*****************************************************************************************
+; The function prototype
+;*****************************************************************************************
+; void sha1_ip5k_init(void)
+; void sha1_ip5k_transform(u32_t *data_input)
+; void sha1_ip5k_output(u32_t *digest)
+
+;*****************************************************************************************
+; Inputs
+;*****************************************************************************************
+; data_input is the pointer to the block of data over which the digest will be calculated.
+;      It should be word aligned.
+;
+; digest is the pointer to the block of data into which the digest (the output) will be written.
+;      It should be word aligned.
+;
+
+;*****************************************************************************************
+; Outputs
+;*****************************************************************************************
+; None
+
+;*****************************************************************************************
+; Hash Constants
+;*****************************************************************************************
+#define HASH_SHA1_IN0 0x67452301
+#define HASH_SHA1_IN1 0xefcdab89
+#define HASH_SHA1_IN2 0x98badcfe
+#define HASH_SHA1_IN3 0x10325476
+#define HASH_SHA1_IN4 0xc3d2e1f0
+
+#define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2
+#define HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1 ((1 << 5) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION)
+
+;*****************************************************************************************
+; An: Address Registers
+;*****************************************************************************************
+#define an_digest a4
+#define an_data_input a4
+#define an_security_block a3
+
+;*****************************************************************************************
+; Hash related defines
+;*****************************************************************************************
+#define hash_control 0x00(an_security_block)
+#define hash_control_low 0x02(an_security_block)
+#define hash_status 0x04(an_security_block)
+
+#define hash_input_0 0x30(an_security_block)
+#define hash_input_1 0x34(an_security_block)
+#define hash_input_2 0x38(an_security_block)
+#define hash_input_3 0x3c(an_security_block)
+#define hash_input_4 0x40(an_security_block)
+
+#define hash_output_0 0x70(an_security_block)
+#define hash_output_0_low 0x72(an_security_block)
+#define hash_output_1 0x74(an_security_block)
+#define hash_output_1_low 0x76(an_security_block)
+#define hash_output_2 0x78(an_security_block)
+#define hash_output_2_low 0x7a(an_security_block)
+#define hash_output_3 0x7c(an_security_block)
+#define hash_output_3_low 0x7e(an_security_block)
+#define hash_output_4 0x80(an_security_block)
+#define hash_output_4_low 0x82(an_security_block)
+
+;*****************************************************************************************
+; Assembly macros
+;*****************************************************************************************
+       ; C compiler reserves RP (A5) for return address during subroutine call.
+       ; Use RP to return to caller
+.macro call_return_macro
+       calli   RP, 0(RP)
+.endm
+
+;*****************************************************************************************
+;      void sha1_ip5k_init(void)
+;              initialize the output registers of the hash module
+
+       ;.section .text.sha1_ip5k_init,"ax",@progbits
+       .section .ocm_text,"ax",@progbits
+       .global _sha1_ip5k_init
+       .func sha1_ip5k_init, _sha1_ip5k_init
+
+_sha1_ip5k_init:
+       moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
+
+       movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1)
+       movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1)
+
+       movei hash_output_0, #%hi(HASH_SHA1_IN0)
+       movei hash_output_0_low, #%lo(HASH_SHA1_IN0)
+
+       movei hash_output_1, #%hi(HASH_SHA1_IN1)
+       movei hash_output_1_low, #%lo(HASH_SHA1_IN1)
+
+       movei hash_output_2, #%hi(HASH_SHA1_IN2)
+       movei hash_output_2_low, #%lo(HASH_SHA1_IN2)
+
+       movei hash_output_3, #%hi(HASH_SHA1_IN3)
+       movei hash_output_3_low, #%lo(HASH_SHA1_IN3)
+
+       movei hash_output_4, #%hi(HASH_SHA1_IN4)
+       movei hash_output_4_low, #%lo(HASH_SHA1_IN4)
+
+       call_return_macro
+       .endfunc
+
+;*****************************************************************************************
+;      void sha1_ip5k_init_digest(u32_t *hash_input)
+;              initialize the output registers of the hash module
+
+       ;.section .text.sha1_ip5k_init_digest,"ax",@progbits
+       .section .ocm_text,"ax",@progbits
+       .global _sha1_ip5k_init_digest
+       .func sha1_ip5k_init_digest, _sha1_ip5k_init_digest
+
+_sha1_ip5k_init_digest:
+       movea an_data_input, D0
+
+       moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
+
+       movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1)
+       movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1)
+
+       move.4 hash_output_0, (an_data_input)4++
+       move.4 hash_output_1, (an_data_input)4++
+       move.4 hash_output_2, (an_data_input)4++
+       move.4 hash_output_3, (an_data_input)4++
+       move.4 hash_output_4, (an_data_input)4++
+
+       call_return_macro
+       .endfunc
+
+;*****************************************************************************************
+;      void sha1_ip5k_transform(u32_t *data_input)
+;              performs intermediate transformation step for the hash calculation
+
+       ;.section .text.sha1_ip5k_transform,"ax",@progbits
+       .section .ocm_text,"ax",@progbits
+       .global _sha1_ip5k_transform
+       .func sha1_ip5k_transform, _sha1_ip5k_transform
+
+_sha1_ip5k_transform:
+       movea an_data_input, D0
+
+       moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
+
+       ; Write the first 128bits (16 bytes)
+       move.4 hash_input_0, (an_data_input)4++
+       move.4 hash_input_1, (an_data_input)4++
+       move.4 hash_input_2, (an_data_input)4++
+       move.4 hash_input_3, (an_data_input)4++
+       move.4 hash_input_4, D0
+
+       move.4 hash_input_0, (an_data_input)4++
+       move.4 hash_input_1, (an_data_input)4++
+       move.4 hash_input_2, (an_data_input)4++
+       move.4 hash_input_3, (an_data_input)4++
+       move.4 hash_input_4, D0
+
+       move.4 hash_input_0, (an_data_input)4++
+       move.4 hash_input_1, (an_data_input)4++
+       move.4 hash_input_2, (an_data_input)4++
+       move.4 hash_input_3, (an_data_input)4++
+       move.4 hash_input_4, D0
+
+       move.4 hash_input_0, (an_data_input)4++
+       move.4 hash_input_1, (an_data_input)4++
+       move.4 hash_input_2, (an_data_input)4++
+       move.4 hash_input_3, (an_data_input)4++
+       move.4 hash_input_4, D0
+
+       pipe_flush 0
+
+sha1_ip5k_transform_wait:
+       ; wait for the module to calculate the output hash
+       btst hash_status, #0
+       jmpne.f sha1_ip5k_transform_wait
+
+       call_return_macro
+       .endfunc
+
+;*****************************************************************************************
+;      void sha1_ip5k_output(u32_t *digest)
+;              Return the hash of the input data
+
+       ;.section .text.sha1_ip5k_output,"ax",@progbits
+       .section .ocm_text,"ax",@progbits
+       .global _sha1_ip5k_output
+       .func sha1_ip5k_output, _sha1_ip5k_output
+
+_sha1_ip5k_output:
+       movea an_digest, D0
+
+       moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
+
+       ; we have finished
+       move.4 0(an_digest), hash_output_0
+       move.4 4(an_digest), hash_output_1
+       move.4 8(an_digest), hash_output_2
+       move.4 12(an_digest), hash_output_3
+       move.4 16(an_digest), hash_output_4
+
+       call_return_macro
+       .endfunc
+
+;*****************************************************************************************
+;END                   ;End of program code
+;*****************************************************************************************
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/.gitignore b/target/linux/ubicom32/files/arch/ubicom32/include/asm/.gitignore
new file mode 100644 (file)
index 0000000..c6b1010
--- /dev/null
@@ -0,0 +1 @@
+/ocm_size.h
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/Kbuild b/target/linux/ubicom32/files/arch/ubicom32/include/asm/Kbuild
new file mode 100644 (file)
index 0000000..c68e168
--- /dev/null
@@ -0,0 +1 @@
+include include/asm-generic/Kbuild.asm
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/a.out.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/a.out.h
new file mode 100644 (file)
index 0000000..8eb0ade
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * arch/ubicom32/include/asm/a.out.h
+ *   Definitions for Ubicom32 a.out executable format.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_A_OUT_H
+#define _ASM_UBICOM32_A_OUT_H
+
+struct exec
+{
+  unsigned long a_info;                /* Use macros N_MAGIC, etc for access */
+  unsigned a_text;             /* length of text, in bytes */
+  unsigned a_data;             /* length of data, in bytes */
+  unsigned a_bss;              /* length of uninitialized data area for file, in bytes */
+  unsigned a_syms;             /* length of symbol table data in file, in bytes */
+  unsigned a_entry;            /* start address */
+  unsigned a_trsize;           /* length of relocation info for text, in bytes */
+  unsigned a_drsize;           /* length of relocation info for data, in bytes */
+};
+
+#define N_TRSIZE(a)    ((a).a_trsize)
+#define N_DRSIZE(a)    ((a).a_drsize)
+#define N_SYMSIZE(a)   ((a).a_syms)
+
+#endif /* _ASM_UBICOM32_A_OUT_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/atomic.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/atomic.h
new file mode 100644 (file)
index 0000000..78d9fcd
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * arch/ubicom32/include/asm/atomic.h
+ *   Atomic operations definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_ATOMIC_H
+#define _ASM_UBICOM32_ATOMIC_H
+
+#include <asm/system.h>
+#include <asm/ubicom32-common.h>
+#include <asm/types.h>
+
+/*
+ * Most instructions on the Ubicom32 processor are atomic in that they
+ * execute in one clock cycle.  However, Linux has several operations
+ * (e.g. compare and swap) which will require more than a single instruction
+ * to perform.   To achieve this, the Ubicom32 processor uses a single
+ * global bit in a scratchpad register as a critical section lock. All
+ * atomic operations acquire this lock.
+ *
+ * NOTE: To AVOID DEADLOCK(s), the atomic lock must only be used for atomic
+ * operations or by the ldsr to avoid disabling a thread performing an atomic
+ * operation.
+ *
+ * Do not attempt to disable interrupts while holding the atomic operations
+ * lock or you will DEADLOCK the system.
+ */
+
+#define ATOMIC_INIT(i) { (i) }
+
+/*
+ * __atomic_add()
+ *     Add i to v and return the result.
+ */
+static inline void __atomic_add(int i, atomic_t *v)
+{
+       atomic_t *vt = v;
+
+       __atomic_lock_acquire();
+       vt->counter += i;
+       __atomic_lock_release();
+}
+
+/*
+ * __atomic_sub()
+ *     Subtract i from v and return the result.
+ */
+static inline void __atomic_sub(int i, atomic_t *v)
+{
+       atomic_t *vt = v;
+
+       __atomic_lock_acquire();
+       vt->counter -= i;
+       __atomic_lock_release();
+}
+
+/*
+ * __atomic_add_return()
+ *     Add i to v and return the result.
+ *
+ * The implementation here looks rather odd because we appear to be doing
+ * the addition twice.  In fact that's exactly what we're doing but with
+ * the ubicom32 instruction set we can do the inner load and add with two
+ * instructions whereas generating both the atomic result and the "ret"
+ * result requires three instructions.  The second add is generally only as
+ * costly as a move instruction and in cases where we compare the result
+ * with a constant the compiler can fold two constant values and do a
+ * single instruction, thus saving an instruction overall!
+ *
+ * At the worst we save one instruction inside the atomic lock.
+ */
+static inline int __atomic_add_return(int i, atomic_t *v)
+{
+       int ret;
+       atomic_t *vt = v;
+
+       __atomic_lock_acquire();
+       ret = vt->counter;
+       vt->counter = ret + i;
+       __atomic_lock_release();
+
+       return ret + i;
+}
+
+/*
+ * __atomic_sub_return()
+ *     Subtract i from v and return the result.
+ *
+ * The implementation here looks rather odd because we appear to be doing
+ * the subtraction twice.  In fact that's exactly what we're doing but with
+ * the ubicom32 instruction set we can do the inner load and sub with two
+ * instructions whereas generating both the atomic result and the "ret"
+ * result requires three instructions.  The second sub is generally only as
+ * costly as a move instruction and in cases where we compare the result
+ * with a constant the compiler can fold two constant values and do a
+ * single instruction, thus saving an instruction overall!
+ *
+ * At the worst we save one instruction inside the atomic lock.
+ */
+static inline int __atomic_sub_return(int i, atomic_t *v)
+{
+       int ret;
+       atomic_t *vt = v;
+
+       __atomic_lock_acquire();
+       ret = vt->counter;
+       vt->counter = ret - i;
+       __atomic_lock_release();
+
+       return ret - i;
+}
+
+/*
+ * PUBLIC API FOR ATOMIC!
+ */
+#define atomic_add(i,v)        (__atomic_add( ((int)i),(v)))
+#define atomic_sub(i,v)        (__atomic_sub( ((int)i),(v)))
+#define atomic_inc(v)  (__atomic_add(   1,(v)))
+#define atomic_dec(v)  (__atomic_sub(   1,(v)))
+#define atomic_add_return(i,v) (__atomic_add_return( ((int)i),(v)))
+#define atomic_sub_return(i,v) (__atomic_sub_return( ((int)i),(v)))
+#define atomic_inc_return(v)   (__atomic_add_return(   1,(v)))
+#define atomic_dec_return(v)   (__atomic_sub_return(   1,(v)))
+#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
+#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
+#define atomic_add_negative(a, v)      (atomic_add_return((a), (v)) < 0)
+#define atomic_sub_and_test(i,v)       (atomic_sub_return((i),(v)) == 0)
+
+/*
+ * atomic_read()
+ *     Acquire the atomic lock and read the variable.
+ */
+static inline int atomic_read(const atomic_t *v)
+{
+       int ret;
+       const atomic_t *vt = v;
+
+       __atomic_lock_acquire();
+       ret = vt->counter;
+       __atomic_lock_release();
+
+       return ret;
+}
+
+/*
+ * atomic_set()
+ *     Acquire the atomic lock and set the variable.
+ */
+static inline void atomic_set(atomic_t *v, int i)
+{
+       atomic_t *vt = v;
+
+       __atomic_lock_acquire();
+       vt->counter = i;
+       __atomic_lock_release();
+}
+
+/*
+ * atomic_cmpxchg
+ *     Acquire the atomic lock and exchange if current == old.
+ */
+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
+{
+       int prev;
+       atomic_t *vt = v;
+
+       __atomic_lock_acquire();
+       prev = vt->counter;
+       if (prev == old) {
+               vt->counter = new;
+       }
+       __atomic_lock_release();
+
+       return prev;
+}
+
+/*
+ * atomic_xchg()
+ *     Acquire the atomic lock and exchange values.
+ */
+static inline int atomic_xchg(atomic_t *v, int new)
+{
+       int prev;
+       atomic_t *vt = v;
+
+       __atomic_lock_acquire();
+       prev = vt->counter;
+       vt->counter = new;
+       __atomic_lock_release();
+
+       return prev;
+}
+
+/*
+ * atomic_add_unless()
+ *     Acquire the atomic lock and add a unless the value is u.
+ */
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+       int prev;
+       atomic_t *vt = v;
+
+       __atomic_lock_acquire();
+       prev = vt->counter;
+       if (prev != u) {
+               vt->counter += a;
+               __atomic_lock_release();
+               return 1;
+       }
+
+       __atomic_lock_release();
+       return 0;
+}
+
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+#include <asm-generic/atomic.h>
+
+/*
+ * The following is not a real function.  The compiler should remove the function
+ * call as long as the user does not pass in a size that __xchg and __cmpxchg
+ * are not prepared for.  If the user does pass in an unknown size, the user
+ * will get a link time error.
+ *
+ * The no return is to prevent a compiler error that can occur when dealing with
+ * uninitialized variables. Given that the function doesn't exist there is no
+ * net effect (and if it did it would not return).
+ */
+extern void __xchg_called_with_bad_pointer(void) __attribute__((noreturn));
+
+/*
+ * __xchg()
+ *     Xchange *ptr for x atomically.
+ *
+ * Must be both locally atomic and atomic on SMP. Ubicom32 does not have an
+ * atomic exchange instruction so we use the global atomic_lock.
+ */
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
+{
+       unsigned long ret;
+
+       __atomic_lock_acquire();
+
+       switch (size) {
+       case 1:
+               ret = *(volatile unsigned char *)ptr;
+               *(volatile unsigned char *)ptr = x;
+               break;
+
+       case 2:
+               ret = *(volatile unsigned short *)ptr;
+               *(volatile unsigned short *)ptr = x;
+               break;
+
+       case 4:
+               ret = *(volatile unsigned int *)ptr;
+               *(volatile unsigned int *)ptr = x;
+               break;
+
+       default:
+               __xchg_called_with_bad_pointer();
+               break;
+       }
+       __atomic_lock_release();
+       return ret;
+}
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+/*
+ * __cmpxchg()
+ *     Compare and Xchange *ptr for x atomically.
+ *
+ * Must be both locally atomic and atomic on SMP. Ubicom32 does not have an
+ * atomic exchange instruction so we use the global atomic_lock.
+ */
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long next, int size)
+{
+       unsigned long prev;
+
+       __atomic_lock_acquire();
+       switch (size) {
+       case 1:
+               prev = *(u8 *)ptr;
+               if (prev == old) {
+                       *(u8 *)ptr = (u8)next;
+               }
+               break;
+
+       case 2:
+               prev = *(u16 *)ptr;
+               if (prev == old) {
+                       *(u16 *)ptr = (u16)next;
+               }
+               break;
+
+       case 4:
+               prev = *(u32 *)ptr;
+               if (prev == old) {
+                       *(u32 *)ptr = (u32)next;
+               }
+               break;
+
+       default:
+               __xchg_called_with_bad_pointer();
+               break;
+       }
+       __atomic_lock_release();
+       return prev;
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define cmpxchg_local(ptr, o, n) \
+       ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), (unsigned long)(n), sizeof(*(ptr))))
+
+#define cmpxchg(ptr, o, n) __cmpxchg((ptr), (o), (n), sizeof(*(ptr)))
+
+#define smp_mb__before_atomic_inc() asm volatile ("" : : : "memory")
+#define smp_mb__after_atomic_inc() asm volatile ("" : : : "memory")
+#define smp_mb__before_atomic_dec() asm volatile ("" : : : "memory")
+#define smp_mb__after_atomic_dec() asm volatile ("" : : : "memory")
+
+#endif /* _ASM_UBICOM32_ATOMIC_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/audio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/audio.h
new file mode 100644 (file)
index 0000000..974d0cd
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * arch/ubicom32/include/asm/audio.h
+ *     Audio include file
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _AUDIO_H
+#define _AUDIO_H
+
+#include <asm/devtree.h>
+#include <asm/audionode.h>
+
+/*
+ * Resource indices used to access IRQs via platform_get_resource
+ */
+#define AUDIO_MEM_RESOURCE     0
+#define AUDIO_TX_IRQ_RESOURCE  0
+#define AUDIO_RX_IRQ_RESOURCE  1
+
+extern struct platform_device * __init audio_device_alloc(const char *driver_name, const char *node_name, const char *inst_name, int priv_size);
+
+#define audio_device_priv(pdev) (((struct ubi32pcm_platform_data *)(((struct platform_device *)(pdev))->dev.platform_data))->priv_data)
+#endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/audionode.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/audionode.h
new file mode 100644 (file)
index 0000000..f18a0e8
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * audionode.h
+ *     audionode and DMA descriptors
+ *
+ * Copyright \81© 2009 Ubicom Inc. <www.ubicom.com>.  All rights reserved.
+ *
+ * This file contains confidential information of Ubicom, Inc. and your use of
+ * this file is subject to the Ubicom Software License Agreement distributed with
+ * this file. If you are uncertain whether you are an authorized user or to report
+ * any unauthorized use, please contact Ubicom, Inc. at +1-408-789-2200.
+ * Unauthorized reproduction or distribution of this file is subject to civil and
+ * criminal penalties.
+ *
+ */
+#ifndef _AUDIONODE_H_
+#define _AUDIONODE_H_
+
+#define AUDIO_INT_FLAG_MORE_SAMPLES 0x00000001
+#define AUDIO_INT_FLAG_COMMAND      0x00000002
+
+/*
+ * Commands the Primary OS sends to the audio device
+ */
+enum audio_command {
+       AUDIO_CMD_NONE,
+       AUDIO_CMD_START,
+       AUDIO_CMD_STOP,
+       AUDIO_CMD_PAUSE,
+       AUDIO_CMD_RESUME,
+       AUDIO_CMD_MUTE,
+       AUDIO_CMD_UNMUTE,
+       AUDIO_CMD_SETUP,
+       AUDIO_CMD_ENABLE,
+       AUDIO_CMD_DISABLE,
+};
+
+/*
+ * Flag bits passed in the registers
+ */
+#define CMD_START_FLAG_LE              (1 << 0)        /* Use Little Endian Mode */
+
+/*
+ * Status bits that audio device can set to indicate reason
+ * for interrupting the Primary OS
+ */
+#define AUDIO_STATUS_PLAY_DMA0_REQUEST (1 << 0) /* Audio device needs samples in DMA0 for playback */
+#define AUDIO_STATUS_PLAY_DMA1_REQUEST (1 << 1) /* Audio device needs samples in DMA1 for playback */
+
+struct audio_dma {
+       /*
+        * NOTE: The active flag shall only be SET by the producer and CLEARED
+        * by the consumer, NEVER the other way around.  For playback, the
+        * Primary OS sets this flag and ipAudio clears it.
+        *
+        * The producer shall not modify the ptr or ctr fields when the transfer
+        * is marked as active, as these are used by the consumer to do the
+        * transfer.
+        */
+       volatile u32_t active;          /* Nonzero if data in ptr/ctr ready to be transferred */
+       volatile void *ptr;             /* Pointer to data to be transferred */
+       volatile u32_t ctr;             /* Counter: number of data units to transfer */
+};
+
+#define AUDIONODE_CAP_BE       (1 << 0)
+#define AUDIONODE_CAP_LE       (1 << 1)
+
+#define AUDIONODE_VERSION      7
+struct audio_node {
+       struct devtree_node dn;
+
+       /*
+        * Version of this node
+        */
+       u32_t                   version;
+
+       /*
+        * Pointer to the registers
+        */
+       struct audio_regs       *regs;
+};
+
+/*
+ * [OCM] Audio registers
+ *     Registers exposed as part of our MMIO area
+ */
+#define AUDIO_REGS_VERSION     7
+struct audio_regs {
+       /*
+        * Version of this register set
+        */
+       u32_t version;
+
+       /*
+        * Interrupt status
+        */
+       volatile u32_t int_status;
+
+       /*
+        * Interrupt request
+        */
+       volatile u32_t int_req;
+
+       /*
+        * Current IRQ being serviced
+        */
+       u32_t cur_irq;
+
+       /*
+        * Maximum number of devices supported
+        */
+       u32_t max_devs;
+
+       /*
+        * [DDR] Device registers for each of the devices
+        */
+       struct audio_dev_regs *adr;
+};
+
+#define AUDIO_DEV_REGS_VERSION 2
+struct audio_dev_regs {
+       u32_t version;                                  /* Version of this register set */
+
+       u8_t name[32];                                  /* Name of this driver */
+       u32_t caps;                                     /* Capabilities of this driver */
+       const u32_t *sample_rates;                      /* Sample Rates supported by this driver */
+       u32_t n_sample_rates;                           /* Number of sample rates supported by this driver */
+       u32_t channel_mask;                             /* A bit set in a particular position means we support this channel configuration */
+       volatile u32_t int_flags;                       /* Reason for interrupting audio device */
+       volatile enum audio_command command;    /* Command from Primary OS */
+       volatile u32_t flags;                           /* Flag bits for this command */
+       volatile u32_t channels;                        /* Number of channels */
+       volatile u32_t sample_rate;                     /* Sample rate */
+       volatile u32_t status;                          /* Status bits sent from ipAudio to Primary OS */
+       void *primary_os_buffer_ptr;                    /*
+                                                        * Playback: Pointer to next sample to be removed from
+                                                        *           Primary OS sample buffer
+                                                        * Capture: Pointer to where next sample will be inserted
+                                                        *          into Primary OS sample buffer
+                                                        */
+
+       /*
+        * These are the transfer requests.  They are used in alternating
+        * order so that when ipAudio is processing one request, the
+        * Primary OS can fill in the other one.
+        *
+        * NOTE: The active bit shall always be SET by the producer and
+        * CLEARED by the consumer, NEVER the other way around.
+        */
+       struct audio_dma dma_xfer_requests[2];
+};
+
+#endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/auxvec.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/auxvec.h
new file mode 100644 (file)
index 0000000..b2275c8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * arch/ubicom32/include/asm/auxvec.h
+ *   Symbolic values for the entries in the auxiliary table
+ *   put on the initial stack.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_AUXVEC_H
+#define _ASM_UBICOM32_AUXVEC_H
+
+#endif /* _ASM_UBICOM32_AUXVEC_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/bitops.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bitops.h
new file mode 100644 (file)
index 0000000..c63837b
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * arch/ubicom32/include/asm/bitops.h
+ *   Bit manipulation definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_BITOPS_H
+#define _ASM_UBICOM32_BITOPS_H
+
+/*
+ * Copyright 1992, Linus Torvalds.
+ */
+
+#include <linux/compiler.h>
+#include <asm/byteorder.h>     /* swab32 */
+
+#ifdef __KERNEL__
+
+#ifndef _LINUX_BITOPS_H
+#error only <linux/bitops.h> can be included directly
+#endif
+
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/__ffs.h>
+
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/ffz.h>
+
+#include <asm/ubicom32-common.h>
+
+static inline void set_bit(int bit, volatile unsigned long *p)
+{
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __atomic_lock_acquire();
+       *p |= mask;
+       __atomic_lock_release();
+}
+
+static inline void clear_bit(int bit, volatile unsigned long *p)
+{
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __atomic_lock_acquire();
+       *p &= ~mask;
+       __atomic_lock_release();
+}
+
+/*
+ * clear_bit() doesn't provide any barrier for the compiler.
+ */
+#define smp_mb__before_clear_bit()     barrier()
+#define smp_mb__after_clear_bit()      barrier()
+
+static inline void change_bit(int bit, volatile unsigned long *p)
+{
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __atomic_lock_acquire();
+       *p ^= mask;
+       __atomic_lock_release();
+}
+
+static inline int test_and_set_bit(int bit, volatile unsigned long *p)
+{
+       unsigned int res;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __atomic_lock_acquire();
+       res = *p;
+       *p = res | mask;
+       __atomic_lock_release();
+
+       return res & mask;
+}
+
+static inline int test_and_clear_bit(int bit, volatile unsigned long *p)
+{
+       unsigned int res;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __atomic_lock_acquire();
+       res = *p;
+       *p = res & ~mask;
+       __atomic_lock_release();
+
+       return res & mask;
+}
+
+static inline int test_and_change_bit(int bit, volatile unsigned long *p)
+{
+       unsigned int res;
+       unsigned long mask = 1UL << (bit & 31);
+
+       p += bit >> 5;
+
+       __atomic_lock_acquire();
+       res = *p;
+       *p = res ^ mask;
+       __atomic_lock_release();
+
+       return res & mask;
+}
+
+#include <asm-generic/bitops/non-atomic.h>
+
+/*
+ * This routine doesn't need to be atomic.
+ */
+static inline int __constant_test_bit(int nr, const volatile unsigned long *addr)
+{
+       return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
+}
+
+static inline int __test_bit(int nr, const volatile unsigned long *addr)
+{
+       int     * a = (int *) addr;
+       int     mask;
+
+       a += nr >> 5;
+       mask = 1 << (nr & 0x1f);
+       return ((mask & *a) != 0);
+}
+
+#define test_bit(nr,addr) (__builtin_constant_p(nr) ?  __constant_test_bit((nr),(addr)) :  __test_bit((nr),(addr)))
+
+#include <asm-generic/bitops/find.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/lock.h>
+
+#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+#include <asm-generic/bitops/minix.h>
+
+#endif /* __KERNEL__ */
+
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+
+#endif /* _ASM_UBICOM32_BITOPS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/board.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/board.h
new file mode 100644 (file)
index 0000000..9df4c0f
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * arch/ubicom32/include/asm/board.h
+ *   Board init and revision definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_BOARD_H
+#define _ASM_UBICOM32_BOARD_H
+
+extern const char *board_get_revision(void);
+extern void __init board_init(void);
+
+#endif /* _ASM_UBICOM32_BOARD_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/bootargs.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bootargs.h
new file mode 100644 (file)
index 0000000..95ec393
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * arch/ubicom32/include/asm/bootargs.h
+ *   Kernel command line via the devtree API.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_BOOTARGS_H
+#define _ASM_UBICOM32_BOOTARGS_H
+
+extern const char *bootargs_get_cmdline(void);
+extern void __init bootargs_init(void);
+
+#endif /* _ASM_UBICOM32_BOOTARGS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/bootinfo.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bootinfo.h
new file mode 100644 (file)
index 0000000..7965391
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * arch/ubicom32/include/asm/bootinfo.h
+ *   Definitions of firmware boot parameters passed to the kernel.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_BOOTINFO_H
+#define _ASM_UBICOM32_BOOTINFO_H
+
+/* Nothing for ubicom32 */
+
+#endif /* _ASM_UBICOM32_BOOTINFO_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/bug.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bug.h
new file mode 100644 (file)
index 0000000..b6a000d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * arch/ubicom32/include/asm/bug.h
+ *   Generic bug.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_BUG_H
+#define _ASM_UBICOM32_BUG_H
+
+#include <linux/kernel.h>
+#include <asm/thread.h>
+
+#if defined(CONFIG_BUG) && defined(CONFIG_STOP_ON_BUG)
+
+/*
+ * BUG()
+ *     Ubicom specific version of the BUG() macro.
+ *
+ * This implementation performs a THREAD_STALL stopping all threads before
+ * calling panic.  This enables a developer to see the "real" state of the
+ * machine (since panic alters the system state).  We do the printf first
+ * because while it is slow, it does not alter system state (like
+ * interrupts).
+ *
+ * TODO: Implement the trap sequence used by other architectures.
+ */
+#define BUG() do { \
+       printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
+       THREAD_STALL; \
+       panic("BUG!"); \
+} while (0)
+
+
+/*
+ * __WARN()
+ *     WARN() using printk() for now.
+ *
+ * TODO: Implement the trap sequence used by other architectures.
+ */
+#define __WARN()                                                       \
+       do {                                                            \
+               printk("WARN: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
+       } while(0)
+
+/*
+ * WARN_ON()
+ *     Ubicom specific version of the WARN_ON macro.
+ *
+ * This implementation performs a printk for the WARN_ON() instead
+ * of faulting into the kernel and using report_bug().
+ *
+ * TODO: Implement the trap sequence used by other architectures.
+ */
+#define WARN_ON(x) ({                                          \
+       int __ret_warn_on = !!(x);                              \
+       if (__builtin_constant_p(__ret_warn_on)) {              \
+               if (__ret_warn_on)                              \
+                       __WARN();                               \
+       } else {                                                \
+               if (unlikely(__ret_warn_on))                    \
+                       __WARN();                               \
+       }                                                       \
+       unlikely(__ret_warn_on);                                \
+})
+
+
+#define HAVE_ARCH_BUG
+#define HAVE_ARCH_WARN_ON
+
+#endif
+
+#include <asm-generic/bug.h>
+
+#endif /* _ASM_UBICOM32_BUG_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/bugs.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/bugs.h
new file mode 100644 (file)
index 0000000..66adfe7
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * arch/ubicom32/include/asm/bugs.h
+ *   Definition of check_bugs() for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 1994  Linus Torvalds
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+/*
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ *     void check_bugs(void);
+ */
+
+#ifndef _ASM_UBICOM32_BUGS_H
+#define _ASM_UBICOM32_BUGS_H
+
+static void check_bugs(void)
+{
+}
+
+#endif /* _ASM_UBICOM32_BUGS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/byteorder.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/byteorder.h
new file mode 100644 (file)
index 0000000..e4cd7c9
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/byteorder.h
+ *   Byte order swapping utility routines.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_BYTEORDER_H
+#define _ASM_UBICOM32_BYTEORDER_H
+
+#include <linux/byteorder/big_endian.h>
+
+#endif /* _ASM_UBICOM32_BYTEORDER_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/cache.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cache.h
new file mode 100644 (file)
index 0000000..5fcd36d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * arch/ubicom32/include/asm/cache.h
+ *   Cache line definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_CACHE_H
+#define _ASM_UBICOM32_CACHE_H
+
+/*
+ * bytes per L1 cache line
+ */
+#define L1_CACHE_SHIFT  5
+#define L1_CACHE_BYTES  (1 << L1_CACHE_SHIFT)
+
+#define __cacheline_aligned
+#define ____cacheline_aligned
+
+#endif /* _ASM_UBICOM32_CACHE_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/cachectl.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cachectl.h
new file mode 100644 (file)
index 0000000..12a9159
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * arch/ubicom32/include/asm/cachectl.h
+ *   Ubicom32 cache control definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_CACHECTL_H
+#define _ASM_UBICOM32_CACHECTL_H
+
+#include <asm/ip5000.h>
+
+/*
+ * mem_cache_control()
+ *     Special cache control operation
+ */
+extern void mem_cache_control(unsigned long cc, unsigned long begin_addr, unsigned long end_addr, unsigned long op);
+
+#endif /* _ASM_UBICOM32_CACHECTL_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/cacheflush.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cacheflush.h
new file mode 100644 (file)
index 0000000..10a8141
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * arch/ubicom32/include/asm/cacheflush.h
+ *   Cache flushing definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_CACHEFLUSH_H
+#define _ASM_UBICOM32_CACHEFLUSH_H
+
+/*
+ * (C) Copyright 2000-2004, Greg Ungerer <gerg@snapgear.com>
+ */
+#include <linux/mm.h>
+#include <asm/cachectl.h>
+#include <asm/ip5000.h>
+
+#define flush_cache_all()                      __flush_cache_all()
+#define flush_cache_mm(mm)                     do { } while (0)
+#define flush_cache_dup_mm(mm)                 do { } while (0)
+#define flush_cache_range(vma, start, end)     __flush_cache_all()
+#define flush_cache_page(vma, vmaddr)          do { } while (0)
+#define flush_dcache_page(page)                        do { } while (0)
+#define flush_dcache_mmap_lock(mapping)                do { } while (0)
+#define flush_dcache_mmap_unlock(mapping)      do { } while (0)
+
+#define flush_dcache_range(start, end)                                 \
+do {                                                                   \
+       /* Flush the data cache and invalidate the I cache. */          \
+       mem_cache_control(DCCR_BASE, start, end, CCR_CTRL_FLUSH_ADDR);  \
+       mem_cache_control(ICCR_BASE, start, end, CCR_CTRL_INV_ADDR);    \
+} while (0)
+
+#define flush_icache_range(start, end)                                 \
+do {                                                                   \
+       /* Flush the data cache and invalidate the I cache. */          \
+       mem_cache_control(DCCR_BASE, start, end, CCR_CTRL_FLUSH_ADDR);  \
+       mem_cache_control(ICCR_BASE, start, end, CCR_CTRL_INV_ADDR);    \
+} while (0)
+
+#define flush_icache_page(vma,pg)              do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)        do { } while (0)
+#define flush_cache_vmap(start, end)           do { } while (0)
+#define flush_cache_vunmap(start, end)         do { } while (0)
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+       memcpy(dst, src, len)
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+       memcpy(dst, src, len)
+
+/*
+ * Cache handling for IP5000
+ */
+extern inline void mem_cache_invalidate_all(unsigned long cc)
+{
+       if (cc == DCCR_BASE)
+               UBICOM32_LOCK(DCCR_LOCK_BIT);
+       else
+               UBICOM32_LOCK(ICCR_LOCK_BIT);
+
+       asm volatile (
+       "       bset    "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_RESET)"      \n\t"
+       "       nop                                                                     \n\t"
+       "       bclr    "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_RESET)"      \n\t"
+       "       pipe_flush 0                                                            \n\t"
+               :
+               : "a"(cc)
+               : "cc"
+       );
+
+       if (cc == DCCR_BASE)
+               UBICOM32_UNLOCK(DCCR_LOCK_BIT);
+       else
+               UBICOM32_UNLOCK(ICCR_LOCK_BIT);
+
+}
+
+static inline void __flush_cache_all(void)
+{
+       /*
+        * Flush Icache
+        */
+       mem_cache_invalidate_all(ICCR_BASE);
+
+       /*
+        * Flush Dcache
+        */
+       mem_cache_invalidate_all(DCCR_BASE);
+}
+
+#endif /* _ASM_UBICOM32_CACHEFLUSH_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/checksum.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/checksum.h
new file mode 100644 (file)
index 0000000..25f8ca6
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * arch/ubicom32/include/asm/checksum.h
+ *   Checksum utilities for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_CHECKSUM_H
+#define _ASM_UBICOM32_CHECKSUM_H
+
+#include <linux/in6.h>
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+__wsum csum_partial(const void *buff, int len, __wsum sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+__wsum csum_partial_copy_nocheck(const void *src, void *dst,
+       int len, __wsum sum);
+
+
+/*
+ * the same as csum_partial_copy, but copies from user space.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+extern __wsum csum_partial_copy_from_user(const void __user *src,
+       void *dst, int len, __wsum sum, int *csum_err);
+
+__sum16 ip_fast_csum(const void *iph, unsigned int ihl);
+
+/*
+ *     Fold a partial checksum
+ */
+
+static inline __sum16 csum_fold(__wsum sum)
+{
+       asm volatile (
+       "       lsr.4   d15, %0, #16    \n\t"
+       "       bfextu  %0, %0, #16     \n\t"
+       "       add.4   %0, d15, %0     \n\t"
+       "       lsr.4   d15, %0, #16    \n\t"
+       "       bfextu  %0, %0, #16     \n\t"
+       "       add.4   %0, d15, %0     \n\t"
+               : "=&d" (sum)
+               : "0"(sum)
+               : "d15"
+       );
+       return (__force __sum16)~sum;
+}
+
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+
+static inline __wsum
+csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
+                 unsigned short proto, __wsum sum)
+{
+       asm volatile (
+       "       add.4   %0, %2, %0      \n\t"
+       "       addc    %0, %3, %0      \n\t"
+       "       addc    %0, %4, %0      \n\t"
+       "       addc    %0, %5, %0      \n\t"
+       "       addc    %0, #0, %0      \n\t"
+               : "=&d" (sum)
+               : "0"(sum), "r" (saddr), "r" (daddr), "r" (len), "r"(proto)
+       );
+       return sum;
+}
+
+static inline __sum16
+csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,
+                 unsigned short proto, __wsum 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
+ */
+extern __sum16 ip_compute_csum(const void *buff, int len);
+
+#define _HAVE_ARCH_IPV6_CSUM
+
+static __inline__ __sum16
+csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,
+               __u32 len, unsigned short proto, __wsum sum)
+{
+       asm volatile (
+       "       add.4   %0, 0(%2), %0   \n\t"
+       "       addc    %0, 4(%2), %0   \n\t"
+       "       addc    %0, 8(%2), %0   \n\t"
+       "       addc    %0, 12(%2), %0  \n\t"
+       "       addc    %0, 0(%3), %0   \n\t"
+       "       addc    %0, 4(%3), %0   \n\t"
+       "       addc    %0, 8(%3), %0   \n\t"
+       "       addc    %0, 12(%3), %0  \n\t"
+       "       addc    %0, %4, %0      \n\t"
+       "       addc    %0, #0, %0      \n\t"
+               : "=&d" (sum)
+               : "0" (sum), "a" (saddr), "a" (daddr), "d" (len + proto)
+       );
+       return csum_fold(sum);
+}
+
+#endif /* _ASM_UBICOM32_CHECKSUM_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/cpu.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cpu.h
new file mode 100644 (file)
index 0000000..c713b62
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * arch/ubicom32/include/asm/cpu.h
+ *   CPU definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 2004-2005 ARM Ltd.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_CPU_H
+#define _ASM_UBICOM32_CPU_H
+
+#include <linux/percpu.h>
+
+struct cpuinfo_ubicom32 {
+       unsigned long tid;                      /* Hardware thread number */
+
+#ifdef CONFIG_SMP
+       volatile unsigned long ipi_pending;     /* Bit map of operations to execute */
+       unsigned long ipi_count;                /* Number of IPI(s) taken on this cpu */
+#endif
+};
+
+DECLARE_PER_CPU(struct cpuinfo_ubicom32, cpu_data);
+
+#endif /* _ASM_UBICOM32_CPU_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/cputime.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/cputime.h
new file mode 100644 (file)
index 0000000..c794443
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/cputime.h
+ *   Generic cputime.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_CPUTIME_H
+#define _ASM_UBICOM32_CPUTIME_H
+
+#include <asm-generic/cputime.h>
+
+#endif /* _ASM_UBICOM32_CPUTIME_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/current.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/current.h
new file mode 100644 (file)
index 0000000..2d549bb
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * arch/ubicom32/include/asm/current.h
+ *   Definition of get_current() for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * (C) Copyright 2000, Lineo, David McCullough <davidm@uclinux.org>
+ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_CURRENT_H
+#define _ASM_UBICOM32_CURRENT_H
+
+#include <linux/thread_info.h>
+
+struct task_struct;
+
+static inline struct task_struct *get_current(void)
+{
+       return(current_thread_info()->task);
+}
+
+#define        current get_current()
+
+#endif /* _ASM_UBICOM32_CURRENT_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/delay.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/delay.h
new file mode 100644 (file)
index 0000000..0e5025c
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * arch/ubicom32/include/asm/delay.h
+ *   Definition of delay routines for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_DELAY_H
+#define _ASM_UBICOM32_DELAY_H
+
+#include <asm/param.h>
+#include <asm/ip5000.h>
+
+static inline void __delay(unsigned long loops)
+{
+       if (loops == 0) {
+               return;
+       }
+
+       asm volatile (
+       "1:     add.4   %0, #-1, %0             \n\t"
+       "       jmpne.t 1b                      \n\t"
+       : "+d" (loops)
+       );
+}
+
+/*
+ *     Ubicom32 processor uses fixed 12MHz external OSC.
+ *     So we use that as reference to count 12 cycles/us
+ */
+
+extern unsigned long loops_per_jiffy;
+
+static inline void _udelay(unsigned long usecs)
+{
+#if defined(CONFIG_UBICOM32_V4) || defined(CONFIG_UBICOM32_V3)
+       asm volatile (
+               "       add.4           d15, 0(%0), %1                  \n\t"
+               "       sub.4           #0, 0(%0), d15                  \n\t"
+               "       jmpmi.w.f       .-4                             \n\t"
+               :
+               : "a"(TIMER_BASE + TIMER_MPTVAL), "d"(usecs * (12000000/1000000))
+               : "d15"
+       );
+#else
+       BUG();
+#endif
+}
+
+/*
+ *     Moved the udelay() function into library code, no longer inlined.
+ */
+extern void udelay(unsigned long usecs);
+
+#endif /* _ASM_UBICOM32_DELAY_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/device.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/device.h
new file mode 100644 (file)
index 0000000..53de082
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * arch/ubicom32/include/asm/device.h
+ *   Generic device.h for Ubicom32 architecture.
+ *
+ *   Used for arch specific extensions to struct device
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_DEVICE_H
+#define _ASM_UBICOM32_DEVICE_H
+
+#include <asm-generic/device.h>
+
+#endif /* _ASM_UBICOM32_DEVICE_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/devtree.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/devtree.h
new file mode 100644 (file)
index 0000000..3380c2b
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * arch/ubicom32/include/asm/devtree.h
+ *   Device Tree Header File (Shared between ultra and the Host OS)
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_DEVTREE_H
+#define _ASM_UBICOM32_DEVTREE_H
+
+#define DEVTREE_MAX_NAME 32
+#define DEVTREE_IRQ_NONE 0xff
+#define DEVTREE_IRQ_DONTCARE 0xff
+#define DEVTREE_NODE_MAGIC 0x10203040
+
+struct devtree_node {
+       struct devtree_node *next;
+       unsigned char sendirq;
+       unsigned char recvirq;
+       char name[DEVTREE_MAX_NAME];
+       unsigned int magic;
+};
+
+extern struct devtree_node *devtree;
+extern struct devtree_node *devtree_find_by_irq(uint8_t sendirq, uint8_t recvirq);
+extern struct devtree_node *devtree_find_node(const char *str);
+extern struct devtree_node *devtree_find_next(struct devtree_node **cur);
+extern int devtree_irq(struct devtree_node *dn, unsigned char *sendirq, unsigned char *recvirq);
+extern void devtree_print(void);
+
+#endif /* _ASM_UBICOM32_DEVTREE_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/div64.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/div64.h
new file mode 100644 (file)
index 0000000..9770261
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/div64.h
+ *   Generic div64.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_DIV64_H
+#define _ASM_UBICOM32_DIV64_H
+
+#include <asm-generic/div64.h>
+
+#endif /* _ASM_UBICOM32_DIV64_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/dma-mapping.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/dma-mapping.h
new file mode 100644 (file)
index 0000000..87639a4
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * arch/ubicom32/include/asm/dma-mapping.h
+ *   Generic dma-mapping.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_DMA_MAPPING_H
+#define _ASM_UBICOM32_DMA_MAPPING_H
+
+#include <linux/scatterlist.h>
+#ifdef CONFIG_PCI
+
+/* we implement the API below in terms of the existing PCI one,
+ * so include it */
+#include <linux/pci.h>
+/* need struct page definitions */
+#include <linux/mm.h>
+
+static inline int
+dma_supported(struct device *dev, u64 mask)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       return pci_dma_supported(to_pci_dev(dev), mask);
+}
+
+static inline int
+dma_set_mask(struct device *dev, u64 dma_mask)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
+}
+
+static inline void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+                  gfp_t flag)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
+}
+
+static inline void
+dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+                   dma_addr_t dma_handle)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle);
+}
+
+static inline dma_addr_t
+dma_map_single(struct device *dev, void *cpu_addr, size_t size,
+              enum dma_data_direction direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction);
+}
+
+static inline void
+dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+                enum dma_data_direction direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction);
+}
+
+static inline dma_addr_t
+dma_map_page(struct device *dev, struct page *page,
+            unsigned long offset, size_t size,
+            enum dma_data_direction direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction);
+}
+
+static inline void
+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+              enum dma_data_direction direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction);
+}
+
+static inline int
+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+          enum dma_data_direction direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
+}
+
+static inline void
+dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+            enum dma_data_direction direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction);
+}
+
+static inline void
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
+                       enum dma_data_direction direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
+                                   size, (int)direction);
+}
+
+static inline void
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
+                          enum dma_data_direction direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
+                                      size, (int)direction);
+}
+
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+                   enum dma_data_direction direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction);
+}
+
+static inline void
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
+                      enum dma_data_direction direction)
+{
+       BUG_ON(dev->bus != &pci_bus_type);
+
+       pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction);
+}
+
+static inline int
+dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return pci_dma_mapping_error(to_pci_dev(dev), dma_addr);
+}
+
+
+#else
+
+static inline int
+dma_supported(struct device *dev, u64 mask)
+{
+       return 0;
+}
+
+static inline int
+dma_set_mask(struct device *dev, u64 dma_mask)
+{
+       BUG();
+       return 0;
+}
+
+static inline void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+                  gfp_t flag)
+{
+       BUG();
+       return NULL;
+}
+
+static inline void
+dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+                   dma_addr_t dma_handle)
+{
+       BUG();
+}
+
+static inline dma_addr_t
+dma_map_single(struct device *dev, void *cpu_addr, size_t size,
+              enum dma_data_direction direction)
+{
+       BUG();
+       return 0;
+}
+
+static inline void
+dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+                enum dma_data_direction direction)
+{
+       BUG();
+}
+
+static inline dma_addr_t
+dma_map_page(struct device *dev, struct page *page,
+            unsigned long offset, size_t size,
+            enum dma_data_direction direction)
+{
+       BUG();
+       return 0;
+}
+
+static inline void
+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+              enum dma_data_direction direction)
+{
+       BUG();
+}
+
+static inline int
+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+          enum dma_data_direction direction)
+{
+       BUG();
+       return 0;
+}
+
+static inline void
+dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+            enum dma_data_direction direction)
+{
+       BUG();
+}
+
+static inline void
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
+                       enum dma_data_direction direction)
+{
+       BUG();
+}
+
+static inline void
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
+                          enum dma_data_direction direction)
+{
+       BUG();
+}
+
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+                   enum dma_data_direction direction)
+{
+       BUG();
+}
+
+static inline void
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
+                      enum dma_data_direction direction)
+{
+       BUG();
+}
+
+static inline int
+dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return 0;
+}
+
+#endif
+
+/* Now for the API extensions over the pci_ one */
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+#define dma_is_consistent(d, h)        (1)
+
+static inline int
+dma_get_cache_alignment(void)
+{
+       /* no easy way to get cache size on all processors, so return
+        * the maximum possible, to be safe */
+       return (1 << INTERNODE_CACHE_SHIFT);
+}
+
+static inline void
+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                             unsigned long offset, size_t size,
+                             enum dma_data_direction direction)
+{
+       /* just sync everything, that's all the pci API can do */
+       dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction);
+}
+
+static inline void
+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+                                unsigned long offset, size_t size,
+                                enum dma_data_direction direction)
+{
+       /* just sync everything, that's all the pci API can do */
+       dma_sync_single_for_device(dev, dma_handle, offset+size, direction);
+}
+
+static inline void
+dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+              enum dma_data_direction direction)
+{
+       /* could define this in terms of the dma_cache ... operations,
+        * but if you get this on a platform, you should convert the platform
+        * to using the generic device DMA API */
+       BUG();
+}
+
+#endif /* _ASM_UBICOM32_DMA_MAPPING_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/dma.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/dma.h
new file mode 100644 (file)
index 0000000..c3a10ac
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * arch/ubicom32/include/asm/dma.h
+ *   DMA definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_DMA_H
+#define _ASM_UBICOM32_DMA_H
+
+/* Nothing so far */
+#define MAX_DMA_ADDRESS 0x00   /* This is quite suspicious */
+
+#endif /* _ASM_UBICOM32_DMA_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/elf.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/elf.h
new file mode 100644 (file)
index 0000000..3abc202
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * arch/ubicom32/include/asm/elf.h
+ *   Definitions for elf executable format for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_ELF_H
+#define _ASM_UBICOM32_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+#include <asm/user.h>
+
+/*
+ * Processor specific flags for the ELF header e_flags field.
+ */
+#define EF_UBICOM32_V3         0x00000001      /* -fmarch=ubicom32v3 */
+#define EF_UBICOM32_V4         0x00000002      /* -fmarch=ubicom32v4 */
+#define EF_UBICOM32_PIC                0x80000000      /* -fpic */
+#define EF_UBICOM32_FDPIC      0x40000000      /* -mfdpic */
+
+/*
+ * Ubicom32 ELF relocation types
+ */
+#define R_UBICOM32_NONE                        0
+#define R_UBICOM32_16                  1
+#define R_UBICOM32_32                  2
+#define R_UBICOM32_LO16                        3
+#define R_UBICOM32_HI16                        4
+#define R_UBICOM32_21_PCREL            5
+#define R_UBICOM32_24_PCREL            6
+#define R_UBICOM32_HI24                        7
+#define R_UBICOM32_LO7_S               8
+#define R_UBICOM32_LO7_2_S             9
+#define R_UBICOM32_LO7_4_S             10
+#define R_UBICOM32_LO7_D               11
+#define R_UBICOM32_LO7_2_D             12
+#define R_UBICOM32_LO7_4_D             13
+#define R_UBICOM32_32_HARVARD          14
+#define R_UBICOM32_LO7_CALLI           15
+#define R_UBICOM32_LO16_CALLI          16
+#define R_UBICOM32_GOT_HI24            17
+#define R_UBICOM32_GOT_LO7_S           18
+#define R_UBICOM32_GOT_LO7_2_S         19
+#define R_UBICOM32_GOT_LO7_4_S         20
+#define R_UBICOM32_GOT_LO7_D           21
+#define R_UBICOM32_GOT_LO7_2_D         22
+#define R_UBICOM32_GOT_LO7_4_D         23
+#define R_UBICOM32_FUNCDESC_GOT_HI24    24
+#define R_UBICOM32_FUNCDESC_GOT_LO7_S   25
+#define R_UBICOM32_FUNCDESC_GOT_LO7_2_S 26
+#define R_UBICOM32_FUNCDESC_GOT_LO7_4_S 27
+#define R_UBICOM32_FUNCDESC_GOT_LO7_D   28
+#define R_UBICOM32_FUNCDESC_GOT_LO7_2_D 29
+#define R_UBICOM32_FUNCDESC_GOT_LO7_4_D 30
+#define R_UBICOM32_GOT_LO7_CALLI        31
+#define R_UBICOM32_FUNCDESC_GOT_LO7_CALLI 32
+#define R_UBICOM32_FUNCDESC_VALUE       33
+#define R_UBICOM32_FUNCDESC             34
+#define R_UBICOM32_GOTOFFSET_LO         35
+#define R_UBICOM32_GOTOFFSET_HI         36
+#define R_UBICOM32_FUNCDESC_GOTOFFSET_LO 37
+#define R_UBICOM32_FUNCDESC_GOTOFFSET_HI 38
+#define R_UBICOM32_GNU_VTINHERIT        200
+#define R_UBICOM32_GNU_VTENTRY          201
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef struct user_ubicom32fp_struct elf_fpregset_t;
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x)->e_machine == EM_UBICOM32)
+
+#define elf_check_fdpic(x) ((x)->e_flags & EF_UBICOM32_FDPIC)
+
+#define elf_check_const_displacement(x) ((x)->e_flags & EF_UBICOM32_PIC)
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS      ELFCLASS32
+#define ELF_DATA       ELFDATA2MSB
+#define ELF_ARCH       EM_UBICOM32
+
+/* For SVR4/m68k the function pointer to be registered with `atexit' is
+   passed in %a1.  Although my copy of the ABI has no such statement, it
+   is actually used on ASV.  */
+#define ELF_PLAT_INIT(_r, load_addr)   _r->a1 = 0
+
+#define ELF_FDPIC_PLAT_INIT(_regs, _exec_map_addr, _interp_map_addr,   \
+                           _dynamic_addr)                              \
+       do {                                                            \
+               _regs->dn[1]    = _exec_map_addr;                       \
+               _regs->dn[2]    = _interp_map_addr;                     \
+               _regs->dn[3]    = _dynamic_addr;                        \
+               _regs->an[1]    = 0; /* dl_fini will be set by ldso */  \
+       } while (0)
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE      4096
+
+#ifdef __KERNEL__
+#ifdef CONFIG_UBICOM32_V4
+#define ELF_FDPIC_CORE_EFLAGS  (EF_UBICOM32_FDPIC | EF_UBICOM32_V4)
+#elif defined CONFIG_UBICOM32_V3
+#define ELF_FDPIC_CORE_EFLAGS  (EF_UBICOM32_FDPIC | EF_UBICOM32_V3)
+#else
+#error Unknown/Unsupported ubicom32 architecture.
+#endif
+#endif
+
+/* 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         0xD0000000UL
+
+/*
+ * For Ubicom32, the elf_gregset_t and struct pt_regs are the same size
+ * data structure so a copy is performed instead of providing the
+ * ELF_CORE_COPY_REGS macro.
+ */
+
+/*
+ * ELF_CORE_COPY_TASK_REGS is needed to dump register state from multi threaded user projects.
+ */
+extern int dump_task_regs(struct task_struct *, elf_gregset_t *);
+#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
+
+/* This yields a mask that user programs can use to figure out what
+   instruction set this cpu supports.  */
+
+#define ELF_HWCAP      (0)
+
+/* 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.  */
+
+#define ELF_PLATFORM  (NULL)
+
+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+
+#endif /* _ASM_UBICOM32_ELF_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/emergency-restart.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/emergency-restart.h
new file mode 100644 (file)
index 0000000..ea39e58
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/emergency-restart.h
+ *   Generic emergency-restart.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_EMERGENCY_RESTART_H
+#define _ASM_UBICOM32_EMERGENCY_RESTART_H
+
+#include <asm-generic/emergency-restart.h>
+
+#endif /* _ASM_UBICOM32_EMERGENCY_RESTART_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/entry.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/entry.h
new file mode 100644 (file)
index 0000000..5ef46e6
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * arch/ubicom32/include/asm/entry.h
+ *   Entry register/stack definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_ENTRY_H
+#define _ASM_UBICOM32_ENTRY_H
+
+#include <asm/setup.h>
+#include <asm/page.h>
+
+#endif /* _ASM_UBICOM32_ENTRY_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/errno.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/errno.h
new file mode 100644 (file)
index 0000000..bf995b1
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/errno.h
+ *   Generic errno.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_ERRNO_H
+#define _ASM_UBICOM32_ERRNO_H
+
+#include <asm-generic/errno.h>
+
+#endif /* _ASM_UBICOM32_ERRNO_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/fb.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/fb.h
new file mode 100644 (file)
index 0000000..9e9cc6b
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * arch/ubicom32/include/asm/fb.h
+ *   Definition of fb_is_primary_device() for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_FB_H
+#define _ASM_UBICOM32_FB_H
+#include <linux/fb.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+       return 0;
+}
+
+#endif /* _ASM_UBICOM32_FB_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/fcntl.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/fcntl.h
new file mode 100644 (file)
index 0000000..810638c
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * arch/ubicom32/include/asm/fcntl.h
+ *   File control bit definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_FCNTL_H
+#define _ASM_UBICOM32_FCNTL_H
+
+#define O_DIRECTORY    040000  /* must be a directory */
+#define O_NOFOLLOW     0100000 /* don't follow links */
+#define O_DIRECT       0200000 /* direct disk access hint - currently ignored */
+#define O_LARGEFILE    0400000
+
+#include <asm-generic/fcntl.h>
+
+#endif /* _ASM_UBICOM32_FCNTL_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/flat.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/flat.h
new file mode 100644 (file)
index 0000000..84edd47
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * arch/ubicom32/include/asm/flat.h
+ *   Definitions to support flat-format executables.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_FLAT_H
+#define _ASM_UBICOM32_FLAT_H
+
+#define ARCH_FLAT_ALIGN 0x80
+#define ARCH_FLAT_ALIGN_TEXT 1
+
+#define  R_UBICOM32_32         2
+#define  R_UBICOM32_HI24       7
+#define  R_UBICOM32_LO7_S      8
+#define  R_UBICOM32_LO7_2_S    9
+#define  R_UBICOM32_LO7_4_S    10
+#define  R_UBICOM32_LO7_D      11
+#define  R_UBICOM32_LO7_2_D    12
+#define  R_UBICOM32_LO7_4_D    13
+#define  R_UBICOM32_LO7_CALLI  15
+#define  R_UBICOM32_LO16_CALLI 16
+
+extern void ubicom32_flat_put_addr_at_rp(unsigned long *rp, u32_t val, u32_t rval, unsigned long  *p);
+extern unsigned long ubicom32_flat_get_addr_from_rp(unsigned long *rp, u32_t relval, u32_t flags, unsigned long *p);
+
+#define        flat_stack_align(sp)                    /* nothing needed */
+#define        flat_argvp_envp_on_stack()              1
+#define        flat_old_ram_flag(flags)                (flags)
+#define        flat_reloc_valid(reloc, size)           ((reloc) <= (size))
+#define        flat_get_addr_from_rp(rp, relval, flags, p)     (ubicom32_flat_get_addr_from_rp(rp, relval,flags, p))
+#define        flat_put_addr_at_rp(rp, val, relval)    do {ubicom32_flat_put_addr_at_rp(rp, val, relval, &persistent);} while(0)
+#define        flat_get_relocate_addr(rel)             ((persistent) ? (persistent & 0x07ffffff) : (rel & 0x07ffffff))
+
+static inline int flat_set_persistent(unsigned int relval, unsigned long *p)
+{
+       if (*p) {
+               return 0;
+       } else {
+               if ((relval >> 27) != R_UBICOM32_32) {
+                       /*
+                        * Something other than UBICOM32_32. The next entry has the relocation.
+                        */
+                       *p = relval;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+#endif /* _ASM_UBICOM32_FLAT_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/fpu.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/fpu.h
new file mode 100644 (file)
index 0000000..496b7dd
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * arch/ubicom32/include/asm/fpu.h
+ *   Floating point state definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_FPU_H
+#define _ASM_UBICOM32_FPU_H
+
+/*
+ * MAX floating point unit state size (FSAVE/FRESTORE)
+ */
+/* No FP unit present then... */
+#define FPSTATESIZE (2) /* dummy size */
+
+#endif /* _ASM_UBICOM32_FPU_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ftrace.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ftrace.h
new file mode 100644 (file)
index 0000000..40a8c17
--- /dev/null
@@ -0,0 +1 @@
+/* empty */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/futex.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/futex.h
new file mode 100644 (file)
index 0000000..8c84b31
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/futex.h
+ *   Generic futex.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_FUTEX_H
+#define _ASM_UBICOM32_FUTEX_H
+
+#include <asm-generic/futex.h>
+
+#endif /* _ASM_UBICOM32_FUTEX_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/gpio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/gpio.h
new file mode 100644 (file)
index 0000000..1f834f3
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * arch/ubicom32/include/asm/gpio.h
+ *   Definitions for GPIO operations on Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_GPIO_H
+#define _ASM_UBICOM32_GPIO_H
+
+#include <linux/compiler.h>
+#include <asm/irq.h>
+
+#include <asm/ip5000.h>
+
+#define ARCH_NR_GPIOS           512
+#define MAX_UBICOM_ONCHIP_GPIO   (9 * 32)
+
+/*
+ * Macros for manipulating GPIO numbers
+ */
+#define gpio_bit(gn)                   (1 << (gn & 0x1f))
+#define gpio_bank(gn)                  (gn >> 5)
+
+#define gpio_pin_index(gn)             (gn & 0x1f)
+#define gpio_port_index(gn)            (gn >> 5)
+
+#define GPIO_RA_0    ((32 * 0) + 0)
+#define GPIO_RA_1    ((32 * 0) + 1)
+#define GPIO_RA_2    ((32 * 0) + 2)
+#define GPIO_RA_3    ((32 * 0) + 3)
+#define GPIO_RA_4    ((32 * 0) + 4)
+#define GPIO_RA_5    ((32 * 0) + 5)
+#define GPIO_RA_6    ((32 * 0) + 6)
+#define GPIO_RA_7    ((32 * 0) + 7)
+
+#define GPIO_RB_0    ((32 * 1) + 0)
+#define GPIO_RB_1    ((32 * 1) + 1)
+#define GPIO_RB_2    ((32 * 1) + 2)
+#define GPIO_RB_3    ((32 * 1) + 3)
+#define GPIO_RB_4    ((32 * 1) + 4)
+#define GPIO_RB_5    ((32 * 1) + 5)
+#define GPIO_RB_6    ((32 * 1) + 6)
+#define GPIO_RB_7    ((32 * 1) + 7)
+#define GPIO_RB_8    ((32 * 1) + 8)
+#define GPIO_RB_9    ((32 * 1) + 9)
+#define GPIO_RB_10   ((32 * 1) + 10)
+#define GPIO_RB_11   ((32 * 1) + 11)
+#define GPIO_RB_12   ((32 * 1) + 12)
+#define GPIO_RB_13   ((32 * 1) + 13)
+#define GPIO_RB_14   ((32 * 1) + 14)
+#define GPIO_RB_15   ((32 * 1) + 15)
+#define GPIO_RB_16   ((32 * 1) + 16)
+#define GPIO_RB_17   ((32 * 1) + 17)
+#define GPIO_RB_18   ((32 * 1) + 18)
+#define GPIO_RB_19   ((32 * 1) + 19)
+
+#define GPIO_RC_0    ((32 * 2) + 0)
+#define GPIO_RC_1    ((32 * 2) + 1)
+#define GPIO_RC_2    ((32 * 2) + 2)
+#define GPIO_RC_3    ((32 * 2) + 3)
+#define GPIO_RC_4    ((32 * 2) + 4)
+#define GPIO_RC_5    ((32 * 2) + 5)
+#define GPIO_RC_6    ((32 * 2) + 6)
+#define GPIO_RC_7    ((32 * 2) + 7)
+#define GPIO_RC_8    ((32 * 2) + 8)
+#define GPIO_RC_9    ((32 * 2) + 9)
+#define GPIO_RC_10   ((32 * 2) + 10)
+#define GPIO_RC_11   ((32 * 2) + 11)
+#define GPIO_RC_12   ((32 * 2) + 12)
+#define GPIO_RC_13   ((32 * 2) + 13)
+#define GPIO_RC_14   ((32 * 2) + 14)
+#define GPIO_RC_15   ((32 * 2) + 15)
+#define GPIO_RC_16   ((32 * 2) + 16)
+#define GPIO_RC_17   ((32 * 2) + 17)
+#define GPIO_RC_18   ((32 * 2) + 18)
+#define GPIO_RC_19   ((32 * 2) + 19)
+#define GPIO_RC_20   ((32 * 2) + 20)
+#define GPIO_RC_21   ((32 * 2) + 21)
+#define GPIO_RC_22   ((32 * 2) + 22)
+#define GPIO_RC_23   ((32 * 2) + 23)
+#define GPIO_RC_24   ((32 * 2) + 24)
+#define GPIO_RC_25   ((32 * 2) + 25)
+#define GPIO_RC_26   ((32 * 2) + 26)
+#define GPIO_RC_27   ((32 * 2) + 27)
+#define GPIO_RC_28   ((32 * 2) + 28)
+#define GPIO_RC_29   ((32 * 2) + 29)
+#define GPIO_RC_30   ((32 * 2) + 30)
+#define GPIO_RC_31   ((32 * 2) + 31)
+
+#define GPIO_RD_0    ((32 * 3) + 0)
+#define GPIO_RD_1    ((32 * 3) + 1)
+#define GPIO_RD_2    ((32 * 3) + 2)
+#define GPIO_RD_3    ((32 * 3) + 3)
+#define GPIO_RD_4    ((32 * 3) + 4)
+#define GPIO_RD_5    ((32 * 3) + 5)
+#define GPIO_RD_6    ((32 * 3) + 6)
+#define GPIO_RD_7    ((32 * 3) + 7)
+#define GPIO_RD_8    ((32 * 3) + 8)
+#define GPIO_RD_9    ((32 * 3) + 9)
+#define GPIO_RD_10   ((32 * 3) + 10)
+#define GPIO_RD_11   ((32 * 3) + 11)
+
+#define GPIO_RE_0    ((32 * 4) + 0)
+#define GPIO_RE_1    ((32 * 4) + 1)
+#define GPIO_RE_2    ((32 * 4) + 2)
+#define GPIO_RE_3    ((32 * 4) + 3)
+#define GPIO_RE_4    ((32 * 4) + 4)
+#define GPIO_RE_5    ((32 * 4) + 5)
+#define GPIO_RE_6    ((32 * 4) + 6)
+#define GPIO_RE_7    ((32 * 4) + 7)
+
+#define GPIO_RF_0    ((32 * 5) + 0)
+#define GPIO_RF_1    ((32 * 5) + 1)
+#define GPIO_RF_2    ((32 * 5) + 2)
+#define GPIO_RF_3    ((32 * 5) + 3)
+#define GPIO_RF_4    ((32 * 5) + 4)
+#define GPIO_RF_5    ((32 * 5) + 5)
+#define GPIO_RF_6    ((32 * 5) + 6)
+#define GPIO_RF_7    ((32 * 5) + 7)
+#define GPIO_RF_8    ((32 * 5) + 8)
+#define GPIO_RF_9    ((32 * 5) + 9)
+#define GPIO_RF_10   ((32 * 5) + 10)
+#define GPIO_RF_11   ((32 * 5) + 11)
+#define GPIO_RF_12   ((32 * 5) + 12)
+#define GPIO_RF_13   ((32 * 5) + 13)
+#define GPIO_RF_14   ((32 * 5) + 14)
+#define GPIO_RF_15   ((32 * 5) + 15)
+
+#define GPIO_RG_0    ((32 * 6) + 0)
+#define GPIO_RG_1    ((32 * 6) + 1)
+#define GPIO_RG_2    ((32 * 6) + 2)
+#define GPIO_RG_3    ((32 * 6) + 3)
+#define GPIO_RG_4    ((32 * 6) + 4)
+#define GPIO_RG_5    ((32 * 6) + 5)
+#define GPIO_RG_6    ((32 * 6) + 6)
+#define GPIO_RG_7    ((32 * 6) + 7)
+#define GPIO_RG_8    ((32 * 6) + 8)
+#define GPIO_RG_9    ((32 * 6) + 9)
+#define GPIO_RG_10   ((32 * 6) + 10)
+#define GPIO_RG_11   ((32 * 6) + 11)
+#define GPIO_RG_12   ((32 * 6) + 12)
+#define GPIO_RG_13   ((32 * 6) + 13)
+#define GPIO_RG_14   ((32 * 6) + 14)
+#define GPIO_RG_15   ((32 * 6) + 15)
+#define GPIO_RG_16   ((32 * 6) + 16)
+#define GPIO_RG_17   ((32 * 6) + 17)
+#define GPIO_RG_18   ((32 * 6) + 18)
+#define GPIO_RG_19   ((32 * 6) + 19)
+#define GPIO_RG_20   ((32 * 6) + 20)
+#define GPIO_RG_21   ((32 * 6) + 21)
+#define GPIO_RG_22   ((32 * 6) + 22)
+#define GPIO_RG_23   ((32 * 6) + 23)
+#define GPIO_RG_24   ((32 * 6) + 24)
+#define GPIO_RG_25   ((32 * 6) + 25)
+#define GPIO_RG_26   ((32 * 6) + 26)
+#define GPIO_RG_27   ((32 * 6) + 27)
+#define GPIO_RG_28   ((32 * 6) + 28)
+#define GPIO_RG_29   ((32 * 6) + 29)
+#define GPIO_RG_30   ((32 * 6) + 30)
+#define GPIO_RG_31   ((32 * 6) + 31)
+
+#define GPIO_RH_0    ((32 * 7) + 0)
+#define GPIO_RH_1    ((32 * 7) + 1)
+#define GPIO_RH_2    ((32 * 7) + 2)
+#define GPIO_RH_3    ((32 * 7) + 3)
+#define GPIO_RH_4    ((32 * 7) + 4)
+#define GPIO_RH_5    ((32 * 7) + 5)
+#define GPIO_RH_6    ((32 * 7) + 6)
+#define GPIO_RH_7    ((32 * 7) + 7)
+#define GPIO_RH_8    ((32 * 7) + 8)
+#define GPIO_RH_9    ((32 * 7) + 9)
+
+#define GPIO_RI_0    ((32 * 8) + 0)
+#define GPIO_RI_1    ((32 * 8) + 1)
+#define GPIO_RI_2    ((32 * 8) + 2)
+#define GPIO_RI_3    ((32 * 8) + 3)
+#define GPIO_RI_4    ((32 * 8) + 4)
+#define GPIO_RI_5    ((32 * 8) + 5)
+#define GPIO_RI_6    ((32 * 8) + 6)
+#define GPIO_RI_7    ((32 * 8) + 7)
+#define GPIO_RI_8    ((32 * 8) + 8)
+#define GPIO_RI_9    ((32 * 8) + 9)
+#define GPIO_RI_10   ((32 * 8) + 10)
+#define GPIO_RI_11   ((32 * 8) + 11)
+#define GPIO_RI_12   ((32 * 8) + 12)
+#define GPIO_RI_13   ((32 * 8) + 13)
+#define GPIO_RI_14   ((32 * 8) + 14)
+#define GPIO_RI_15   ((32 * 8) + 15)
+
+/*
+ * The following section defines extra GPIO available to some boards.
+ * These GPIO are generally external to the processor (i.e. SPI/I2C
+ * expander chips).
+ *
+ * Note that these defines show all possible GPIO available, however,
+ * depending on the actual board configuration, some GPIO are not
+ * available for use.
+ */
+#ifdef CONFIG_IP7500MEDIA
+/*
+ * U15
+ */
+#define IP7500MEDIA_U15_BASE   (32 * 10)
+#define IP7500MEDIA_IO0                (IP7500MEDIA_U15_BASE + 0)
+#define IP7500MEDIA_IO1                (IP7500MEDIA_U15_BASE + 1)
+#define IP7500MEDIA_IO2                (IP7500MEDIA_U15_BASE + 2)
+#define IP7500MEDIA_IO3                (IP7500MEDIA_U15_BASE + 3)
+#define IP7500MEDIA_IO4                (IP7500MEDIA_U15_BASE + 4)
+#define IP7500MEDIA_IO5                (IP7500MEDIA_U15_BASE + 5)
+#define IP7500MEDIA_IO6                (IP7500MEDIA_U15_BASE + 6)
+#define IP7500MEDIA_IO7                (IP7500MEDIA_U15_BASE + 7)
+
+/*
+ * U16
+ */
+#define IP7500MEDIA_U16_BASE   (32 * 11)
+#define IP7500MEDIA_IO8                (IP7500MEDIA_U16_BASE + 0)
+#define IP7500MEDIA_IO9                (IP7500MEDIA_U16_BASE + 1)
+#define IP7500MEDIA_IO10       (IP7500MEDIA_U16_BASE + 2)
+#define IP7500MEDIA_IO11       (IP7500MEDIA_U16_BASE + 3)
+#define IP7500MEDIA_IO12       (IP7500MEDIA_U16_BASE + 4)
+#define IP7500MEDIA_IO13       (IP7500MEDIA_U16_BASE + 5)
+#define IP7500MEDIA_IO14       (IP7500MEDIA_U16_BASE + 6)
+#define IP7500MEDIA_IO15       (IP7500MEDIA_U16_BASE + 7)
+
+/*
+ * U17
+ */
+#define IP7500MEDIA_U17_BASE   (32 * 12)
+#define IP7500MEDIA_IO16       (IP7500MEDIA_U17_BASE + 0)
+#define IP7500MEDIA_IO17       (IP7500MEDIA_U17_BASE + 1)
+#define IP7500MEDIA_IO18       (IP7500MEDIA_U17_BASE + 2)
+#define IP7500MEDIA_IO19       (IP7500MEDIA_U17_BASE + 3)
+#define IP7500MEDIA_IO20       (IP7500MEDIA_U17_BASE + 4)
+#define IP7500MEDIA_IO21       (IP7500MEDIA_U17_BASE + 5)
+#define IP7500MEDIA_IO22       (IP7500MEDIA_U17_BASE + 6)
+#define IP7500MEDIA_IO23       (IP7500MEDIA_U17_BASE + 7)
+
+/*
+ * U18
+ */
+#define IP7500MEDIA_U18_BASE   (32 * 13)
+#define IP7500MEDIA_IO24       (IP7500MEDIA_U18_BASE + 0)
+#define IP7500MEDIA_IO25       (IP7500MEDIA_U18_BASE + 1)
+#define IP7500MEDIA_IO26       (IP7500MEDIA_U18_BASE + 2)
+#define IP7500MEDIA_IO27       (IP7500MEDIA_U18_BASE + 3)
+#define IP7500MEDIA_IO28       (IP7500MEDIA_U18_BASE + 4)
+#define IP7500MEDIA_IO29       (IP7500MEDIA_U18_BASE + 5)
+#define IP7500MEDIA_IO30       (IP7500MEDIA_U18_BASE + 6)
+#define IP7500MEDIA_IO31       (IP7500MEDIA_U18_BASE + 7)
+#endif
+
+#ifdef CONFIG_IP7145DPF
+/*
+ * U48
+ */
+#define IP7145DPF_U48_BASE     (32 * 10)
+#define IP7145DPF_IO0          (IP7145DPF_U48_BASE + 0)
+#define IP7145DPF_IO1          (IP7145DPF_U48_BASE + 1)
+#define IP7145DPF_IO2          (IP7145DPF_U48_BASE + 2)
+#define IP7145DPF_IO3          (IP7145DPF_U48_BASE + 3)
+#define IP7145DPF_IO4          (IP7145DPF_U48_BASE + 4)
+#define IP7145DPF_IO5          (IP7145DPF_U48_BASE + 5)
+#define IP7145DPF_IO6          (IP7145DPF_U48_BASE + 6)
+#define IP7145DPF_IO7          (IP7145DPF_U48_BASE + 7)
+
+/*
+ * U72
+ */
+#define IP7145DPF_U72_BASE     (32 * 11)
+#define IP7145DPF_IOB0         (IP7145DPF_U72_BASE + 0)
+#define IP7145DPF_IOB1         (IP7145DPF_U72_BASE + 1)
+#define IP7145DPF_IOB2         (IP7145DPF_U72_BASE + 2)
+#define IP7145DPF_IOB3         (IP7145DPF_U72_BASE + 3)
+#define IP7145DPF_IOB4         (IP7145DPF_U72_BASE + 4)
+#define IP7145DPF_IOB5         (IP7145DPF_U72_BASE + 5)
+#define IP7145DPF_IOB6         (IP7145DPF_U72_BASE + 6)
+#define IP7145DPF_IOB7         (IP7145DPF_U72_BASE + 7)
+#endif
+
+#include <asm-generic/gpio.h>
+
+/*
+ * The following macros bypass gpiolib to generate direct references
+ * to the port registers.  These assume, minimally, that either
+ * gpio_direction_input() or gpio_direction_output() have already been
+ * called to setup the pin direction and to enable the pin function to
+ * be gpio.  These macros generate the hardware port address based on
+ * the assumption that all ports are 32 bits wide (even though we know
+ * they are not).  This is so we can efficiently turn pin numbers into
+ * port addresses without a lookup.
+ *
+ * These operations must be done in one instruction to prevent clobbering
+ * other thread's accesses to the same port.
+ */
+#define UBICOM32_GPIO_ENABLE(pin)                              \
+       do {                                                    \
+               asm volatile ("or.4 (%[port]), (%[port]), %[mask]\n\t"                                          \
+                               :                                                                               \
+                               : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_mask),  \
+                                 [mask] "d" (gpio_bit(pin))                                                    \
+                               : "cc", "memory"                                                                \
+               );                                                                                              \
+       } while (0);
+
+#define UBICOM32_GPIO_DISABLE(pin)                             \
+       do {                                                    \
+               asm volatile ("and.4 (%[port]), (%[port]), %[mask]\n\t"                                         \
+                               :                                                                               \
+                               : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_mask),  \
+                                 [mask] "d" (~gpio_bit(pin))                                                   \
+                               : "cc", "memory"                                                                \
+               );                                                                                              \
+       } while (0);
+
+#define UBICOM32_GPIO_SET_PIN_INPUT(pin)                       \
+       do {                                                    \
+               asm volatile ("and.4 (%[port]), (%[port]), %[mask]\n\t"                                         \
+                               :                                                                               \
+                               : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_ctl),   \
+                                 [mask] "d" (~gpio_bit(pin))                                                   \
+                               : "cc", "memory"                                                                \
+               );                                                                                              \
+       } while (0);
+
+#define UBICOM32_GPIO_SET_PIN_OUTPUT(pin)                      \
+       do {                                                    \
+               asm volatile ("or.4 (%[port]), (%[port]), %[mask]\n\t"                                          \
+                               :                                                                               \
+                               : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_ctl),   \
+                                 [mask] "d" (gpio_bit(pin))                                                    \
+                               : "cc", "memory"                                                                \
+               );                                                                                              \
+       } while (0);
+
+#define UBICOM32_GPIO_SET_PIN_TOGGLE(pin)                      \
+       do {                                                    \
+               asm volatile ("xor.4 (%[port]), (%[port]), %[mask]\n\t"                                         \
+                               :                                                                               \
+                               : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_out),   \
+                                 [mask] "d" (gpio_bit(pin))                                                    \
+                               : "cc", "memory"                                                                \
+               );                                                                                              \
+       } while (0);
+
+#define UBICOM32_GPIO_SET_PIN_HIGH(pin)                                \
+       do {                                                    \
+               asm volatile ("or.4 (%[port]), (%[port]), %[mask]\n\t"                                          \
+                               :                                                                               \
+                               : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_out),   \
+                                 [mask] "d" (gpio_bit(pin))                                                    \
+                               : "cc", "memory"                                                                \
+               );                                                                                              \
+       } while (0);
+
+#define UBICOM32_GPIO_SET_PIN_LOW(pin)                         \
+       do {                                                    \
+               asm volatile ("and.4 (%[port]), (%[port]), %[mask]\n\t"                                         \
+                               :                                                                               \
+                               : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_out),   \
+                                 [mask] "d" (~gpio_bit(pin))                                                   \
+                               : "cc", "memory"                                                                \
+               );                                                                                              \
+       } while (0);
+
+#define UBICOM32_GPIO_SET_PIN(pin, val) \
+  if ( val ) {                          \
+    UBICOM32_GPIO_SET_PIN_HIGH(pin);    \
+  } else {                              \
+    UBICOM32_GPIO_SET_PIN_LOW(pin);    \
+  }
+
+#define UBICOM32_GPIO_GET_PIN(pin)                                    \
+  (0 != (UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_in  \
+        & gpio_bit(pin)))
+
+
+static inline int gpio_get_value(unsigned gpio)
+{
+  if (gpio <= MAX_UBICOM_ONCHIP_GPIO)
+    return UBICOM32_GPIO_GET_PIN(gpio);
+  else
+    return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+  if (gpio <= MAX_UBICOM_ONCHIP_GPIO)
+    {
+      UBICOM32_GPIO_SET_PIN(gpio, value);
+    }
+  else
+    {
+      __gpio_set_value(gpio, value);
+    }
+}
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+  return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+#if defined(IP5000) || defined(IP5000_REV2)
+  if ((gpio >= GPIO_RA_4) && (gpio <= GPIO_RA_6))
+    return 25;
+  else
+    return -ENXIO;
+
+#elif defined(IP7000) || defined(IP7000_REV2)
+  if ((gpio >= GPIO_RA_4) && (gpio <= GPIO_RA_6))
+    return 44 + (gpio - GPIO_RA_4);
+  else
+    return -ENXIO;
+
+#else
+    return -ENXIO;
+
+#endif
+}
+
+static inline int irq_to_gpio(unsigned gpio)
+{
+       return -ENXIO;
+}
+
+extern struct ubicom32_io_port *ubi_gpio_get_port(unsigned gpio);
+
+extern int __init ubi_gpio_init(void);
+
+#endif /* _ASM_UBICOM32_GPIO_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/hardirq.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/hardirq.h
new file mode 100644 (file)
index 0000000..e230481
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * arch/ubicom32/include/asm/hardirq.h
+ *   Definition of ack_bad_irq() for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 1997, 98, 99, 2000, 01, 05 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2001 MIPS Technologies, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_HARDIRQ_H
+#define _ASM_UBICOM32_HARDIRQ_H
+
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+/*
+ * The hardirq mask has to be large enough to have space
+ * for potentially all IRQ sources in the system nesting
+ * on a single CPU.  For Ubicom32, we have 64 IRQ sources.
+ */
+#define HARDIRQ_BITS   6
+#if (1 << HARDIRQ_BITS) < NR_IRQS
+# error HARDIRQ_BITS is too low!
+#endif
+
+typedef struct {
+       unsigned int __softirq_pending;
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+
+extern void ack_bad_irq(unsigned int irq);
+
+#endif /* _ASM_UBICOM32_HARDIRQ_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/hw_irq.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/hw_irq.h
new file mode 100644 (file)
index 0000000..9dece31
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * arch/ubicom32/include/asm/hw_irq.h
+ *   Ubicom32 architecture APIC support.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_HW_IRQ_H
+#define _ASM_UBICOM32_HW_IRQ_H
+
+#endif /* _ASM_UBICOM32_HW_IRQ_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/io.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/io.h
new file mode 100644 (file)
index 0000000..ad526a3
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * arch/ubicom32/include/asm/io.h
+ *   I/O memory accessor functions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_IO_H
+#define _ASM_UBICOM32_IO_H
+
+#ifdef __KERNEL__
+#include <linux/string.h>
+#include <linux/compiler.h>
+
+static inline unsigned short _swapw(volatile unsigned short v)
+{
+    return ((v << 8) | (v >> 8));
+}
+
+static inline unsigned int _swapl(volatile unsigned long v)
+{
+    return ((v << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24));
+}
+
+#ifndef CONFIG_PCI
+#define readb(addr) \
+    ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; })
+#define readw(addr) \
+    ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; })
+#define readl(addr) \
+    ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
+
+#define writeb(b,addr) (void)((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b))
+#else /*CONFIG_PCI */
+
+#define PCI_CPU_REG_BASE (0x00000000UL)   /* taking lower 2GB space */
+#define PCI_DEV_REG_BASE (0x80000000UL)
+
+#if PCI_CPU_REG_BASE > PCI_DEV_REG_BASE
+#define IS_PCI_ADDRESS(x) (((unsigned int)(x)&(PCI_CPU_REG_BASE)) == 0)
+#else
+#define IS_PCI_ADDRESS(x) ((unsigned int)(x)&(PCI_DEV_REG_BASE))
+#endif
+
+extern unsigned int ubi32_pci_read_u32(const volatile void __iomem *addr);
+extern unsigned short ubi32_pci_read_u16(const volatile void __iomem *addr);
+extern unsigned char ubi32_pci_read_u8(const volatile void __iomem *addr);
+extern  void ubi32_pci_write_u32(unsigned int val, const volatile void __iomem *addr);
+extern  void ubi32_pci_write_u16(unsigned short val, const volatile void __iomem *addr);
+extern  void ubi32_pci_write_u8(unsigned char val, const volatile void __iomem *addr);
+
+static  inline unsigned char readb(const volatile void __iomem *addr)
+{
+       if (IS_PCI_ADDRESS(addr))
+               return ubi32_pci_read_u8(addr);
+       else
+               return (unsigned char)(*(volatile unsigned char *)addr);
+}
+static inline unsigned short readw(const volatile void __iomem *addr)
+{
+       if (IS_PCI_ADDRESS(addr))
+               return ubi32_pci_read_u16(addr);
+       else
+               return (unsigned short)(*(volatile unsigned short *)addr);
+}
+
+static  inline unsigned int  readl(const volatile void __iomem *addr)
+{
+       if (IS_PCI_ADDRESS(addr))
+               return ubi32_pci_read_u32(addr);
+       else
+               return (unsigned int)(*(volatile unsigned int *)addr);
+}
+
+static inline void writel(unsigned int val, volatile void __iomem *addr)
+{
+       if (IS_PCI_ADDRESS(addr))
+                ubi32_pci_write_u32(val, addr);
+        else
+               *(volatile unsigned int *)addr = val;
+}
+
+static inline void writew(unsigned short val, volatile void __iomem *addr)
+{
+       if (IS_PCI_ADDRESS(addr))
+                ubi32_pci_write_u16(val, addr);
+        else
+               *(volatile unsigned short *)addr = val;
+}
+
+static inline void writeb(unsigned char val, volatile void __iomem *addr)
+{
+       if (IS_PCI_ADDRESS(addr))
+                ubi32_pci_write_u8(val, addr);
+        else
+               *(volatile unsigned char *)addr = val;
+}
+#endif
+
+#define readb_relaxed(addr) readb(addr)
+#define readw_relaxed(addr) readw(addr)
+#define readl_relaxed(addr) readl(addr)
+
+
+#define __raw_readb readb
+#define __raw_readw readw
+#define __raw_readl readl
+#define __raw_writeb writeb
+#define __raw_writew writew
+#define __raw_writel writel
+
+static inline void io_outsb(unsigned int addr, const void *buf, int len)
+{
+       volatile unsigned char *ap = (volatile unsigned char *) addr;
+       unsigned char *bp = (unsigned char *) buf;
+       while (len--)
+               *ap = *bp++;
+}
+
+static inline void io_outsw(unsigned int addr, const void *buf, int len)
+{
+       volatile unsigned short *ap = (volatile unsigned short *) addr;
+       unsigned short *bp = (unsigned short *) buf;
+       while (len--)
+               *ap = _swapw(*bp++);
+}
+
+static inline void io_outsl(unsigned int addr, const void *buf, int len)
+{
+       volatile unsigned int *ap = (volatile unsigned int *) addr;
+       unsigned int *bp = (unsigned int *) buf;
+       while (len--)
+               *ap = _swapl(*bp++);
+}
+
+static inline void io_insb(unsigned int addr, void *buf, int len)
+{
+       volatile unsigned char *ap = (volatile unsigned char *) addr;
+       unsigned char *bp = (unsigned char *) buf;
+       while (len--)
+               *bp++ = *ap;
+}
+
+static inline void io_insw(unsigned int addr, void *buf, int len)
+{
+       volatile unsigned short *ap = (volatile unsigned short *) addr;
+       unsigned short *bp = (unsigned short *) buf;
+       while (len--)
+               *bp++ = _swapw(*ap);
+}
+
+static inline void io_insl(unsigned int addr, void *buf, int len)
+{
+       volatile unsigned int *ap = (volatile unsigned int *) addr;
+       unsigned int *bp = (unsigned int *) buf;
+       while (len--)
+               *bp++ = _swapl(*ap);
+}
+
+#define mmiowb()
+
+/*
+ *     make the short names macros so specific devices
+ *     can override them as required
+ */
+#ifndef CONFIG_PCI
+#define memset_io(a,b,c)       memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c)   memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c)     memcpy((void *)(a),(b),(c))
+#else
+extern void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned len);
+extern void memcpy_toio(volatile void __iomem *to, const void *from, unsigned len);
+extern void memset_io(volatile void __iomem *addr, int val, size_t count);
+#endif
+
+#define inb(addr)    readb(addr)
+#define inw(addr)    readw(addr)
+#define inl(addr)    readl(addr)
+#define outb(x,addr) ((void) writeb(x,addr))
+#define outw(x,addr) ((void) writew(x,addr))
+#define outl(x,addr) ((void) writel(x,addr))
+
+#define inb_p(addr)    inb(addr)
+#define inw_p(addr)    inw(addr)
+#define inl_p(addr)    inl(addr)
+#define outb_p(x,addr) outb(x,addr)
+#define outw_p(x,addr) outw(x,addr)
+#define outl_p(x,addr) outl(x,addr)
+
+#define outsb(a,b,l) io_outsb(a,b,l)
+#define outsw(a,b,l) io_outsw(a,b,l)
+#define outsl(a,b,l) io_outsl(a,b,l)
+
+#define insb(a,b,l) io_insb(a,b,l)
+#define insw(a,b,l) io_insw(a,b,l)
+#define insl(a,b,l) io_insl(a,b,l)
+
+#ifndef CONFIG_PCI
+#define ioread8_rep(a,d,c)     insb(a,d,c)
+#define ioread16_rep(a,d,c)    insw(a,d,c)
+#define ioread32_rep(a,d,c)    insl(a,d,c)
+#define iowrite8_rep(a,s,c)    outsb(a,s,c)
+#define iowrite16_rep(a,s,c)   outsw(a,s,c)
+#define iowrite32_rep(a,s,c)   outsl(a,s,c)
+#else
+extern void  ioread8_rep(void __iomem *port, void *buf, unsigned long count);
+extern void  ioread16_rep(void __iomem *port, void *buf, unsigned long count);
+extern void  ioread32_rep(void __iomem *port, void *buf, unsigned long count);
+extern void  iowrite8_rep(void __iomem *port, const void *buf, unsigned long count);
+extern void  iowrite16_rep(void __iomem *port, const void *buf, unsigned long count);
+extern void  iowrite32_rep(void __iomem *port, const void *buf, unsigned long count);
+#endif
+
+
+#ifndef CONFIG_PCI
+#define ioread8(X)                     readb(X)
+#define ioread16(X)                    readw(X)
+#define ioread32(X)                    readl(X)
+#define iowrite8(val,X)                        writeb(val,X)
+#define iowrite16(val,X)               writew(val,X)
+#define iowrite32(val,X)               writel(val,X)
+#else /*CONFIG_PCI */
+extern  unsigned char  ioread8(void __iomem *addr);
+extern  unsigned short ioread16(void __iomem *addr);
+extern  unsigned int  ioread32(void __iomem *addr);
+extern  void iowrite8(unsigned char val, void __iomem *addr);
+extern  void iowrite16(unsigned short val, void __iomem *addr);
+extern  void iowrite32(unsigned int val, void __iomem *addr);
+#endif /* CONFIG_PCI */
+
+#define IO_SPACE_LIMIT 0xffff
+
+/* Values for nocacheflag and cmode */
+#define IOMAP_FULL_CACHING             0
+#define IOMAP_NOCACHE_SER              1
+#define IOMAP_NOCACHE_NONSER           2
+#define IOMAP_WRITETHROUGH             3
+
+extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag);
+extern void __iounmap(void *addr, unsigned long size);
+
+static inline void *ioremap(unsigned long physaddr, unsigned long size)
+{
+       return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
+}
+static inline void *ioremap_nocache(unsigned long physaddr, unsigned long size)
+{
+       return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
+}
+static inline void *ioremap_writethrough(unsigned long physaddr, unsigned long size)
+{
+       return __ioremap(physaddr, size, IOMAP_WRITETHROUGH);
+}
+static inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size)
+{
+       return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
+}
+
+extern void iounmap(void *addr);
+
+#define ioport_map(port, nr)            ((void __iomem*)(port))
+#define ioport_unmap(addr)
+
+
+/* Pages to physical address... */
+#define page_to_phys(page)      ((page - mem_map) << PAGE_SHIFT)
+#define page_to_bus(page)       ((page - mem_map) << PAGE_SHIFT)
+
+/*
+ * Macros used for converting between virtual and physical mappings.
+ */
+#define phys_to_virt(vaddr)    ((void *) (vaddr))
+#define virt_to_phys(vaddr)    ((unsigned long) (vaddr))
+
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
+/*
+ * 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
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_UBICOM32_IO_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ioctl.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ioctl.h
new file mode 100644 (file)
index 0000000..10d8dd7
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/ioctl.h
+ *   Generic ioctl.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_IOCTL_H
+#define _ASM_UBICOM32_IOCTL_H
+
+#include <asm-generic/ioctl.h>
+
+#endif /* _ASM_UBICOM32_IOCTL_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ioctls.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ioctls.h
new file mode 100644 (file)
index 0000000..c8e2c79
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * arch/ubicom32/include/asm/ioctls.h
+ *   Definitions of ioctls for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_IOCTLS_H
+#define _ASM_UBICOM32_IOCTLS_H
+
+#include <asm/ioctl.h>
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TCGETS         0x5401
+#define TCSETS         0x5402
+#define TCSETSW                0x5403
+#define TCSETSF                0x5404
+#define TCGETA         0x5405
+#define TCSETA         0x5406
+#define TCSETAW                0x5407
+#define TCSETAF                0x5408
+#define TCSBRK         0x5409
+#define TCXONC         0x540A
+#define TCFLSH         0x540B
+#define TIOCEXCL       0x540C
+#define TIOCNXCL       0x540D
+#define TIOCSCTTY      0x540E
+#define TIOCGPGRP      0x540F
+#define TIOCSPGRP      0x5410
+#define TIOCOUTQ       0x5411
+#define TIOCSTI                0x5412
+#define TIOCGWINSZ     0x5413
+#define TIOCSWINSZ     0x5414
+#define TIOCMGET       0x5415
+#define TIOCMBIS       0x5416
+#define TIOCMBIC       0x5417
+#define TIOCMSET       0x5418
+#define TIOCGSOFTCAR   0x5419
+#define TIOCSSOFTCAR   0x541A
+#define FIONREAD       0x541B
+#define TIOCINQ                FIONREAD
+#define TIOCLINUX      0x541C
+#define TIOCCONS       0x541D
+#define TIOCGSERIAL    0x541E
+#define TIOCSSERIAL    0x541F
+#define TIOCPKT                0x5420
+#define FIONBIO                0x5421
+#define TIOCNOTTY      0x5422
+#define TIOCSETD       0x5423
+#define TIOCGETD       0x5424
+#define TCSBRKP                0x5425  /* Needed for POSIX tcsendbreak() */
+#define TIOCSBRK       0x5427  /* BSD compatibility */
+#define TIOCCBRK       0x5428  /* BSD compatibility */
+#define TIOCGSID       0x5429  /* Return the session ID of FD */
+#define TCGETS2                _IOR('T',0x2A, struct termios2)
+#define TCSETS2                _IOW('T',0x2B, struct termios2)
+#define TCSETSW2       _IOW('T',0x2C, struct termios2)
+#define TCSETSF2       _IOW('T',0x2D, struct termios2)
+#define TIOCGPTN       _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK     _IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define FIONCLEX       0x5450  /* these numbers need to be adjusted. */
+#define FIOCLEX                0x5451
+#define FIOASYNC       0x5452
+#define TIOCSERCONFIG  0x5453
+#define TIOCSERGWILD   0x5454
+#define TIOCSERSWILD   0x5455
+#define TIOCGLCKTRMIOS 0x5456
+#define TIOCSLCKTRMIOS 0x5457
+#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TIOCMIWAIT     0x545C  /* wait for a change on serial input line(s) */
+#define TIOCGICOUNT    0x545D  /* read serial port inline interrupt counts */
+#define FIOQSIZE       0x545E
+
+/* Used for packet mode */
+#define TIOCPKT_DATA            0
+#define TIOCPKT_FLUSHREAD       1
+#define TIOCPKT_FLUSHWRITE      2
+#define TIOCPKT_STOP            4
+#define TIOCPKT_START           8
+#define TIOCPKT_NOSTOP         16
+#define TIOCPKT_DOSTOP         32
+
+#define TIOCSER_TEMT    0x01   /* Transmitter physically empty */
+
+#endif /* _ASM_UBICOM32_IOCTLS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ip5000-asm.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ip5000-asm.h
new file mode 100644 (file)
index 0000000..62929e4
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * arch/ubicom32/include/asm/ip5000-asm.h
+ *     Instruction macros for the IP5000.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_IP5000_ASM_H
+#define _ASM_UBICOM32_IP5000_ASM_H
+
+#if !defined(__LINKER__)
+
+#if defined(__ASSEMBLY__)
+.macro cycles  quant
+.if    (\quant) == 1
+       nop
+.else
+.if    (((\quant) + 3) / 8) > 0
+.rept  (((\quant) + 3) / 8)
+       jmpt.f          .+4
+.endr
+.endif
+.if    ((((\quant) + 3) % 8) / 4) > 0
+       jmpt.t          .+4
+.endif
+.endif
+.endm
+#else
+/*
+ * Same macro as above just in C inline asm
+ */
+asm ("                                 \n\
+.macro cycles  quant                   \n\
+.if    (\\quant) == 1                  \n\
+       nop                             \n\
+.else                                  \n\
+.if    (((\\quant) + 3) / 8) > 0       \n\
+.rept  (((\\quant) + 3) / 8)           \n\
+       jmpt.f          .+4             \n\
+.endr                                  \n\
+.endif                                 \n\
+.if    ((((\\quant) + 3) % 8) / 4) > 0 \n\
+       jmpt.t          .+4             \n\
+.endif                                 \n\
+.endif                                 \n\
+.endm                                  \n\
+");
+#endif
+
+
+#if defined(__ASSEMBLY__)
+.macro pipe_flush      cyc
+       cycles          11 - (\cyc)
+.endm
+#else
+/*
+ * Same macro as above just in C inline asm
+ */
+asm ("                                 \n\
+.macro pipe_flush      cyc             \n\
+       cycles          11 - (\\cyc)    \n\
+.endm                                  \n\
+");
+
+#endif
+
+#if defined(__ASSEMBLY__)
+.macro setcsr_flush    cyc
+       cycles          5 - (\cyc)
+.endm
+#else
+/*
+ * Same macro as above just in C inline asm
+ */
+asm ("                                 \n\
+.macro setcsr_flush    cyc             \n\
+       cycles          5 - (\\cyc)     \n\
+.endm                                  \n\
+");
+#endif
+
+/*
+ * Macros for prefetch (using miss-aligned memory write)
+ */
+#if defined(__ASSEMBLY__)
+
+.macro pre_fetch_macro thread_num, Ascratch, Aaddress length
+       bclr            MT_TRAP_EN, MT_TRAP_EN, #(\thread_num)
+       bset            \Ascratch, \Aaddress, #0        ; force a miss-aligned address
+       jmpt.t          .+4                             ; delay for both address setup and trap disable
+       move.4          (\Ascratch), #0
+       .if             (\length > 32)
+       move.4          32(\Ascratch), #0
+       .endif
+       .if             (\length > 64)
+       move.4          64(\Ascratch), #0
+       .endif
+       .if             (\length > 96)
+       move.4          96(\Ascratch), #0
+       .endif
+       .if             (\length > 128)
+       invalid_instruction                             ; maximum pre-fetch size is 4 cache lines
+       .endif
+       bset            MT_TRAP_EN, MT_TRAP_EN, #(\thread_num)
+.endm
+
+#else
+/*
+ * Same macro as above just in C inline asm
+ */
+asm ("                                                         \n\
+.macro pre_fetch_macro thread_num, Ascratch, Aaddress length   \n\
+       bclr            MT_TRAP_EN, MT_TRAP_EN, #(\thread_num)  \n\
+       bset            \\Ascratch, \\Aaddress, #0      ; force a miss-aligned address \n\
+       jmpt.t          .+4                             ; delay for both address setup and trap disable \n\
+       move.4          (\\Ascratch), #0                        \n\
+       .if             (\\length > 32)                         \n\
+       move.4          32(\\Ascratch), #0                      \n\
+       .endif                                                  \n\
+       .if             (\\length > 64)                         \n\
+       move.4          64(\\Ascratch), #0                      \n\
+       .endif                                                  \n\
+       .if             (\\length > 96)                         \n\
+       move.4          96(\\Ascratch), #0                      \n\
+       .endif                                                  \n\
+       .if             (\\length > 128)                        \n\
+       invalid_instruction                             ; maximum pre-fetch size is 4 cache lines \n\
+       .endif                                                  \n\
+       bset            MT_TRAP_EN, MT_TRAP_EN, #(\\thread_num) \n\
+.endm                                                          \n\
+");
+#endif
+
+#endif /* !defined(__LINKER__) */
+#endif /* defined _ASM_UBICOM32_IP5000_ASM_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ip5000.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ip5000.h
new file mode 100644 (file)
index 0000000..b616ebe
--- /dev/null
@@ -0,0 +1,845 @@
+/*
+ * arch/ubicom32/include/asm/ip5000.h
+ *   Specific details for the Ubicom IP5000 processor.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_IP5000_H
+#define _ASM_UBICOM32_IP5000_H
+
+#include <asm/memory_map.h>
+
+/*
+ * Inline assembly define
+ */
+#define S(arg) #arg
+#define D(arg) S(arg)
+
+/*
+ * Assembler include file
+ */
+#include <asm/ip5000-asm.h>
+
+/*
+ * Timing
+ */
+#define JMPT_PENALTY 3
+#define JMPF_PENALTY 7
+#define RET_PENALTY 7
+
+/*
+ * Threads
+ */
+#if defined(IP5000) || defined(IP5000_REV2)
+#define THREAD_COUNT 10
+#elif defined(IP7000) || defined(IP7000_REV2)
+#define THREAD_COUNT 12
+#else
+#error "Unknown IP5K silicon"
+#endif
+
+/*
+ * Arch
+ */
+#if defined(IP5000) || defined(IP5000_REV2)
+#define UBICOM32_ARCH_VERSION 3
+#elif defined(IP7000) || defined(IP7000_REV2)
+#define UBICOM32_ARCH_VERSION 4
+#else
+#error "Unknown IP5K silicon"
+#endif
+
+
+/*
+ * Registers
+ */
+#define ROSR_INT (1 << 0)
+
+/* Interrupts */
+#define INT_CHIP(reg, bit) (((reg) << 5) | (bit))
+#define INT_REG(interrupt) (((interrupt) >> 5) * 4)
+#define INT_SET(interrupt) 0x0114 + INT_REG(interrupt)
+#define INT_CLR(interrupt) 0x0124 + INT_REG(interrupt)
+#define INT_STAT(interrupt) 0x0104 + INT_REG(interrupt)
+#define INT_MASK(interrupt) 0x00C0 + INT_REG(interrupt)
+#define INT_BIT(interrupt) ((interrupt) & 0x1F)
+#define INT_BIT_MASK(interrupt) (1 << INT_BIT(interrupt))
+
+/*
+ * The LOCK_INT and THREAD_INT are used to wake up corresponding thread. They are sharing
+ * the same set of SW interrupt resource.
+ *
+ * LOCK_INT(n): One SW INT per NRT thread that can participate lock operation.
+ *     The threads that can participate lock are application threads and DSR thread.
+ *     (Lock locks - numbers are hard-coded in lock.h)
+ * THREAD_INT(n):   One SW INT per HRT thread for wake up trigger.
+ */
+#define LOCK_INT(thread)       INT_CHIP(0, (thread))
+#define THREAD_INT(thread)     INT_CHIP(0, (thread))
+
+/*
+ * The SYSTEM_INT and DSR_INT are sharing the same set of SW interrupt resource.
+ *
+ * SYSTEM_INT(n): One SW INT per NRT threads (application threads) as system queue interrupt,
+ *     and for DSR as self-trigger interrupt.
+ *     (The application threads include at least thread 0)
+ * DSR_INT(n):    One SW INT per HRT thread to request DSR service.
+ */
+#define SYSTEM_INT(thread)     INT_CHIP(0, THREAD_COUNT + (thread))
+#define DSR_INT(thread)                INT_CHIP(0, THREAD_COUNT + (thread))
+
+/* GLOBAL_CTRL */
+#define GLOBAL_CTRL_TRAP_RST_EN (1 << 9)
+#define GLOBAL_CTRL_AERROR_RST_EN (1 << 8)
+#define GLOBAL_CTRL_MT_MIN_DELAY(x) ((x) << 3)
+#define GLOBAL_CTRL_HRT_BANK_SELECT (1 << 2)
+#define GLOBAL_CTRL_INT_EN (1 << 0)
+
+/*
+ * HRT Tables
+ */
+#define HRT_TABLE0_BASE 0x0800
+#define HRT_TABLE1_BASE 0x0900
+#define HRT_TABLE_SIZE 64
+
+/*
+ * Break Point Trap Register
+ */
+#define ASYNCERROR_INT INT_CHIP(0, 31)
+#define BREAKPOINT_INT INT_CHIP(1, 31)
+
+/*
+ * Port interrupts
+ *     The non-existing FIFO INTs are mapped to INT2 for the ports.
+ */
+#define IO_PORT_PTR_TO_NUM(port) (((port) & 0x0000ffff) >> 12)
+#define RX_FIFO_INT(port) \
+       ((IO_PORT_PTR_TO_NUM(port) == 0) ? INT_CHIP(0, 25) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 1) ? INT_CHIP(0, 26) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 2) ? INT_CHIP(0, 29) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 3) ? INT_CHIP(1, 24) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 4) ? INT_CHIP(1, 27) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 5) ? INT_CHIP(1, 16) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 6) ? INT_CHIP(1, 19) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 7) ? INT_CHIP(1, 20) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 8) ? INT_CHIP(1, 21) : \
+       INT_CHIP(1, 15))))))))))
+#define TX_FIFO_INT(port) \
+       ((IO_PORT_PTR_TO_NUM(port) == 0) ? INT_CHIP(0, 24) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 1) ? INT_CHIP(0, 27) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 2) ? INT_CHIP(0, 29) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 3) ? INT_CHIP(1, 25) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 4) ? INT_CHIP(1, 28) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 5) ? INT_CHIP(1, 17) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 6) ? INT_CHIP(1, 19) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 7) ? INT_CHIP(1, 20) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 8) ? INT_CHIP(1, 22) : \
+       INT_CHIP(1, 15))))))))))
+#define PORT_OTHER_INT(port) \
+       ((IO_PORT_PTR_TO_NUM(port) == 0) ? INT_CHIP(0, 25) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 1) ? INT_CHIP(0, 28) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 2) ? INT_CHIP(0, 29) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 3) ? INT_CHIP(1, 26) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 4) ? INT_CHIP(1, 29) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 5) ? INT_CHIP(1, 18) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 6) ? INT_CHIP(1, 19) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 7) ? INT_CHIP(1, 20) : \
+       ((IO_PORT_PTR_TO_NUM(port) == 8) ? INT_CHIP(1, 23) : \
+       INT_CHIP(1, 15))))))))))
+
+/*
+ * On Chip Peripherals Base.
+ */
+#define OCP_BASE       0x01000000
+#define OCP_GENERAL    0x000
+#define OCP_TIMERS     0x100
+#define OCP_TRNG       0x200   /* True Random Number Generator Control Reigsters */
+#define OCP_DEBUG      0x300
+#define OCP_SECURITY   0x400
+#define OCP_ICCR       0x500   /* I-Cache Control Registers */
+#define OCP_DCCR       0x600   /* D-Cache Control Registers */
+#define OCP_OCMC       0x700   /* On Chip Memory Control Registers */
+#define OCP_STATISTICS 0x800   /* Statistics Counters */
+#define OCP_MTEST      0x900   /* Memory Test Registers */
+#define OCP_MCFG       0xa00   /* Memory Configuration Registers -- IP7000 only */
+#define OCP_DEBUG_INST 0x000   /* Up to 16M */
+
+/*
+ * General Configuration Registers (PLL)
+ */
+#define GENERAL_CFG_BASE (OCP_BASE + OCP_GENERAL)
+#define GEN_CLK_CORE_CFG 0x00
+#define GEN_CLK_IO_CFG 0x04
+#define GEN_CLK_DDR_CFG 0x08
+#define GEN_CLK_DDRDS_CFG 0x0c
+#define GEN_CLK_SLIP_CLR 0x10
+#define GEN_CLK_SLIP_START 0x14
+#define GEN_CLK_SERDES_SEL 0x18        /* IP7000 only */
+#define GEN_CLK_DDR_CFG2 0x1c  /* IP7000 only */
+#define GEN_DDR_CAL_CTRL 0x30  /* IP5000 only */
+#define GEN_DDR_CAL_STAT 0x34  /* IP5000 only */
+#define GEN_USB_DFT_CTRL 0x38  /* IP5000 only */
+#define GEN_USB_DFT_STAT 0x3c  /* IP5000 only */
+#define GEN_USB_PHY_CFG 0x40   /* IP7000 only */
+#define GEN_USB_PHY_TEST 0x44  /* IP7000 only */
+#define GEN_USB_PHY_STAT 0x48  /* IP7000 only */
+#define GEN_SW_RESET 0x80
+#define GEN_RESET_REASON 0x84
+#define GEN_BOND_CFG 0x88
+#define GEN_IO_PU_CFG 0x8c
+#define GEN_MEM_RM_CFG 0x90
+#define GEN_IO_CONFIG 0x94
+
+#define GEN_CLK_PLL_SECURITY_BIT_NO 31
+#define GEN_CLK_PLL_SECURITY (1 << GEN_CLK_PLL_SECURITY_BIT_NO)
+#define GEN_CLK_PLL_ENSAT (1 << 30)
+#define GEN_CLK_PLL_FASTEN (1 << 29)
+#define GEN_CLK_PLL_NR(v) (((v) - 1) << 23)
+#define GEN_CLK_PLL_NF(v) (((v) - 1) << 11)
+#define GEN_CLK_PLL_OD(v) (((v) - 1) << 8)
+#define GEN_CLK_PLL_RESET (1 << 7)
+#define GEN_CLK_PLL_BYPASS (1 << 6)
+#define GEN_CLK_PLL_POWERDOWN (1 << 5)
+#define GEN_CLK_PLL_SELECT (1 << 4)
+
+#define GEN_GET_CLK_PLL_NR(v) ((((v) >> 23) & 0x003f) + 1)
+#define GEN_GET_CLK_PLL_NF(v) ((((v) >> 11) & 0x0fff) + 1)
+#define GEN_GET_CLK_PLL_OD(v) ((((v) >> 8) & 0x7) + 1)
+
+
+#define RESET_FLAG_DST_MEM_ERROR (1 << 18)
+#define RESET_FLAG_SRC1_MEM_ERROR (1 << 17)
+#define RESET_FLAG_WRITE_ADDR (1 << 16)
+#define RESET_FLAG_DST_SYNC_ERROR (1 << 15)
+#define RESET_FLAG_SRC1_SYNC_ERROR (1 << 14)
+#define RESET_FLAG_DST_ALGN_ERROR (1 << 13)
+#define RESET_FLAG_SRC1_ALGN_ERROR (1 << 12)
+#define RESET_FLAG_DST_ADDR_ERROR (1 << 11)
+#define RESET_FLAG_SRC1_ADDR_ERROR (1 << 10)
+#define RESET_FLAG_ILLEGAL_INST (1 << 9)
+#define RESET_FLAG_INST_SYNC_ERROR (1 << 8)
+#define RESET_FLAG_INST_ADDR_ERROR (1 << 7)
+#define RESET_FLAG_DATA_PORT_ERROR (1 << 6)
+#define RESET_FLAG_INST_PORT_ERROR (1 << 5)
+#define RESET_FLAG_SW_RESET (1 << 4)
+#define RESET_FLAG_DEBUG (1 << 3)
+#define RESET_FLAG_WATCHDOG (1 << 2)
+#define RESET_FLAG_POWER_ON (1 << 1)
+#define RESET_FLAG_EXTERNAL (1 << 0)
+
+/*
+ * Timer block
+ */
+#define TIMER_BASE (OCP_BASE + OCP_TIMERS)
+#define TIMER_MPTVAL 0x00
+#define TIMER_RTCOM 0x04
+#define TIMER_TKEY 0x08
+#define TIMER_WDCOM 0x0c
+#define TIMER_WDCFG 0x10
+#define TIMER_SYSVAL 0x14
+#define TIMER_SYSCOM(tmr) (0x18 + (tmr) * 4)
+#define TIMER_TRN_CFG 0x100
+#define TIMER_TRN 0x104
+
+#define TIMER_COUNT 10
+#define TIMER_INT(tmr) INT_CHIP(1, (tmr))
+#define TIMER_TKEYVAL 0xa1b2c3d4
+#define TIMER_WATCHDOG_DISABLE 0x4d3c2b1a
+#define TIMER_TRN_CFG_ENABLE_OSC 0x00000007
+
+#ifndef __ASSEMBLY__
+/*
+ * ubicom32_io_timer
+ */
+struct ubicom32_io_timer {
+       volatile u32_t mptval;
+       volatile u32_t rtcom;
+       volatile u32_t tkey;
+       volatile u32_t wdcom;
+       volatile u32_t wdcfg;
+       volatile u32_t sysval;
+       volatile u32_t syscom[TIMER_COUNT];
+       volatile u32_t reserved[64 - 6 - TIMER_COUNT];  // skip all the way to OCP-TRNG section
+       volatile u32_t rsgcfg;
+       volatile u32_t trn;
+};
+
+#define UBICOM32_IO_TIMER ((struct ubicom32_io_timer *)TIMER_BASE)
+#endif
+
+#define UBICOM32_VECTOR_TO_TIMER_INDEX(vector) (vector - TIMER_INT(0))
+
+/*
+ * OCP-Debug Module (Mailbox)
+ */
+#define ISD_MAILBOX_BASE (OCP_BASE + OCP_DEBUG)
+#define ISD_MAILBOX_IN 0x00
+#define ISD_MAILBOX_OUT 0x04
+#define ISD_MAILBOX_STATUS 0x08
+
+#define ISD_MAILBOX_INT INT_CHIP(1, 30)
+
+#define ISD_MAILBOX_STATUS_IN_FULL (1 << 31)
+#define ISD_MAILBOX_STATUS_IN_EMPTY (1 << 30)
+#define ISD_MAILBOX_STATUS_OUT_FULL (1 << 29)
+#define ISD_MAILBOX_STATUS_OUT_EMPTY (1 << 28)
+
+/*
+ * OCP-Security
+ */
+#define SECURITY_BASE (OCP_BASE + OCP_SECURITY)
+#define SECURITY_BASE_EFFECTIVE_ADDRESS (SECURITY_BASE >> 7) // To load the base address in a single instruction
+#define SECURITY_CTRL 0x00
+#define SECURITY_CTRL_BYTE_OFFSET(x) ((x) << 16)
+#define SECURITY_CTRL_KEY_SIZE(x) ((x) << 8)
+#define SECURITY_CTRL_HASH_ALG_NONE (0 << 4)
+#define SECURITY_CTRL_HASH_ALG_MD5 (1 << 4)
+#define SECURITY_CTRL_HASH_ALG_SHA1 (2 << 4)
+#define SECURITY_CTRL_CBC (1 << 3)
+#define SECURITY_CTRL_CIPHER_ALG_AES (0 << 1)
+#define SECURITY_CTRL_CIPHER_ALG_NONE (1 << 1)
+#define SECURITY_CTRL_CIPHER_ALG_DES (2 << 1)
+#define SECURITY_CTRL_CIPHER_ALG_3DES (3 << 1)
+#define SECURITY_CTRL_ENCIPHER (1 << 0)
+#define SECURITY_CTRL_DECIPHER (0 << 0)
+#define SECURITY_STAT 0x04
+#define SECURITY_STAT_BUSY (1 << 0)
+#define SECURITY_KEY_VALUE(x) (0x10 + (x) * 4)
+#define SECURITY_KEY_IN(x) (0x30 + (x) * 4)
+#define SECURITY_KEY_OUT(x) (0x50 + (x) * 4)
+#define SECURITY_KEY_HASH(x) (0x70 + (x) * 4)
+
+/*
+ * OCP-ICCR
+ */
+#define ICCR_BASE (OCP_BASE + OCP_ICCR)
+#define ICACHE_TOTAL_SIZE 16384                        /* in bytes */
+
+/*
+ * OCP-DCCR
+ */
+#define DCCR_BASE (OCP_BASE + OCP_DCCR)
+#if defined(IP5000) || defined(IP5000_REV2)
+#define DCACHE_TOTAL_SIZE 8192                 /* in bytes */
+#elif defined(IP7000) || defined(IP7000_REV2)
+#define DCACHE_TOTAL_SIZE 16384                        /* in bytes */
+#endif
+
+#if defined(IP5000) || defined(IP5000_REV2) || defined(IP7000) || defined(IP7000_REV2)
+#define DCACHE_WRITE_QUEUE_LENGTH 6
+#else
+#error "Unknown IP5K silicon"
+#endif
+
+#define CACHE_LINE_SIZE 32                     /* in bytes */
+
+#define CCR_ADDR 0x00
+#define CCR_RDD 0x04
+#define CCR_WRD 0x08
+#define CCR_STAT 0x0c
+#define CCR_CTRL 0x10
+
+#define CCR_STAT_MCBE 0
+#define CCR_STAT_WIDEL 1                       /* D-cache only */
+
+#define CCR_CTRL_DONE 0
+#define CCR_CTRL_RESET 2
+#define CCR_CTRL_VALID 3
+#define CCR_CTRL_RD_DATA (1 << 4)
+#define CCR_CTRL_RD_TAG (2 << 4)
+#define CCR_CTRL_WR_DATA (3 << 4)
+#define CCR_CTRL_WR_TAG (4 << 4)
+#define CCR_CTRL_INV_INDEX (5 << 4)
+#define CCR_CTRL_INV_ADDR (6 << 4)
+#define CCR_CTRL_FLUSH_INDEX (7 << 4)          /* D-cache only */
+#define CCR_CTRL_FLUSH_INV_INDEX (8 << 4)      /* D-cache only */
+#define CCR_CTRL_FLUSH_ADDR (9 << 4)           /* D-cache only */
+#define CCR_CTRL_FLUSH_INV_ADDR (10 << 4)      /* D-cache only */
+
+/*
+ * OCP-OCMC
+ */
+#define OCMC_BASE (OCP_BASE + OCP_OCMC)
+#define OCMC_BANK_MASK 0x00
+#define OCMC_BIST_CNTL 0x04    /* IP5000 only */
+#define OCMC_BIST_STAT 0x08    /* IP5000 only */
+
+#define OCMC_BANK_PROG(n) ((1<<(n))-1)
+
+#define OCMC_BIST_WRCK (1 << 7)
+#define OCMC_BIST_RESET (1 << 5)
+#define OCMC_BIST_SMART (1 << 4)
+#define OCMC_BIST_RUN (1 << 3)
+#define OCMC_BIST_REPAIR (1 << 2)
+
+#define OCMC_BIST_READY (1 << 3)
+#define OCMC_BIST_FAIL (1 << 2)
+
+/*
+ * OCP-STATISTICS
+ */
+#define STATISTICS_BASE (OCP_BASE + OCP_STATISTICS)
+#define STAT_COUNTER_CTRL(n) ((n)*8)
+#define STAT_COUNTER(n) ((n)*8 + 4)
+
+#define STAT_EVENT_MP_INST 0
+#define STAT_EVENT_OCM_ACCESS 4
+#define STAT_EVENT_OCM_REQ 5
+#define STAT_EVENT_IC_REQ_INVAL 13
+#define STAT_EVENT_IC_MISS_INVAL 14
+#define STAT_EVENT_IC_REQ_INVAL_NACK 15
+#define STAT_EVENT_IC_REQ_VAL 16
+#define STAT_EVENT_IC_MISS_VAL 17
+#define STAT_EVENT_IC_REQ_VAL_NACK 18
+#define STAT_EVENT_IC_MISS_Q 19
+#define STAT_EVENT_DC_RD_REQ 20
+#define STAT_EVENT_DC_RD_MISS 21
+#define STAT_EVENT_DC_WR_REQ 22
+#define STAT_EVENT_DC_WR_MISS 23
+#define STAT_EVENT_DC_MISS_Q 24
+#define STAT_EVENT_DC_WB_FULL 25
+#define STAT_EVENT_DC_REQ_NACK 26
+#define STAT_EVENT_DC_CORE_REQ 27
+#define STAT_EVENT_DC_MISS 28
+#define STAT_EVENT_DC_EVICT 29
+#define STAT_EVENT_TRUE 30
+#define STAT_EVENT_FALSE 31
+
+/*
+ * OCP_MTEST
+ */
+#define MTEST_BASE (OCP_BASE + OCP_MTEST)
+#define MTEST_ADDR 0x00
+#define MTEST_WR 0x04
+#define MTEST_RD 0x08
+#define MTEST_CTRL 0x0c
+
+/*
+ * OCP_MCFG (IP7000 only)
+ */
+#define MCFG_BASE (OCP_BASE + OCP_MCFG)
+#define MCFG_CTRL 0x00
+#define MCFG_WCFG 0x04
+#define MCFG_RCFG 0x08
+
+/*
+ * Port registers
+ */
+#define IO_BASE 0x02000000
+#define RA (IO_BASE + 0x00000000)
+#define RB (IO_BASE + 0x00001000)
+#define RC (IO_BASE + 0x00002000)
+#define RD (IO_BASE + 0x00003000)
+#define RE (IO_BASE + 0x00004000)
+#define RF (IO_BASE + 0x00005000)
+#define RG (IO_BASE + 0x00006000)
+#define RH (IO_BASE + 0x00007000)
+#define RI (IO_BASE + 0x00008000)
+#define RJ (IO_BASE + 0x00009000)
+#define RLATCH (IO_BASE + 0x00ff0000)  // For latched output only
+#define IO_PORT_BR_OFFSET 0x00000800
+
+/*
+ * General I/O Register Map (per port)
+ */
+#define IO_FUNC 0x00
+#define IO_GPIO_CTL 0x04
+#define IO_GPIO_OUT 0x08
+#define IO_GPIO_IN 0x0C
+#define IO_INT_STATUS 0x10
+#define IO_INT_MASK 0x14
+#define IO_INT_SET 0x18
+#define IO_INT_CLR 0x1C
+#define IO_TX_FIFO 0x20
+#define IO_TX_FIFO_HI 0x24
+#define IO_RX_FIFO 0x28
+#define IO_RX_FIFO_HI 0x2c
+#define IO_CTL0 0x30
+#define IO_CTL1 0x34
+#define IO_CTL2 0x38
+#define IO_STATUS0 0x3c
+#define IO_STATUS1 0x40
+#define IO_STATUS2 0x44
+#define IO_FIFO_WATER 0x48
+#define IO_FIFO_LEVEL 0x4c
+#define IO_GPIO_MASK 0x50
+
+#define IO_FUNC_FUNCTION_RESET(func) ((1 << ((func) - 1)) << 4)        /* Function 0 doesn't need reset */
+#define IO_FUNC_RX_FIFO (1 << 3)
+#define IO_FUNC_SELECT(func) ((func) << 0)
+
+/*
+ * External interrupt pins.
+ */
+#define EXT_INT_IO_BIT(pin) ((pin) + 5)        // Interrupt pin number -> I/O INT bit
+#define EXT_INT_RISING_EDGE(pin) (0x2 << (2*(pin) + 7))
+#define EXT_INT_FALLING_EDGE(pin) (0x1 << (2*(pin) + 7))
+
+/*
+ * Flash
+ */
+#define IO_XFL_BASE RA
+
+#define IO_XFL_INT_START (1 << 16)
+#define IO_XFL_INT_ERR (1 << 8)
+#define IO_XFL_INT_DONE (1 << 0)
+
+#define IO_XFL_CTL0_MASK (0xffe07fff)
+#define IO_XFL_CTL0_RD_CMD(cmd) (((cmd) & 0xff) << 24)
+#define IO_XFL_CTL0_RD_DUMMY(n) (((n) & 0x7) << 21)
+#define IO_XFL_CTL0_CLK_WIDTH(core_cycles) ((((core_cycles) + 1) & 0x7e) << 8) /* must be even number */
+#define IO_XFL_CTL0_CE_WAIT(spi_cycles) (((spi_cycles) & 0x3f) << 2)
+#define IO_XFL_CTL0_MCB_LOCK (1 << 1)
+#define IO_XFL_CTL0_ENABLE (1 << 0)
+#define IO_XFL_CTL0_FAST_VALUE(div, wait) (IO_XFL_CTL0_RD_CMD(0xb) | IO_XFL_CTL0_RD_DUMMY(1) | IO_XFL_CTL0_CLK_WIDTH(div) | IO_XFL_CTL0_CE_WAIT(wait) | IO_XFL_CTL0_ENABLE)
+#define IO_XFL_CTL0_VALUE(div, wait) (IO_XFL_CTL0_RD_CMD(3) | IO_XFL_CTL0_CLK_WIDTH(div) | IO_XFL_CTL0_CE_WAIT(wait) | IO_XFL_CTL0_ENABLE)
+
+#define IO_XFL_CTL1_MASK (0xc0003fff)
+#define IO_XFL_CTL1_FC_INST(inst) (((inst) & 0x3) << 30)
+#define IO_XFL_CTL1_FC_DATA(n) (((n) & 0x3ff) << 4)
+#define IO_XFL_CTL1_FC_DUMMY(n) (((n) & 0x7) << 1)
+#define IO_XFL_CTL1_FC_ADDR (1 << 0)
+
+#define IO_XFL_CTL2_FC_CMD(cmd) (((cmd) & 0xff) << 24)
+#define IO_XFL_CTL2_FC_ADDR(addr) ((addr) & 0x00ffffff)        /* Only up to 24 bits */
+
+#define IO_XFL_STATUS0_MCB_ACTIVE (1 << 0)
+#define IO_XFL_STATUS0_IOPCS_ACTIVE (1 << 1)
+
+/*
+ * SDRAM
+ */
+#define IO_SDRAM_DATA_BASE RG
+#define IO_SDRAM_CNTL_BASE RH
+
+#define IO_SDRAM_CTRL0_EN_REF (1 << 0)
+
+/*
+ * Port function code (common fucntion codes for all I/O ports)
+ */
+#define IO_PORTX_FUNC_GPIO 0x00
+#define IO_PORTX_FUNC_XFL 0x01
+#define IO_PORTX_FUNC_PCI 0x01
+#define IO_PORTX_FUNC_SERDES 0x01
+#define IO_PORTX_FUNC_GMII 0x01
+#define IO_PORTX_FUNC_DDR 0x01
+#define IO_PORTX_FUNC_PCIX 0x01
+#define IO_PORTX_FUNC_USB2_0 0x01
+#define IO_PORTX_FUNC_GPIO_INT_CLK 0x02
+#define IO_PORTX_FUNC_PLIO 0x02
+#define IO_PORTX_FUNC_GPIO_INT 0x03
+#define IO_PORTX_FUNC_MII 0x03
+
+/*
+ * Port 0
+ */
+#define IO_PORT0_FUNC_GPIO IO_PORTX_FUNC_GPIO
+#define IO_PORT0_FUNC_XFL_INT_CLK IO_PORTX_FUNC_XFL    // Default mode after reset
+#define IO_PORT0_FUNC_GPIO_INT_CLK IO_PORTX_FUNC_GPIO_INT_CLK
+#define IO_PORT0_FUNC_GPIO_INT IO_PORTX_FUNC_GPIO_INT
+
+/*
+ * Port 1
+ */
+#define IO_PORT1_FUNC_GPIO IO_PORTX_FUNC_GPIO
+#define IO_PORT1_FUNC_PCI IO_PORTX_FUNC_PCI            // PCI control
+#define IO_PORT1_FUNC_MII IO_PORTX_FUNC_MII            // port 4 MII extension
+
+/*
+ * Port 2
+ */
+#define IO_PORT2_FUNC_GPIO IO_PORTX_FUNC_GPIO
+#define IO_PORT2_FUNC_PCI IO_PORTX_FUNC_PCI            // PCI data I/O
+#define IO_PORT2_FUNC_PLIO IO_PORTX_FUNC_PLIO          // Extended LM
+
+/*
+ * Port 3
+ */
+#define IO_PORT3_FUNC_GPIO IO_PORTX_FUNC_GPIO
+#define IO_PORT3_FUNC_SERDES IO_PORTX_FUNC_SERDES
+#define IO_PORT3_FUNC_PLIO IO_PORTX_FUNC_PLIO
+
+/*
+ * Port 4
+ */
+#define IO_PORT4_FUNC_GPIO IO_PORTX_FUNC_GPIO
+#define IO_PORT4_FUNC_SERDES IO_PORTX_FUNC_SERDES
+#define IO_PORT4_FUNC_PLIO IO_PORTX_FUNC_PLIO          // Extended LM
+#define IO_PORT4_FUNC_MII IO_PORTX_FUNC_MII
+
+/*
+ * Port 5
+ */
+#define IO_PORT5_FUNC_GPIO IO_PORTX_FUNC_GPIO
+#define IO_PORT5_FUNC_GMII IO_PORTX_FUNC_GMII
+
+/*
+ * Port 6
+ */
+#define IO_PORT6_FUNC_GPIO IO_PORTX_FUNC_GPIO
+#define IO_PORT6_FUNC_DDR IO_PORTX_FUNC_DDR
+
+/*
+ * Port 7
+ */
+#define IO_PORT7_FUNC_GPIO IO_PORTX_FUNC_GPIO
+#define IO_PORT7_FUNC_DDR IO_PORTX_FUNC_DDR
+
+/*
+ * Port 8
+ */
+#define IO_PORT8_FUNC_GPIO IO_PORTX_FUNC_GPIO
+#define IO_PORT8_FUNC_PCIX IO_PORTX_FUNC_PCIX
+#define IO_PORT8_FUNC_PLIO IO_PORTX_FUNC_PLIO          // Extended LM
+#define IO_PORT8_FUNC_MII IO_PORTX_FUNC_MII            // port 4 MII extension
+
+/*
+ * Port 9
+ */
+#define IO_PORT9_FUNC_USB2_0 IO_PORTX_FUNC_USB2_0
+
+/*
+ * FIFO
+ */
+#define IO_PORTX_INT_FIFO_TX_RESET (1 << 31)
+#define IO_PORTX_INT_FIFO_RX_RESET (1 << 30)
+#define IO_PORTX_INT_FIFO_TX_UF (1 << 15)
+#define IO_PORTX_INT_FIFO_TX_WM (1 << 14)
+#define IO_PORTX_INT_FIFO_RX_OF (1 << 13)
+#define IO_PORTX_INT_FIFO_RX_WM (1 << 12)
+
+#define IO_PORTX_FUNC_FIFO_TX_WM(n) ((n) << 16)
+#define IO_PORTX_FUNC_FIFO_RX_WM(n) ((n) << 0)
+
+/*
+ * MII
+ */
+#define IO_PORTX_INT_MII_TX_ERR_SEND (1 << 18)
+#define IO_PORTX_INT_MII_TX_HALT (1 << 17)
+#define IO_PORTX_INT_MII_TX_START (1 << 16)
+#define IO_PORTX_INT_MII_THRESHOLD (1 << 8)
+#define IO_PORTX_INT_MII_RX_EOP (1 << 7)
+#define IO_PORTX_INT_MII_RX_SFD (1 << 6)
+#define IO_PORTX_INT_MII_RX_ERR (1 << 5)
+#define IO_PORTX_INT_MII_TX_EOP (1 << 4)
+#define IO_PORTX_INT_MII_COL (1 << 3)
+#define IO_PORTX_INT_MII_CRS (1 << 2)
+#define IO_PORTX_INT_MII_ODD_NIB_ERR (1 << 1)
+#define IO_PORTX_INT_MII_FALSE_CARRIER (1 << 0)
+
+/*
+ * SerDes
+ */
+#define IO_PORTX_INT_SERDES_TXBUF_VALID (1 << 16)
+#define IO_PORTX_INT_SERDES_RXERR (1 << 7)
+#define IO_PORTX_INT_SERDES_RXEOP (1 << 6)
+#define IO_PORTX_INT_SERDES_SYND (1 << 5)
+#define IO_PORTX_INT_SERDES_TXBE (1 << 4)
+#define IO_PORTX_INT_SERDES_TXEOP (1 << 3)
+#define IO_PORTX_INT_SERDES_SXLP (1 << 2)
+#define IO_PORTX_INT_SERDES_RXBF (1 << 1)
+#define IO_PORTX_INT_SERDES_RXCRS (1 << 0)
+
+#ifndef __ASSEMBLY__
+struct ubicom32_io_port {
+       volatile u32_t function;
+       volatile u32_t gpio_ctl;
+       volatile u32_t gpio_out;
+       volatile u32_t gpio_in;
+       volatile u32_t int_status;
+       volatile u32_t int_mask;
+       volatile u32_t int_set;
+       volatile u32_t int_clr;
+       volatile u32_t tx_fifo;
+       volatile u32_t tx_fifo_hi;
+       volatile u32_t rx_fifo;
+       volatile u32_t rx_fifo_hi;
+       volatile u32_t ctl0;
+       volatile u32_t ctl1;
+       volatile u32_t ctl2;
+       volatile u32_t status0;
+       volatile u32_t status1;
+       volatile u32_t status2;
+       volatile u32_t fifo_watermark;
+       volatile u32_t fifo_level;
+       volatile u32_t gpio_mask;
+};
+
+#define UBICOM32_IO_PORT(port) ((struct ubicom32_io_port *)((port)))
+#endif
+
+#ifndef __ASSEMBLY__
+/*
+ * ubicom32_set_interrupt()
+ */
+extern inline void ubicom32_set_interrupt(u8_t interrupt)
+{
+       u32_t ibit = INT_BIT_MASK(interrupt);
+
+       if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) {
+               asm volatile (
+                       "move.4         "D(INT_SET(INT_CHIP(0, 0)))", %0\n\t"
+                       :
+                       : "r" (ibit)
+               );
+
+               return;
+       }
+
+       asm volatile (
+               "move.4         "D(INT_SET(INT_CHIP(1, 0)))", %0\n\t"
+               :
+               : "r" (ibit)
+       );
+}
+
+/*
+ * ubicom32_clear_interrupt()
+ */
+extern inline void ubicom32_clear_interrupt(u8_t interrupt)
+{
+       u32_t ibit = INT_BIT_MASK(interrupt);
+
+       if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) {
+               asm volatile (
+                       "move.4         "D(INT_CLR(INT_CHIP(0, 0)))", %0\n\t"
+                       :
+                       : "r" (ibit)
+               );
+
+               return;
+       }
+
+       asm volatile (
+               "move.4         "D(INT_CLR(INT_CHIP(1, 0)))", %0\n\t"
+               :
+               : "r" (ibit)
+       );
+}
+
+/*
+ * ubicom32_enable_interrupt()
+ */
+extern inline void ubicom32_enable_interrupt(u8_t interrupt)
+{
+       u32_t ibit = INT_BIT_MASK(interrupt);
+
+       if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) {
+               asm volatile (
+                       "or.4           "D(INT_MASK(INT_CHIP(0, 0)))", "D(INT_MASK(INT_CHIP(0, 0)))", %0\n\t"
+                       :
+                       : "d" (ibit)
+               );
+
+               return;
+       }
+
+       asm volatile (
+               "or.4           "D(INT_MASK(INT_CHIP(1, 0)))", "D(INT_MASK(INT_CHIP(1, 0)))", %0\n\t"
+               :
+               : "d" (ibit)
+       );
+}
+
+/*
+ * ubicom32_disable_interrupt()
+ */
+extern inline void ubicom32_disable_interrupt(u8_t interrupt)
+{
+       u32_t ibit = ~INT_BIT_MASK(interrupt);
+
+       if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) {
+               asm volatile (
+                       "and.4          "D(INT_MASK(INT_CHIP(0, 0)))", "D(INT_MASK(INT_CHIP(0, 0)))", %0\n\t"
+                       :
+                       : "d" (ibit)
+               );
+
+               return;
+       }
+
+       asm volatile (
+               "and.4          "D(INT_MASK(INT_CHIP(1, 0)))", "D(INT_MASK(INT_CHIP(1, 0)))", %0\n\t"
+               :
+               : "d" (ibit)
+       );
+}
+
+/*
+ * ubicom32_enable_global_interrupts()
+ */
+extern inline void ubicom32_enable_global_interrupts(void)
+{
+       asm volatile(
+               "bset           GLOBAL_CTRL, GLOBAL_CTRL, #%bit("D(GLOBAL_CTRL_INT_EN)")"
+       );
+}
+
+/*
+ * ubicom32_disable_global_interrupts()
+ */
+extern inline void ubicom32_disable_global_interrupts(void)
+{
+       asm volatile(
+               "bclr           GLOBAL_CTRL, GLOBAL_CTRL, #%bit("D(GLOBAL_CTRL_INT_EN)")"
+       );
+}
+
+/*
+ * ubicom32_get_reset_reason()
+ */
+extern inline u32_t ubicom32_get_reset_reason(void)
+{
+       return *(u32_t *)(GENERAL_CFG_BASE + GEN_RESET_REASON);
+}
+
+/*
+ * ubicom32_read_reg()
+ */
+extern inline u32_t ubicom32_read_reg(volatile void *reg)
+{
+       u32_t v;
+       asm volatile (
+               "move.4         %[dest], %[src] \n\t"
+               : [dest] "=r" (v)
+               : [src] "m" (*(u32_t *)reg)
+       );
+       return v;
+}
+
+/*
+ * ubicom32_write_reg()
+ */
+extern inline void ubicom32_write_reg(volatile void *reg, u32_t v)
+{
+       asm volatile (
+               "move.4         %[dest], %[src] \n\t"
+               :
+               : [src] "r" (v), [dest] "m" (*(u32_t *)reg)
+       );
+}
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_UBICOM32_IP5000_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ipcbuf.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ipcbuf.h
new file mode 100644 (file)
index 0000000..76acafb
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * arch/ubicom32/include/asm/ipcbuf.h
+ *   Definition of ipc64_perm struct for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_IPCBUF_H
+#define _ASM_UBICOM32_IPCBUF_H
+
+/*
+ * The user_ipc_perm structure for m68k 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 /* _ASM_UBICOM32_IPCBUF_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/irq.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/irq.h
new file mode 100644 (file)
index 0000000..b552589
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * arch/ubicom32/include/asm/irq.h
+ *   IRQ definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_IRQ_H
+#define _ASM_UBICOM32_IRQ_H
+
+#include <asm/irqflags.h>
+
+/*
+ * We setup the IRQS to cover the full range of interrupt registers in
+ * processor.
+ */
+#define NR_IRQS                64
+
+#define irq_canonicalize(irq) (irq)
+
+extern int irq_soft_alloc(unsigned int *soft);
+extern void ack_bad_irq(unsigned int irq);
+extern void do_IRQ(int irq, struct pt_regs *fp);
+
+#endif /* _ASM_UBICOM32_IRQ_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/irq_regs.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/irq_regs.h
new file mode 100644 (file)
index 0000000..afc33e4
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/irq_regs.h
+ *   Generic irq_regs.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_IRQ_REGS_H
+#define _ASM_UBICOM32_IRQ_REGS_H
+
+#include <asm-generic/irq_regs.h>
+
+#endif /* _ASM_UBICOM32_IRQ_REGS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/irqflags.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..f40906e
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * arch/ubicom32/include/asm/irqflags.h
+ *   Raw implementation of local IRQ functions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_IRQFLAGS_H
+#define _ASM_UBICOM32_IRQFLAGS_H
+
+#include <linux/thread_info.h>
+#include <asm/ubicom32-common.h>
+#if defined(CONFIG_SMP)
+#include <asm/smp.h>
+#endif
+#include <asm/ldsr.h>
+
+#if defined(CONFIG_PREEMPT)
+#error Not supported by Ubicom32 irq handling, yet!
+#endif
+
+/*
+ * raw_local_irq_enable()
+ *     Enable interrupts for this thread.
+ */
+static inline void raw_local_irq_enable(void)
+{
+       ldsr_local_irq_enable();
+}
+
+/*
+ * raw_local_irq_disable()
+ *     Disable interrupts for this thread.
+ */
+static inline void raw_local_irq_disable(void)
+{
+       ldsr_local_irq_disable();
+}
+
+/*
+ * raw_local_save_flags()
+ *     Get the current IRQ state.
+ */
+#define raw_local_save_flags(flags)            \
+do {                                           \
+       (flags) = ldsr_local_irq_is_disabled(); \
+} while (0)
+
+/*
+ * raw_local_irq_save()
+ *     Save the current interrupt state and disable interrupts.
+ */
+#define raw_local_irq_save(flags)              \
+do {                                           \
+       (flags) = ldsr_local_irq_save();        \
+} while (0)
+
+/*
+ * raw_local_irq_restore()
+ *     Restore the IRQ state back to flags.
+ */
+static inline void raw_local_irq_restore(unsigned long flags)
+{
+       ldsr_local_irq_restore(flags);
+}
+
+/*
+ * raw_irqs_disabled_flags()
+ *     Return true if the flags indicate that IRQ(s) are disabled.
+ */
+static inline int raw_irqs_disabled_flags(unsigned long flags)
+{
+       return (flags);
+}
+
+#endif /* _ASM_UBICOM32_IRQFLAGS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/kdebug.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/kdebug.h
new file mode 100644 (file)
index 0000000..514bd27
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/kdebug.h
+ *   Generic kdebug.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_KDEBUG_H
+#define _ASM_UBICOM32_KDEBUG_H
+
+#include <asm-generic/kdebug.h>
+
+#endif /* _ASM_UBICOM32_KDEBUG_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/kmap_types.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/kmap_types.h
new file mode 100644 (file)
index 0000000..5f4ffea
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * arch/ubicom32/include/asm/kmap_types.h
+ *   Definition of km_type's for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_KMAP_TYPES_H
+#define _ASM_UBICOM32_KMAP_TYPES_H
+
+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 /* _ASM_UBICOM32_KMAP_TYPES_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ldsr.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ldsr.h
new file mode 100644 (file)
index 0000000..b829c87
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * arch/ubicom32/include/asm/ldsr.h
+ *   Ubicom32 LDSR interface definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_LDSR_H
+#define _ASM_UBICOM32_LDSR_H
+
+#include <asm/ubicom32-common.h>
+#include <asm/types.h>
+#include <asm/thread.h>
+
+extern unsigned int ldsr_soft_irq_mask;
+
+/*
+ * ldsr_local_irq_is_disabled()
+ *     Test if interrupts are disabled for this thread?
+ */
+static inline int ldsr_local_irq_is_disabled(void)
+{
+       int ret;
+       thread_t self = thread_get_self();
+       unsigned int mask = (1 << self);
+
+       asm volatile (
+       "       and.4   %0, scratchpad1, %1     \n\t"
+               : "=r" (ret)
+               : "d" (mask)
+               : "cc"
+       );
+
+       /*
+        *  We return a simple 1 == disabled, 0 == enabled
+        *  losing which tid this is for, because Linux
+        *  can restore interrupts on a different thread.
+        */
+       return ret >> self;
+}
+
+/*
+ * ldsr_local_irq_save()
+ *     Get the current interrupt state and disable interrupts.
+ */
+static inline unsigned int ldsr_local_irq_save(void)
+{
+       int ret;
+       thread_t self = thread_get_self();
+       unsigned int mask = (1 << self);
+
+       /*
+        * Ensure the compiler can not optimize out the code
+        * (volatile) and that it does not "cache" values around
+        * the interrupt state change (memory).  This ensures
+        * that interrupt changes are treated as a critical
+        * section.
+        */
+       asm volatile (
+       "       and.4   %0, scratchpad1, %1             \n\t"
+       "       or.4    scratchpad1, scratchpad1, %1    \n\t"
+               : "=&r" (ret)
+               : "d" (mask)
+               : "cc", "memory"
+       );
+
+       /*
+        *  We return a simple 1 == disabled, 0 == enabled
+        *  losing which tid this is for, because Linux
+        *  can restore interrupts on a different thread.
+        */
+       return ret >> self;
+}
+
+/*
+ * ldsr_local_irq_restore()
+ *     Restore this cpu's interrupt enable/disable state.
+ *
+ * Note: flags is either 0 or 1.
+ */
+static inline void ldsr_local_irq_restore(unsigned int flags)
+{
+       unsigned int temp;
+       thread_t self = thread_get_self();
+       unsigned int mask = (1 << self);
+       flags = (flags << self);
+
+       /*
+        * Ensure the compiler can not optimize out the code
+        * (volatile) and that it does not "cache" values around
+        * the interrupt state change (memory).  This ensures
+        * that interrupt changes are treated as a critical
+        * section.
+        *
+        * Atomic change to our bit in scratchpad1 without
+        * causing any temporary glitch in the value and
+        * without effecting other values.  Also this uses
+        * no branches so no penalties.
+        */
+       asm volatile (
+       "       xor.4   %0, scratchpad1, %1             \n\t"
+       "       and.4   %0, %2, %0                      \n\t"
+       "       xor.4   scratchpad1, scratchpad1, %0    \n\t"
+       "       move.4  int_set0, %3                    \n\t"
+               : "=&d"(temp)
+               : "d"(flags), "r"(mask), "r"(ldsr_soft_irq_mask)
+               : "cc", "memory"
+       );
+}
+
+/*
+ * ldsr_local_irq_disable_interrupt()
+ *     Disable ints for this thread.
+ */
+static inline void ldsr_local_irq_disable(void)
+{
+       unsigned int mask = (1 << thread_get_self());
+
+       /*
+        * Ensure the compiler can not optimize out the code
+        * (volatile) and that it does not "cache" values around
+        * the interrupt state change (memory).  This ensures
+        * that interrupt changes are treated as a critical
+        * section.
+        */
+       asm  volatile (
+       "       or.4    scratchpad1, scratchpad1, %0    \n\t"
+               :
+               : "d" (mask)
+               : "cc", "memory"
+       );
+}
+
+/*
+ * ldsr_local_irq_enable_interrupt
+ *     Enable ints for this thread.
+ */
+static inline void ldsr_local_irq_enable(void)
+{
+       unsigned int mask = (1 << thread_get_self());
+
+       /*
+        * Ensure the compiler can not optimize out the code
+        * (volatile) and that it does not "cache" values around
+        * the interrupt state change (memory).  This ensures
+        * that interrupt changes are treated as a critical
+        * section.
+        */
+       asm volatile (
+       "       and.4   scratchpad1, scratchpad1, %0    \n\t"
+       "       move.4  int_set0, %1                    \n\t"
+               :
+               : "d" (~mask), "r" (ldsr_soft_irq_mask)
+               : "cc", "memory"
+       );
+}
+
+extern void ldsr_init(void);
+extern void ldsr_set_trap_irq(unsigned int irq);
+extern void ldsr_mask_vector(unsigned int vector);
+extern void ldsr_unmask_vector(unsigned int vector);
+extern void ldsr_enable_vector(unsigned int vector);
+extern void ldsr_disable_vector(unsigned int vector);
+extern thread_t ldsr_get_threadid(void);
+
+#endif /* _ASM_UBICOM32_LDSR_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/linkage.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/linkage.h
new file mode 100644 (file)
index 0000000..63d56a2
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * arch/ubicom32/include/asm/linkage.h
+ *   Definition of Ubicom32 architecture specific linkage types.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_LINKAGE_H
+#define _ASM_UBICOM32_LINKAGE_H
+
+#define __ocm_text __section(.ocm_text)
+#define __ocm_data __section(.ocm_data)
+
+#endif /* _ASM_UBICOM32_LINKAGE_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/local.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/local.h
new file mode 100644 (file)
index 0000000..9c79317
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/local.h
+ *   Generic local.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_LOCAL_H
+#define _ASM_UBICOM32_LOCAL_H
+
+#include <asm-generic/local.h>
+
+#endif /* _ASM_UBICOM32_LOCAL_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/machdep.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/machdep.h
new file mode 100644 (file)
index 0000000..c358154
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * arch/ubicom32/include/asm/machdep.h
+ *   Machine dependent utility routines.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_MACHDEP_H
+#define _ASM_UBICOM32_MACHDEP_H
+
+#include <linux/interrupt.h>
+
+/* Hardware clock functions */
+extern unsigned long hw_timer_offset(void);
+
+/* machine dependent power off functions */
+extern void (*mach_reset)(void);
+extern void (*mach_halt)(void);
+extern void (*mach_power_off)(void);
+
+extern void config_BSP(char *command, int len);
+
+#endif /* _ASM_UBICOM32_MACHDEP_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/mc146818rtc.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mc146818rtc.h
new file mode 100644 (file)
index 0000000..89b3c56
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * arch/ubicom32/include/asm/mc146818rtc.h
+ *   Generic mc146818rtc.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+/*
+ * Machine dependent access functions for RTC registers.
+ */
+#ifndef _ASM_UBICOM32_MC146818RTC_H
+#define _ASM_UBICOM32_MC146818RTC_H
+
+/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */
+
+#endif /* _ASM_UBICOM32_MC146818RTC_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/memory_map.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/memory_map.h
new file mode 100644 (file)
index 0000000..a1c3219
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * arch/ubicom32/include/asm/memory_map.h
+ *   Machine memory maps/
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_MEMORY_MAP_H
+#define _ASM_UBICOM32_MEMORY_MAP_H
+
+/*
+ * Memory Size
+ */
+#define OCM_SECTOR_SIZE        0x00008000              /* 32K */
+
+#if defined(CONFIG_UBICOM32_V3)
+#define OCMSIZE        0x00030000      /* 192K on-chip RAM for both program and data */
+#elif defined(CONFIG_UBICOM32_V4)
+#define OCMSIZE        0x0003C000      /* 240K on-chip RAM for both program and data */
+#else
+#error "Unknown IP5K silicon"
+#endif
+
+#define OCMSTART       0x3ffc0000 /* alias from 0x03000000 for easy
+                                   * jump to/from SDRAM */
+#define OCMEND         (OCMSTART + OCMSIZE)
+
+#define SDRAMSTART     0x40000000
+
+#define KERNELSTART    (SDRAMSTART + 0x00400000)
+
+#define FLASHSTART     0x60000000
+
+/*
+ * CODELOADER / OS_SYSCALL OCM Reservations
+ * Don't change these unless you know what you are doing.
+ */
+#define CODELOADER_SIZE  0x30
+#define CODELOADER_BEGIN OCMSTART /* Must be OCM start for gdb to work. */
+#define CODELOADER_END  (CODELOADER_BEGIN + CODELOADER_SIZE)
+
+#define OS_SYSCALL_BEGIN CODELOADER_END        /* system_call at this address */
+#define OS_SYSCALL_SIZE  (512 - CODELOADER_SIZE)
+#define OS_SYSCALL_END  (OS_SYSCALL_BEGIN + OS_SYSCALL_SIZE)
+
+#endif /* _ASM_UBICOM32_MEMORY_MAP_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/mman.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mman.h
new file mode 100644 (file)
index 0000000..a2a3efe
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * arch/ubicom32/include/asm/mman.h
+ *   Memory mapping definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_MMAN_H
+#define _ASM_UBICOM32_MMAN_H
+
+#include <asm-generic/mman.h>
+
+#define MAP_GROWSDOWN  0x0100          /* stack-like segment */
+#define MAP_DENYWRITE  0x0800          /* ETXTBSY */
+#define MAP_EXECUTABLE 0x1000          /* mark it as an executable */
+#define MAP_LOCKED     0x2000          /* pages are locked */
+#define MAP_NORESERVE  0x4000          /* don't check for reservations */
+#define MAP_POPULATE   0x8000          /* populate (prefault) pagetables */
+#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 /* _ASM_UBICOM32_MMAN_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/mmu.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mmu.h
new file mode 100644 (file)
index 0000000..71b604b
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * arch/ubicom32/include/asm/mmu.h
+ *   Definition of mm_context_t struct for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 2002, David McCullough <davidm@snapgear.com>
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_MMU_H
+#define _ASM_UBICOM32_MMU_H
+
+typedef struct {
+       struct vm_list_struct   *vmlist;
+       unsigned long           end_brk;
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+       unsigned long   exec_fdpic_loadmap;
+       unsigned long   interp_fdpic_loadmap;
+#endif
+} mm_context_t;
+
+#endif /* _ASM_UBICOM32_MMU_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/mmu_context.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mmu_context.h
new file mode 100644 (file)
index 0000000..0123a6c
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * arch/ubicom32/include/asm/mmu_context.h
+ *   MMU context definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 2004, Microtronix Datacom Ltd., All rights reserved.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_MMU_CONTEXT_H
+#define _ASM_UBICOM32_MMU_CONTEXT_H
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+extern inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+       // mm->context = virt_to_phys(mm->pgd);
+       return(0);
+}
+
+#define destroy_context(mm)            do { } while(0)
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
+{
+}
+
+#define deactivate_mm(tsk,mm)  do { } while (0)
+
+extern inline void activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm)
+{
+}
+
+#endif /* _ASM_UBICOM32_MMU_CONTEXT_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/module.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/module.h
new file mode 100644 (file)
index 0000000..1c891c6
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * arch/ubicom32/include/asm/module.h
+ *   Ubicom32 architecture specific module definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_MODULE_H
+#define _ASM_UBICOM32_MODULE_H
+
+struct mod_arch_specific {
+       void *ocm_inst;
+       int ocm_inst_size;
+};
+
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Ehdr Elf32_Ehdr
+
+#define ARCH_PROC_MODULES_EXTRA(m,mod) \
+       seq_printf(m, " OCM(%d bytes @ 0x%p)", \
+                  (mod)->arch.ocm_inst_size, (mod)->arch.ocm_inst)
+
+#define ARCH_OOPS_MODULE_EXTRA(mod) \
+       printk(KERN_INFO "%p %u OCM(%p %u)\n", \
+               (mod)->module_core, (mod)->core_size, \
+               (mod)->arch.ocm_inst, (mod)->arch.ocm_inst_size)
+#endif /* _ASM_UBICOM32_MODULE_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/msgbuf.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/msgbuf.h
new file mode 100644 (file)
index 0000000..8d575e0
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * arch/ubicom32/include/asm/msgbuf.h
+ *   Definition of msqid64_ds struct for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_MSGBUF_H
+#define _ASM_UBICOM32_MSGBUF_H
+
+/*
+ * The msqid64_ds structure for ubicom32 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 /* _ASM_UBICOM32_MSGBUF_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/mutex.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/mutex.h
new file mode 100644 (file)
index 0000000..5ab4de0
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * arch/ubicom32/include/asm/mutex.h
+ *   Generic mutex.h for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+/*
+ * Pull in the generic implementation for the mutex fastpath.
+ *
+ * TODO: implement optimized primitives instead, or leave the generic
+ * implementation in place, or pick the atomic_xchg() based generic
+ * implementation. (see asm-generic/mutex-xchg.h for details)
+ */
+
+#ifndef _ASM_UBICOM32_MUTEX_H
+#define _ASM_UBICOM32_MUTEX_H
+
+#include <asm-generic/mutex-dec.h>
+
+#endif /* _ASM_UBICOM32_MUTEX_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/namei.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/namei.h
new file mode 100644 (file)
index 0000000..8010c14
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * arch/ubicom32/include/asm/namei.h
+ *   Definition of __emul_prefix() for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_NAMEI_H
+#define _ASM_UBICOM32_NAMEI_H
+
+/* This dummy routine maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define __emul_prefix() NULL
+
+#endif /* _ASM_UBICOM32_NAMEI_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm-alloc.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm-alloc.h
new file mode 100644 (file)
index 0000000..ee29d84
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * arch/ubicom32/include/asm/ocm-alloc.h
+ *   Ubicom32 architecture specific ocm definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_OCM_ALLOC_H
+#define _ASM_UBICOM32_OCM_ALLOC_H
+
+
+extern void *ocm_inst_alloc(size_t size, pid_t pid);
+extern int ocm_free(const void *ptr);
+extern int ocm_inst_free(const void *ptr);
+
+#endif /* _ASM_UBICOM32_OCM_ALLOC_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm_size.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm_size.h
new file mode 100644 (file)
index 0000000..55778fe
--- /dev/null
@@ -0,0 +1,3 @@
+#define APP_OCM_CODE_SIZE (0x3ffc2e00-0x3ffc0000)
+#define APP_OCM_DATA_SIZE (0x3ffd3500-0x3ffc8000)
+
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm_text.lds.inc b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ocm_text.lds.inc
new file mode 100644 (file)
index 0000000..5456cab
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * arch/ubicom32/include/asm/ocm_text.lds.inc
+ *     <TODO: Replace with short file description>
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+*(.text.do_csum)
+*(.text.tcp_packet)
+*(.text.ipt_do_table)
+*(.text.nf_conntrack_in)
+*(.text.ip_forward)
+*(.text.dev_queue_xmit)
+*(.text.netif_receive_skb)
+*(.text.ip_route_input)
+*(.text.ip_finish_output)
+*(.text.nf_iterate)
+*(.text.__hash_conntrack)
+*(.text.memset)
+*(.text.memcpy)
+*(.text.ip_rcv)
+*(.text.__nf_conntrack_find)
+*(.text.dev_hard_start_xmit)
+*(.text.vlan_dev_hard_start_xmit)
+*(.text.vlan_dev_hard_header)
+*(.text.__nf_ct_refresh_acct)
+*(.text.tcp_error)
+*(.text.pfifo_fast_enqueue)
+*(.text.ipv4_confirm)
+*(.text.ip_output)
+*(.text.neigh_connected_output)
+*(.text.nf_hook_slow)
+*(.text.nf_nat_packet)
+*(.text.local_bh_enable)
+*(.text.pfifo_fast_dequeue)
+*(.text.ubi32_eth_receive)
+*(.text.nf_nat_fn)
+*(.text.skb_checksum)
+*(.text.memmove)
+*(.text.ubi32_eth_tx_done)
+*(.text.eth_header)
+*(.text.skb_release_data)
+*(.text.nf_conntrack_find_get)
+*(.text.process_backlog)
+*(.text.vlan_skb_recv)
+*(.text.ip_rcv_finish)
+*(.text.__qdisc_run)
+*(.text.skb_push)
+*(.text.eth_type_trans)
+*(.text.__alloc_skb)
+*(.text.netif_rx)
+*(.text.nf_ip_checksum)
+*(.text.__skb_checksum_complete_head)
+*(.text.ipv4_conntrack_defrag)
+*(.text.tcp_pkt_to_tuple)
+*(.text.kfree)
+*(.text.tcp_manip_pkt)
+*(.text.skb_put)
+*(.text.nf_ct_get_tuple)
+*(.text.__kmalloc)
+*(.text.ubi32_eth_start_xmit)
+*(.text.free_block)
+*(.text.ipt_hook)
+*(.text.kmem_cache_free)
+*(.text.skb_pull_rcsum)
+*(.text.cache_alloc_refill)
+*(.text.skb_release_head_state)
+*(.text.manip_pkt)
+*(.text.ip_sabotage_in)
+*(.text.ip_forward_finish)
+*(.text.kmem_cache_alloc)
+*(.text.local_bh_disable)
+*(.text.ipv4_pkt_to_tuple)
+*(.text.inet_proto_csum_replace4)
+*(.text.__nf_ct_l4proto_find)
+*(.text.csum_partial)
+*(.text.neigh_resolve_output)
+*(.text.__kfree_skb)
+*(.text.kfree_skb)
+*(.text.__find_vlan_dev)
+*(.text.ldsr_ctxsw_thread)
+*(.text.__do_IRQ)
+*(.text.skb_pull)
+*(.text.ipv4_invert_tuple)
+*(.text.nf_ct_invert_tuplepr)
+*(.text.skb_make_writable)
+*(.text.ipv4_get_l4proto)
+*(.text.handle_IRQ_event)
+*(.text.net_rx_action)
+*(.text.__do_softirq)
+*(.text.nf_nat_in)
+*(.text.note_interrupt)
+*(.text.ipv4_conntrack_in)
+*(.text.dst_release)
+*(.text.tasklet_action)
+*(.text.nf_nat_out)
+*(.text.nf_ct_invert_tuple)
+*(.text.do_IRQ)
+*(.text.__tasklet_schedule)
+*(.text.__skb_checksum_complete)
+*(.text.ubi32_eth_interrupt)
+*(.text.dev_kfree_skb_any)
+*(.text.ret_from_interrupt_to_kernel)
+*(.text.preemptive_context_save)
+*(.text.irq_ack_vector)
+*(.text.update_wall_time)
+*(.text.ldsr_thread)
+*(.text.irq_exit)
+*(.text.ubi32_eth_do_tasklet)
+*(.text.__napi_schedule)
+*(.text.idle_cpu)
+*(.text.run_timer_softirq)
+*(.text.ldsr_mask_vector)
+*(.text.irq_enter)
+*(.text.ldsr_get_lsb)
+*(.text.ldsr_unmask_vector)
+*(.text.ip_fast_csum)
+*(.text.hrtimer_run_queues)
+*(.text.tcp_invert_tuple)
+*(.text.T___705)
+*(.text.run_posix_cpu_timers)
+*(.text.free_hot_cold_page)
+*(.text.lock_timer_base)
+*(.text.calc_delta_mine)
+*(.text.slab_destroy)
+*(.text.rcu_pending)
+*(.text.scheduler_tick)
+*(.text.hrtimer_run_pending)
+*(.text.do_softirq)
+*(.text.del_timer)
+*(.text.irq_end_vector)
+*(.text.pci_read_u32)
+*(.text.udivmodsi4)
+*(.text.memcmp)
+*(.text.memset)
+*(.text.__slab_alloc)
+*(.text.br_handle_frame)
+*(.text.br_fdb_update)
+*(.text.__br_fdb_get)
+*(.text.br_forward)
+*(.text.br_handle_frame_finish)
+*(.text.pci_write_u32)
+*(.text.kmem_freepages)
+*(.text.br_dev_queue_push_xmit)
+*(.text.ioread32)
+*(.text.next_zones_zonelist)
+*(.text.ubi32_pci_read_u32)
+*(.text.zone_watermark_ok)
+*(.text.__rmqueue_smallest)
+*(.text.ubi32_eth_napi_poll)
+*(.text.ubi32_pci_write_u32)
+*(.text.ubi32_pci_read_u32)
+*(.text._local_bh_enable)
+*(.text._local_bh_disable)
+*(.text.get_slab)
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/page.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/page.h
new file mode 100644 (file)
index 0000000..89c6ce6
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * arch/ubicom32/include/asm/page.h
+ *   Memory page related operations and definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_PAGE_H
+#define _ASM_UBICOM32_PAGE_H
+
+/* PAGE_SHIFT determines the page size */
+
+#define PAGE_SHIFT     12
+#define PAGE_SIZE      (1 << PAGE_SHIFT)
+#define PAGE_MASK      (~(PAGE_SIZE-1))
+
+#include <asm/setup.h>
+
+#ifndef __ASSEMBLY__
+
+#define get_user_page(vaddr)           __get_free_page(GFP_KERNEL)
+#define free_user_page(page, addr)     free_page(addr)
+
+#define clear_page(page)       memset((page), 0, PAGE_SIZE)
+#define copy_page(to,from)     memcpy((to), (from), PAGE_SIZE)
+
+#define clear_user_page(page, vaddr, pg)       clear_page(page)
+#define copy_user_page(to, from, vaddr, pg)    copy_page(to, from)
+
+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
+       alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
+#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd[16]; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+typedef struct page *pgtable_t;
+
+#define pte_val(x)     ((x).pte)
+#define pmd_val(x)     ((&x)->pmd[0])
+#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) } )
+
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+
+#endif /* !__ASSEMBLY__ */
+
+#include <asm/page_offset.h>
+
+#define PAGE_OFFSET            (PAGE_OFFSET_RAW)
+
+#ifndef __ASSEMBLY__
+
+#define __pa(vaddr)            virt_to_phys((void *)(vaddr))
+#define __va(paddr)            phys_to_virt((unsigned long)(paddr))
+
+#define virt_to_pfn(kaddr)     (__pa(kaddr) >> PAGE_SHIFT)
+#define pfn_to_virt(pfn)       __va((pfn) << PAGE_SHIFT)
+
+#define virt_to_page(addr)     (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT))
+#define page_to_virt(page)     ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
+
+#define pfn_to_page(pfn)       virt_to_page(pfn_to_virt(pfn))
+#define page_to_pfn(page)      virt_to_pfn(page_to_virt(page))
+#define pfn_valid(pfn)         ((pfn) < max_mapnr)
+
+#define        virt_addr_valid(kaddr)  (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
+                               ((void *)(kaddr) < (void *)memory_end))
+
+#endif /* __ASSEMBLY__ */
+
+#ifdef __KERNEL__
+#include <asm-generic/page.h>
+#endif
+
+#endif /* _ASM_UBICOM32_PAGE_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/page_offset.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/page_offset.h
new file mode 100644 (file)
index 0000000..8536568
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * arch/ubicom32/include/asm/page_offset.h
+ *   Definition of PAGE_OFFSET_RAW for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_PAGE_OFFSET_H
+#define _ASM_UBICOM32_PAGE_OFFSET_H
+
+/* This handles the memory map.. */
+#define        PAGE_OFFSET_RAW         0x3ffc0000
+
+#endif /* _ASM_UBICOM32_PAGE_OFFSET_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/param.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/param.h
new file mode 100644 (file)
index 0000000..00e5a79
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * arch/ubicom32/include/asm/param.h
+ *   Definition of miscellaneous constants, including HZ.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_PARAM_H
+#define _ASM_UBICOM32_PARAM_H
+
+#ifdef __KERNEL__
+#define HZ CONFIG_HZ
+#define        USER_HZ         HZ
+#define        CLOCKS_PER_SEC  (USER_HZ)
+#endif
+
+#ifndef HZ
+#define HZ     100
+#endif
+
+#define EXEC_PAGESIZE  4096
+
+#ifndef NOGROUP
+#define NOGROUP                (-1)
+#endif
+
+#define MAXHOSTNAMELEN 64      /* max length of hostname */
+
+#endif /* _ASM_UBICOM32_PARAM_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/pci.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/pci.h
new file mode 100644 (file)
index 0000000..0dce8bd
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * arch/ubicom32/include/asm/pci.h
+ *   Definitions of PCI operations for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_PCI_H
+#define _ASM_UBICOM32_PCI_H
+
+#include <asm/io.h>
+
+/* 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    (1)
+
+
+
+/*
+ * Perform a master read/write to the PCI bus.
+ * These functions return a PCI_RESP_xxx code.
+ */
+extern u8 pci_read_u32(u8 pci_cmd, u32 address, u32 *data);
+extern u8 pci_write_u32(u8 pci_cmd, u32 address, u32 data);
+extern u8 pci_read_u16(u8 pci_cmd, u32 address, u16 *data);
+extern u8 pci_write_u16(u8 pci_cmd, u32 address, u16 data);
+extern u8 pci_read_u8(u8 pci_cmd, u32 address, u8 *data);
+extern u8 pci_write_u8(u8 pci_cmd, u32 address, u8 data);
+
+
+#define PCIBIOS_MIN_IO          0x100
+#define PCIBIOS_MIN_MEM         0x10000000
+
+#define pcibios_assign_all_busses()    0
+#define pcibios_scan_all_fns(a, b)     0
+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);
+
+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                   */
+        u64             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;
+};
+
+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;
+}
+
+static inline void pcibios_set_master(struct pci_dev *dev)
+{
+        /* No special bus mastering setup handling */
+}
+#define HAVE_ARCH_PCI_SET_DMA_MAX_SEGMENT_SIZE 1
+#define HAVE_ARCH_PCI_SET_DMA_SEGMENT_BOUNDARY 1
+
+#ifdef CONFIG_PCI
+static inline void * pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+                     dma_addr_t *dma_handle)
+{
+    void *vaddr = kmalloc(size, GFP_KERNEL);
+    if(vaddr != NULL) {
+        *dma_handle = virt_to_phys(vaddr);
+    }
+    return vaddr;
+}
+
+static  inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+{
+       return 1;
+}
+
+static  inline void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+       void *cpu_addr, dma_addr_t dma_handle)
+{
+       kfree(cpu_addr);
+       return;
+}
+
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+       size_t size, int direction)
+{
+        return virt_to_phys(ptr);
+}
+
+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+       size_t size, int direction)
+{
+        return;
+}
+
+static inline dma_addr_t
+pci_map_page(struct pci_dev *hwdev, struct page *page,
+             unsigned long offset, size_t size, int direction)
+{
+        return pci_map_single(hwdev, page_address(page) + offset, size, (int)direction);
+}
+
+static inline void
+pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address,
+               size_t size, int direction)
+{
+       pci_unmap_single(hwdev, dma_address, size, direction);
+}
+
+static inline int
+pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+           int nents, int direction)
+{
+        return nents;
+}
+
+static inline void
+pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+             int nents, int direction)
+{
+}
+
+static inline void
+pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg,
+                int nelems, int direction)
+{
+}
+
+static inline void
+pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg,
+                int nelems, int direction)
+{
+}
+
+static inline void
+pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle,
+                    size_t size, int direction)
+{
+}
+
+static inline void
+pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle,
+                    size_t size, int direction)
+{
+}
+
+static inline int
+pci_dma_mapping_error(struct pci_dev *hwdev, dma_addr_t dma_addr)
+{
+        return dma_addr == 0;
+}
+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
+#endif
+
+#endif /* _ASM_UBICOM32_PCI_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/pcm_tio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/pcm_tio.h
new file mode 100644 (file)
index 0000000..13b5fc1
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * arch/ubicom32/include/asm/pcm_tio.h
+ *   Ubicom32 architecture PCM TIO definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _ASM_UBICOM32_PCM_TIO_H
+#define _ASM_UBICOM32_PCM_TIO_H
+
+#include <asm/devtree.h>
+
+#define PCM_TIO_REGS_VERSION   2
+struct pcm_tio_regs {
+       /*
+        * set this value to 1 to reload the parameters and restart the HRT
+        */
+       u32_t           reload;
+
+       /*
+        * Pointers to the input and output buffers
+        */
+       void            *input_buf;
+       void            *output_buf;
+
+       /*
+        * Buffer size (see pcm_hrt.S for constraints)
+        */
+       u32_t           buffer_size;
+
+       /*
+        * Current cycle.  This variable increases every time half the buffer
+        * is consumed.
+        */
+       u32_t           cycle;
+
+       /*
+        * Fields below this line are not accessed by the HRT.  They are purely
+        * informational for the user of this TIO.
+        */
+
+       /*
+        * Version of this structure
+        */
+       u32_t           version;
+
+       /*
+        * Number of channels supported
+        */
+       u32_t           channels;
+
+       /*
+        * Maximum buffer size
+        */
+       u32_t           max_buffer_size;
+};
+
+/*
+ * Our device node
+ */
+#define PCM_TIO_NODE_VERSION   1
+struct pcm_tio_node {
+       struct devtree_node     dn;
+       u32_t                   version;
+       struct pcm_tio_regs     *regs;
+};
+
+#endif
+
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/percpu.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/percpu.h
new file mode 100644 (file)
index 0000000..4d51e60
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/percpu.h
+ *   Generic percpu.h for the Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_PERCPU_H
+#define _ASM_UBICOM32_PERCPU_H
+
+#include <asm-generic/percpu.h>
+
+#endif /* _ASM_UBICOM32_PERCPU_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/pgalloc.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/pgalloc.h
new file mode 100644 (file)
index 0000000..397d19e
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * arch/ubicom32/include/asm/pgalloc.h
+ *   Page table allocation definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_PGALLOC_H
+#define _ASM_UBICOM32_PGALLOC_H
+
+#include <linux/mm.h>
+#include <asm/setup.h>
+
+#define check_pgt_cache()      do { } while (0)
+
+#endif /* _ASM_UBICOM32_PGALLOC_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/pgtable.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/pgtable.h
new file mode 100644 (file)
index 0000000..70ad115
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * arch/ubicom32/include/asm/pgtable.h
+ *   Ubicom32 pseudo page table definitions and operations.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 2004   Microtronix Datacom Ltd
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *   and various works, Alpha, ix86, M68K, Sparc, ...et al
+ */
+#ifndef _ASM_UBICOM32_PGTABLE_H
+#define _ASM_UBICOM32_PGTABLE_H
+
+#include <asm-generic/4level-fixup.h>
+
+//vic - this bit copied from m68knommu version
+#include <asm/setup.h>
+#include <asm/io.h>
+#include <linux/sched.h>
+
+typedef pte_t *pte_addr_t;
+
+#define pgd_present(pgd)       (1)       /* pages are always present on NO_MM */
+#define pgd_none(pgd)          (0)
+#define pgd_bad(pgd)           (0)
+#define pgd_clear(pgdp)
+#define kern_addr_valid(addr)  (1)
+#define        pmd_offset(a, b)        ((void *)0)
+
+#define PAGE_NONE              __pgprot(0)    /* these mean nothing to NO_MM */
+#define PAGE_SHARED            __pgprot(0)    /* these mean nothing to NO_MM */
+#define PAGE_COPY              __pgprot(0)    /* these mean nothing to NO_MM */
+#define PAGE_READONLY          __pgprot(0)    /* these mean nothing to NO_MM */
+#define PAGE_KERNEL            __pgprot(0)    /* these mean nothing to NO_MM */
+//vic - this bit copied from m68knommu version
+
+extern void paging_init(void);
+#define swapper_pg_dir ((pgd_t *) 0)
+
+#define __swp_type(x)          (0)
+#define __swp_offset(x)                (0)
+#define __swp_entry(typ,off)   ((swp_entry_t) { ((typ) | ((off) << 7)) })
+#define __pte_to_swp_entry(pte)        ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x)  ((pte_t) { (x).val })
+
+/*
+ * pgprot_noncached() is only for infiniband pci support, and a real
+ * implementation for RAM would be more complicated.
+ */
+#define pgprot_noncached(prot) (prot)
+
+static inline int pte_file(pte_t pte) { return 0; }
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+#define ZERO_PAGE(vaddr)       (virt_to_page(0))
+
+extern unsigned int kobjsize(const void *objp);
+extern int is_in_rom(unsigned long);
+
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init()   do { } while (0)
+
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)                \
+               remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+extern inline void flush_cache_mm(struct mm_struct *mm)
+{
+}
+
+extern inline void flush_cache_range(struct mm_struct *mm,
+                                    unsigned long start,
+                                    unsigned long end)
+{
+}
+
+/* Push the page at kernel virtual address and clear the icache */
+extern inline void flush_page_to_ram (unsigned long address)
+{
+}
+
+/* Push n pages at kernel virtual address and clear the icache */
+extern inline void flush_pages_to_ram (unsigned long address, int n)
+{
+}
+
+/*
+ * All 32bit addresses are effectively valid for vmalloc...
+ * Sort of meaningless for non-VM targets.
+ */
+#define        VMALLOC_START   0
+#define        VMALLOC_END     0xffffffff
+
+#define arch_enter_lazy_mmu_mode()     do {} while (0)
+#define arch_leave_lazy_mmu_mode()     do {} while (0)
+#define arch_flush_lazy_mmu_mode()     do {} while (0)
+#define arch_enter_lazy_cpu_mode()     do {} while (0)
+#define arch_leave_lazy_cpu_mode()     do {} while (0)
+#define arch_flush_lazy_cpu_mode()     do {} while (0)
+
+#endif /* _ASM_UBICOM32_PGTABLE_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/plio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/plio.h
new file mode 100644 (file)
index 0000000..ade78f2
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * plio.h
+ *     PLIO defines.
+ *
+ * Copyright Â© 2009 Ubicom Inc. <www.ubicom.com>.  All Rights Reserved.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ * This file contains confidential information of Ubicom, Inc. and your use of
+ * this file is subject to the Ubicom Software License Agreement distributed with
+ * this file. If you are uncertain whether you are an authorized user or to report
+ * any unauthorized use, please contact Ubicom, Inc. at +1-408-789-2200.
+ * Unauthorized reproduction or distribution of this file is subject to civil and
+ * criminal penalties.
+ */
+
+#ifndef __PLIO__H__
+#define __PLIO__H__
+
+#include <asm/ip5000.h>
+#include <asm/thread.h>
+
+#define PLIO_PORT              RD
+#define PLIO_EXT_PORT          RI
+
+#define TRANSMIT_FIFO_WATERMARK 8
+
+/*
+ * PLIO non-blocking register definitions
+ */
+#define PLIO_FN                2
+
+typedef struct {
+       unsigned        : 10;
+       unsigned        rxfifo_thread_enable: 1;   /* allowed rxfifo thread enable */
+       unsigned        : 1;
+       unsigned        rxfifo_thread: 4;          /* allowed rxfifo thread access */
+       unsigned        : 4;
+       unsigned        br_thread: 4;              /* allowed blocking region thread access */
+       unsigned        fn_reset: 4;               /* function reset bit vector */
+       unsigned        rxfifo_sel: 1;             /* select between RXFIFO 0 and 1 */
+       unsigned        fn_sel: 3;                 /* select port function */
+} plio_io_function_t;
+
+typedef struct {
+       unsigned        : 24;
+       unsigned        pin:8;
+} plio_gpio_t;
+
+typedef struct {
+       unsigned        : 16;
+       unsigned        txfifo_uf: 1;              /* TXFIFO underflow */
+       unsigned        txfifo_wm: 1;              /* TXFIFO watermark */
+       unsigned        rxfifo_of: 1;              /* RXFIFO overflow */
+       unsigned        rxfifo_wm: 1;              /* RXFIFO watermark */
+       unsigned        : 5;
+       unsigned        lreg_int_addr_rd: 1;       /* read from specified LREG address */
+       unsigned        lreg_int_addr_wr: 1;       /* write to specified LREG address */
+       unsigned        extctl_int: 4;             /* synchronized external interrupts */
+       unsigned        pfsm_int: 1;               /* state machine */
+} plio_intstat_t;
+
+typedef struct {
+       unsigned        txfifo_reset: 1;           /* TXFIFO reset for int_set only */
+       unsigned        rxfifo_reset: 1;           /* RXFIFO reset for int_set only */
+       unsigned        : 11;
+       unsigned        idif_txfifo_flush: 1;      /* flush TXFIFO and idif_txfifo */
+       unsigned        idif_rxfifo_flush: 1;      /* flush RXFIFO and idif_rxfifo */
+       unsigned        pfsm_start: 1;             /* input to fsm */
+       unsigned        txfifo_uf: 1;              /* TXFIFO underflow */
+       unsigned        txfifo_wm: 1;              /* TXFIFO watermark */
+       unsigned        rxfifo_of: 1;              /* RXFIFO overflow */
+       unsigned        rxfifo_wm: 1;              /* RXFIFO watermark */
+       unsigned        : 5;
+       unsigned        lreg_int_addr_rd: 1;       /* read from specified LREG address */
+       unsigned        lreg_int_addr_wr: 1;       /* write to specified LREG address */
+       unsigned        extctl_int: 4;             /* synchronized external interrupts */
+       unsigned        pfsm_int: 1;               /* state machine */
+} plio_intset_t;
+
+typedef enum {
+       PLIO_PORT_MODE_D,
+       PLIO_PORT_MODE_DE,
+       PLIO_PORT_MODE_DI,
+       PLIO_PORT_MODE_DEI,
+       PLIO_PORT_MODE_DC,
+} plio_port_mode_t;
+
+typedef enum {
+       PLIO_CLK_CORE,  /* CORE CLK */
+       PLIO_CLK_IO,    /* IO CLK */
+       PLIO_CLK_EXT,   /* EXT CLK */
+} plio_clk_src_t;
+typedef struct {
+       unsigned                : 4;
+       unsigned                edif_iaena_sel: 1;         /* Input Address Enable Select */
+       unsigned                edif_iaclk_sel: 1;         /* Input Address Clock Select */
+       unsigned                edif_iald_inv: 1;          /* Input Address Strobe Invert */
+       unsigned                edif_idclk_sel: 1;         /* Input Data Clock Select */
+       unsigned                edif_idld_inv: 1;          /* Input Data Strobe Invert */
+       unsigned                edif_ds: 3;                /* specify IDR and ODR data shift */
+       unsigned                edif_cmp_mode: 1;          /* configure IDR comparator output */
+       unsigned                edif_idena_sel: 1;         /* Input Data Enable Select */
+       unsigned                ecif_extclk_ena: 1;        /* plio_extctl output select */
+       unsigned                idif_tx_fifo_cmd_sel: 1;   /* select pfsm_cmd data word position */
+       unsigned                ptif_porti_cfg: 2;         /* select port I pin configuration */
+       unsigned                ptif_portd_cfg: 3;         /* select port D pin configuration */
+       plio_port_mode_t        ptif_port_mode: 3;      /* select other plio ports  */
+       unsigned                icif_clk_plio_ext_inv: 1;  /* invert external plio clock when set */
+       unsigned                icif_rst_plio: 1;          /* reset plio function and io fifos */
+       plio_clk_src_t          icif_clk_src_sel: 2;      /* select plio clock source */
+       unsigned                pfsm_prog: 1;              /* enable pfsm programming */
+       unsigned                pfsm_cmd: 3;               /* software input to pfsm */
+} plio_fctl0_t;
+
+typedef struct {
+       unsigned        : 2;
+       unsigned        idif_byteswap_tx: 3;       /* swap TXFIFO byte order */
+       unsigned        idif_byteswap_rx: 3;       /* swap RXFIFO byte order */
+       unsigned        : 1;
+       unsigned        lreg_ena: 1;               /* enable local register map */
+       unsigned        lreg_addr_fifo_cmp_ena: 1; /* enable a specific LREG address from/to TX/RX fifos */
+       unsigned        lreg_addr_fifo_cmp: 5;     /* LREG address routed from/to TX/RX fifos */
+       unsigned        : 1;
+       unsigned        dcod_iald_idld_sel: 2;     /* select address/data strobes */
+       unsigned        dcod_rw_src_sel: 1;        /* select LREG strobe source */
+       unsigned        dcod_rd_sel: 5;            /* select read strobe source */
+       unsigned        dcod_wr_sel: 5;            /* select write strobe source */
+       unsigned        dcod_rd_lvl: 1;            /* select active level of read strobe */
+       unsigned        dcod_wr_lvl: 1;            /* select active level of read strobe */
+} plio_fctl1_t;
+
+typedef struct {
+       unsigned        icif_eclk_div: 16;         /* external plio clock divider */
+       unsigned        icif_iclk_div: 16;         /* internal plio clock divider */
+} plio_fctl2_t;
+
+typedef struct {
+       unsigned        : 27;
+       unsigned        pfsm_state: 5;             /* current pfsm state */
+} plio_stat_0_t;
+
+typedef struct {
+       unsigned        : 3;
+       unsigned        lreg_r_int_addr: 5;
+       unsigned        : 11;
+       unsigned        lreg_w_int_addr: 5;
+       unsigned        lreg_w_int_data: 8;
+} plio_stat_1_t;
+
+typedef struct {
+       unsigned        : 32;
+} plio_stat_2_t;
+
+typedef struct {
+       unsigned        tx: 16;
+       unsigned        rx: 16;
+} plio_io_fifo_wm_t, plio_io_fifo_lvl_t;
+
+
+/* plio blocking region register definitions
+ */
+typedef struct {
+       unsigned         ns1: 5;
+       unsigned         ic1: 7;
+       unsigned         ec1: 4;
+       unsigned         ns0: 5;
+       unsigned         ic0: 7;
+       unsigned         ec0: 4;
+} plio_sram_t;
+
+typedef struct {
+       unsigned         : 2;
+       unsigned         s9: 3;
+       unsigned         s8: 3;
+       unsigned         s7: 3;
+       unsigned         s6: 3;
+       unsigned         s5: 3;
+       unsigned         s4: 3;
+       unsigned         s3: 3;
+       unsigned         s2: 3;
+       unsigned         s1: 3;
+       unsigned         s0: 3;
+} plio_grpsel_t;
+
+typedef struct {
+       unsigned        s7: 4;
+       unsigned        s6: 4;
+       unsigned        s5: 4;
+       unsigned        s4: 4;
+       unsigned        s3: 4;
+       unsigned        s2: 4;
+       unsigned        s1: 4;
+       unsigned        s0: 4;
+} plio_cs_lut_t;
+
+typedef struct {
+       unsigned        lut3: 8;
+       unsigned        lut2: 8;
+       unsigned        lut1: 8;
+       unsigned        lut0: 8;
+} plio_extctl_t;
+
+typedef struct {
+       plio_grpsel_t   grpsel[4];
+       u16_t           cv[16];
+       plio_cs_lut_t   cs_lut[4];
+       plio_extctl_t   extctl_o_lut[8];
+} plio_pfsm_t;
+
+typedef struct {
+       u32_t           odr_oe_sel;
+       u32_t           odr_oe;
+       u32_t           cmp;
+       u32_t           ncmp;
+       u32_t           cmp_mask;
+} plio_edif_t;
+
+typedef enum {
+       PLIO_ECIF_CLK_OUT       = 9,
+       PLIO_ECIF_IALD          = 9,
+       PLIO_ECIF_CLK_IN        = 8,
+       PLIO_ECIF_IDLD          = 8,
+       PLIO_ECIF_INT           = 2,
+} plio_ecif_output_t;
+
+typedef struct {
+       u32_t           bypass_sync;
+       u32_t           ift;
+       u32_t           output_type;
+       u32_t           output_ena;
+       u32_t           output_lvl;
+} plio_ecif_t;
+
+typedef struct {
+       u32_t           idr_addr_pos_mask;
+       u32_t           reserved;
+       u32_t           lreg_bar;
+} plio_dcod_t;
+
+typedef struct {
+       u32_t           addr_rd_ena;
+       u32_t           addr_wr_ena;
+       u32_t           addr_rd_int_ena;
+       u32_t           addr_wr_int_ena;
+} plio_lcfg_t;
+
+
+/*
+ * PLIO configuration
+ */
+typedef struct {
+       plio_fctl0_t    fctl0;
+       plio_fctl1_t    fctl1;
+       plio_fctl2_t    fctl2;
+} plio_fctl_t;
+
+typedef struct {
+       plio_pfsm_t     pfsm;
+       plio_edif_t     edif;
+       plio_ecif_t     ecif;
+       plio_dcod_t     dcod;
+       plio_lcfg_t     lcfg;
+} plio_config_t;
+
+typedef struct {
+       plio_io_function_t      function;
+       plio_gpio_t             gpio_ctl;
+       plio_gpio_t             gpio_out;
+       plio_gpio_t             gpio_in;
+       plio_intstat_t          intstat;
+       plio_intstat_t          intmask;
+       plio_intset_t           intset;
+       plio_intstat_t          intclr;
+       unsigned                tx_lo;
+       unsigned                tx_hi;
+       unsigned                rx_lo;
+       unsigned                rx_hi;
+       plio_fctl0_t            fctl0;
+       plio_fctl1_t            fctl1;
+       plio_fctl2_t            fctl2;
+       plio_stat_0_t           stat0;
+       plio_stat_1_t           stat1;
+       plio_stat_2_t           stat2;
+       plio_io_fifo_wm_t       fifo_wm;
+       plio_io_fifo_lvl_t      fifo_lvl;
+} plio_nbr_t;
+
+typedef struct {
+       u32_t                   pfsm_sram[256];
+       plio_config_t           config;
+} plio_br_t;
+
+#define PLIO_NBR       ((plio_nbr_t *)(PLIO_PORT))
+#define PLIO_BR                ((plio_br_t *)((PLIO_PORT + IO_PORT_BR_OFFSET)))
+#define PEXT_NBR       ((plio_nbr_t *)(PLIO_EXT_PORT))
+
+extern void plio_init(const plio_fctl_t *plio_fctl, const plio_config_t *plio_config, const plio_sram_t plio_sram_cfg[], int sram_cfg_size);
+
+#endif // __PLIO__H__
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/poll.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/poll.h
new file mode 100644 (file)
index 0000000..8e92b76
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * arch/ubicom32/include/asm/poll.h
+ *   Ubicom32 specific poll() related flags definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_POLL_H
+#define _ASM_UBICOM32_POLL_H
+
+#define POLLWRNORM     POLLOUT
+#define POLLWRBAND     0x0100
+
+#include <asm-generic/poll.h>
+
+#endif /* _ASM_UBICOM32_POLL_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/posix_types.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/posix_types.h
new file mode 100644 (file)
index 0000000..40b69f8
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * arch/ubicom32/include/asm/posix_types.h
+ *   Ubicom32 architecture posix types.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 2004   Microtronix Datacom Ltd
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef __ARCH_UBICOM32_POSIX_TYPES_H
+#define __ARCH_UBICOM32_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 long  __kernel_ino_t;
+typedef unsigned short __kernel_mode_t;
+typedef unsigned short __kernel_nlink_t;
+typedef long           __kernel_off_t;
+typedef int            __kernel_pid_t;
+typedef unsigned short __kernel_ipc_pid_t;
+typedef unsigned short __kernel_uid_t;
+typedef unsigned short __kernel_gid_t;
+typedef unsigned int   __kernel_size_t;
+typedef int            __kernel_ssize_t;
+typedef int            __kernel_ptrdiff_t;
+typedef long           __kernel_time_t;
+typedef long           __kernel_suseconds_t;
+typedef long           __kernel_clock_t;
+typedef int            __kernel_timer_t;
+typedef int            __kernel_clockid_t;
+typedef int            __kernel_daddr_t;
+typedef char *         __kernel_caddr_t;
+typedef unsigned short __kernel_uid16_t;
+typedef unsigned short __kernel_gid16_t;
+typedef unsigned int   __kernel_uid32_t;
+typedef unsigned int   __kernel_gid32_t;
+
+typedef unsigned short __kernel_old_uid_t;
+typedef unsigned short __kernel_old_gid_t;
+typedef unsigned short __kernel_old_dev_t;
+
+#ifdef __GNUC__
+typedef long long      __kernel_loff_t;
+#endif
+
+typedef struct {
+#if defined(__KERNEL__) || defined(__USE_ALL)
+       int     val[2];
+#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+       int     __val[2];
+#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+} __kernel_fsid_t;
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#undef __FD_SET
+#define        __FD_SET(d, set)        ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
+
+#undef __FD_CLR
+#define        __FD_CLR(d, set)        ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
+
+#undef __FD_ISSET
+#define        __FD_ISSET(d, set)      ((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
+
+#undef __FD_ZERO
+#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
+
+#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+
+#endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/processor.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/processor.h
new file mode 100644 (file)
index 0000000..92e49e8
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * arch/ubicom32/include/asm/processor.h
+ *   Thread related definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 1995 Hamish Macdonald
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_PROCESSOR_H
+#define _ASM_UBICOM32_PROCESSOR_H
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
+#include <linux/compiler.h>
+#include <linux/threads.h>
+#include <asm/types.h>
+#include <asm/segment.h>
+#include <asm/fpu.h>
+#include <asm/ptrace.h>
+#include <asm/current.h>
+#include <asm/thread_info.h>
+
+#if defined(CONFIG_UBICOM32_V3)
+       #define CPU "IP5K"
+#endif
+#if defined(CONFIG_UBICOM32_V4)
+       #define CPU "IP7K"
+#endif
+#ifndef CPU
+       #define CPU "UNKNOWN"
+#endif
+
+/*
+ * User space process size: 1st byte beyond user address space.
+ */
+extern unsigned long memory_end;
+#define TASK_SIZE      (memory_end)
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's. We won't be using it
+ */
+#define TASK_UNMAPPED_BASE     0
+
+/*
+ * This is the structure where we are going to save callee-saved registers.
+ * A5 is the return address, A7 is the stack pointer, A6 is the frame
+ * pointer.  This is the frame that is created because of switch_to. This
+ * is not the frame due to interrupt preemption or because of syscall entry.
+ */
+
+struct thread_struct {
+       unsigned long  d10;             /* D10  */
+       unsigned long  d11;             /* D11  */
+       unsigned long  d12;             /* D12  */
+       unsigned long  d13;             /* D13  */
+       unsigned long  a1;              /* A1  */
+       unsigned long  a2;              /* A2  */
+       unsigned long  a5;              /* A5 return address. */
+       unsigned long  a6;              /* A6 */
+       unsigned long  sp;              /* A7 kernel stack pointer. */
+};
+
+#define INIT_THREAD  { \
+       0, 0, 0, 0, 0, 0, 0, 0, \
+       sizeof(init_stack) + (unsigned long) init_stack - 8, \
+}
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ *
+ * pass the data segment into user programs if it exists,
+ * it can't hurt anything as far as I can tell
+ */
+/*
+ * Do necessary setup to start up a newly executed thread.
+ */
+#define start_thread(regs, new_pc, new_sp)      \
+       do {                                     \
+               regs->pc = new_pc & ~3;          \
+               regs->an[5] = new_pc & ~3;       \
+               regs->an[7] = new_sp;            \
+               regs->nesting_level = -1;        \
+               regs->frame_type = UBICOM32_FRAME_TYPE_NEW_THREAD; \
+               regs->thread_type = NORMAL_THREAD; \
+       } while(0)
+
+/* Forward declaration, a strange C thing */
+struct task_struct;
+
+/* Free all resources held by a thread. */
+static inline void release_thread(struct task_struct *dead_task)
+{
+}
+
+/* Prepare to copy thread state - unlazy all lazy status */
+#define prepare_to_copy(tsk)   do { } while (0)
+
+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+/*
+ * Free current thread data structures etc..
+ */
+static inline void exit_thread(void)
+{
+}
+
+unsigned long thread_saved_pc(struct task_struct *tsk);
+unsigned long get_wchan(struct task_struct *p);
+
+#define        KSTK_EIP(tsk)   (tsk->thread.a5)
+#define        KSTK_ESP(tsk)   (tsk->thread.sp)
+
+#define cpu_relax()    barrier()
+
+extern void processor_init(void);
+extern unsigned int processor_timers(void);
+extern unsigned int processor_threads(void);
+extern unsigned int processor_frequency(void);
+extern int processor_interrupts(unsigned int *int0, unsigned int *int1);
+extern void processor_ocm(unsigned long *socm, unsigned long *eocm);
+extern void processor_dram(unsigned long *sdram, unsigned long *edram);
+
+#define THREAD_SIZE_LONGS      (THREAD_SIZE/sizeof(unsigned long))
+#define KSTK_TOP(info)                                                 \
+({                                                                     \
+       unsigned long *__ptr = (unsigned long *)(info);                 \
+       (unsigned long)(&__ptr[THREAD_SIZE_LONGS]);                     \
+})
+
+#define task_pt_regs(task)                                             \
+({                                                                     \
+       struct pt_regs *__regs__;                                       \
+       __regs__ = (struct pt_regs *)(KSTK_TOP(task_stack_page(task))-8); \
+       __regs__ - 1;                                                   \
+})
+
+#endif /* _ASM_UBICOM32_PROCESSOR_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/profilesample.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/profilesample.h
new file mode 100644 (file)
index 0000000..6e42269
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * arch/ubicom32/mach-common/profile.h
+ *   Private data for the profile module
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#ifndef _PROFILESAMPLE_H_
+#define _PROFILESAMPLE_H_
+
+/*
+ * a sample taken by the ipProfile package for sending to the profilertool
+ */
+struct profile_sample {
+       unsigned int pc;                        /* PC value */
+       unsigned int a5;                        /* a5 contents for parent of leaf function */
+       unsigned int parent;                    /* return address from stack, to find the caller */
+       unsigned int latency;                   /* CPU clocks since the last message dispatch in this thread (thread 0 ony for now) */
+       unsigned short active;                  /* which threads are active - for accurate counting */
+       unsigned short d_blocked;               /* which threads are blocked due to D cache misses */
+       unsigned short i_blocked;               /* which threads are blocked due to I cache misses */
+       unsigned char cond_codes;               /* for branch prediction */
+       unsigned char thread;                   /* I-blocked, D-blocked, 4-bit thread number */
+};
+
+#endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ptrace.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ptrace.h
new file mode 100644 (file)
index 0000000..aeae2c7
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * arch/ubicom32/include/asm/ptrace.h
+ *   Ubicom32 architecture ptrace support.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_PTRACE_H
+#define _ASM_UBICOM32_PTRACE_H
+
+#ifndef __ASSEMBLY__
+
+/*
+ * We use hard coded constants because this is shared with user
+ * space and the values are NOT allowed to change.  Only fields
+ * that are intended to be exposed get values.
+ */
+#define PT_D0           0
+#define PT_D1           4
+#define PT_D2           8
+#define PT_D3           12
+#define PT_D4           16
+#define PT_D5           20
+#define PT_D6           24
+#define PT_D7           28
+#define PT_D8           32
+#define PT_D9           36
+#define PT_D10          40
+#define PT_D11          44
+#define PT_D12          48
+#define PT_D13          52
+#define PT_D14          56
+#define PT_D15          60
+#define PT_A0           64
+#define PT_A1           68
+#define PT_A2           72
+#define PT_A3           76
+#define PT_A4           80
+#define PT_A5           84
+#define PT_A6           88
+#define PT_A7           92
+#define PT_SP           92
+#define PT_ACC0HI       96
+#define PT_ACC0LO       100
+#define PT_MAC_RC16     104
+#define PT_ACC1HI       108
+#define PT_ACC1LO       112
+#define PT_SOURCE3      116
+#define PT_INST_CNT     120
+#define PT_CSR          124
+#define PT_DUMMY_UNUSED 128
+#define PT_INT_MASK0    132
+#define PT_INT_MASK1    136
+#define PT_TRAP_CAUSE   140
+#define PT_PC           144
+#define PT_ORIGINAL_D0  148
+#define PT_FRAME_TYPE   152
+
+/*
+ * The following 'registers' are not registers at all but are used
+ * locate the relocated sections.
+ */
+#define PT_TEXT_ADDR           200
+#define PT_TEXT_END_ADDR       204
+#define PT_DATA_ADDR           208
+#define PT_EXEC_FDPIC_LOADMAP  212
+#define PT_INTERP_FDPIC_LOADMAP        216
+
+/*
+ * This struct defines the way the registers are stored on the
+ * stack during a system call.
+ */
+enum thread_type {
+       NORMAL_THREAD,
+       KERNEL_THREAD,
+};
+
+#define UBICOM32_FRAME_TYPE_SYSCALL    -1 /* System call frame */
+#define UBICOM32_FRAME_TYPE_INVALID    0 /* Invalid frame, no longer in use */
+#define UBICOM32_FRAME_TYPE_INTERRUPT  1 /* Interrupt frame */
+#define UBICOM32_FRAME_TYPE_TRAP       2 /* Trap frame */
+#define UBICOM32_FRAME_TYPE_SIGTRAMP   3 /* Signal trampoline frame. */
+#define UBICOM32_FRAME_TYPE_NEW_THREAD 4 /* New Thread. */
+
+struct pt_regs {
+       /*
+        * Data Registers
+        */
+       unsigned long dn[16];
+
+       /*
+        * Address Registers
+        */
+       unsigned long an[8];
+
+       /*
+        * Per thread misc registers.
+        */
+       unsigned long acc0[2];
+       unsigned long mac_rc16;
+       unsigned long acc1[2];
+       unsigned long source3;
+       unsigned long inst_cnt;
+       unsigned long csr;
+       unsigned long dummy_unused;
+       unsigned long int_mask0;
+       unsigned long int_mask1;
+       unsigned long trap_cause;
+       unsigned long pc;
+       unsigned long original_dn_0;
+
+       /*
+        * Frame type. Syscall frames are -1. For other types look above.
+        */
+       unsigned long frame_type;
+
+       /*
+        * These fields are not exposed to ptrace.
+        */
+       unsigned long previous_pc;
+       long nesting_level;             /* When the kernel in in user space this
+                                        * will be -1. */
+       unsigned long thread_type;      /* This indicates if this is a kernel
+                                        * thread. */
+};
+
+/*
+ * This is the extended stack used by signal handlers and the context
+ * switcher: it's pushed after the normal "struct pt_regs".
+ */
+struct switch_stack {
+       unsigned long  dummy;
+};
+
+#ifdef __KERNEL__
+
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS         12
+#define PTRACE_SETREGS         13
+
+#ifndef PS_S
+#define PS_S  (0x2000)
+#define PS_M  (0x1000)
+#endif
+
+extern  int __user_mode(unsigned long sp);
+
+#define user_mode(regs) (__user_mode((regs->an[7])))
+#define user_stack(regs) ((regs)->an[7])
+#define instruction_pointer(regs) ((regs)->pc)
+#define profile_pc(regs) instruction_pointer(regs)
+extern void show_regs(struct pt_regs *);
+#endif /* __KERNEL__ */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_UBICOM32_PTRACE_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/range-protect-asm.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/range-protect-asm.h
new file mode 100644 (file)
index 0000000..87459e4
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * arch/ubicom32/include/asm/range-protect-asm.h
+ *   Assembly macros for enabling memory protection.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_RANGE_PROTECT_ASM_H
+#define _ASM_UBICOM32_RANGE_PROTECT_ASM_H
+
+#if defined(__ASSEMBLY__)
+
+#include <asm/thread-asm.h>
+
+/*
+ * You should only use the enable/disable ranges when you have the atomic lock,
+ * if you do not there will be problems.
+ */
+
+/*
+ * enable_kernel_ranges
+ *     Enable the kernel ranges (disabling protection) for thread,
+ *     where thread == (1 << thread number)
+ */
+.macro enable_kernel_ranges thread
+#ifdef CONFIG_PROTECT_KERNEL
+       or.4    I_RANGE0_EN, I_RANGE0_EN, \thread        /* Enable Range Register */
+       or.4    D_RANGE0_EN, D_RANGE0_EN, \thread
+       or.4    D_RANGE1_EN, D_RANGE1_EN, \thread
+#endif
+.endm
+
+/*
+ * enable_kernel_ranges_for_current
+ *     Enable the kernel ranges (disabling protection) for this thread
+ */
+.macro enable_kernel_ranges_for_current scratch_reg
+#ifdef CONFIG_PROTECT_KERNEL
+       thread_get_self_mask \scratch_reg
+       enable_kernel_ranges \scratch_reg
+#endif
+.endm
+
+/*
+ * disable_kernel_ranges
+ *     Disables the kernel ranges (enabling protection) for thread
+ *     where thread == (1 << thread number)
+ */
+.macro disable_kernel_ranges thread
+#ifdef CONFIG_PROTECT_KERNEL
+       not.4   \thread, \thread
+       and.4   I_RANGE0_EN, I_RANGE0_EN, \thread        /* Disable Range Register */
+       and.4   D_RANGE0_EN, D_RANGE0_EN, \thread
+       and.4   D_RANGE1_EN, D_RANGE1_EN, \thread
+#endif
+.endm
+
+/*
+ * disable_kernel_ranges_for_current
+ *     Disable kernel ranges (enabling protection) for this thread
+ */
+.macro disable_kernel_ranges_for_current scratch_reg
+#ifdef CONFIG_PROTECT_KERNEL
+       thread_get_self_mask \scratch_reg
+       disable_kernel_ranges \scratch_reg
+#endif
+.endm
+#endif
+
+#endif  /* _ASM_UBICOM32_RANGE_PROTECT_ASM_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/range-protect.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/range-protect.h
new file mode 100644 (file)
index 0000000..b4bd2f0
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * arch/ubicom32/include/asm/range-protect.h
+ *   Assembly macros declared in C for enabling memory protection.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_RANGE_PROTECT_H
+#define _ASM_UBICOM32_RANGE_PROTECT_H
+
+#if !defined(__ASSEMBLY__)
+#include <asm/thread.h>
+/*
+ * The following macros should be the identical to the ones in
+ * range-protect-asm.h
+ *
+ * You should only use the enable/disable ranges when you have the atomic lock,
+ * if you do not there will be problems.
+ */
+
+/*
+ * enable_kernel_ranges
+ *     Enable the kernel ranges (disabling protection) for thread,
+ *     where thread == (1 << thread number)
+ */
+asm (
+       ".macro enable_kernel_ranges thread                     \n\t"
+#ifdef CONFIG_PROTECT_KERNEL
+       "       or.4    I_RANGE0_EN, I_RANGE0_EN, \\thread      \n\t" /* Enable Range Register */
+       "       or.4    D_RANGE0_EN, D_RANGE0_EN, \\thread      \n\t"
+       "       or.4    D_RANGE1_EN, D_RANGE1_EN, \\thread      \n\t"
+#endif
+       ".endm                                                  \n\t"
+);
+
+#else /* __ASSEMBLY__ */
+
+#include <asm/range-protect-asm.h>
+
+#endif
+#endif  /* _ASM_UBICOM32_RANGE_PROTECT_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/resource.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/resource.h
new file mode 100644 (file)
index 0000000..0a59a4f
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/resource.h
+ *   Generic definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_RESOURCE_H
+#define _ASM_UBICOM32_RESOURCE_H
+
+#include <asm-generic/resource.h>
+
+#endif /* _ASM_UBICOM32_RESOURCE_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ring_tio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ring_tio.h
new file mode 100644 (file)
index 0000000..c02a445
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * arch/ubicom32/include/asm/ring_tio.h
+ *   Ubicom32 architecture Ring TIO definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _ASM_UBICOM32_RING_TIO_H
+#define _ASM_UBICOM32_RING_TIO_H
+
+#include <asm/devtree.h>
+
+#define RING_TIO_NODE_VERSION  2
+
+/*
+ * Devtree node for ring
+ */
+struct ring_tio_node {
+       struct devtree_node     dn;
+
+       u32_t                   version;
+       void                    *regs;
+};
+
+extern void ring_tio_init(const char *node_name);
+
+#endif /* _ASM_UBICOM32_RING_TIO_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/scatterlist.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/scatterlist.h
new file mode 100644 (file)
index 0000000..4fb4df1
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * arch/ubicom32/include/asm/scatterlist.h
+ *   Definitions of struct scatterlist for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SCATTERLIST_H
+#define _ASM_UBICOM32_SCATTERLIST_H
+
+#include <linux/mm.h>
+#include <asm/types.h>
+
+struct scatterlist {
+#ifdef CONFIG_DEBUG_SG
+       unsigned long   sg_magic;
+#endif
+       unsigned long   page_link;
+       unsigned int    offset;
+       dma_addr_t      dma_address;
+       unsigned int    length;
+};
+
+#define sg_dma_address(sg)      ((sg)->dma_address)
+#define sg_dma_len(sg)          ((sg)->length)
+
+#define ISA_DMA_THRESHOLD      (0xffffffff)
+
+#endif /* _ASM_UBICOM32_SCATTERLIST_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/sd_tio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sd_tio.h
new file mode 100644 (file)
index 0000000..ecb2b82
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * arch/ubicom32/include/asm/sd_tio.h
+ *   SD TIO definitions
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _ASM_UBICOM32_SD_TIO_H
+#define _ASM_UBICOM32_SD_TIO_H
+
+#include <asm/devtree.h>
+
+/*
+ * Devtree node for SD
+ */
+struct sd_tio_node {
+       struct devtree_node     dn;
+       void                    *regs;
+};
+
+#endif /* _ASM_UBICOM32_SD_TIO_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/sections.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sections.h
new file mode 100644 (file)
index 0000000..eb7d24b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/sections.h
+ *   Generic sections.h definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SECTIONS_H
+#define _ASM_UBICOM32_SECTIONS_H
+
+#include <asm-generic/sections.h>
+
+#endif /* _ASM_UBICOM32_SECTIONS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/segment.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/segment.h
new file mode 100644 (file)
index 0000000..3f10490
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * arch/ubicom32/include/asm/segment.h
+ *   Memory segment definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SEGMENT_H
+#define _ASM_UBICOM32_SEGMENT_H
+
+/* define constants */
+/* Address spaces (FC0-FC2) */
+#define USER_DATA     (1)
+#ifndef __USER_DS
+#define __USER_DS     (USER_DATA)
+#endif
+#define USER_PROGRAM  (2)
+#define SUPER_DATA    (5)
+#ifndef __KERNEL_DS
+#define __KERNEL_DS   (SUPER_DATA)
+#endif
+#define SUPER_PROGRAM (6)
+#define CPU_SPACE     (7)
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+       unsigned long seg;
+} mm_segment_t;
+
+#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
+#define USER_DS                MAKE_MM_SEG(__USER_DS)
+#define KERNEL_DS      MAKE_MM_SEG(__KERNEL_DS)
+
+/*
+ * Get/set the SFC/DFC registers for MOVES instructions
+ */
+
+static inline mm_segment_t get_fs(void)
+{
+    return USER_DS;
+}
+
+static inline mm_segment_t get_ds(void)
+{
+    /* return the supervisor data space code */
+    return KERNEL_DS;
+}
+
+static inline void set_fs(mm_segment_t val)
+{
+}
+
+#define segment_eq(a,b)        ((a).seg == (b).seg)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_UBICOM32_SEGMENT_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/semaphore-helper.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/semaphore-helper.h
new file mode 100644 (file)
index 0000000..ad0aaf0
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * arch/ubicom32/include/asm/semaphore-helper.h
+ *   Semaphore related definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SEMAPHORE_HELPER_H
+#define _ASM_UBICOM32_SEMAPHORE_HELPER_H
+
+/*
+ * SMP- and interrupt-safe semaphores helper functions.
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ *
+ * m68k version by Andreas Schwab
+ */
+
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+static inline void wake_one_more(struct semaphore * sem)
+{
+       atomic_inc(&sem->waking);
+}
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&semaphore_wake_lock, flags);
+       ret = 0;
+       if (atomic_read(&sem->waking) > 0) {
+               atomic_dec(&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
+ */
+static inline int waking_non_zero_interruptible(struct semaphore *sem,
+                                               struct task_struct *tsk)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&semaphore_wake_lock, flags);
+       ret = 0;
+       if (atomic_read(&sem->waking) > 0) {
+               atomic_dec(&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_trylock:
+ *     1       failed to lock
+ *     0       got the lock
+ */
+static inline int waking_non_zero_trylock(struct semaphore *sem)
+{
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&semaphore_wake_lock, flags);
+       ret = 1;
+       if (atomic_read(&sem->waking) > 0) {
+               atomic_dec(&sem->waking);
+               ret = 0;
+       } else
+               atomic_inc(&sem->count);
+       spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+       return ret;
+}
+
+#endif /* _ASM_UBICOM32_SEMAPHORE_HELPER_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/semaphore.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/semaphore.h
new file mode 100644 (file)
index 0000000..d20ead3
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * arch/ubicom32/include/asm/semaphore.h
+ *   Interrupt-safe semaphores for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * (C) Copyright 1996 Linus Torvalds
+ * m68k version by Andreas Schwab
+ * Copyright (C) 2004   Microtronix Datacom Ltd
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SEMAPHORE_H
+#define _ASM_UBICOM32_SEMAPHORE_H
+
+#define RW_LOCK_BIAS            0x01000000
+
+#ifndef __ASSEMBLY__
+
+#include <linux/linkage.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/rwsem.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+
+struct semaphore {
+       atomic_t count;
+       atomic_t waking;
+       wait_queue_head_t wait;
+};
+
+#define __SEMAPHORE_INITIALIZER(name, n)                               \
+{                                                                      \
+       .count          = ATOMIC_INIT(n),                               \
+       .waking         = ATOMIC_INIT(0),                               \
+       .wait           = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait)    \
+}
+
+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+       struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
+
+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
+
+static inline void sema_init (struct semaphore *sem, int val)
+{
+       *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val);
+}
+
+static inline void init_MUTEX (struct semaphore *sem)
+{
+       sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+{
+       sema_init(sem, 0);
+}
+
+asmlinkage void __down_failed(void /* special register calling convention */);
+asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
+asmlinkage int  __down_failed_trylock(void  /* params in registers */);
+asmlinkage void __up_wakeup(void /* special register calling convention */);
+
+asmlinkage void __down(struct semaphore * sem);
+asmlinkage int  __down_interruptible(struct semaphore * sem);
+asmlinkage int  __down_trylock(struct semaphore * sem);
+asmlinkage void __up(struct semaphore * sem);
+
+extern spinlock_t semaphore_wake_lock;
+
+/*
+ * This is ugly, but we want the default case to fall through.
+ * "down_failed" is a special asm handler that calls the C
+ * routine that actually waits.
+ */
+static inline void down(struct semaphore * sem)
+{
+       might_sleep();
+
+       if (atomic_dec_return(&sem->count) < 0)
+               __down(sem);
+}
+
+static inline int down_interruptible(struct semaphore * sem)
+{
+       int ret = 0;
+
+
+       might_sleep();
+
+       if(atomic_dec_return(&sem->count) < 0)
+               ret = __down_interruptible(sem);
+       return ret;
+}
+
+static inline int down_trylock(struct semaphore * sem)
+{
+       int ret = 0;
+
+       if (atomic_dec_return (&sem->count) < 0)
+               ret = __down_trylock(sem);
+       return ret;
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ * The default case (no contention) will result in NO
+ * jumps for both down() and up().
+ */
+static inline void up(struct semaphore * sem)
+{
+       if (atomic_inc_return(&sem->count) <= 0)
+               __up(sem);
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_UBICOM32_SEMAPHORE_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/sembuf.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sembuf.h
new file mode 100644 (file)
index 0000000..996a7a0
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * arch/ubicom32/include/asm/sembuf.h
+ *   The semid64_ds structure for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SEMBUF_H
+#define _ASM_UBICOM32_SEMBUF_H
+
+/*
+ * The semid64_ds structure for ubicom32 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 /* _ASM_UBICOM32_SEMBUF_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/setup.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/setup.h
new file mode 100644 (file)
index 0000000..ad8dc57
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * arch/ubicom32/include/asm/setup.h
+ *   Kernel command line length definition.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 2004, Microtronix Datacom Ltd., All rights reserved.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_SETUP_H
+#define _ASM_UBICOM32_SETUP_H
+
+#define COMMAND_LINE_SIZE 512
+
+#endif /* _ASM_UBICOM32_SETUP_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/shmbuf.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/shmbuf.h
new file mode 100644 (file)
index 0000000..7cc4339
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * arch/ubicom32/include/asm/shmbuf.h
+ *   The shmid64_ds structure for the Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SHMBUF_H
+#define _ASM_UBICOM32_SHMBUF_H
+
+/*
+ * The shmid64_ds structure for m68k 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 /* _ASM_UBICOM32_SHMBUF_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/shmparam.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/shmparam.h
new file mode 100644 (file)
index 0000000..851d062
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * arch/ubicom32/include/asm/shmparam.h
+ *   Shared memory definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 2004   Microtronix Datacom Ltd
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *   Alpha, ix86, M68K, Sparc, ...et al
+ */
+#ifndef _ASM_UBICOM32_SHMPARAM_H
+#define _ASM_UBICOM32_SHMPARAM_H
+
+#define        SHMLBA          PAGE_SIZE       /* attach addr a multiple of this */
+
+#endif /* _ASM_UBICOM32_SHMPARAM_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/sigcontext.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sigcontext.h
new file mode 100644 (file)
index 0000000..8bbeb82
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * arch/ubicom32/include/asm/sigcontext.h
+ *   Definition of sigcontext struct for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SIGCONTEXT_H
+#define _ASM_UBICOM32_SIGCONTEXT_H
+
+#include <asm/ptrace.h>
+
+struct sigcontext {
+       struct pt_regs sc_regs;
+};
+
+#endif /* _ASM_UBICOM32_SIGCONTEXT_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/siginfo.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/siginfo.h
new file mode 100644 (file)
index 0000000..be0a465
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/siginfo.h
+ *   Generic siginfo.h definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SIGINFO_H
+#define _ASM_UBICOM32_SIGINFO_H
+
+#include <asm-generic/siginfo.h>
+
+#endif /* _ASM_UBICOM32_SIGINFO_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/signal.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/signal.h
new file mode 100644 (file)
index 0000000..a334e19
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * arch/ubicom32/include/asm/signal.h
+ *   Signal related definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SIGNAL_H
+#define _ASM_UBICOM32_SIGNAL_H
+
+#include <linux/types.h>
+
+/* Avoid too many header ordering problems.  */
+struct siginfo;
+
+#ifdef __KERNEL__
+/* Most things should be clean enough to redefine this at will, if care
+   is taken to make libc match.  */
+
+#define _NSIG          64
+#define _NSIG_BPW      32
+#define _NSIG_WORDS    (_NSIG / _NSIG_BPW)
+
+typedef unsigned long old_sigset_t;            /* at least 32 bits */
+
+typedef struct {
+       unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#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
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * 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_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
+
+#include <asm-generic/signal.h>
+
+#ifdef __KERNEL__
+struct old_sigaction {
+       __sighandler_t sa_handler;
+       old_sigset_t sa_mask;
+       unsigned long sa_flags;
+       void (*sa_restorer)(void);
+};
+
+struct sigaction {
+       __sighandler_t sa_handler;
+       unsigned long sa_flags;
+       void (*sa_restorer)(void);
+       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 *ss_sp;
+       int ss_flags;
+       size_t ss_size;
+} stack_t;
+
+#ifdef __KERNEL__
+
+#include <asm/sigcontext.h>
+#undef __HAVE_ARCH_SIG_BITOPS
+
+#define ptrace_signal_deliver(regs, cookie) do { } while (0)
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_UBICOM32_SIGNAL_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/smp.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/smp.h
new file mode 100644 (file)
index 0000000..651a536
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * arch/ubicom32/include/asm/smp.h
+ *   SMP definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SMP_H
+#define _ASM_UBICOM32_SMP_H
+
+#ifndef CONFIG_SMP
+#error you should not include smp.h if smp is off
+#endif
+
+#ifndef ASSEMBLY
+#include <linux/bitops.h>
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <asm/ip5000.h>
+
+typedef unsigned long address_t;
+extern unsigned int smp_ipi_irq;
+
+/*
+ * This magic constant controls our willingness to transfer
+ * a process across CPUs.
+ *
+ * Such a transfer incurs cache and tlb
+ * misses. The current value is inherited from i386. Still needs
+ * to be tuned for parisc.
+ */
+#define PROC_CHANGE_PENALTY    15              /* Schedule penalty */
+#define NO_PROC_ID             0xFF            /* No processor magic marker */
+#define ANY_PROC_ID            0xFF            /* Any processor magic marker */
+
+#ifdef CONFIG_SMP
+#define raw_smp_processor_id() (current_thread_info()->cpu)
+#endif /* CONFIG_SMP */
+
+static inline int __cpu_disable (void)
+{
+  return 0;
+}
+
+static inline void __cpu_die (unsigned int cpu)
+{
+       while(1) {
+       };
+}
+
+extern int __cpu_up(unsigned int cpu);
+extern void smp_send_timer_all(void);
+extern void smp_timer_broadcast(const struct cpumask *mask);
+extern void smp_set_affinity(unsigned int irq, const struct cpumask *dest);
+extern void arch_send_call_function_single_ipi(int cpu);
+#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+
+/*
+ * TODO: Once these are fully tested, we should turn them into
+ * inline macros for performance.
+ */
+extern unsigned long smp_get_affinity(unsigned int irq, int *all);
+extern void smp_reset_ipi(unsigned long mask);
+
+#endif /* !ASSEMBLY */
+#endif /*  _ASM_UBICOM32_SMP_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/socket.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/socket.h
new file mode 100644 (file)
index 0000000..2d95c24
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * arch/ubicom32/include/asm/socket.h
+ *   Socket options definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SOCKET_H
+#define _ASM_UBICOM32_SOCKET_H
+
+#include <asm/sockios.h>
+
+/* For setsockopt(2) */
+#define SOL_SOCKET     1
+
+#define SO_DEBUG       1
+#define SO_REUSEADDR   2
+#define SO_TYPE                3
+#define SO_ERROR       4
+#define SO_DONTROUTE   5
+#define SO_BROADCAST   6
+#define SO_SNDBUF      7
+#define SO_RCVBUF      8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
+#define SO_KEEPALIVE   9
+#define SO_OOBINLINE   10
+#define SO_NO_CHECK    11
+#define SO_PRIORITY    12
+#define SO_LINGER      13
+#define SO_BSDCOMPAT   14
+/* To add :#define SO_REUSEPORT 15 */
+#define SO_PASSCRED    16
+#define SO_PEERCRED    17
+#define SO_RCVLOWAT    18
+#define SO_SNDLOWAT    19
+#define SO_RCVTIMEO    20
+#define SO_SNDTIMEO    21
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION             22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT       23
+#define SO_SECURITY_ENCRYPTION_NETWORK         24
+
+#define SO_BINDTODEVICE        25
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER        26
+#define SO_DETACH_FILTER        27
+
+#define SO_PEERNAME             28
+#define SO_TIMESTAMP           29
+#define SCM_TIMESTAMP          SO_TIMESTAMP
+
+#define SO_ACCEPTCONN          30
+
+#define SO_PEERSEC              31
+#define SO_PASSSEC             34
+#define SO_TIMESTAMPNS         35
+#define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
+
+#define SO_MARK                        36
+
+#define SO_TIMESTAMPING                37
+#define SCM_TIMESTAMPING       SO_TIMESTAMPING
+
+#endif /* _ASM_UBICOM32_SOCKET_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/sockios.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/sockios.h
new file mode 100644 (file)
index 0000000..5a7708d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * arch/ubicom32/include/asm/sockios.h
+ *   Socket-level ioctl definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SOCKIOS_H
+#define _ASM_UBICOM32_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 (timeval) */
+#define SIOCGSTAMPNS   0x8907          /* Get stamp (timespec) */
+
+#endif /* _ASM_UBICOM32_SOCKIOS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/spinlock.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/spinlock.h
new file mode 100644 (file)
index 0000000..4008058
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * arch/ubicom32/include/asm/spinlock.h
+ *   Spinlock related definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SPINLOCK_H
+#define _ASM_UBICOM32_SPINLOCK_H
+
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/spinlock_types.h>
+
+/*
+ * __raw_spin_lock()
+ *     Lock the lock.
+ */
+static inline void __raw_spin_lock(raw_spinlock_t *x)
+{
+       asm volatile (
+       "1:     bset    %0, %0, #0      \n\t"
+       "       jmpne.f 1b              \n\t"
+               : "+U4" (x->lock)
+               :
+               : "memory", "cc"
+       );
+}
+
+/*
+ * __raw_spin_unlock()
+ *     Unlock the lock.
+ */
+static inline void __raw_spin_unlock(raw_spinlock_t *x)
+{
+       asm volatile (
+       "       bclr    %0, %0, #0      \n\t"
+               : "+U4" (x->lock)
+               :
+               : "memory", "cc"
+       );
+}
+
+/*
+ * __raw_spin_is_locked()
+ *     Test if the lock is locked.
+ */
+static inline int __raw_spin_is_locked(raw_spinlock_t *x)
+{
+       return x->lock;
+}
+
+/*
+ * __raw_spin_unlock_wait()
+ *     Wait for the lock to be unlocked.
+ *
+ * Note: the caller has not guarantee that the lock will not
+ * be acquired before they get to it.
+ */
+static inline void __raw_spin_unlock_wait(raw_spinlock_t *x)
+{
+       do {
+               cpu_relax();
+       } while (__raw_spin_is_locked(x));
+}
+
+/*
+ * __raw_spin_trylock()
+ *     Try the lock, return 0 on failure, 1 on success.
+ */
+static inline int __raw_spin_trylock(raw_spinlock_t *x)
+{
+       int ret = 0;
+
+       asm volatile (
+       "       bset    %1, %1, #0      \n\t"
+       "       jmpne.f 1f              \n\t"
+       "       move.4  %0, #1          \n\t"
+       "1:                             \n\t"
+               : "+r" (ret), "+U4" (x->lock)
+               :
+               : "memory", "cc"
+       );
+
+       return ret;
+}
+
+/*
+ * __raw_spin_lock_flags()
+ *     Spin waiting for the lock (enabling IRQ(s))
+ */
+static inline void __raw_spin_lock_flags(raw_spinlock_t *x, unsigned long flags)
+{
+       mb();
+       while (!__raw_spin_trylock(x)) {
+               /*
+                * If the flags from the IRQ are set, interrupts are disabled and we
+                * need to re-enable them.
+                */
+               if (!flags) {
+                       cpu_relax();
+               } else {
+                       raw_local_irq_enable();
+                       cpu_relax();
+                       raw_local_irq_disable();
+               }
+       }
+       mb();
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Linux rwlocks are unfair to writers; they can be starved for an indefinite
+ * time by readers.  With care, they can also be taken in interrupt context.
+ *
+ * In Ubicom32 architecture implementation, we have a spinlock and a counter.
+ * Readers use the lock to serialise their access to the counter (which
+ * records how many readers currently hold the lock).
+ * Writers hold the spinlock, preventing any readers or other writers from
+ * grabbing the rwlock.
+ */
+
+/*
+ * __raw_read_lock()
+ *     Increment the counter in the rwlock.
+ *
+ * Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to grab the same read lock
+ */
+static inline void __raw_read_lock(raw_rwlock_t *rw)
+{
+       unsigned long flags;
+       raw_local_irq_save(flags);
+       __raw_spin_lock_flags(&rw->lock, flags);
+       rw->counter++;
+       __raw_spin_unlock(&rw->lock);
+       raw_local_irq_restore(flags);
+}
+
+/*
+ * __raw_read_unlock()
+ *     Decrement the counter.
+ *
+ * Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to grab the same read lock
+ */
+static inline void __raw_read_unlock(raw_rwlock_t *rw)
+{
+       unsigned long flags;
+       raw_local_irq_save(flags);
+       __raw_spin_lock_flags(&rw->lock, flags);
+       rw->counter--;
+       __raw_spin_unlock(&rw->lock);
+       raw_local_irq_restore(flags);
+}
+
+/*
+ * __raw_read_trylock()
+ *     Increment the counter if we can.
+ *
+ * Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to grab the same read lock
+ */
+static inline int __raw_read_trylock(raw_rwlock_t *rw)
+{
+       unsigned long flags;
+ retry:
+       raw_local_irq_save(flags);
+       if (__raw_spin_trylock(&rw->lock)) {
+               rw->counter++;
+               __raw_spin_unlock(&rw->lock);
+               raw_local_irq_restore(flags);
+               return 1;
+       }
+
+       raw_local_irq_restore(flags);
+
+       /*
+        * If write-locked, we fail to acquire the lock
+        */
+       if (rw->counter < 0) {
+               return 0;
+       }
+
+       /*
+        * Wait until we have a realistic chance at the lock
+        */
+       while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0) {
+               cpu_relax();
+       }
+
+       goto retry;
+}
+
+/*
+ * __raw_write_lock()
+ *
+ * Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to read_trylock() this lock
+ */
+static inline void __raw_write_lock(raw_rwlock_t *rw)
+{
+       unsigned long flags;
+retry:
+       raw_local_irq_save(flags);
+       __raw_spin_lock_flags(&rw->lock, flags);
+
+       if (rw->counter != 0) {
+               __raw_spin_unlock(&rw->lock);
+               raw_local_irq_restore(flags);
+
+               while (rw->counter != 0)
+                       cpu_relax();
+
+               goto retry;
+       }
+
+       rw->counter = -1; /* mark as write-locked */
+       mb();
+       raw_local_irq_restore(flags);
+}
+
+static inline void __raw_write_unlock(raw_rwlock_t *rw)
+{
+       rw->counter = 0;
+       __raw_spin_unlock(&rw->lock);
+}
+
+/* Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to read_trylock() this lock */
+static inline int __raw_write_trylock(raw_rwlock_t *rw)
+{
+       unsigned long flags;
+       int result = 0;
+
+       raw_local_irq_save(flags);
+       if (__raw_spin_trylock(&rw->lock)) {
+               if (rw->counter == 0) {
+                       rw->counter = -1;
+                       result = 1;
+               } else {
+                       /* Read-locked.  Oh well. */
+                       __raw_spin_unlock(&rw->lock);
+               }
+       }
+       raw_local_irq_restore(flags);
+
+       return result;
+}
+
+/*
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+static inline int __raw_read_can_lock(raw_rwlock_t *rw)
+{
+       return rw->counter >= 0;
+}
+
+/*
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+static inline int __raw_write_can_lock(raw_rwlock_t *rw)
+{
+       return !rw->counter;
+}
+
+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
+
+#define _raw_spin_relax(lock)  cpu_relax()
+#define _raw_read_relax(lock)  cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
+#endif /* _ASM_UBICOM32_SPINLOCK_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/spinlock_types.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/spinlock_types.h
new file mode 100644 (file)
index 0000000..3745bca
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * arch/ubicom32/include/asm/spinlock_types.h
+ *   Spinlock related structure definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SPINLOCK_TYPES_H
+#define _ASM_UBICOM32_SPINLOCK_TYPES_H
+
+typedef struct {
+       volatile unsigned int lock;
+} raw_spinlock_t;
+
+typedef struct {
+       raw_spinlock_t lock;
+       volatile int counter;
+} raw_rwlock_t;
+
+#define __RAW_SPIN_LOCK_UNLOCKED       { 0 }
+#define __RAW_RW_LOCK_UNLOCKED         { __RAW_SPIN_LOCK_UNLOCKED, 0 }
+
+#endif /* _ASM_UBICOM32_SPINLOCK_TYPES_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/stacktrace.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/stacktrace.h
new file mode 100644 (file)
index 0000000..f278ac7
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * arch/ubicom32/include/asm/stacktrace.h
+ *   Stacktrace functions for the Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_STACKTRACE_H
+#define _ASM_UBICOM32_STACKTRACE_H
+
+#define between(a, b, c)       (( \
+                       ((unsigned long) a) >= ((unsigned long) b)) && \
+                       (((unsigned long)a) <= ((unsigned long)c)))
+
+/*
+ * These symbols are filled in by the linker.
+ */
+extern unsigned long _stext;
+extern unsigned long _etext;
+
+/* OCM text goes from __ocm_text_run_begin to __data_begin */
+extern unsigned long __ocm_text_run_begin;
+extern unsigned long __data_begin;
+
+/* Account for OCM case - see stacktrace.c maybe combine(also trap.c) */
+/*
+ * ubicom32_is_kernel()
+ *
+ *     Check to see if the given address belongs to the kernel.
+ * NOMMU does not permit any other means.
+ */
+static inline int ubicom32_is_kernel(unsigned long addr)
+{
+       int is_kernel = between(addr, &_stext, &_etext) || \
+                       between(addr, &__ocm_text_run_begin, &__data_begin);
+
+#ifdef CONFIG_MODULES
+       if (!is_kernel)
+               is_kernel = is_module_address(addr);
+#endif
+       return is_kernel;
+}
+
+extern unsigned long stacktrace_iterate(
+                               unsigned long **trace,
+                               unsigned long stext, unsigned long etext,
+                               unsigned long ocm_stext, unsigned long ocm_etext,
+                               unsigned long sstack, unsigned long estack);
+#ifdef CONFIG_STACKTRACE
+void stacktrace_save_entries(struct task_struct *tsk, struct stack_trace *trace, unsigned long sp);
+#endif
+#endif /* _ASM_UBICOM32_STACKTRACE_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/stat.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/stat.h
new file mode 100644 (file)
index 0000000..e333c60
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * arch/ubicom32/include/asm/stat.h
+ *   File status definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_STAT_H
+#define _ASM_UBICOM32_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;
+};
+
+struct stat {
+       unsigned short st_dev;
+       unsigned short __pad1;
+       unsigned long  st_ino;
+       unsigned short st_mode;
+       unsigned short st_nlink;
+       unsigned short st_uid;
+       unsigned short st_gid;
+       unsigned short st_rdev;
+       unsigned short __pad2;
+       unsigned long  st_size;
+       unsigned long  st_blksize;
+       unsigned long  st_blocks;
+       unsigned long  st_atime;
+       unsigned long  __unused1;
+       unsigned long  st_mtime;
+       unsigned long  __unused2;
+       unsigned long  st_ctime;
+       unsigned long  __unused3;
+       unsigned long  __unused4;
+       unsigned long  __unused5;
+};
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat64 {
+       unsigned long long      st_dev;
+       unsigned char   __pad1[2];
+
+#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 char   __pad3[2];
+
+       long long       st_size;
+       unsigned long   st_blksize;
+
+       unsigned long long      st_blocks;      /* Number 512-byte blocks allocated. */
+
+       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 /* _ASM_UBICOM32_STAT_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/statfs.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/statfs.h
new file mode 100644 (file)
index 0000000..15890d4
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/statfs.h
+ *   Generic statfs.h definitions
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_STATFS_H
+#define _ASM_UBICOM32_STATFS_H
+
+#include <asm-generic/statfs.h>
+
+#endif /* _ASM_UBICOM32_STATFS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/string.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/string.h
new file mode 100644 (file)
index 0000000..7f24bf5
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * arch/ubicom32/include/asm/string.h
+ *   String operation definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_STRING_H
+#define _ASM_UBICOM32_STRING_H
+
+#define __HAVE_ARCH_MEMSET
+extern void *memset(void *b, int c, size_t len);
+
+#define __HAVE_ARCH_MEMCPY
+extern void *memcpy(void *to, const void *from, size_t len);
+
+#define __HAVE_ARCH_MEMMOVE
+extern void * memmove(void *to, const void *from, size_t len);
+
+#endif /* _ASM_UBICOM32_STRING_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/swab.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/swab.h
new file mode 100644 (file)
index 0000000..180a503
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * arch/ubicom32/include/asm/byteorder.h
+ *   Byte order swapping utility routines.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_BYTEORDER_H
+#define _ASM_UBICOM32_BYTEORDER_H
+
+#include <linux/types.h>
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+#  define __BYTEORDER_HAS_U64__
+#  define __SWAB_64_THRU_32__
+#endif
+
+#if defined(IP7000) || defined(IP7000_REV2)
+
+#define __arch__swab16 __builtin_ubicom32_swapb_2
+#define __arch__swab32 __builtin_ubicom32_swapb_4
+
+#endif /* IP7000 */
+
+#endif /* _ASM_UBICOM32_BYTEORDER_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/switch-dev.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/switch-dev.h
new file mode 100644 (file)
index 0000000..ed67e94
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * arch/ubicom32/include/asm/switch-dev.h
+ *   generic Ethernet switch platform data definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SWITCH_DEV_H
+#define _ASM_UBICOM32_SWITCH_DEV_H
+
+#define SWITCH_DEV_FLAG_HW_RESET       0x01
+#define SWITCH_DEV_FLAG_SW_RESET       0x02
+
+struct switch_core_platform_data {
+       /*
+        * See flags above
+        */
+       u32_t           flags;
+
+       /*
+        * GPIO to use for nReset
+        */
+       int             pin_reset;
+
+       /*
+        * Name of this switch
+        */
+       const char      *name;
+};
+
+#endif /* _ASM_UBICOM32_SWITCH_DEV_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/system.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/system.h
new file mode 100644 (file)
index 0000000..c3ec608
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * arch/ubicom32/include/asm/system.h
+ *   Low level switching definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_SYSTEM_H
+#define _ASM_UBICOM32_SYSTEM_H
+
+#include <linux/irqflags.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/entry.h>
+#include <asm/ldsr.h>
+#include <asm/irq.h>
+#include <asm/percpu.h>
+#include <asm/ubicom32-common.h>
+#include <asm/processor.h>
+
+/*
+ * switch_to(n) should switch tasks to task ptr, first checking that
+ * ptr isn't the current task, in which case it does nothing.
+ */
+asmlinkage void resume(void);
+extern void *__switch_to(struct task_struct *prev,
+               struct thread_struct *prev_switch,
+               struct thread_struct *next_switch);
+
+/*
+ * We will need a per linux thread sw_ksp for the switch_to macro to
+ * track the kernel stack pointer for the current thread on that linux thread.
+ */
+#define switch_to(prev,next,last)                                      \
+({                                                                     \
+       void *_last;                                                    \
+       _last = (void *)                                                \
+               __switch_to(prev, &prev->thread, &next->thread);        \
+       (last) = _last;                                                 \
+})
+
+/*
+ * Force strict CPU ordering.
+ * Not really required on ubicom32...
+ */
+#define nop()  asm volatile ("nop"::)
+#define mb()   asm volatile (""   : : :"memory")
+#define rmb()  asm volatile (""   : : :"memory")
+#define wmb()  asm volatile (""   : : :"memory")
+#define set_mb(var, value)     ({ (var) = (value); wmb(); })
+
+#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()       mb()
+#define smp_rmb()      rmb()
+#define smp_wmb()      wmb()
+#define smp_read_barrier_depends()     do { } while(0)
+#endif
+
+#define read_barrier_depends()  ((void)0)
+
+/*
+ * The following defines change how the scheduler calls the switch_to()
+ * macro.
+ *
+ * 1) The first causes the runqueue to be unlocked on entry to
+ * switch_to().  Since our ctx code does not play with the runqueue
+ * we do not need it unlocked.
+ *
+ * 2) The later turns interrupts on during a ctxsw to reduce the latency of
+ * interrupts during ctx.  At this point in the port, we believe that this
+ * latency is not a problem since we have very little code to perform a ctxsw.
+ */
+// #define __ARCH_WANT_UNLOCKED_CTXSW
+// #define __ARCH_WANT_INTERRUPTS_ON_CTXSW
+
+#endif /* _ASM_UBICOM32_SYSTEM_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/termbits.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/termbits.h
new file mode 100644 (file)
index 0000000..a7b3381
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * arch/ubicom32/include/asm/termbits.h
+ *   Terminal/serial port definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_TERMBITS_H
+#define _ASM_UBICOM32_TERMBITS_H
+
+#include <linux/posix_types.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                      /* Shift from CBAUD to CIBAUD */
+
+/* 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
+
+
+/* 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_UBICOM32_TERMBITS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/termios.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/termios.h
new file mode 100644 (file)
index 0000000..5c16fe7
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * arch/ubicom32/include/asm/termios.h
+ *   Ubicom32 termio definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_TERMIOS_H
+#define _ASM_UBICOM32_TERMIOS_H
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+struct winsize {
+       unsigned short ws_row;
+       unsigned short ws_col;
+       unsigned short ws_xpixel;
+       unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+       unsigned short c_iflag;         /* input mode flags */
+       unsigned short c_oflag;         /* output mode flags */
+       unsigned short c_cflag;         /* control mode flags */
+       unsigned short c_lflag;         /* local mode flags */
+       unsigned char c_line;           /* line discipline */
+       unsigned char c_cc[NCC];        /* control characters */
+};
+
+#ifdef __KERNEL__
+/*     intr=^C         quit=^|         erase=del       kill=^U
+       eof=^D          vtime=\0        vmin=\1         sxtc=\0
+       start=^Q        stop=^S         susp=^Z         eol=\0
+       reprint=^R      discard=^U      werase=^W       lnext=^V
+       eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+#endif
+
+/* modem lines */
+#define TIOCM_LE       0x001
+#define TIOCM_DTR      0x002
+#define TIOCM_RTS      0x004
+#define TIOCM_ST       0x008
+#define TIOCM_SR       0x010
+#define TIOCM_CTS      0x020
+#define TIOCM_CAR      0x040
+#define TIOCM_RNG      0x080
+#define TIOCM_DSR      0x100
+#define TIOCM_CD       TIOCM_CAR
+#define TIOCM_RI       TIOCM_RNG
+#define TIOCM_OUT1     0x2000
+#define TIOCM_OUT2     0x4000
+#define TIOCM_LOOP     0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+#ifdef __KERNEL__
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+#define user_termio_to_kernel_termios(termios, termio) \
+({ \
+       unsigned short tmp; \
+       get_user(tmp, &(termio)->c_iflag); \
+       (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \
+       get_user(tmp, &(termio)->c_oflag); \
+       (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \
+       get_user(tmp, &(termio)->c_cflag); \
+       (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \
+       get_user(tmp, &(termio)->c_lflag); \
+       (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \
+       get_user((termios)->c_line, &(termio)->c_line); \
+       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 termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#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_UBICOM32_TERMIOS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread-asm.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread-asm.h
new file mode 100644 (file)
index 0000000..f956603
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * arch/ubicom32/include/asm/thread-asm.h
+ *   Ubicom32 architecture specific thread definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_THREAD_ASM_H
+#define _ASM_UBICOM32_THREAD_ASM_H
+
+/*
+ * thread_get_self
+ *     Read and shift the current thread into reg
+ *
+ * Note that we don't need to mask the result as bits 6 through 31 of the
+ * ROSR are zeroes.
+ */
+.macro thread_get_self reg
+       lsr.4   \reg, ROSR, #2
+.endm
+
+/*
+ * thread_get_self_mask
+ *     Read and shift the current thread mask into reg
+ */
+.macro thread_get_self_mask reg
+       lsr.4   \reg, ROSR, #2
+       lsl.4   \reg, #1, \reg   /* Thread bit */
+.endm
+
+#endif /* _ASM_UBICOM32_THREAD_ASM_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread.h
new file mode 100644 (file)
index 0000000..69c925e
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * arch/ubicom32/include/asm/thread.h
+ *   Ubicom32 architecture specific thread definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_THREAD_H
+#define _ASM_UBICOM32_THREAD_H
+
+#if !defined(__ASSEMBLY__)
+
+#include <asm/ptrace.h>
+#include <asm/ubicom32-common.h>
+
+typedef int thread_t;
+typedef unsigned char thread_type_t;
+typedef void (*thread_exec_fn_t)(void *arg);
+
+#define THREAD_NULL 0x40
+#define THREAD_TYPE_HRT (1 << 0)
+#define THREAD_TYPE_SPECIAL 0
+#define THREAD_TYPE_NORMAL 0
+#define THREAD_TYPE_BACKGROUND (1 << 1)
+
+/*
+ * This is the upper bound on the maximum hardware threads that one will find
+ * on a Ubicom processor. It is used to size per hardware thread data structures.
+ */
+#define THREAD_ARCHITECTURAL_MAX 16
+
+/*
+ * TODO: Rename this at some point to be thread_
+ */
+extern unsigned int sw_ksp[THREAD_ARCHITECTURAL_MAX];
+
+
+/*
+ * thread_get_self()
+ */
+static inline thread_t thread_get_self(void)
+{
+       thread_t result;
+
+       /*
+        * Note that ROSR has zeroes in bits 6 through 31 and so we don't need
+        * to do any additional bit masking here.
+        */
+       asm (
+               "lsr.4  %0, ROSR, #2    \n\t"
+               : "=d" (result)
+               :
+               : "cc"
+       );
+
+       return result;
+}
+
+/*
+ * thread_suspend()
+ */
+static inline void thread_suspend(void)
+{
+       asm volatile (
+               "suspend\n\t"
+               :
+               :
+       );
+}
+
+/*
+ * thread_resume()
+ */
+static inline void thread_resume(thread_t thread)
+{
+       asm volatile (
+               "move.4         MT_ACTIVE_SET, %0       \n\t"
+               "pipe_flush     0                       \n\t"
+               "pipe_flush     0                       \n\t"
+               :
+               : "d" (1 << thread)
+       );
+}
+
+
+
+/*
+ * thread_enable_mask()
+ *     Enable all threads in the mask.
+ *
+ * All writes to MT_EN must be protected by the MT_EN_LOCK bit
+ */
+static inline void thread_enable_mask(unsigned int mask)
+{
+       /*
+        * must flush the pipeline twice.
+        * first pipe_flush is to ensure write to MT_EN is completed
+        * second one is to ensure any new instructions from
+        * the targeted thread (the one being disabled), that
+        * are issued while the write to MT_EN is being executed,
+        * are completed.
+        */
+       UBICOM32_LOCK(MT_EN_LOCK_BIT);
+       asm volatile (
+               "or.4           MT_EN, MT_EN, %0        \n\t"
+               "pipe_flush     0                       \n\t"
+               "pipe_flush     0                       \n\t"
+               :
+               : "d" (mask)
+               : "cc"
+       );
+       UBICOM32_UNLOCK(MT_EN_LOCK_BIT);
+}
+
+/*
+ * thread_enable()
+ */
+static inline void thread_enable(thread_t thread)
+{
+       thread_enable_mask(1 << thread);
+}
+
+/*
+ * thread_disable_mask()
+ *     Disable all threads in the mask.
+ *
+ * All writes to MT_EN must be protected by the MT_EN_LOCK bit
+ */
+static inline void thread_disable_mask(unsigned int mask)
+{
+       /*
+        * must flush the pipeline twice.
+        * first pipe_flush is to ensure write to MT_EN is completed
+        * second one is to ensure any new instructions from
+        * the targeted thread (the one being disabled), that
+        * are issued while the write to MT_EN is being executed,
+        * are completed.
+        */
+       UBICOM32_LOCK(MT_EN_LOCK_BIT);
+       asm volatile (
+               "and.4          MT_EN, MT_EN, %0        \n\t"
+               "pipe_flush     0                       \n\t"
+               "pipe_flush     0                       \n\t"
+               :
+               : "d" (~mask)
+               : "cc"
+       );
+       UBICOM32_UNLOCK(MT_EN_LOCK_BIT);
+}
+
+/*
+ * thread_disable()
+ */
+static inline void thread_disable(thread_t thread)
+{
+       thread_disable_mask(1 << thread);
+}
+
+/*
+ * thread_disable_others()
+ *     Disable all other threads
+ */
+static inline void thread_disable_others(void)
+{
+       thread_t self = thread_get_self();
+       thread_disable_mask(~(1 << self));
+}
+
+/*
+ * thread_is_trapped()
+ *     Is the specified tid trapped?
+ */
+static inline int thread_is_trapped(thread_t tid)
+{
+       int thread_mask = (1 << tid);
+       int trap_thread;
+
+       asm (
+               "move.4         %0, MT_TRAP             \n\t"
+               : "=d" (trap_thread)
+               :
+       );
+       return (trap_thread & thread_mask);
+}
+
+/*
+ * thread_is_enabled()
+ *     Is the specified tid enabled?
+ */
+static inline int thread_is_enabled(thread_t tid)
+{
+       int thread_mask = (1 << tid);
+       int enabled_threads;
+
+       asm (
+               "move.4         %0, MT_EN               \n\t"
+               : "=d" (enabled_threads)
+               :
+       );
+       return (enabled_threads & thread_mask);
+}
+
+/*
+ * thread_get_instruction_count()
+ */
+static inline unsigned int thread_get_instruction_count(void)
+{
+       unsigned int result;
+       asm (
+               "move.4         %0, INST_CNT            \n\t"
+               : "=r" (result)
+       );
+       return result;
+}
+
+/*
+ * thread_get_pc()
+ *     pc could point to a speculative and cancelled instruction unless thread is disabled
+ */
+static inline void *thread_get_pc(thread_t thread)
+{
+       void *result;
+       asm (
+               "move.4         csr, %1         \n\t"
+               "setcsr_flush   0               \n\t"
+               "move.4         %0, pc          \n\t"
+               "move.4         csr, #0         \n\t"
+               "setcsr_flush   0               \n\t"
+               : "=r" (result)
+               : "r" ((thread << 9) | (1 << 8))
+       );
+       return result;
+}
+
+/*
+ * thread_get_trap_cause()
+ *     This should be called only when the thread is not running
+ */
+static inline unsigned int thread_get_trap_cause(thread_t thread)
+{
+       unsigned int result;
+       asm (
+               "move.4         csr, %1         \n\t"
+               "setcsr_flush   0               \n\t"
+               "move.4         %0, trap_cause  \n\t"
+               "move.4         csr, #0         \n\t"
+               "setcsr_flush   0               \n\t"
+               : "=r" (result)
+               : "r" ((thread << 9) | (1 << 8))
+       );
+       return result;
+}
+
+/*
+ * THREAD_STALL macro.
+ */
+#define THREAD_STALL \
+               asm volatile ( \
+                       "move.4 mt_dbg_active_clr, #-1  \n\t" \
+                       "pipe_flush 0                   \n\t" \
+                       : \
+                       : \
+               )
+
+extern unsigned int thread_get_mainline(void);
+extern void thread_set_mainline(thread_t tid);
+extern thread_t thread_alloc(void);
+extern thread_t thread_start(thread_t thread, thread_exec_fn_t exec, void *arg, unsigned int *sp_high, thread_type_t type);
+
+/*
+ * asm macros
+ */
+asm (
+/*
+ * thread_get_self
+ *     Read and shift the current thread into reg
+ *
+ * Note that we don't need to mask the result as bits 6 through 31 of the
+ * ROSR are zeroes.
+ */
+".macro        thread_get_self reg             \n\t"
+"      lsr.4   \\reg, ROSR, #2         \n\t"
+".endm                                 \n\t"
+
+/*
+ * thread_get_self_mask
+ *     Read and shift the current thread mask into reg
+ */
+".macro        thread_get_self_mask reg        \n\t"
+"      lsr.4   \\reg, ROSR, #2         \n\t"
+"      lsl.4   \\reg, #1, \\reg        \n\t"    /* Thread bit */
+".endm                                 \n\t"
+);
+
+#else /* __ASSEMBLY__ */
+
+#include <asm/thread-asm.h>
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_UBICOM32_THREAD_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread_info.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/thread_info.h
new file mode 100644 (file)
index 0000000..55c69da
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * arch/ubicom32/include/asm/thread_info.h
+ *   Ubicom32 architecture low-level thread information.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Adapted from the i386 and PPC versions by Greg Ungerer (gerg@snapgear.com)
+ * Copyright (C) 2002  David Howells (dhowells@redhat.com)
+ * - Incorporating suggestions made by Linus Torvalds and Dave Miller
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_THREAD_INFO_H
+#define _ASM_UBICOM32_THREAD_INFO_H
+
+#include <asm/page.h>
+
+/*
+ * Size of kernel stack for each process. This must be a power of 2...
+ */
+#ifdef CONFIG_4KSTACKS
+#define THREAD_SIZE_ORDER (0)
+#else
+#define THREAD_SIZE_ORDER (1)
+#endif
+
+/*
+ * for asm files, THREAD_SIZE is now generated by asm-offsets.c
+ */
+#define THREAD_SIZE (PAGE_SIZE<<THREAD_SIZE_ORDER)
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+/*
+ * low level task data.
+ */
+struct thread_info {
+       struct task_struct *task;               /* main task structure */
+       struct exec_domain *exec_domain;        /* execution domain */
+       unsigned long      flags;               /* low level flags */
+       int                cpu;                 /* cpu we're on */
+       int                preempt_count;       /* 0 => preemptable, <0 => BUG */
+       int                interrupt_nesting;   /* Interrupt nesting level. */
+       struct restart_block restart_block;
+};
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ */
+#define INIT_THREAD_INFO(tsk)                  \
+{                                              \
+       .task           = &tsk,                 \
+       .exec_domain    = &default_exec_domain, \
+       .flags          = 0,                    \
+       .cpu            = 0,                    \
+       .interrupt_nesting      = 0,            \
+       .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)
+{
+       struct thread_info *ti;
+
+       asm (
+               "and.4  %0, sp, %1\n\t"
+               : "=&r" (ti)
+               : "d" (~(THREAD_SIZE-1))
+               : "cc"
+       );
+
+       return ti;
+}
+
+#define STACK_WARN (THREAD_SIZE / 8)
+
+#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR 1
+
+/* thread information allocation */
+#define alloc_thread_info(tsk) ((struct thread_info *) \
+                               __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER))
+#define free_thread_info(ti)   free_pages((unsigned long) (ti), THREAD_SIZE_ORDER)
+#endif /* __ASSEMBLY__ */
+
+#define        PREEMPT_ACTIVE  0x4000000
+
+/*
+ * thread information flag bit numbers
+ */
+#define TIF_SYSCALL_TRACE      0       /* syscall trace active */
+#define TIF_SIGPENDING         1       /* signal pending */
+#define TIF_NEED_RESCHED       2       /* rescheduling necessary */
+#define TIF_POLLING_NRFLAG     3       /* true if poll_idle() is polling
+                                          TIF_NEED_RESCHED */
+#define TIF_MEMDIE             4
+
+/* as above, but as bit values */
+#define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
+#define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
+#define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
+
+#define _TIF_WORK_MASK         0x0000FFFE      /* work to do on interrupt/exception return */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_UBICOM32_THREAD_INFO_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/timex.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/timex.h
new file mode 100644 (file)
index 0000000..93ee3db
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * arch/ubicom32/include/asm/timex.h
+ *   Ubicom32 architecture timex specifications.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_TIMEX_H
+#define _ASM_UBICOM32_TIMEX_H
+
+#define CLOCK_TICK_RATE        266000000
+
+// #define ARCH_HAS_READ_CURRENT_TIMER
+
+typedef unsigned long cycles_t;
+
+static inline cycles_t get_cycles(void)
+{
+       return 0;
+}
+
+extern int timer_alloc(void);
+extern void timer_set(int timervector, unsigned int cycles);
+extern int timer_reset(int timervector, unsigned int cycles);
+extern void timer_tick_init(void);
+extern void timer_device_init(void);
+
+#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+extern void local_timer_interrupt(void);
+#endif
+
+#if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+extern int local_timer_setup(unsigned int cpu);
+#endif
+
+#endif /* _ASM_UBICOM32_TIMEX_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/tlb.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/tlb.h
new file mode 100644 (file)
index 0000000..cd45996
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * arch/ubicom32/include/asm/tlb.h
+ *   Ubicom32 architecture TLB operations.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_TLB_H
+#define _ASM_UBICOM32_TLB_H
+
+/*
+ * ubicom32 doesn't need any special per-pte or
+ * per-vma handling..
+ */
+#define tlb_start_vma(tlb, vma)        do { } while (0)
+#define tlb_end_vma(tlb, vma)  do { } while (0)
+#define __tlb_remove_tlb_entry(tlb, ptep, address)     do { } while (0)
+
+/*
+ * .. because we flush the whole mm when it
+ * fills up.
+ */
+#define tlb_flush(tlb)
+
+#include <asm-generic/tlb.h>
+
+#endif /* _ASM_UBICOM32_TLB_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/tlbflush.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/tlbflush.h
new file mode 100644 (file)
index 0000000..0317aca
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * arch/ubicom32/include/asm/tlbflush.h
+ *   TLB operations for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 2000 Lineo, David McCullough <davidm@uclinux.org>
+ * Copyright (C) 2000-2002, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_TLB_FLUSH_H
+#define _ASM_UBICOM32_TLB_FLUSH_H
+
+#include <asm/setup.h>
+
+/*
+ * flush all user-space atc entries.
+ */
+static inline void __flush_tlb(void)
+{
+       BUG();
+}
+
+static inline void __flush_tlb_one(unsigned long addr)
+{
+       BUG();
+}
+
+#define flush_tlb() __flush_tlb()
+
+/*
+ * flush all atc entries (both kernel and user-space entries).
+ */
+static inline void flush_tlb_all(void)
+{
+       BUG();
+}
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+       BUG();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
+{
+       BUG();
+}
+
+static inline void flush_tlb_range(struct mm_struct *mm,
+                                  unsigned long start, unsigned long end)
+{
+       BUG();
+}
+
+static inline void flush_tlb_kernel_page(unsigned long addr)
+{
+       BUG();
+}
+
+#endif /* _ASM_UBICOM32_TLB_FLUSH_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/topology.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/topology.h
new file mode 100644 (file)
index 0000000..b4de143
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/topology.h
+ *   Generic topology.h definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_TOPOLOGY_H
+#define _ASM_UBICOM32_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_UBICOM32_TOPOLOGY_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/traps.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/traps.h
new file mode 100644 (file)
index 0000000..9edcca9
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * arch/ubicom32/include/asm/traps.h
+ *   Trap related definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_TRAPS_H
+#define _ASM_UBICOM32_TRAPS_H
+
+/*
+ * Trap causes passed from ultra to Host OS
+ */
+#define TRAP_CAUSE_TOTAL               13
+#define TRAP_CAUSE_DST_RANGE_ERR       12
+#define TRAP_CAUSE_SRC1_RANGE_ERR      11
+#define TRAP_CAUSE_I_RANGE_ERR         10
+#define TRAP_CAUSE_DCAPT               9
+#define TRAP_CAUSE_DST_SERROR          8
+#define TRAP_CAUSE_SRC1_SERROR         7
+#define TRAP_CAUSE_DST_MISALIGNED      6
+#define TRAP_CAUSE_SRC1_MISALIGNED     5
+#define TRAP_CAUSE_DST_DECODE_ERR      4
+#define TRAP_CAUSE_SRC1_DECODE_ERR     3
+#define TRAP_CAUSE_ILLEGAL_INST                2
+#define TRAP_CAUSE_I_SERROR            1
+#define TRAP_CAUSE_I_DECODE_ERR                0
+
+extern void trap_handler(int irq, struct pt_regs *regs);
+extern void trap_init_interrupt(void);
+extern void unaligned_emulate(unsigned int thread);
+extern int unaligned_only(unsigned int cause);
+
+#endif /* _ASM_UBICOM32_TRAPS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/types.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/types.h
new file mode 100644 (file)
index 0000000..5b960dd
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * arch/ubicom32/include/asm/types.h
+ *   Date type definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_TYPES_H
+#define _ASM_UBICOM32_TYPES_H
+
+/*
+ * This file is never included by application software unless
+ * explicitly requested (e.g., via linux/types.h) in which case the
+ * application is Linux specific so (user-) name space pollution is
+ * not a major issue.  However, for interoperability, libraries still
+ * need to be careful to avoid a name clashes.
+ */
+
+#include <asm-generic/int-ll64.h>
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned short umode_t;
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+#define BITS_PER_LONG 32
+
+#ifndef __ASSEMBLY__
+
+/* DMA addresses are always 32-bits wide */
+
+typedef u32 dma_addr_t;
+typedef u32 dma64_addr_t;
+
+/*
+ * XXX These are "Ubicom style" typedefs. They should be removed in all files used by linux.
+ */
+typedef u32 u32_t;
+typedef s32 s32_t;
+typedef u16 u16_t;
+typedef s16 s16_t;
+typedef u8 u8_t;
+typedef s8 s8_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_UBICOM32_TYPES_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/uaccess.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/uaccess.h
new file mode 100644 (file)
index 0000000..eef739d
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * arch/ubicom32/include/asm/uaccess.h
+ *   User space memory access functions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *   arch/alpha
+ */
+#ifndef _ASM_UBICOM32_UACCESS_H
+#define _ASM_UBICOM32_UACCESS_H
+
+/*
+ * User space memory access functions
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+
+#include <asm/segment.h>
+
+#define VERIFY_READ    0
+#define VERIFY_WRITE   1
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue.  No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+struct exception_table_entry
+{
+       unsigned long insn, fixup;
+};
+
+/*
+ * Ubicom32 does not currently support the exception table handling.
+ */
+extern unsigned long search_exception_table(unsigned long);
+
+
+#if defined(CONFIG_ACCESS_OK_CHECKS_ENABLED)
+extern int __access_ok(unsigned long addr, unsigned long size);
+#else
+static inline int __access_ok(unsigned long addr, unsigned long size)
+{
+       return 1;
+}
+#endif
+#define access_ok(type, addr, size) \
+       likely(__access_ok((unsigned long)(addr), (size)))
+
+/*
+ * The following functions do not exist.  They keep callers
+ * of put_user and get_user from passing unsupported argument
+ * types.  They result in a link time error.
+ */
+extern int __put_user_bad(void);
+extern int __get_user_bad(void);
+
+/*
+ * __put_user_no_check()
+ *     Put the requested data into the user space verifying the address
+ *
+ * Careful to not
+ * (a) re-use the arguments for side effects (sizeof/typeof is ok)
+ * (b) require any knowledge of processes at this stage
+ */
+#define __put_user_no_check(x, ptr, size)              \
+({                                                     \
+       int __pu_err = 0;                               \
+       __typeof__(*(ptr)) __user *__pu_addr = (ptr);   \
+       switch (size) {                                 \
+       case 1:                                         \
+       case 2:                                         \
+       case 4:                                         \
+       case 8:                                         \
+               *__pu_addr = (__typeof__(*(ptr)))x;     \
+               break;                                  \
+       default:                                        \
+               __pu_err = __put_user_bad();            \
+               break;                                  \
+       }                                               \
+       __pu_err;                                       \
+})
+
+/*
+ * __put_user_check()
+ *     Put the requested data into the user space verifying the address
+ *
+ * Careful to not
+ * (a) re-use the arguments for side effects (sizeof/typeof is ok)
+ * (b) require any knowledge of processes at this stage
+ *
+ * If requested, access_ok() will verify that ptr is a valid user
+ * pointer.
+ */
+#define __put_user_check(x, ptr, size)                         \
+({                                                             \
+       int __pu_err = -EFAULT;                                 \
+       __typeof__(*(ptr)) __user *__pu_addr = (ptr);           \
+       if (access_ok(VERIFY_WRITE, __pu_addr, size)) {         \
+               __pu_err = 0;                                   \
+               switch (size) {                                 \
+               case 1:                                         \
+               case 2:                                         \
+               case 4:                                         \
+               case 8:                                         \
+                       *__pu_addr = (__typeof__(*(ptr)))x;     \
+                       break;                                  \
+               default:                                        \
+                       __pu_err = __put_user_bad();            \
+                       break;                                  \
+               }                                               \
+       }                                                       \
+       __pu_err;                                               \
+})
+
+/*
+ * __get_user_no_check()
+ *     Read the value at ptr into x.
+ *
+ * If requested, access_ok() will verify that ptr is a valid user
+ * pointer.  If the caller passes a modifying argument for ptr (e.g. x++)
+ * this macro will not work.
+ */
+#define __get_user_no_check(x, ptr, size)                      \
+({                                                             \
+       int __gu_err = 0;                                       \
+       __typeof__((x)) __gu_val = 0;                           \
+       const __typeof__(*(ptr)) __user *__gu_addr = (ptr);     \
+       switch (size) {                                         \
+       case 1:                                                 \
+       case 2:                                                 \
+       case 4:                                                 \
+       case 8:                                                 \
+               __gu_val = (__typeof__((x)))*(__gu_addr);       \
+               break;                                          \
+       default:                                                \
+               __gu_err = __get_user_bad();                    \
+               (x) = 0;                                        \
+               break;                                          \
+       }                                                       \
+       (x) = __gu_val;                                         \
+       __gu_err;                                               \
+})
+
+/*
+ * __get_user_check()
+ *     Read the value at ptr into x.
+ *
+ * If requested, access_ok() will verify that ptr is a valid user
+ * pointer.
+ */
+#define __get_user_check(x, ptr, size)                                 \
+({                                                                     \
+       int __gu_err = -EFAULT;                                         \
+       __typeof__(x) __gu_val = 0;                                     \
+       const __typeof__(*(ptr)) __user *__gu_addr = (ptr);             \
+       if (access_ok(VERIFY_READ, __gu_addr, size)) {                  \
+               __gu_err = 0;                                           \
+               switch (size) {                                         \
+               case 1:                                                 \
+               case 2:                                                 \
+               case 4:                                                 \
+               case 8:                                                 \
+                       __gu_val = (__typeof__((x)))*(__gu_addr);       \
+                       break;                                          \
+               default:                                                \
+                       __gu_err = __get_user_bad();                    \
+                       (x) = 0;                                        \
+                       break;                                          \
+               }                                                       \
+       }                                                               \
+       (x) = __gu_val;                                                 \
+       __gu_err;                                                       \
+})
+
+/*
+ * The "xxx" versions are allowed to perform some amount of address
+ * space checking.  See access_ok().
+ */
+#define put_user(x,ptr) \
+       __put_user_check((__typeof__(*(ptr)))(x),(ptr), sizeof(*(ptr)))
+#define get_user(x,ptr) \
+       __get_user_check((x), (ptr), sizeof(*(ptr)))
+
+/*
+ * The "__xxx" versions do not do address space checking, useful when
+ * doing multiple accesses to the same area (the programmer has to do the
+ * checks by hand with "access_ok()")
+ */
+#define __put_user(x,ptr) \
+       __put_user_no_check((__typeof__(*(ptr)))(x),(ptr), sizeof(*(ptr)))
+#define __get_user(x,ptr) \
+       __get_user_no_check((x), (ptr), sizeof(*(ptr)))
+
+/*
+ * __copy_tofrom_user_no_check()
+ *     Copy the data either to or from user space.
+ *
+ * Return the number of bytes NOT copied.
+ */
+static inline unsigned long
+__copy_tofrom_user_no_check(void *to, const void *from, unsigned long n)
+{
+       memcpy(to, from, n);
+       return 0;
+}
+
+/*
+ * copy_to_user()
+ *     Copy the kernel data to user space.
+ *
+ * Return the number of bytes that were copied.
+ */
+static inline unsigned long
+copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+       if (!access_ok(VERIFY_WRITE, to, n)) {
+               return n;
+       }
+       return __copy_tofrom_user_no_check((__force void *)to, from, n);
+}
+
+/*
+ * copy_from_user()
+ *     Copy the user data to kernel space.
+ *
+ * Return the number of bytes that were copied.  On error, we zero
+ * out the destination.
+ */
+static inline unsigned long
+copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+       if (!access_ok(VERIFY_READ, from, n)) {
+               return n;
+       }
+       return __copy_tofrom_user_no_check(to, (__force void *)from, n);
+}
+
+#define __copy_to_user(to, from, n) \
+       __copy_tofrom_user_no_check((__force void *)to, from, n)
+#define __copy_from_user(to, from, n) \
+       __copy_tofrom_user_no_check(to, (__force void *)from, n)
+#define __copy_to_user_inatomic(to, from, n) \
+       __copy_tofrom_user_no_check((__force void *)to, from, n)
+#define __copy_from_user_inatomic(to, from, n) \
+       __copy_tofrom_user_no_check(to, (__force void *)from, n)
+
+#define copy_to_user_ret(to, from, n, retval) \
+       ({ if (copy_to_user(to, from, n)) return retval; })
+
+#define copy_from_user_ret(to, from, n, retval) \
+       ({ if (copy_from_user(to, from, n)) return retval; })
+
+/*
+ * strncpy_from_user()
+ *     Copy a null terminated string from userspace.
+ *
+ * dst - Destination in kernel space.  The buffer must be at least count.
+ * src - Address of string in user space.
+ * count - Maximum number of bytes to copy (including the trailing NULL).
+ *
+ * Returns the length of the string (not including the trailing NULL.  If
+ * count is smaller than the length of the string, we copy count bytes
+ * and return count.
+ *
+ */
+static inline long strncpy_from_user(char *dst, const __user char *src, long count)
+{
+       char *tmp;
+       if (!access_ok(VERIFY_READ, src, 1)) {
+               return -EFAULT;
+       }
+
+       strncpy(dst, src, count);
+       for (tmp = dst; *tmp && count > 0; tmp++, count--) {
+               ;
+       }
+       return(tmp - dst);
+}
+
+/*
+ * strnlen_user()
+ *     Return the size of a string (including the ending 0)
+ *
+ * Return -EFAULT on exception, a value greater than <n> if too long
+ */
+static inline long strnlen_user(const __user char *src, long n)
+{
+       if (!access_ok(VERIFY_READ, src, 1)) {
+               return -EFAULT;
+       }
+       return(strlen(src) + 1);
+}
+
+#define strlen_user(str) strnlen_user(str, 32767)
+
+/*
+ * __clear_user()
+ *     Zero Userspace
+ */
+static inline unsigned long __clear_user(__user void *to, unsigned long n)
+{
+       memset(to, 0, n);
+       return 0;
+}
+
+/*
+ * clear_user()
+ *     Zero user space (check for valid addresses)
+ */
+static inline unsigned long clear_user(__user void *to, unsigned long n)
+{
+       if (!access_ok(VERIFY_WRITE, to, n)) {
+               return -EFAULT;
+       }
+       return __clear_user(to, n);
+}
+
+#endif /* _ASM_UBICOM32_UACCESS_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/uart_tio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/uart_tio.h
new file mode 100644 (file)
index 0000000..19ef82e
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * arch/ubicom32/include/asm/uart_tio.h
+ *   Ubicom32 architecture UART TIO definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _ASM_UBICOM32_UART_TIO_H
+#define _ASM_UBICOM32_UART_TIO_H
+
+#include <asm/devtree.h>
+
+#define UARTTIO_RX_FIFO_SIZE           16
+#define UARTTIO_TX_FIFO_SIZE           16
+
+/*
+ * Interrupt flags
+ */
+#define UARTTIO_UART_INT_RX            0x00000001      // set when a character has been recevied (TODO: add watermark)
+#define UARTTIO_UART_INT_RXOVF         0x00000002      // set when the receive buffer has overflowed
+#define UARTTIO_UART_INT_RXFRAME       0x00000004      // set when there has been a framing error
+
+#define UARTTIO_UART_INT_TX            0x00000100      // set every time a character is transmitted
+#define UARTTIO_UART_INT_TXBE          0x00000200      // set when the transmit buffer is empty (TODO: add watermark)
+
+#define UARTTIO_UART_FLAG_ENABLED      0x80000000
+#define UARTTIO_UART_FLAG_SET_RATE      0x00000001      // set to update baud rate
+#define UARTTIO_UART_FLAG_RESET         0x00000002      // set to reset the port
+struct uarttio_uart {
+       volatile u32_t                  flags;
+
+       volatile u32_t                  baud_rate;
+       volatile u32_t                  current_baud_rate;
+       u32_t                           bit_time;
+
+       /*
+        * Modem status register
+        */
+       volatile u32_t                  status;
+
+       /*
+        * Interrupt registers
+        */
+       volatile u32_t                  int_mask;
+       volatile u32_t                  int_flags;
+
+       /*
+        * Ports and pins
+        */
+       u32_t                           rx_port;
+       u32_t                           tx_port;
+
+       u8_t                            rx_pin;
+       u8_t                            tx_pin;
+
+       /*
+        * Configuration Data
+        */
+       u8_t                            rx_bits;
+       u8_t                            rx_stop_bits;
+       u8_t                            tx_bits;
+       u8_t                            tx_stop_bits;
+
+       /*
+        * RX state machine data
+        */
+       u32_t                           rx_timer;
+       u32_t                           rx_bit_pos;
+       u32_t                           rx_byte;
+       u32_t                           rx_fifo_head;
+       u32_t                           rx_fifo_tail;
+       u32_t                           rx_fifo_size;
+
+       /*
+        * TX state machine data
+        */
+       u32_t                           tx_timer;
+       u32_t                           tx_bit_pos;
+       u32_t                           tx_byte;
+       u32_t                           tx_fifo_head;
+       u32_t                           tx_fifo_tail;
+       u32_t                           tx_fifo_size;
+
+       /*
+        * FIFOs
+        */
+       u8_t                            rx_fifo[UARTTIO_RX_FIFO_SIZE];
+       u8_t                            tx_fifo[UARTTIO_TX_FIFO_SIZE];
+};
+
+#define UARTTIO_VP_VERSION             1
+struct uarttio_regs {
+       u32_t                           version;
+
+       u32_t                           thread;
+
+       u32_t                           max_uarts;
+
+       struct uarttio_uart             uarts[0];
+};
+
+#define UARTTIO_NODE_VERSION           1
+struct uarttio_node {
+       struct devtree_node             dn;
+
+       u32_t                           version;
+       struct uarttio_regs             *regs;
+       u32_t                           regs_sz;
+};
+
+#endif /* _ASM_UBICOM32_UART_TIO_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubi32-cs4384.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubi32-cs4384.h
new file mode 100644 (file)
index 0000000..18e7634
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * arch/ubicom32/include/asm/ubi32-cs4384.h
+ *   Ubicom32 architecture CS4384 driver platform data definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _ASM_UBICOM32_UBI32_CS4384_H
+#define _ASM_UBICOM32_UBI32_CS4384_H
+
+enum ubi32_cs4384_mclk_source {
+       UBI32_CS4384_MCLK_PWM_0,
+       UBI32_CS4384_MCLK_PWM_1,
+       UBI32_CS4384_MCLK_PWM_2,
+       UBI32_CS4384_MCLK_CLKDIV_1,
+       UBI32_CS4384_MCLK_OTHER,
+};
+
+struct ubi32_cs4384_mclk_entry {
+       /*
+        * Rate, in Hz, of this entry
+        */
+       int rate;
+
+       /*
+        * The divider to program to get the rate
+        */
+       int div;
+};
+
+struct ubi32_cs4384_platform_data {
+       enum ubi32_cs4384_mclk_source   mclk_src;
+
+       int                             n_mclk;
+       struct ubi32_cs4384_mclk_entry  *mclk_entries;
+};
+#endif /* _ASM_UBICOM32_UBI32_CS4384_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubi32-pcm.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubi32-pcm.h
new file mode 100644 (file)
index 0000000..ab14b36
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * arch/ubicom32/include/asm/ubi32-pcm.h
+ *   Ubicom32 architecture PCM driver platform data definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _ASM_UBICOM32_UBI32_PCM_H
+#define _ASM_UBICOM32_UBI32_PCM_H
+
+/*
+ * This function is called when the sample rate has changed
+ */
+typedef int (*ubi32_pcm_set_rate_fn_t)(void *appdata, int rate);
+
+struct ubi32pcm_platform_data {
+       /*
+        * Name of the audio node/inst
+        */
+       const char              *node_name;
+       const char              *inst_name;
+       int                     inst_num;
+
+       /*
+        * Application specific data provided when calling functions
+        */
+       void                    *appdata;
+
+       /*
+        * Functions called when various things happen
+        */
+       ubi32_pcm_set_rate_fn_t set_rate;
+
+       /*
+        * Pointer to optional upper layer data (i.e. DAC config, etc)
+        */
+       void                    *priv_data;
+};
+#endif /* _ASM_UBICOM32_UBI32_PCM_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-common-asm.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-common-asm.h
new file mode 100644 (file)
index 0000000..82696bb
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32-common-asm.h
+ *   Ubicom32 atomic lock operations.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_UBICOM32_COMMON_ASM_H
+#define _ASM_UBICOM32_UBICOM32_COMMON_ASM_H
+
+/*
+ * atomic_lock_acquire macro
+ *     Equivalent to __atomic_lock_acquire()
+ */
+.macro atomic_lock_acquire
+       bset scratchpad1, scratchpad1, #ATOMIC_LOCK_BIT
+       jmpne.f .-4
+.endm
+
+/*
+ * atomic_lock_release macro
+ *     Equivalent to __atomic_lock_release()
+ */
+.macro atomic_lock_release
+       bclr scratchpad1, scratchpad1, #ATOMIC_LOCK_BIT
+.endm
+
+#endif /* _ASM_UBICOM32_UBICOM32_COMMON_ASM_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-common.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-common.h
new file mode 100644 (file)
index 0000000..1f05a8c
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32-common.h
+ *   Ubicom32 atomic lock operations.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_UBICOM32_COMMON_H
+#define _ASM_UBICOM32_UBICOM32_COMMON_H
+
+#define S(arg) #arg
+#define D(arg) S(arg)
+/*
+ * scratchpad1 is owned by the LDSR.
+ *
+ * The upper bits provide 16 global spinlocks.  Acquiring one of these
+ * global spinlocks synchornizes across multiple threads and prevents
+ * the LDSR from delivering any interrupts while the lock is held.
+ * Use these locks only when absolutely required.
+ *
+ * The lower 16 bits of scratchpad1 are used as per thread interrupt
+ * enable/disable bits.  These bits will prevent a thread from receiving
+ * any interrupts.
+ *
+ * Bit Usage:
+ * - MT_EN_LOCK_BIT   - Protects writes to MT_EN, so code can read current value
+ *                     then write a new value atomically (profiler for example)
+ * - ATOMIC_LOCK_BIT - Used to provide general purpose atomic handling.
+ * - LDSR_LOCK_BIT   - Used by the LDSR exclusively to provide protection.
+ * - DCCR_LOCK_BIT   - Used to limit access to the DCCR cache control peripheral
+ * - ICCR_LOCK_BIT   - Used to limit access to the ICCR cache control peripheral
+ * - LSB 16 bits     - Used by the LDSR to represent thread enable/disable bits.
+ */
+#define MT_EN_LOCK_BIT 31
+#define ATOMIC_LOCK_BIT 30
+#define LDSR_LOCK_BIT   29
+#define PCI_LOCK_BIT   28
+#define ICCR_LOCK_BIT  27
+#define DCCR_LOCK_BIT  26
+
+#if !defined(__ASSEMBLY__)
+
+#define UBICOM32_TRYLOCK(bit) \
+       asm volatile (                                                \
+       "       move.4 %0, #0                                   \n\t" \
+       "       bset scratchpad1, scratchpad1, #"D(bit)"        \n\t" \
+       "       jmpne.f 1f                                      \n\t" \
+       "       move.4 %0, #1                                   \n\t" \
+       "1:                                                     \n\t" \
+               : "=r" (ret)                                          \
+               :                                                     \
+               : "cc", "memory"                                      \
+       )                                                             \
+
+#define UBICOM32_UNLOCK(bit) \
+       asm volatile (                                                \
+       "       bclr scratchpad1, scratchpad1, #"D(bit)"        \n\t" \
+               :                                                     \
+               :                                                     \
+               : "cc", "memory"                                      \
+       )                                                             \
+
+#define UBICOM32_LOCK(bit) \
+       asm volatile (                                                \
+       "1:     bset scratchpad1, scratchpad1, #"D(bit)"        \n\t" \
+       "       jmpne.f 1b                                      \n\t" \
+               :                                                     \
+               :                                                     \
+               : "cc", "memory"                                      \
+       )                                                             \
+
+/*
+ * __atomic_lock_trylock()
+ *     Attempt to acquire the lock, return TRUE if acquired.
+ */
+static inline int __atomic_lock_trylock(void)
+{
+       int ret;
+       UBICOM32_TRYLOCK(ATOMIC_LOCK_BIT);
+       return ret;
+}
+
+/*
+ * __atomic_lock_release()
+ *     Release the global atomic lock.
+ *
+ * Note: no one is suspended waiting since this lock is a spinning lock.
+ */
+static inline void __atomic_lock_release(void)
+{
+       UBICOM32_UNLOCK(ATOMIC_LOCK_BIT);
+}
+
+/*
+ * __atomic_lock_acquire()
+ *     Acquire the global atomic lock, spin if not available.
+ */
+static inline void __atomic_lock_acquire(void)
+{
+       UBICOM32_LOCK(ATOMIC_LOCK_BIT);
+}
+#else /* __ASSEMBLY__ */
+
+#include <asm/ubicom32-common-asm.h>
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_UBICOM32_UBICOM32_COMMON_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-spi-gpio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-spi-gpio.h
new file mode 100644 (file)
index 0000000..b5379e3
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32-spi-gpio.h
+ *   Platform driver data definitions for GPIO based SPI driver.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_UBICOM32_SPI_GPIO_H
+#define _ASM_UBICOM32_UBICOM32_SPI_GPIO_H
+
+struct ubicom32_spi_gpio_platform_data {
+       /*
+        * GPIO to use for MOSI, MISO, CLK
+        */
+       int     pin_mosi;
+       int     pin_miso;
+       int     pin_clk;
+
+       /*
+        * Default state of CLK line
+        */
+       int     clk_default;
+
+       /*
+        * Number of chip selects on this bus
+        */
+       int     num_chipselect;
+
+       /*
+        * The bus number of this chip
+        */
+       int     bus_num;
+};
+
+struct ubicom32_spi_gpio_controller_data {
+       /*
+        * GPIO to use for chip select
+        */
+       int     pin_cs;
+};
+
+#endif /* _ASM_UBICOM32_UBICOM32_SPI_GPIO_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-tio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32-tio.h
new file mode 100644 (file)
index 0000000..4d87e5c
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32-tio.h
+ *   Threaded I/O interface definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_UBICOM32_TIO_H
+#define _ASM_UBICOM32_UBICOM32_TIO_H
+
+extern u8_t usb_tio_read_u16(u32_t address, u16_t *data);
+extern u8_t usb_tio_read_u8(u32_t address, u8_t *data);
+
+extern u8_t usb_tio_write_u16(u32_t address, u16_t data);
+extern u8_t usb_tio_write_u8(u32_t address, u8_t data);
+
+extern u8_t usb_tio_read_fifo(u32_t address, u32_t buffer, u32_t bytes);
+extern u8_t usb_tio_write_fifo(u32_t address, u32_t buffer, u32_t bytes);
+extern u8_t usb_tio_write_fifo_sync(u32_t address, u32_t buffer, u32_t bytes);
+extern void usb_tio_read_int_status(u8_t *int_usb, u16_t *int_tx, u16_t *int_rx);
+
+#endif /* _ASM_UBICOM32_UBICOM32_TIO_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32bl.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32bl.h
new file mode 100644 (file)
index 0000000..498c754
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32bl.h
+ *   Ubicom32 architecture backlight driver platform data definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_UBICOM32_BL_H
+#define _ASM_UBICOM32_UBICOM32_BL_H
+
+/*
+ * Different backlight control mechanisms
+ */
+enum ubicom32bl_pwm_types {
+       /*
+        * PWM controlled backlight
+        */
+       UBICOM32BL_TYPE_PWM,
+
+       /*
+        * HRT based PWM backlight
+        */
+       UBICOM32BL_TYPE_PWM_HRT,
+
+       /*
+        * No dimming, just on or off
+        */
+       UBICOM32BL_TYPE_BINARY,
+};
+
+struct ubicom32bl_platform_data {
+       /*
+        * Default intensity of the backlight 0-255
+        */
+       u8_t                            default_intensity;
+
+       /*
+        * TRUE if the backlight sense is active low. (inverted)
+        * FALSE if the backlight sense is active high.
+        */
+       bool                            invert;
+
+       /*
+        * Type of the backlight
+        */
+       enum ubicom32bl_pwm_types       type;
+
+       /*
+        * GPIO of the backlight if UBICOM32BL_TYPE_PWM_HRT, UBICOM32BL_TYPE_BINARY
+        */
+       unsigned                        gpio;
+
+       /*
+        * PWM channel and parameters of the backlight if UBICOM32BL_TYPE_PWM
+        *      pre_scaler: sets the rate at which the PWM timer is clocked. (clk_core / 2^pre_scaler)
+        *      period: sets the period of the timer in timer cycles
+        * The duty cycle will be directly proportional to the brightness setting.
+        */
+       u32_t                           pwm_channel;
+       u8_t                            pwm_prescale;
+       u16_t                           pwm_period;
+};
+
+#endif /* _ASM_UBICOM32_UBICOM32_BL_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32fb.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32fb.h
new file mode 100644 (file)
index 0000000..ae994e2
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32fb.h
+ *   Ubicom32 architecture video frame buffer definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _ASM_UBICOM32_UBICOM32FB_H
+#define _ASM_UBICOM32_UBICOM32FB_H
+
+#include <linux/ioctl.h>
+
+/*
+ * Set next frame
+ */
+#define UBICOM32FB_IOCTL_SET_NEXT_FRAME                _IOW('r',  1, void *)
+#define UBICOM32FB_IOCTL_SET_NEXT_FRAME_SYNC   _IOW('r',  2, void *)
+
+/*
+ * Set Mode
+ */
+#define UBICOM32FB_IOCTL_SET_MODE              _IOW('r',  3, void *)
+struct ubicom32fb_mode {
+       unsigned long   width;
+       unsigned long   height;
+       unsigned long   flags;
+       void            *next_frame;
+};
+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_SCAN_ORDER  (1 << 8)
+
+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_BLOCK_ORDER (1 << 7)
+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV             (1 << 6)
+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_VSUB            (1 << 5)
+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_16_255   (1 << 4)
+
+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_0_255    (1 << 3)
+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_2_1                (1 << 2)
+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_1_1                (1 << 1)
+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_SCALE_ENABLE    (1 << 0)
+
+#endif /* _ASM_UBICOM32_UBICOM32FB_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32hid.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32hid.h
new file mode 100644 (file)
index 0000000..d324313
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32hid.h
+ *   Ubicom32 architecture HID driver platform data definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_UBICOM32_HID_H
+#define _ASM_UBICOM32_UBICOM32_HID_H
+
+enum ubicom32hid_bl_types {
+       /*
+        * On or off, using command SET_BL_EN, PB4
+        */
+       UBICOM32HID_BL_TYPE_BINARY,
+
+       /*
+        * Dimmable, using command SET_PWM, PB3
+        */
+       UBICOM32HID_BL_TYPE_PWM,
+};
+
+/*
+ * IR code mapping to event code.
+ *     If there are no button mappings and no ir mappings
+ *     then no input driver will be registered.
+ */
+struct ubicom32hid_ir {
+       /*
+        * Input event code (KEY_*, SW_*, etc)
+        */
+       int             code;
+
+       /*
+        * Input event type (EV_KEY, EV_SW, etc)
+        */
+       int             type;
+
+       /*
+        * The IR code of this button.
+        */
+       uint32_t        ir_code;
+};
+
+/*
+ * Button mapping to event code.
+ *     If there are no button mappings and no ir mappings
+ *     then no input driver will be registered.
+ */
+struct ubicom32hid_button {
+       /*
+        * Input event code (KEY_*, SW_*, etc)
+        */
+       int             code;
+
+       /*
+        * Input event type (EV_KEY, EV_SW, etc)
+        */
+       int             type;
+
+       /*
+        * Bit number of this button.
+        */
+       uint8_t         bit;
+};
+
+struct ubicom32hid_platform_data {
+       /*
+        * Default intensity of the backlight 0-255
+        */
+       u8_t                            default_intensity;
+
+       /*
+        * GPIO number of the reset line and its polarity.
+        */
+       unsigned                        gpio_reset;
+       int                             gpio_reset_polarity;
+
+       /*
+        * TRUE if the backlight sense is active low. (inverted)
+        * FALSE if the backlight sense is active high.
+        */
+       bool                            invert;
+
+       /*
+        * Type of the backlight we are controlling
+        */
+       enum ubicom32hid_bl_types       type;
+
+       /*
+        * Optional polling rate for input, in ms, defaults to 100ms
+        */
+       int                             poll_interval;
+
+       /*
+        * Optional name to register as input device
+        */
+       const char                      *input_name;
+
+       /*
+        * Button mapping array
+        */
+       const struct ubicom32hid_button *buttons;
+       int                             nbuttons;
+
+       /*
+        * IR mapping array
+        */
+       const struct ubicom32hid_ir     *ircodes;
+       int                             nircodes;
+};
+
+#endif /* _ASM_UBICOM32_UBICOM32_HID_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32input.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32input.h
new file mode 100644 (file)
index 0000000..dea5c79
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32input.h
+ *   Ubicom32 Input driver, based on gpio-keys
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *
+ * TODO: add groups for inputs which can be sampled together
+ */
+
+#ifndef _ASM_UBICOM32_UBICOM32_INPUT_H
+#define _ASM_UBICOM32_UBICOM32_INPUT_H
+
+struct ubicom32input_button {
+       /*
+        * Input event code (KEY_*, SW_*, etc)
+        */
+       int             code;
+
+       /*
+        * Input event type (EV_KEY, EV_SW, etc)
+        */
+       int             type;
+
+       /*
+        * GPIO to poll
+        */
+       int             gpio;
+
+       /*
+        * 1 for active low, 0 for active high
+        */
+       int             active_low;
+
+       /*
+        * Description, used for reserving GPIOs
+        */
+       const char      *desc;
+};
+
+struct ubicom32input_platform_data {
+       struct ubicom32input_button     *buttons;
+       int                             nbuttons;
+
+       /*
+        * Optional poll interval, in ms, defaults to 50ms
+        */
+       int                             poll_interval;
+
+       /*
+        * Option Name of this driver
+        */
+       const char                      *name;
+};
+
+#endif /* _ASM_UBICOM32_UBICOM32_INPUT_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32input_i2c.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32input_i2c.h
new file mode 100644 (file)
index 0000000..eb16723
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32input_i2c.h
+ *   Ubicom32 architecture Input driver over I2C platform data definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *
+ * TODO: add groups for inputs which can be sampled together
+ */
+
+#ifndef _ASM_UBICOM32_UBICOM32_INPUT_I2C_H
+#define _ASM_UBICOM32_UBICOM32_INPUT_I2C_H
+
+struct ubicom32input_i2c_button {
+       /*
+        * Input event code (KEY_*, SW_*, etc)
+        */
+       int             code;
+
+       /*
+        * Input event type (EV_KEY, EV_SW, etc)
+        */
+       int             type;
+
+       /*
+        * Bit number of this button. (0 - ngpio)
+        */
+       int             bit;
+
+       /*
+        * 1 for active low, 0 for active high
+        */
+       int             active_low;
+};
+
+struct ubicom32input_i2c_platform_data {
+       struct ubicom32input_i2c_button *buttons;
+       int                             nbuttons;
+
+       /*
+        * Optional poll interval, in ms, defaults to 100ms
+        */
+       int                             poll_interval;
+
+       /*
+        * Option Name of this driver
+        */
+       const char                      *name;
+};
+
+#endif /* _ASM_UBICOM32_UBICOM32_INPUT_I2C_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32lcd.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32lcd.h
new file mode 100644 (file)
index 0000000..eea5340
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32lcd.h
+ *   Ubicom32 architecture LCD driver platform data definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _ASM_UBICOM32_UBICOM32_LCD_H
+#define _ASM_UBICOM32_UBICOM32_LCD_H
+
+#include <asm/ip5000.h>
+
+struct ubicom32lcd_platform_data {
+       int                     pin_cs;
+       int                     pin_rs;
+       int                     pin_rd;
+       int                     pin_wr;
+       int                     pin_reset;
+       int                     data_shift;
+       struct ubicom32_io_port *port_data;
+};
+
+#endif /* _ASM_UBICOM32_UBICOM32_LCD_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32lcdpower.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32lcdpower.h
new file mode 100644 (file)
index 0000000..03b8a7e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32lcdpower.h
+ *   Ubicom32 architecture LCD driver platform data definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_UBICOM32_LCDPOWER_H
+#define _ASM_UBICOM32_UBICOM32_LCDPOWER_H
+
+struct ubicom32lcdpower_platform_data {
+       /*
+        * GPIO and polarity for VGH signal.  A FALSE polarity is active low, TRUE is active high.
+        */
+       int             vgh_gpio;
+       bool            vgh_polarity;
+};
+
+#endif /* _ASM_UBICOM32_UBICOM32_LCDPOWER_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32ring.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32ring.h
new file mode 100644 (file)
index 0000000..dd9c8f7
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32ring.h
+ * Userspace I/O platform driver for Ubicom32 ring buffers
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _ASM_UBICOM32_UBICOM32RING_H
+#define _ASM_UBICOM32_UBICOM32RING_H
+
+#define UIO_UBICOM32RING_REG_VERSION   2
+
+struct uio_ubicom32ring_desc {
+       volatile unsigned int           head;
+       volatile unsigned int           tail;
+       unsigned int                    entries;
+       volatile unsigned int           ring[0];
+};
+
+struct uio_ubicom32ring_regs {
+       unsigned int                    version;
+
+       /*
+        * Magic type used to identify the ring set.  Each driver will
+        * have a different magic value.
+        */
+       unsigned int                    magic;
+
+       /*
+        * Registers defined by the driver
+        */
+       unsigned int                    regs_size;
+       void                            *regs;
+
+       /*
+        * The locations of the rings
+        *
+        * DO NOT ADD ANYTHING BELOW THIS LINE
+        */
+       unsigned int                    num_rings;
+       struct uio_ubicom32ring_desc    *rings[0];
+};
+
+/*
+ * ringtio_ring_flush
+ */
+static inline void ringtio_ring_flush(struct uio_ubicom32ring_desc *rd)
+{
+       rd->head = rd->tail = 0;
+}
+
+/*
+ * ringtio_ring_get
+ */
+static inline int ringtio_ring_get(struct uio_ubicom32ring_desc *rd, void **val)
+{
+       if (rd->head == rd->tail) {
+               return 0;
+       }
+
+       *val = (void *)rd->ring[rd->head++];
+       if (rd->head == rd->entries) {
+               rd->head = 0;
+       }
+       return 1;
+}
+
+/*
+ * ringtio_ring_put
+ */
+static inline int ringtio_ring_put(struct uio_ubicom32ring_desc *rd, void *val)
+{
+       unsigned int newtail = rd->tail + 1;
+       if (newtail == rd->entries) {
+               newtail = 0;
+       }
+
+       if (newtail == rd->head) {
+               return 0;
+       }
+
+       rd->ring[rd->tail] = (unsigned int)val;
+       rd->tail = newtail;
+       return 1;
+}
+
+#endif /* _ASM_UBICOM32_UBICOM32RING_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32sd.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32sd.h
new file mode 100644 (file)
index 0000000..b5cebfa
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32sd.h
+ *   Ubicom32SD public include file
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _ASM_UBICOM32_UBICOM32_SD_H
+#define _ASM_UBICOM32_UBICOM32_SD_H
+
+struct ubicom32sd_card {
+       /*
+        * GPIOs of PWR, WP and CD lines.
+        * Polarity is 1 for active high and 0 for active low
+        */
+       int                             pin_pwr;
+       bool                            pwr_polarity;
+       int                             pin_wp;
+       bool                            wp_polarity;
+       int                             pin_cd;
+       bool                            cd_polarity;
+};
+
+struct ubicom32sd_platform_data {
+       int                     ncards;
+
+       struct ubicom32sd_card  *cards;
+};
+
+#endif /* _ASM_UBICOM32_UBICOM32_SD_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32suart.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ubicom32suart.h
new file mode 100644 (file)
index 0000000..824d0de
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * arch/ubicom32/include/asm/ubicom32suart.h
+ *   <TODO: Replace with short file description>
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_UBICOM32_SUART_H
+#define _ASM_UBICOM32_UBICOM32_SUART_H
+
+/*
+ * Platform resource id for serdes uart clock parameter
+ */
+#define UBICOM32_SUART_IORESOURCE_CLOCK                (1)
+
+#endif /* _ASM_UBICOM32_UBICOM32_SUART_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/ucontext.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/ucontext.h
new file mode 100644 (file)
index 0000000..71c1129
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * arch/ubicom32/include/asm/ucontext.h
+ *   Definition of ucontext structure for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_UCONTEXT_H
+#define _ASM_UBICOM32_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 /* _ASM_UBICOM32_UCONTEXT_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/unaligned.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/unaligned.h
new file mode 100644 (file)
index 0000000..41b2646
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * arch/ubicom32/include/asm/unaligned.h
+ *   Ubicom32 architecture unaligned memory access definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *
+ * TODO: This is a copy of arm unaligned handling that probably needs
+ * to be optimized for UBICOM32, but it works for now.
+ */
+
+#ifndef _ASM_UBICOM32_UNALIGNED_H
+#define _ASM_UBICOM32_UNALIGNED_H
+
+#include <asm/types.h>
+
+#include <linux/unaligned/le_byteshift.h>
+#include <linux/unaligned/be_byteshift.h>
+#include <linux/unaligned/generic.h>
+
+#define get_unaligned  __get_unaligned_be
+#define put_unaligned  __put_unaligned_be
+
+#endif /* _ASM_UBICOM32_UNALIGNED_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/unistd.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/unistd.h
new file mode 100644 (file)
index 0000000..2c7ba56
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * arch/ubicom32/include/asm/unistd.h
+ *   Ubicom32 architecture syscall definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_UNISTD_H
+#define _ASM_UBICOM32_UNISTD_H
+
+/*
+ * This file contains the system call numbers.
+ */
+
+#define __NR_restart_syscall      0
+#define __NR_exit                1
+#define __NR_fork                2
+#define __NR_read                3
+#define __NR_write               4
+#define __NR_open                5
+#define __NR_close               6
+#define __NR_waitpid             7
+#define __NR_creat               8
+#define __NR_link                9
+#define __NR_unlink             10
+#define __NR_execve             11
+#define __NR_chdir              12
+#define __NR_time               13
+#define __NR_mknod              14
+#define __NR_chmod              15
+#define __NR_chown              16
+#define __NR_break              17
+#define __NR_oldstat            18
+#define __NR_lseek              19
+#define __NR_getpid             20
+#define __NR_mount              21
+#define __NR_umount             22
+#define __NR_setuid             23
+#define __NR_getuid             24
+#define __NR_stime              25
+#define __NR_ptrace             26
+#define __NR_alarm              27
+#define __NR_oldfstat           28
+#define __NR_pause              29
+#define __NR_utime              30
+#define __NR_stty               31
+#define __NR_gtty               32
+#define __NR_access             33
+#define __NR_nice               34
+#define __NR_ftime              35
+#define __NR_sync               36
+#define __NR_kill               37
+#define __NR_rename             38
+#define __NR_mkdir              39
+#define __NR_rmdir              40
+#define __NR_dup                41
+#define __NR_pipe               42
+#define __NR_times              43
+#define __NR_prof               44
+#define __NR_brk                45
+#define __NR_setgid             46
+#define __NR_getgid             47
+#define __NR_signal             48
+#define __NR_geteuid            49
+#define __NR_getegid            50
+#define __NR_acct               51
+#define __NR_umount2            52
+#define __NR_lock               53
+#define __NR_ioctl              54
+#define __NR_fcntl              55
+#define __NR_mpx                56
+#define __NR_setpgid            57
+#define __NR_ulimit             58
+#define __NR_oldolduname        59
+#define __NR_umask              60
+#define __NR_chroot             61
+#define __NR_ustat              62
+#define __NR_dup2               63
+#define __NR_getppid            64
+#define __NR_getpgrp            65
+#define __NR_setsid             66
+#define __NR_sigaction          67
+#define __NR_sgetmask           68
+#define __NR_ssetmask           69
+#define __NR_setreuid           70
+#define __NR_setregid           71
+#define __NR_sigsuspend                 72
+#define __NR_sigpending                 73
+#define __NR_sethostname        74
+#define __NR_setrlimit          75
+#define __NR_getrlimit          76
+#define __NR_getrusage          77
+#define __NR_gettimeofday       78
+#define __NR_settimeofday       79
+#define __NR_getgroups          80
+#define __NR_setgroups          81
+#define __NR_select             82
+#define __NR_symlink            83
+#define __NR_oldlstat           84
+#define __NR_readlink           85
+#define __NR_uselib             86
+#define __NR_swapon             87
+#define __NR_reboot             88
+#define __NR_readdir            89
+#define __NR_mmap               90
+#define __NR_munmap             91
+#define __NR_truncate           92
+#define __NR_ftruncate          93
+#define __NR_fchmod             94
+#define __NR_fchown             95
+#define __NR_getpriority        96
+#define __NR_setpriority        97
+#define __NR_profil             98
+#define __NR_statfs             99
+#define __NR_fstatfs           100
+#define __NR_ioperm            101
+#define __NR_socketcall                102
+#define __NR_syslog            103
+#define __NR_setitimer         104
+#define __NR_getitimer         105
+#define __NR_stat              106
+#define __NR_lstat             107
+#define __NR_fstat             108
+#define __NR_olduname          109
+#define __NR_iopl              /* 110 */ not supported
+#define __NR_vhangup           111
+#define __NR_idle              /* 112 */ Obsolete
+#define __NR_vm86              /* 113 */ not supported
+#define __NR_wait4             114
+#define __NR_swapoff           115
+#define __NR_sysinfo           116
+#define __NR_ipc               117
+#define __NR_fsync             118
+#define __NR_sigreturn         119
+#define __NR_clone             120
+#define __NR_setdomainname     121
+#define __NR_uname             122
+#define __NR_cacheflush                123
+#define __NR_adjtimex          124
+#define __NR_mprotect          125
+#define __NR_sigprocmask       126
+#define __NR_create_module     127
+#define __NR_init_module       128
+#define __NR_delete_module     129
+#define __NR_get_kernel_syms   130
+#define __NR_quotactl          131
+#define __NR_getpgid           132
+#define __NR_fchdir            133
+#define __NR_bdflush           134
+#define __NR_sysfs             135
+#define __NR_personality       136
+#define __NR_afs_syscall       137 /* Syscall for Andrew File System */
+#define __NR_setfsuid          138
+#define __NR_setfsgid          139
+#define __NR__llseek           140
+#define __NR_getdents          141
+#define __NR__newselect                142
+#define __NR_flock             143
+#define __NR_msync             144
+#define __NR_readv             145
+#define __NR_writev            146
+#define __NR_getsid            147
+#define __NR_fdatasync         148
+#define __NR__sysctl           149
+#define __NR_mlock             150
+#define __NR_munlock           151
+#define __NR_mlockall          152
+#define __NR_munlockall                153
+#define __NR_sched_setparam            154
+#define __NR_sched_getparam            155
+#define __NR_sched_setscheduler                156
+#define __NR_sched_getscheduler                157
+#define __NR_sched_yield               158
+#define __NR_sched_get_priority_max    159
+#define __NR_sched_get_priority_min    160
+#define __NR_sched_rr_get_interval     161
+#define __NR_nanosleep         162
+#define __NR_mremap            163
+#define __NR_setresuid         164
+#define __NR_getresuid         165
+#define __NR_getpagesize       166
+#define __NR_query_module      167
+#define __NR_poll              168
+#define __NR_nfsservctl                169
+#define __NR_setresgid         170
+#define __NR_getresgid         171
+#define __NR_prctl             172
+#define __NR_rt_sigreturn      173
+#define __NR_rt_sigaction      174
+#define __NR_rt_sigprocmask    175
+#define __NR_rt_sigpending     176
+#define __NR_rt_sigtimedwait   177
+#define __NR_rt_sigqueueinfo   178
+#define __NR_rt_sigsuspend     179
+#define __NR_pread64           180
+#define __NR_pwrite64          181
+#define __NR_lchown            182
+#define __NR_getcwd            183
+#define __NR_capget            184
+#define __NR_capset            185
+#define __NR_sigaltstack       186
+#define __NR_sendfile          187
+#define __NR_getpmsg           188     /* some people actually want streams */
+#define __NR_putpmsg           189     /* some people actually want streams */
+#define __NR_vfork             190
+#define __NR_ugetrlimit                191
+#define __NR_mmap2             192
+#define __NR_truncate64                193
+#define __NR_ftruncate64       194
+#define __NR_stat64            195
+#define __NR_lstat64           196
+#define __NR_fstat64           197
+#define __NR_chown32           198
+#define __NR_getuid32          199
+#define __NR_getgid32          200
+#define __NR_geteuid32         201
+#define __NR_getegid32         202
+#define __NR_setreuid32                203
+#define __NR_setregid32                204
+#define __NR_getgroups32       205
+#define __NR_setgroups32       206
+#define __NR_fchown32          207
+#define __NR_setresuid32       208
+#define __NR_getresuid32       209
+#define __NR_setresgid32       210
+#define __NR_getresgid32       211
+#define __NR_lchown32          212
+#define __NR_setuid32          213
+#define __NR_setgid32          214
+#define __NR_setfsuid32                215
+#define __NR_setfsgid32                216
+#define __NR_pivot_root                217
+#define __NR_getdents64                220
+#define __NR_gettid            221
+#define __NR_tkill             222
+#define __NR_setxattr          223
+#define __NR_lsetxattr         224
+#define __NR_fsetxattr         225
+#define __NR_getxattr          226
+#define __NR_lgetxattr         227
+#define __NR_fgetxattr         228
+#define __NR_listxattr         229
+#define __NR_llistxattr                230
+#define __NR_flistxattr                231
+#define __NR_removexattr       232
+#define __NR_lremovexattr      233
+#define __NR_fremovexattr      234
+#define __NR_futex             235
+#define __NR_sendfile64                236
+#define __NR_mincore           237
+#define __NR_madvise           238
+#define __NR_fcntl64           239
+#define __NR_readahead         240
+#define __NR_io_setup          241
+#define __NR_io_destroy                242
+#define __NR_io_getevents      243
+#define __NR_io_submit         244
+#define __NR_io_cancel         245
+#define __NR_fadvise64         246
+#define __NR_exit_group                247
+#define __NR_lookup_dcookie    248
+#define __NR_epoll_create      249
+#define __NR_epoll_ctl         250
+#define __NR_epoll_wait                251
+#define __NR_remap_file_pages  252
+#define __NR_set_tid_address   253
+#define __NR_timer_create      254
+#define __NR_timer_settime     255
+#define __NR_timer_gettime     256
+#define __NR_timer_getoverrun  257
+#define __NR_timer_delete      258
+#define __NR_clock_settime     259
+#define __NR_clock_gettime     260
+#define __NR_clock_getres      261
+#define __NR_clock_nanosleep   262
+#define __NR_statfs64          263
+#define __NR_fstatfs64         264
+#define __NR_tgkill            265
+#define __NR_utimes            266
+#define __NR_fadvise64_64      267
+#define __NR_mbind             268
+#define __NR_get_mempolicy     269
+#define __NR_set_mempolicy     270
+#define __NR_mq_open           271
+#define __NR_mq_unlink         272
+#define __NR_mq_timedsend      273
+#define __NR_mq_timedreceive   274
+#define __NR_mq_notify         275
+#define __NR_mq_getsetattr     276
+#define __NR_waitid            277
+#define __NR_vserver           278
+#define __NR_add_key           279
+#define __NR_request_key       280
+#define __NR_keyctl            281
+#define __NR_ioprio_set                282
+#define __NR_ioprio_get                283
+#define __NR_inotify_init      284
+#define __NR_inotify_add_watch 285
+#define __NR_inotify_rm_watch  286
+#define __NR_migrate_pages     287
+#define __NR_openat            288
+#define __NR_mkdirat           289
+#define __NR_mknodat           290
+#define __NR_fchownat          291
+#define __NR_futimesat         292
+#define __NR_fstatat64         293
+#define __NR_unlinkat          294
+#define __NR_renameat          295
+#define __NR_linkat            296
+#define __NR_symlinkat         297
+#define __NR_readlinkat                298
+#define __NR_fchmodat          299
+#define __NR_faccessat         300
+#define __NR_pselect6          301
+#define __NR_ppoll             302
+#define __NR_unshare           303
+#define __NR_set_robust_list   304
+#define __NR_get_robust_list   305
+#define __NR_splice            306
+#define __NR_sync_file_range   307
+#define __NR_tee               308
+#define __NR_vmsplice          309
+#define __NR_move_pages                310
+#define __NR_sched_setaffinity 311
+#define __NR_sched_getaffinity 312
+#define __NR_kexec_load                313
+#define __NR_getcpu            314
+#define __NR_epoll_pwait       315
+#define __NR_utimensat         316
+#define __NR_signalfd          317
+#define __NR_timerfd_create    318
+#define __NR_eventfd           319
+#define __NR_fallocate         320
+#define __NR_timerfd_settime   321
+#define __NR_timerfd_gettime   322
+#define __NR_signalfd4         323
+#define __NR_eventfd2          324
+#define __NR_epoll_create1     325
+#define __NR_dup3              326
+#define __NR_pipe2             327
+#define __NR_inotify_init1     328
+
+#ifdef __KERNEL__
+
+#define NR_syscalls            329
+
+#define __ARCH_WANT_IPC_PARSE_VERSION
+#define __ARCH_WANT_OLD_READDIR
+#define __ARCH_WANT_OLD_STAT
+#define __ARCH_WANT_STAT64
+#define __ARCH_WANT_SYS_ALARM
+#define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_PAUSE
+#define __ARCH_WANT_SYS_SGETMASK
+#define __ARCH_WANT_SYS_SIGNAL
+#define __ARCH_WANT_SYS_TIME
+#define __ARCH_WANT_SYS_UTIME
+#define __ARCH_WANT_SYS_WAITPID
+#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_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")
+#define cond_syscall(x) long x(void)  __attribute__((weak,alias("sys_ni_syscall")))
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_UBICOM32_UNISTD_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/user.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/user.h
new file mode 100644 (file)
index 0000000..2e79786
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * arch/ubicom32/include/asm/user.h
+ *   Ubicom32 architecture core file definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_USER_H
+#define _ASM_UBICOM32_USER_H
+
+#include <asm/ptrace.h>
+#include <asm/page.h>
+/*
+ * Adapted from <asm-powerpc/user.h>
+ *
+ * Core file format: The core file is written in such a way that gdb
+ * can understand it and provide useful information to the user (under
+ * linux we use the `trad-core' bfd, NOT the osf-core).  The 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 handy at some point.  All of the registers
+ *     are stored as part of the upage.  The upage should always be
+ *     only one page long.
+ *  data: The data segment follows next.  We use current->end_text to
+ *     current->brk to pick up all of the user variables, plus any memory
+ *     that may have been sbrk'ed.  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 usp to
+ *     current->start_stack, so we round each of these in order to be able
+ *     to write an integer number of pages.
+ */
+
+struct user_ubicom32fp_struct {
+};
+
+struct user {
+       struct pt_regs  regs;                   /* entire machine state */
+       size_t          u_tsize;                /* text size (pages) */
+       size_t          u_dsize;                /* data size (pages) */
+       size_t          u_ssize;                /* stack size (pages) */
+       unsigned long   start_code;             /* text starting address */
+       unsigned long   start_data;             /* data starting address */
+       unsigned long   start_stack;            /* stack starting address */
+       long int        signal;                 /* signal causing core dump */
+       unsigned long   u_ar0;                  /* help gdb find registers */
+       unsigned long   magic;                  /* identifies a core file */
+       char            u_comm[32];             /* user command name */
+};
+
+#define NBPG                   PAGE_SIZE
+#define UPAGES                 1
+#define HOST_TEXT_START_ADDR   (u.start_code)
+#define HOST_DATA_START_ADDR   (u.start_data)
+#define HOST_STACK_END_ADDR    (u.start_stack + u.u_ssize * NBPG)
+
+#endif /* _ASM_UBICOM32_USER_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/vdc_tio.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/vdc_tio.h
new file mode 100644 (file)
index 0000000..cc45fc5
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * arch/ubicom32/include/asm/vdc_tio.h
+ *   Ubicom32 architecture VDC TIO definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_VDC_TIO_H
+#define _ASM_UBICOM32_VDC_TIO_H
+
+#include <asm/devtree.h>
+
+#define VDCTIO_VP_VERSION                      5
+
+#define VDCTIO_SCALE_FLAG_VSUB                 (1 << 9)
+#define VDCTIO_SCALE_FLAG_YUV_SCAN_ORDER       (1 << 8)
+#define VDCTIO_SCALE_FLAG_YUV_BLOCK_ORDER      (1 << 7)
+#define VDCTIO_SCALE_FLAG_YUV                  (1 << 6)
+#define VDCTIO_SCALE_FLAG_VRANGE_16_255                (1 << 5)
+#define VDCTIO_SCALE_FLAG_VRANGE_0_255         (1 << 4)
+#define VDCTIO_SCALE_FLAG_HSUB_2_1             (1 << 3)
+#define VDCTIO_SCALE_FLAG_HSUB_1_1             (1 << 2)
+#define VDCTIO_SCALE_FLAG_SET_FRAME_BUFFER     (1 << 1)
+#define VDCTIO_SCALE_FLAG_ENABLE               (1 << 0)
+
+#define VDCTIO_NEXT_FRAME_FLAG_YUV_BIT         0
+#define VDCTIO_NEXT_FRAME_FLAG_YUV             (1 << (VDCTIO_NEXT_FRAME_FLAG_YUV_BIT))
+
+#define VDCTIO_CAPS_SUPPORTS_SCALING           (1 << 0)
+
+#define VDCTIO_COMMAND_START                   (1 << 3)
+#define VDCTIO_COMMAND_SET_COEFF               (1 << 2)
+#define VDCTIO_COMMAND_SET_LUT                 (1 << 1)
+#define VDCTIO_COMMAND_SET_SCALE_MODE          (1 << 0)
+
+/*
+ * Command / Data registers to access the VDC
+ */
+struct vdc_tio_vp_regs {
+       /*
+        * Version of this TIO register map
+        */
+       u32_t           version;
+
+       volatile u32_t  command;
+
+       /*
+        * Next frame pointer, when the command VDCTIO_COMMAND_SET_FRAME_BUFFER is set,
+        * the vdc will take the pointer here and display it.
+        */
+       void            *next_frame;
+       u32_t           next_frame_flags;
+
+       /*
+        * These map directly into the PIXP registers 0x20-0x80.
+        * DO NOT change the order of these three variables.
+        */
+       u32_t           red_lut[6];
+       u32_t           blue_lut[6];
+       u32_t           green_lut[13];
+
+       /*
+        * These map directly into the PIXP registers 0x04, 0x08
+        */
+       u32_t           coeff0;
+       u32_t           coeff1;
+
+       /*
+        * There are used to set the scaling parameters
+        */
+       u32_t           x_in;
+       u32_t           x_out;
+       u32_t           y_in;
+       u32_t           y_out;
+       u32_t           scale_flags;
+
+       /*
+        * Current frame number, monotonically increasing number
+        */
+       u32_t           frame_number;
+
+       /*
+        * These variables tell the guest OS what the underlying hardware looks like
+        */
+       u32_t           caps;
+       u32_t           xres;
+       u32_t           yres;
+       u32_t           fb_align;
+       u8_t            bpp;
+       u8_t            rbits;
+       u8_t            gbits;
+       u8_t            bbits;
+       u8_t            rshift;
+       u8_t            gshift;
+       u8_t            bshift;
+};
+
+/*
+ * Devtree node for VDC
+ */
+struct vdc_tio_node {
+       struct devtree_node     dn;
+
+       struct vdc_tio_vp_regs  *regs;
+};
+
+extern void vdc_tio_init(void);
+
+#endif /* _ASM_UBICOM32_VDC_TIO_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/vga.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/vga.h
new file mode 100644 (file)
index 0000000..793435f
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * arch/ubicom32/include/asm/vga.h
+ *   Ubicom32 low level  VGA/frame buffer definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * (c) 1998 Martin Mares <mj@ucw.cz>
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#ifndef _ASM_UBICOM32_VGA_H
+#define _ASM_UBICOM32_VGA_H
+
+#include <asm/byteorder.h>
+
+/*
+ *     On the PC, we can just recalculate addresses and then
+ *     access the videoram directly without any black magic.
+ */
+
+#define VGA_MAP_MEM(x, s)      (0xb0000000L + (unsigned long)(x))
+
+#define vga_readb(x)   (*(x))
+#define vga_writeb(x, y)       (*(y) = (x))
+
+#define VT_BUF_HAVE_RW
+/*
+ *  These are only needed for supporting VGA or MDA text mode, which use little
+ *  endian byte ordering.
+ *  In other cases, we can optimize by using native byte ordering and
+ *  <linux/vt_buffer.h> has already done the right job for us.
+ */
+
+#undef scr_writew
+#undef scr_readw
+
+static inline void scr_writew(u16 val, volatile u16 *addr)
+{
+       *addr = cpu_to_le16(val);
+}
+
+static inline u16 scr_readw(volatile const u16 *addr)
+{
+       return le16_to_cpu(*addr);
+}
+
+#define scr_memcpyw(d, s, c) memcpy(d, s, c)
+#define scr_memmovew(d, s, c) memmove(d, s, c)
+#define VT_BUF_HAVE_MEMCPYW
+#define VT_BUF_HAVE_MEMMOVEW
+
+#endif /* _ASM_UBICOM32_VGA_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/include/asm/xor.h b/target/linux/ubicom32/files/arch/ubicom32/include/asm/xor.h
new file mode 100644 (file)
index 0000000..31edcce
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * arch/ubicom32/include/asm/xor.h
+ *   Generic xor.h definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _ASM_UBICOM32_XOR_H
+#define _ASM_UBICOM32_XOR_H
+
+#include <asm-generic/xor.h>
+
+#endif /* _ASM_UBICOM32_XOR_H */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/Makefile b/target/linux/ubicom32/files/arch/ubicom32/kernel/Makefile
new file mode 100644 (file)
index 0000000..6294fa2
--- /dev/null
@@ -0,0 +1,64 @@
+#
+# arch/ubicom32/kernel/Makefile
+#      Main Makefile for the Ubicom32 arch directory.
+#
+# (C) Copyright 2009, Ubicom, Inc.
+#
+# This file is part of the Ubicom32 Linux Kernel Port.
+#
+# The Ubicom32 Linux Kernel Port 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.
+#
+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+# see <http://www.gnu.org/licenses/>.
+#
+# Ubicom32 implementation derived from (with many thanks):
+#   arch/m68knommu
+#   arch/blackfin
+#   arch/parisc
+#
+
+extra-y := head.o vmlinux.lds
+
+obj-y += \
+       devtree.o \
+       dma.o \
+       flat.o \
+       init_task.o \
+       irq.o \
+       ldsr.o \
+       os_node.o \
+       process.o \
+       processor.o \
+       ptrace.o \
+       setup.o \
+       signal.o \
+       stacktrace.o \
+       sys_ubicom32.o \
+       syscalltable.o \
+       thread.o \
+       time.o \
+       traps.o \
+       ubicom32_context_switch.o \
+       ubicom32_ksyms.o \
+       ubicom32_syscall.o \
+       unaligned_trap.o
+
+obj-$(CONFIG_MODULES)                          += module.o
+obj-$(CONFIG_COMEMPCI)                         += comempci.o
+obj-$(CONFIG_SMP)                              += smp.o topology.o
+obj-$(CONFIG_ACCESS_OK_CHECKS_ENABLED)         += uaccess.o
+obj-$(CONFIG_GENERIC_CLOCKEVENTS)              += timer_device.o
+obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)    += timer_broadcast.o
+
+ifndef CONFIG_GENERIC_CLOCKEVENTS
+obj-y                  += timer_tick.o
+endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/asm-offsets.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/asm-offsets.c
new file mode 100644 (file)
index 0000000..639a536
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * arch/ubicom32/kernel/asm-offsets.c
+ *   Ubicom32 architecture definitions needed by assembly language modules.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/ptrace.h>
+#include <linux/hardirq.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/thread_info.h>
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+       /* offsets into the task struct */
+       DEFINE(TASK_STATE, offsetof(struct task_struct, state));
+       DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+       DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
+       DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
+       DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+       DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
+       DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+       DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
+
+       /* offsets into the kernel_stat struct */
+//     DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
+
+       /* offsets into the irq_cpustat_t struct */
+       DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
+
+       /* offsets into the thread struct */
+       DEFINE(THREAD_D10, offsetof(struct thread_struct, d10));
+       DEFINE(THREAD_D11, offsetof(struct thread_struct, d11));
+       DEFINE(THREAD_D12, offsetof(struct thread_struct, d12));
+       DEFINE(THREAD_D13, offsetof(struct thread_struct, d13));
+       DEFINE(THREAD_A1, offsetof(struct thread_struct, a1));
+       DEFINE(THREAD_A2, offsetof(struct thread_struct, a2));
+       DEFINE(THREAD_A5, offsetof(struct thread_struct, a5));
+       DEFINE(THREAD_A6, offsetof(struct thread_struct, a6));
+       DEFINE(THREAD_SP, offsetof(struct thread_struct, sp));
+
+       /* offsets into the pt_regs */
+       DEFINE(PT_D0, offsetof(struct pt_regs, dn[0]));
+       DEFINE(PT_D1, offsetof(struct pt_regs, dn[1]));
+       DEFINE(PT_D2, offsetof(struct pt_regs, dn[2]));
+       DEFINE(PT_D3, offsetof(struct pt_regs, dn[3]));
+       DEFINE(PT_D4, offsetof(struct pt_regs, dn[4]));
+       DEFINE(PT_D5, offsetof(struct pt_regs, dn[5]));
+       DEFINE(PT_D6, offsetof(struct pt_regs, dn[6]));
+       DEFINE(PT_D7, offsetof(struct pt_regs, dn[7]));
+       DEFINE(PT_D8, offsetof(struct pt_regs, dn[8]));
+       DEFINE(PT_D9, offsetof(struct pt_regs, dn[9]));
+       DEFINE(PT_D10, offsetof(struct pt_regs, dn[10]));
+       DEFINE(PT_D11, offsetof(struct pt_regs, dn[11]));
+       DEFINE(PT_D12, offsetof(struct pt_regs, dn[12]));
+       DEFINE(PT_D13, offsetof(struct pt_regs, dn[13]));
+       DEFINE(PT_D14, offsetof(struct pt_regs, dn[14]));
+       DEFINE(PT_D15, offsetof(struct pt_regs, dn[15]));
+       DEFINE(PT_A0, offsetof(struct pt_regs, an[0]));
+       DEFINE(PT_A1, offsetof(struct pt_regs, an[1]));
+       DEFINE(PT_A2, offsetof(struct pt_regs, an[2]));
+       DEFINE(PT_A3, offsetof(struct pt_regs, an[3]));
+       DEFINE(PT_A4, offsetof(struct pt_regs, an[4]));
+       DEFINE(PT_A5, offsetof(struct pt_regs, an[5]));
+       DEFINE(PT_A6, offsetof(struct pt_regs, an[6]));
+       DEFINE(PT_A7, offsetof(struct pt_regs, an[7]));
+       DEFINE(PT_SP, offsetof(struct pt_regs, an[7]));
+
+       DEFINE(PT_ACC0HI, offsetof(struct pt_regs, acc0[0]));
+       DEFINE(PT_ACC0LO, offsetof(struct pt_regs, acc0[1]));
+       DEFINE(PT_MAC_RC16, offsetof(struct pt_regs, mac_rc16));
+
+       DEFINE(PT_ACC1HI, offsetof(struct pt_regs, acc1[0]));
+       DEFINE(PT_ACC1LO, offsetof(struct pt_regs, acc1[1]));
+
+       DEFINE(PT_SOURCE3, offsetof(struct pt_regs, source3));
+       DEFINE(PT_INST_CNT, offsetof(struct pt_regs, inst_cnt));
+       DEFINE(PT_CSR, offsetof(struct pt_regs, csr));
+       DEFINE(PT_DUMMY_UNUSED, offsetof(struct pt_regs, dummy_unused));
+
+       DEFINE(PT_INT_MASK0, offsetof(struct pt_regs, int_mask0));
+       DEFINE(PT_INT_MASK1, offsetof(struct pt_regs, int_mask1));
+
+       DEFINE(PT_PC, offsetof(struct pt_regs, pc));
+
+       DEFINE(PT_TRAP_CAUSE, offsetof(struct pt_regs, trap_cause));
+
+       DEFINE(PT_SIZE, sizeof(struct pt_regs));
+
+       DEFINE(PT_FRAME_TYPE, offsetof(struct pt_regs, frame_type));
+
+       DEFINE(PT_ORIGINAL_D0, offsetof(struct pt_regs, original_dn_0));
+       DEFINE(PT_PREVIOUS_PC, offsetof(struct pt_regs, previous_pc));
+
+       /* offsets into the kernel_stat struct */
+//     DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
+
+       /* signal defines */
+       DEFINE(SIGSEGV, SIGSEGV);
+       //DEFINE(SEGV_MAPERR, SEGV_MAPERR);
+       DEFINE(SIGTRAP, SIGTRAP);
+       //DEFINE(TRAP_TRACE, TRAP_TRACE);
+
+       DEFINE(PT_PTRACED, PT_PTRACED);
+       DEFINE(PT_DTRACE, PT_DTRACE);
+
+       DEFINE(ASM_THREAD_SIZE, THREAD_SIZE);
+
+       /* Offsets in thread_info structure */
+       DEFINE(TI_TASK, offsetof(struct thread_info, task));
+       DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
+       DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
+       DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
+       DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
+       DEFINE(TI_INTR_NESTING, offsetof(struct thread_info, interrupt_nesting));
+       DEFINE(ASM_TIF_NEED_RESCHED, TIF_NEED_RESCHED);
+       DEFINE(ASM_TIF_SYSCALL_TRACE, TIF_SYSCALL_TRACE);
+       DEFINE(ASM_TIF_SIGPENDING, TIF_SIGPENDING);
+
+       return 0;
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/devtree.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/devtree.c
new file mode 100644 (file)
index 0000000..1f824d2
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * arch/ubicom32/kernel/devtree.c
+ *   Ubicom32 architecture device tree implementation.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <asm/devtree.h>
+
+/*
+ * The device tree.
+ */
+struct devtree_node *devtree;
+
+/*
+ * devtree_print()
+ *     Print the device tree.
+ */
+void devtree_print(void)
+{
+       struct devtree_node *p = devtree;
+       printk(KERN_INFO "Device Tree:\n");
+       while (p) {
+               if (p->magic != DEVTREE_NODE_MAGIC) {
+                       printk(KERN_EMERG
+                              "device tree has improper node: %p\n", p);
+                       return;
+               }
+               printk(KERN_INFO "\t%p: sendirq=%03d, recvirq=%03d, "
+                      " name=%s\n", p, p->sendirq, p->recvirq, p->name);
+               p = p->next;
+       }
+}
+EXPORT_SYMBOL(devtree_print);
+
+/*
+ * devtree_irq()
+ *     Return the IRQ(s) associated with devtree node.
+ */
+int devtree_irq(struct devtree_node *dn,
+               unsigned char *sendirq,
+               unsigned char *recvirq)
+{
+       if (dn->magic != DEVTREE_NODE_MAGIC) {
+               printk(KERN_EMERG "improper node: %p\n", dn);
+               if (sendirq) {
+                       *sendirq = DEVTREE_IRQ_NONE;
+               }
+               if (recvirq) {
+                       *recvirq = DEVTREE_IRQ_NONE;
+               }
+               return -EFAULT;
+       }
+
+       /*
+        * Copy the devtree irq(s) to the output parameters.
+        */
+       if (sendirq) {
+               *sendirq = dn->sendirq;
+       }
+       if (recvirq) {
+               *recvirq = dn->recvirq;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(devtree_irq);
+
+/*
+ * devtree_find_next()
+ *     Provide an iterator for walking the device tree.
+ */
+struct devtree_node *devtree_find_next(struct devtree_node **cur)
+{
+       struct devtree_node *p = *cur;
+       if (!p) {
+               *cur = devtree;
+               return devtree;
+       }
+       p = p->next;
+       *cur = p;
+       return p;
+}
+
+/*
+ * devtree_find_by_irq()
+ *     Return the node associated with a given irq.
+ */
+struct devtree_node *devtree_find_by_irq(uint8_t sendirq, uint8_t recvirq)
+{
+       struct devtree_node *p = devtree;
+
+       if (sendirq == recvirq) {
+               printk(KERN_EMERG "identical request makes no sense sendirq = "
+                      "%d, recvirq= %d\n", sendirq, recvirq);
+               return NULL;
+       }
+
+       while (p) {
+               if (p->magic != DEVTREE_NODE_MAGIC) {
+                       printk(KERN_EMERG
+                              "device tree has improper node: %p\n", p);
+                       return NULL;
+               }
+
+               /*
+                * See if we can find a match on the IRQ(s) specified.
+                */
+               if ((sendirq == p->sendirq) && (recvirq == p->recvirq)) {
+                       return p;
+               }
+
+               if ((sendirq == DEVTREE_IRQ_DONTCARE) &&
+                   (p->recvirq == recvirq)) {
+                       return p;
+               }
+
+               if ((recvirq == DEVTREE_IRQ_DONTCARE) &&
+                   (p->sendirq == sendirq)) {
+                       return p;
+               }
+
+               p = p->next;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(devtree_find_by_irq);
+
+/*
+ * devtree_find_node()
+ *     Find a node in the device tree by name.
+ */
+struct devtree_node *devtree_find_node(const char *str)
+{
+       struct devtree_node *p = devtree;
+       while (p) {
+               if (p->magic != DEVTREE_NODE_MAGIC) {
+                       printk(KERN_EMERG
+                              "device tree has improper node: %p\n", p);
+                       return NULL;
+               }
+               if (strcmp(p->name, str) == 0) {
+                       return p;
+               }
+               p = p->next;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(devtree_find_node);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/dma.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/dma.c
new file mode 100644 (file)
index 0000000..f618105
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * arch/ubicom32/kernel/dma.c
+ *   Ubicom32 architecture dynamic DMA mapping support.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *
+ * We never have any address translations to worry about, so this
+ * is just alloc/free.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/io.h>
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+                          dma_addr_t *dma_handle, int gfp)
+{
+       void *ret;
+       /* ignore region specifiers */
+       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
+
+       if (dev == NULL || (*dev->dma_mask < 0xffffffff))
+               gfp |= GFP_DMA;
+       ret = (void *)__get_free_pages(gfp, get_order(size));
+
+       if (ret != NULL) {
+               memset(ret, 0, size);
+               *dma_handle = virt_to_phys(ret);
+       }
+       return ret;
+}
+
+void dma_free_coherent(struct device *dev, size_t size,
+                        void *vaddr, dma_addr_t dma_handle)
+{
+       free_pages((unsigned long)vaddr, get_order(size));
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/flat.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/flat.c
new file mode 100644 (file)
index 0000000..e8eb459
--- /dev/null
@@ -0,0 +1,206 @@
+/*
+ * arch/ubicom32/kernel/flat.c
+ *   Ubicom32 architecture flat executable format support.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/flat.h>
+
+unsigned long ubicom32_flat_get_addr_from_rp(unsigned long *rp,
+                                            u32_t relval,
+                                            u32_t flags,
+                                            unsigned long *persistent)
+{
+       u32_t relval_reloc_type = relval >> 27;
+       u32_t insn = *rp;
+
+       if (*persistent) {
+               /*
+                * relval holds the relocation that has to be adjusted.
+                */
+               if (relval == 0) {
+                       *persistent = 0;
+               }
+
+               return relval;
+       }
+
+       if (relval_reloc_type == R_UBICOM32_32) {
+               /*
+                * insn holds the relocation
+                */
+               return insn;
+       }
+
+       /*
+        * We don't know this one.
+        */
+       return 0;
+}
+
+void ubicom32_flat_put_addr_at_rp(unsigned long *rp,
+                                 u32_t val,
+                                 u32_t relval,
+                                 unsigned long *persistent)
+{
+       u32_t reloc_type = (relval >> 27) & 0x1f;
+       u32_t insn = *rp;
+
+       /*
+        * If persistent is set then it contains the relocation type.
+        */
+       if (*persistent) {
+               /*
+                * If persistent is set then it contains the relocation type.
+                */
+               reloc_type = (*persistent >> 27) & 0x1f;
+       }
+
+       switch (reloc_type) {
+       case R_UBICOM32_32:
+               /*
+                * Store the 32 bits as is.
+                */
+               *rp = val;
+               break;
+       case R_UBICOM32_HI24:
+               {
+                       /*
+                        * 24 bit relocation that is part of the MOVEAI
+                        * instruction. The 24 bits come from bits 7 - 30 of the
+                        * relocation. The 24 bits eventually get split into 2
+                        * fields in the instruction encoding.
+                        *
+                        * - Bits 7 - 27 of the relocation are encoded into bits
+                        * 0 - 20 of the instruction.
+                        *
+                        * - Bits 28 - 30 of the relocation are encoded into bit
+                        * 24 - 26 of the instruction.
+                        */
+                       u32_t mask = 0x1fffff | (0x7 << 24);
+                       u32_t valid24bits = (val >> 7) & 0xffffff;
+                       u32_t bot_21 = valid24bits & 0x1fffff;
+                       u32_t upper_3_bits = ((valid24bits & 0xe00000) << 3);
+                       insn &= ~mask;
+
+                       insn |= bot_21;
+                       insn |= upper_3_bits;
+                       *rp = insn;
+               }
+               break;
+       case R_UBICOM32_LO7_S:
+       case R_UBICOM32_LO7_2_S:
+       case R_UBICOM32_LO7_4_S:
+               {
+                       /*
+                        * Bits 0 - 6 of the relocation are encoded into the
+                        * 7bit unsigned immediate fields of the SOURCE-1 field
+                        * of the instruction.  The immediate value is left
+                        * shifted by (0, 1, 2) based on the operand size.
+                        */
+                       u32_t mask = 0x1f | (0x3 << 8);
+                       u32_t bottom, top;
+                       val &= 0x7f;
+                       if (reloc_type == R_UBICOM32_LO7_2_S) {
+                               val >>= 1;
+                       } else if (reloc_type == R_UBICOM32_LO7_4_S) {
+                               val >>= 2;
+                       }
+
+                       bottom  = val & 0x1f;
+                       top = val >> 5;
+                       insn &= ~mask;
+                       insn |= bottom;
+                       insn |= (top << 8);
+                       BUG_ON(*rp != insn);
+                       *rp = insn;
+                       break;
+               }
+       case R_UBICOM32_LO7_D:
+       case R_UBICOM32_LO7_2_D:
+       case R_UBICOM32_LO7_4_D:
+               {
+                       /*
+                        * Bits 0 - 6 of the relocation are encoded into the
+                        * 7bit unsigned immediate fields of the DESTINATION
+                        * field of the instruction.  The immediate value is
+                        * left shifted by (0, 1, 2) based on the operand size.
+                        */
+                       u32_t mask = (0x1f | (0x3 << 8)) << 16;
+                       u32_t bottom, top;
+                       val &= 0x7f;
+                       if (reloc_type == R_UBICOM32_LO7_2_D) {
+                               val >>= 1;
+                       } else if (reloc_type == R_UBICOM32_LO7_4_D) {
+                               val >>= 2;
+                       }
+                       bottom  = (val & 0x1f) << 16;
+                       top = (val >> 5) << 16;
+                       insn &= ~mask;
+                       insn |= bottom;
+                       insn |= (top << 8);
+                       BUG_ON(*rp != insn);
+                       *rp = insn;
+                       break;
+               }
+       case R_UBICOM32_LO7_CALLI:
+       case R_UBICOM32_LO16_CALLI:
+               {
+                       /*
+                        * Extract the offset for a CALLI instruction. The
+                        * offsets can be either 7 bits or 18 bits. Since all
+                        * instructions in ubicom32 architecture are at work
+                        * aligned addresses the truncated offset is right
+                        * shifted by 2 before being encoded in the instruction.
+                        */
+                       if (reloc_type == R_UBICOM32_LO7_CALLI) {
+                               val &= 0x7f;
+                       } else {
+                               val &= 0x3ffff;
+                       }
+
+                       val >>= 2;
+
+                       insn &= ~0x071f071f;
+                       insn |= (val & 0x1f) << 0;
+                       val >>= 5;
+                       insn |= (val & 0x07) << 8;
+                       val >>= 3;
+                       insn |= (val & 0x1f) << 16;
+                       val >>= 5;
+                       insn |= (val & 0x07) << 24;
+                       if (reloc_type == R_UBICOM32_LO7_CALLI) {
+                               BUG_ON(*rp != insn);
+                       }
+                       *rp = insn;
+               }
+               break;
+       }
+
+       if (*persistent) {
+               *persistent = 0;
+       }
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/head.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/head.S
new file mode 100644 (file)
index 0000000..0c60504
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * arch/ubicom32/kernel/head.S
+ *     <TODO: Replace with short file description>
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/page_offset.h>
+#define __ASM__
+#include <asm/ip5000.h>
+
+
+#define SRC_AN A3
+#define DST_AN A4
+
+#define PARAM_DN D0
+#define TMP_DN D15
+#define TMP2_DN D14
+
+/*
+ * The following code is placed at the start of the Linux section of memory.
+ * This is the primary entry point for Linux.
+ *
+ * However, we also want the syscall entry/exit code to be at a fixed address.
+ * So we take the primary entry point and reserve 16 bytes.  That address is
+ * where the system_call entry point exists.  This 16 bytes basically allows
+ * us to jump around the system_call entry point code to the actual startup
+ * code.
+ *
+ * Linux Memory Map (see vlinux.lds.S):
+ * 0x40400000 - Primary Entry Point for Linux (jump around code below).
+ * 0x40400010 - Old syscall Entry Point.
+ */
+
+       .sect   .skip_syscall, "ax", @progbits
+       .global __skip_syscall_section
+__skip_syscall_section:
+       moveai          A3, #%hi(_start)
+       lea.1           A3, %lo(_start)(A3)
+       ret             A3
+/*
+ * __os_node_offset contains the offset from KERNELBASE to the os_node, it is
+ * not intended to be used by anything except the boot code.
+ */
+__os_node_offset:
+.long  (_os_node - KERNELSTART)
+
+.text
+.global        _start
+
+/*
+ * start()
+ *     This is the start of the Linux kernel.
+ */
+_start:
+       move.4          SCRATCHPAD1, #0
+
+
+/*
+ * Setup the range registers... the loader has setup a few, but we will go ahead
+ * and correct them for our own limits. Note that once set these are never
+ * changed again.  The ranges are as follows
+ *
+ *  D_RANGE0 - io block (set up by loaded)
+ *
+ *  I_RANGE0 and D_RANGE1 - kernel/ultra loader address space bottom of ocm-> top
+ *     of ram typically 0x3ffc0000 - 0x440000000
+ *  I_RANGE1 - kernel / userspace transition area (aka syscalls, context switches)
+ *     typically 0x3FFC0030 - ~0x3FFC0200
+ *  I_RANGE2 / D_RANGE2 - slab area
+ *     typically 0x40A00000 - ~0x44000000
+ *  I_RANGE3
+ *     old system call interface if enabled.
+ *
+ *   D_RANGE3, D_RANGE4 - unused.
+ */
+       moveai          SRC_AN, #%hi(PAGE_OFFSET_RAW)
+       lea.4           SRC_AN, %lo(PAGE_OFFSET_RAW)(SRC_AN)
+       move.4          D_RANGE1_LO, SRC_AN
+       move.4          I_RANGE0_LO, SRC_AN
+
+; don't try to calculate I_RANGE_HI, see below
+;      moveai          SRC_AN, #%hi(___init_end-4)
+;      lea.4           SRC_AN, %lo(___init_end-4)(SRC_AN)
+;      move.4          I_RANGE0_HI, SRC_AN
+
+       moveai          SRC_AN, #%hi(SDRAMSTART + CONFIG_MIN_RAMSIZE-4)
+       lea.4           SRC_AN, %lo(SDRAMSTART + CONFIG_MIN_RAMSIZE-4)(SRC_AN)
+       move.4          D_RANGE1_HI, SRC_AN
+
+; for now allow the whole ram to be executable as well so we don't run into problems
+; once we load user more code.
+       move.4          I_RANGE0_HI, SRC_AN
+
+#ifdef CONFIG_PROTECT_KERNEL
+; when kernel protection is enabled, we only open up syscall and non kernel text
+; for userspace apps, for now only irange registers registers 1 and 2 are used for userspace.
+
+       ;; syscall range
+       moveai          SRC_AN, #%hi(__syscall_text_run_begin)
+       lea.4           SRC_AN, %lo(__syscall_text_run_begin)(SRC_AN)
+       move.4          I_RANGE1_LO, SRC_AN
+       moveai          SRC_AN, #%hi(__syscall_text_run_end)
+       lea.4           SRC_AN, %lo(__syscall_text_run_end)(SRC_AN)
+       move.4          I_RANGE1_HI, SRC_AN
+
+       ;; slab instructions
+       moveai          SRC_AN, #%hi(_edata)
+       lea.4           SRC_AN, %lo(_edata)(SRC_AN)
+       move.4          I_RANGE2_LO, SRC_AN
+       ;; End of DDR is already in range0 hi so just copy it.
+       move.4          I_RANGE2_HI, I_RANGE0_HI
+
+#ifdef CONFIG_OLD_40400010_SYSTEM_CALL
+       ;; create a small hole for old syscall location
+       moveai          SRC_AN, #%hi(0x40400000)
+       lea.4           I_RANGE3_LO, 0x10(SRC_AN)
+       lea.4           I_RANGE3_HI, 0x14(SRC_AN)
+#endif
+       ;; slab data (same as slab instructions but starting a little earlier).
+       moveai          SRC_AN, #%hi(_data_protection_end)
+       lea.4           SRC_AN, %lo(_data_protection_end)(SRC_AN)
+       move.4          D_RANGE2_LO, SRC_AN
+       move.4          D_RANGE2_HI, I_RANGE0_HI
+
+;; enable ranges
+       ;; skip I_RANGE0_EN
+       move.4          I_RANGE1_EN, #-1
+       move.4          I_RANGE2_EN, #-1
+#ifdef CONFIG_OLD_40400010_SYSTEM_CALL
+       move.4          I_RANGE3_EN, #-1
+#else
+       move.4          I_RANGE3_EN, #0
+#endif
+       ;; skip D_RANGE0_EN or D_RANGE1_EN
+       move.4          D_RANGE2_EN, #-1
+       move.4          D_RANGE3_EN, #0
+       move.4          D_RANGE4_EN, #0
+#endif
+
+;
+; If __ocm_free_begin is smaller than __ocm_free_end the
+; setup OCM text and data ram banks properly
+;
+       moveai          DST_AN, #%hi(__ocm_free_begin)
+       lea.4           TMP_DN, %lo(__ocm_free_begin)(DST_AN)
+       moveai          DST_AN, #%hi(__ocm_free_end)
+       lea.4           TMP2_DN, %lo(__ocm_free_end)(DST_AN)
+       sub.4           #0, TMP2_DN, TMP_DN
+       jmple.f         2f
+       moveai          DST_AN, #%hi(__data_begin)
+       lea.4           TMP_DN, %lo(__data_begin)(DST_AN)
+       moveai          DST_AN, #%hi(OCMSTART)
+       lea.4           TMP2_DN, %lo(OCMSTART)(DST_AN)
+       sub.4           TMP_DN, TMP_DN, TMP2_DN
+       lsr.4           TMP_DN, TMP_DN, #15
+       lsl.4           TMP_DN, #1, TMP_DN
+       moveai          DST_AN, #%hi(OCMC_BASE)
+       add.4           OCMC_BANK_MASK(DST_AN), #-1, TMP_DN
+       pipe_flush      0
+2:
+;
+; Load .ocm_text
+;
+       moveai          DST_AN, #%hi(__ocm_text_run_end)
+       lea.4           TMP_DN, %lo(__ocm_text_run_end)(DST_AN)
+       moveai          DST_AN, #%hi(__ocm_text_run_begin)
+       lea.4           DST_AN, %lo(__ocm_text_run_begin)(DST_AN)
+       moveai          SRC_AN, #%hi(__ocm_text_load_begin)
+       lea.4           SRC_AN, %lo(__ocm_text_load_begin)(SRC_AN)
+       jmpt.t          2f
+
+1:      move.4          (DST_AN)4++, (SRC_AN)4++
+
+2:      sub.4           #0, DST_AN, TMP_DN
+       jmpne.t         1b
+;
+; Load .syscall_text
+;
+       moveai          DST_AN, #%hi(__syscall_text_run_end)
+       lea.4           TMP_DN, %lo(__syscall_text_run_end)(DST_AN)
+       moveai          DST_AN, #%hi(__syscall_text_run_begin)
+       lea.4           DST_AN, %lo(__syscall_text_run_begin)(DST_AN)
+       moveai          SRC_AN, #%hi(__syscall_text_load_begin)
+       lea.4           SRC_AN, %lo(__syscall_text_load_begin)(SRC_AN)
+       jmpt.t          2f
+
+1:     move.4          (DST_AN)4++, (SRC_AN)4++
+
+2:     sub.4           #0, DST_AN, TMP_DN
+       jmpne.t         1b
+
+;
+; Load .ocm_data
+;
+       moveai          DST_AN, #%hi(__ocm_data_run_end)
+       lea.4           TMP_DN, %lo(__ocm_data_run_end)(DST_AN)
+       moveai          DST_AN, #%hi(__ocm_data_run_begin)
+       lea.4           DST_AN, %lo(__ocm_data_run_begin)(DST_AN)
+       moveai          SRC_AN, #%hi(__ocm_data_load_begin)
+       lea.4           SRC_AN, %lo(__ocm_data_load_begin)(SRC_AN)
+       jmpt.t          2f
+
+1:      move.4          (DST_AN)4++, (SRC_AN)4++
+
+2:      sub.4           #0, DST_AN, TMP_DN
+       jmpne.t         1b
+
+; Clear .bss
+;
+       moveai          SRC_AN, #%hi(_ebss)
+       lea.4           TMP_DN, %lo(_ebss)(SRC_AN)
+       moveai          DST_AN, #%hi(_sbss)
+       lea.4           DST_AN, %lo(_sbss)(DST_AN)
+       jmpt.t          2f
+
+1:     move.4          (DST_AN)4++, #0
+
+2:     sub.4           #0, DST_AN, TMP_DN
+       jmpne.t         1b
+
+; save our parameter to devtree (after clearing .bss)
+       moveai          DST_AN, #%hi(devtree)
+       lea.4           DST_AN, %lo(devtree)(DST_AN)
+       move.4          (DST_AN), PARAM_DN
+
+       moveai          sp, #%hi(init_thread_union)
+       lea.4           sp, %lo(init_thread_union)(sp)
+       movei           TMP_DN, #ASM_THREAD_SIZE
+       add.4           sp, sp, TMP_DN
+       move.4          -4(sp)++, #0 ; nesting level = 0
+       move.4          -4(sp)++, #1 ; KERNEL_THREAD
+
+;; ip3k-elf-gdb backend now sets scratchpad3 to 1 when either continue
+;; or single step commands are issued. scratchpad3 is set to 0 when the
+;; debugger detaches from the board.
+       move.4          TMP_DN, scratchpad3
+       lsl.4           TMP_DN, TMP_DN, #0x0
+       jmpeq.f         _jump_to_start_kernel
+_ok_to_set_break_points_in_linux:
+;; THREAD_STALL
+       move.4          mt_dbg_active_clr,#-1
+;; stalling the threads isn't instantaneous.. need to flush the pipe.
+       pipe_flush      0
+       pipe_flush      0
+
+_jump_to_start_kernel:
+       moveai          SRC_AN, #%hi(start_kernel)
+       lea.4           SRC_AN, %lo(start_kernel)(SRC_AN)
+       ret             SRC_AN
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/init_task.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/init_task.c
new file mode 100644 (file)
index 0000000..ff06344
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * arch/ubicom32/kernel/init_task.c
+ *   Ubicom32 architecture task initialization implementation.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/init_task.h>
+#include <linux/fs.h>
+#include <linux/mqueue.h>
+#include <linux/uaccess.h>
+#include <asm/pgtable.h>
+
+///static struct fs_struct init_fs = INIT_FS;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+struct mm_struct init_mm = INIT_MM(init_mm);
+EXPORT_SYMBOL(init_mm);
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_task);
+
+/*
+ * Initial thread structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+union thread_union init_thread_union
+       __attribute__((__section__(".data.init_task"))) =
+               { INIT_THREAD_INFO(init_task) };
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c
new file mode 100644 (file)
index 0000000..c041f23
--- /dev/null
@@ -0,0 +1,597 @@
+/*
+ * arch/ubicom32/kernel/irq.c
+ *   Ubicom32 architecture IRQ support.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/types.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/ldsr.h>
+#include <asm/ip5000.h>
+#include <asm/machdep.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread.h>
+#include <asm/devtree.h>
+
+unsigned int irq_soft_avail;
+static struct irqaction ubicom32_reserve_action[NR_IRQS];
+
+#if !defined(CONFIG_DEBUG_IRQMEASURE)
+#define IRQ_DECLARE_MEASUREMENT
+#define IRQ_MEASUREMENT_START()
+#define IRQ_MEASUREMENT_END(irq)
+#else
+#define IRQ_DECLARE_MEASUREMENT \
+       int __diff;             \
+       unsigned int __tstart;
+
+#define IRQ_MEASUREMENT_START() \
+       __tstart = UBICOM32_IO_TIMER->sysval;
+
+#define IRQ_MEASUREMENT_END(irq) \
+       __diff = (int)UBICOM32_IO_TIMER->sysval - (int)__tstart; \
+       irq_measurement_update((irq), __diff);
+
+/*
+ * We keep track of the time spent in both irq_enter()
+ * and irq_exit().
+ */
+#define IRQ_WEIGHT 32
+
+struct irq_measurement {
+       volatile unsigned int min;
+       volatile unsigned int avg;
+       volatile unsigned int max;
+};
+
+static DEFINE_SPINLOCK(irq_measurement_lock);
+
+/*
+ *  Add 1 in for softirq (irq_exit());
+ */
+static struct irq_measurement irq_measurements[NR_IRQS + 1];
+
+/*
+ * irq_measurement_update()
+ *     Update an entry in the measurement array for this irq.
+ */
+static void irq_measurement_update(int irq, int sample)
+{
+       struct irq_measurement *im = &irq_measurements[irq];
+       spin_lock(&irq_measurement_lock);
+       if ((im->min == 0) || (im->min > sample)) {
+               im->min = sample;
+       }
+       if (im->max < sample) {
+               im->max = sample;
+       }
+       im->avg = ((im->avg * (IRQ_WEIGHT - 1)) + sample) / IRQ_WEIGHT;
+       spin_unlock(&irq_measurement_lock);
+}
+#endif
+
+/*
+ * irq_kernel_stack_check()
+ *     See if the kernel stack is within STACK_WARN of the end.
+ */
+static void irq_kernel_stack_check(int irq, struct pt_regs *regs)
+{
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+       unsigned long sp;
+
+       /*
+        * Make sure that we are not close to the top of the stack and thus
+        * can not really service this interrupt.
+        */
+       asm volatile (
+               "and.4          %0, SP, %1 \n\t"
+               : "=d" (sp)
+               : "d" (THREAD_SIZE - 1)
+               : "cc"
+       );
+
+       if (sp < (sizeof(struct thread_info) + STACK_WARN)) {
+               printk(KERN_WARNING
+                       "cpu[%d]: possible overflow detected sp remain: %p, "
+                      "irq: %d, regs: %p\n",
+                       thread_get_self(), (void *)sp, irq, regs);
+               dump_stack();
+       }
+
+       if (sp < (sizeof(struct thread_info) + 16)) {
+               THREAD_STALL;
+       }
+#endif
+}
+
+/*
+ * irq_get_lsb()
+ *     Get the LSB set in value
+ */
+static int irq_get_lsb(unsigned int value)
+{
+       static unsigned char irq_bits[8] = {
+               3, 0, 1, 0, 2, 0, 1, 0
+       };
+       u32_t nextbit = 0;
+
+       value = (value >> nextbit) | (value << ((sizeof(value) * 8) - nextbit));
+
+       /*
+        * It's unlikely that we find that we execute the body of this while
+        * loop.  50% of the time we won't take this at all and then of the
+        * cases where we do about 50% of those we only execute once.
+        */
+       if (!(value & 0xffff)) {
+               nextbit += 0x10;
+               value >>= 16;
+       }
+
+       if (!(value & 0xff)) {
+               nextbit += 0x08;
+               value >>= 8;
+       }
+
+       if (!(value & 0xf)) {
+               nextbit += 0x04;
+               value >>= 4;
+       }
+
+       nextbit += irq_bits[value & 0x7];
+       if (nextbit > 63) {
+               panic("nextbit out of range: %d\n", nextbit);
+       }
+       return nextbit;
+}
+
+/*
+ * ubicom32_reserve_handler()
+ *     Bogus handler associated with pre-reserved IRQ(s).
+ */
+static irqreturn_t ubicom32_reserve_handler(int irq, void *dev_id)
+{
+       BUG();
+       return IRQ_HANDLED;
+}
+
+/*
+ * __irq_disable_vector()
+ *     Disable the interrupt by clearing the appropriate bit in the
+ *     LDSR Mask Register.
+ */
+static void __irq_disable_vector(unsigned int irq)
+{
+       ldsr_disable_vector(irq);
+}
+
+/*
+ * __irq_ack_vector()
+ *     Acknowledge the specific interrupt by clearing the associate bit in
+ *     hardware
+ */
+static void __irq_ack_vector(unsigned int irq)
+{
+       if (irq < 32) {
+               asm volatile ("move.4 INT_CLR0, %0" : : "d" (1 << irq));
+       } else {
+               asm volatile ("move.4 INT_CLR1, %0" : : "d" (1 << (irq - 32)));
+       }
+}
+
+/*
+ * __irq_enable_vector()
+ *     Clean and then enable the interrupt by setting the appropriate bit in
+ *     the LDSR Mask Register.
+ */
+static void __irq_enable_vector(unsigned int irq)
+{
+       /*
+        * Acknowledge, really clear the vector.
+        */
+       __irq_ack_vector(irq);
+       ldsr_enable_vector(irq);
+}
+
+/*
+ * __irq_mask_vector()
+ */
+static void __irq_mask_vector(unsigned int irq)
+{
+       ldsr_mask_vector(irq);
+}
+
+/*
+ * __irq_unmask_vector()
+ */
+static void __irq_unmask_vector(unsigned int irq)
+{
+       ldsr_unmask_vector(irq);
+}
+
+/*
+ * __irq_end_vector()
+ *     Called once an interrupt is completed (reset the LDSR mask).
+ */
+static void __irq_end_vector(unsigned int irq)
+{
+       ldsr_unmask_vector(irq);
+}
+
+#if defined(CONFIG_SMP)
+/*
+ * __irq_set_affinity()
+ *     Set the cpu affinity for this interrupt.
+ *     affinity container allocated at boot
+ */
+static void __irq_set_affinity(unsigned int irq, const struct cpumask *dest)
+{
+       smp_set_affinity(irq, dest);
+       cpumask_copy(irq_desc[irq].affinity, dest);
+}
+#endif
+
+/*
+ * On-Chip Generic Interrupt function handling.
+ */
+static struct irq_chip ubicom32_irq_chip = {
+       .name           = "Ubicom32",
+       .startup        = NULL,
+       .shutdown       = NULL,
+       .enable         = __irq_enable_vector,
+       .disable        = __irq_disable_vector,
+       .ack            = __irq_ack_vector,
+       .mask           = __irq_mask_vector,
+       .unmask         = __irq_unmask_vector,
+       .end            = __irq_end_vector,
+#if defined(CONFIG_SMP)
+       .set_affinity   = __irq_set_affinity,
+#endif
+};
+
+/*
+ * do_IRQ()
+ *     Primary interface for handling IRQ() requests.
+ */
+asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
+{
+       struct pt_regs *oldregs;
+       struct thread_info *ti = current_thread_info();
+
+       IRQ_DECLARE_MEASUREMENT;
+
+       /*
+        * Mark that we are inside of an interrupt and
+        * that interrupts are disabled.
+        */
+       oldregs = set_irq_regs(regs);
+       ti->interrupt_nesting++;
+       trace_hardirqs_off();
+       irq_kernel_stack_check(irq, regs);
+
+       /*
+        * Start the interrupt sequence
+        */
+       irq_enter();
+
+       /*
+        * Execute the IRQ handler and any pending SoftIRQ requests.
+        */
+       BUG_ON(!irqs_disabled());
+       IRQ_MEASUREMENT_START();
+       __do_IRQ(irq);
+       IRQ_MEASUREMENT_END(irq);
+       BUG_ON(!irqs_disabled());
+
+       /*
+        * TODO: Since IRQ's are disabled when calling irq_exit()
+        * modify Kconfig to set __ARCH_IRQ_EXIT_IRQS_DISABLED flag.
+        * This will slightly improve performance by enabling
+        * softirq handling to avoid disabling/disabled interrupts.
+        */
+       IRQ_MEASUREMENT_START();
+       irq_exit();
+       IRQ_MEASUREMENT_END(NR_IRQS);
+       BUG_ON(!irqs_disabled());
+
+       /*
+        * Outside of an interrupt (or nested exit).
+        */
+       set_irq_regs(oldregs);
+       trace_hardirqs_on();
+       ti->interrupt_nesting--;
+}
+
+/*
+ * irq_soft_alloc()
+ *     Allocate a soft IRQ.
+ */
+int irq_soft_alloc(unsigned int *soft)
+{
+       if (irq_soft_avail == 0) {
+               printk(KERN_NOTICE "no soft irqs to allocate\n");
+               return -EFAULT;
+       }
+
+       *soft = irq_get_lsb(irq_soft_avail);
+       irq_soft_avail &= ~(1 << *soft);
+       return 0;
+}
+
+/*
+ * ack_bad_irq()
+ *     Called to handle an bad irq request.
+ */
+void ack_bad_irq(unsigned int irq)
+{
+       printk(KERN_ERR "IRQ: unexpected irq=%d\n", irq);
+       __irq_end_vector(irq);
+}
+
+/*
+ * show_interrupts()
+ *     Return a string that displays the state of each of the interrupts.
+ */
+int show_interrupts(struct seq_file *p, void *v)
+{
+       struct irqaction *ap;
+       int irq = *((loff_t *) v);
+       int j;
+
+       if (irq >= NR_IRQS) {
+               return 0;
+       }
+
+       if (irq == 0) {
+               seq_puts(p, "           ");
+               for_each_online_cpu(j) {
+                       seq_printf(p, "CPU%d       ", j);
+               }
+               seq_putc(p, '\n');
+       }
+
+       ap = irq_desc[irq].action;
+       if (ap) {
+               seq_printf(p, "%3d: ", irq);
+               for_each_online_cpu(j) {
+                       seq_printf(p, "%10u ", kstat_irqs_cpu(irq, j));
+               }
+               seq_printf(p, "%14s  ", irq_desc[irq].chip->name);
+               seq_printf(p, "%s", ap->name);
+               for (ap = ap->next; ap; ap = ap->next) {
+                       seq_printf(p, ", %s", ap->name);
+               }
+               seq_putc(p, '\n');
+       }
+       return 0;
+}
+
+#if defined(CONFIG_DEBUG_IRQMEASURE)
+static unsigned int irq_cycles_to_micro(unsigned int cycles, unsigned int frequency)
+{
+       unsigned int micro = (cycles / (frequency / 1000000));
+       return micro;
+}
+
+/*
+ * irq_measurement_show()
+ *     Print out the min, avg, max values for each IRQ
+ *
+ * By request, the max value is reset after each dump.
+ */
+static int irq_measurement_show(struct seq_file *p, void *v)
+{
+       struct irqaction *ap;
+       unsigned int freq = processor_frequency();
+       int irq = *((loff_t *) v);
+
+
+       if (irq == 0) {
+               seq_puts(p, "\tmin\tavg\tmax\t(micro-seconds)\n");
+       }
+
+       if (irq > NR_IRQS) {
+               return 0;
+       }
+
+       if (irq == NR_IRQS) {
+               unsigned int min, avg, max;
+               spin_lock(&irq_measurement_lock);
+               min = irq_cycles_to_micro(irq_measurements[irq].min, freq);
+               avg = irq_cycles_to_micro(irq_measurements[irq].avg, freq);
+               max = irq_cycles_to_micro(irq_measurements[irq].max, freq);
+               irq_measurements[irq].max = 0;
+               spin_unlock(&irq_measurement_lock);
+               seq_printf(p, "   \t%u\t%u\t%u\tsoftirq\n", min, avg, max);
+               return 0;
+       }
+
+       ap = irq_desc[irq].action;
+       if (ap) {
+               unsigned int min, avg, max;
+               spin_lock(&irq_measurement_lock);
+               min = irq_cycles_to_micro(irq_measurements[irq].min, freq);
+               avg = irq_cycles_to_micro(irq_measurements[irq].avg, freq);
+               max = irq_cycles_to_micro(irq_measurements[irq].max, freq);
+               irq_measurements[irq].max = 0;
+               spin_unlock(&irq_measurement_lock);
+               seq_printf(p, "%2u:\t%u\t%u\t%u\t%s\n", irq, min, avg, max, ap->name);
+       }
+       return 0;
+}
+
+static void *irq_measurement_start(struct seq_file *f, loff_t *pos)
+{
+       return (*pos <= NR_IRQS) ? pos : NULL;
+}
+
+static void *irq_measurement_next(struct seq_file *f, void *v, loff_t *pos)
+{
+       (*pos)++;
+       if (*pos > NR_IRQS)
+               return NULL;
+       return pos;
+}
+
+static void irq_measurement_stop(struct seq_file *f, void *v)
+{
+       /* Nothing to do */
+}
+
+static const struct seq_operations irq_measurement_seq_ops = {
+       .start = irq_measurement_start,
+       .next  = irq_measurement_next,
+       .stop  = irq_measurement_stop,
+       .show  = irq_measurement_show,
+};
+
+static int irq_measurement_open(struct inode *inode, struct file *filp)
+{
+       return seq_open(filp, &irq_measurement_seq_ops);
+}
+
+static const struct file_operations irq_measurement_fops = {
+       .open           = irq_measurement_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static int __init irq_measurement_init(void)
+{
+       proc_create("irq_measurements", 0, NULL, &irq_measurement_fops);
+       return 0;
+}
+module_init(irq_measurement_init);
+#endif
+
+/*
+ * init_IRQ(void)
+ *     Initialize the on-chip IRQ subsystem.
+ */
+void __init init_IRQ(void)
+{
+       int irq;
+       struct devtree_node *p = NULL;
+       struct devtree_node *iter = NULL;
+       unsigned int mask = 0;
+       unsigned int reserved = 0;
+
+       /*
+        * Pull out the list of software interrupts that are avialable to
+        * Linux and provide an allocation function for them.  The first
+        * 24 interrupts of INT0 are software interrupts.
+        */
+       irq_soft_avail = 0;
+       if (processor_interrupts(&irq_soft_avail, NULL) < 0) {
+               printk(KERN_WARNING "No Soft IRQ(s) available\n");
+       }
+       irq_soft_avail &= ((1 << 24) - 1);
+
+       /*
+        * Initialize all of the on-chip interrupt handling
+        * to use a common set of interrupt functions.
+        */
+       for (irq = 0; irq < NR_IRQS; irq++) {
+               irq_desc[irq].status = IRQ_DISABLED;
+               irq_desc[irq].action = NULL;
+               irq_desc[irq].depth = 1;
+               set_irq_chip(irq, &ubicom32_irq_chip);
+       }
+
+       /*
+        * The sendirq of a devnode is not registered within Linux but instead
+        * is used by the software I/O thread.  These interrupts are reserved.
+        * The recvirq is used by Linux and registered by a device driver, these
+        * are not reserved.
+        *
+        * recvirq(s) that are in the software interrupt range are not supposed
+        * to be marked as reserved.  We track this while we scan the device
+        * nodes.
+        */
+       p = devtree_find_next(&iter);
+       while (p) {
+               unsigned char sendirq, recvirq;
+               devtree_irq(p, &sendirq, &recvirq);
+
+               /*
+                * If the sendirq is valid, mark that irq as taken by the
+                * devtree node.
+                */
+               if (sendirq < NR_IRQS) {
+                       ubicom32_reserve_action[sendirq].handler =
+                               ubicom32_reserve_handler;
+                       ubicom32_reserve_action[sendirq].name = p->name;
+                       irq_desc[sendirq].action =
+                               &ubicom32_reserve_action[sendirq];
+                       mask |= (1 << sendirq);
+               }
+
+               /*
+                * Track the relevant recieve IRQ(s)
+                */
+               if (recvirq < 24) {
+                       mask |= (1 << recvirq);
+               }
+
+               /*
+                * Move to the next node.
+                */
+               p = devtree_find_next(&iter);
+       }
+
+       /*
+        * Remove these bits from the irq_soft_avail list and then use the
+        * result as the list of pre-reserved IRQ(s).
+        */
+       reserved = ~irq_soft_avail & ~mask;
+       for (irq = 0; irq < 24; irq++) {
+               if ((reserved & (1 << irq))) {
+                       ubicom32_reserve_action[irq].handler =
+                               ubicom32_reserve_handler;
+                       ubicom32_reserve_action[irq].name = "reserved";
+                       irq_desc[irq].action = &ubicom32_reserve_action[irq];
+               }
+       }
+
+       /*
+        * Initialize the LDSR which is the Ubicom32 programmable
+        * interrupt controller.
+        */
+       ldsr_init();
+
+       /*
+        * The Ubicom trap code needs a 2nd init after IRQ(s) are setup.
+        */
+       trap_init_interrupt();
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ldsr.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/ldsr.c
new file mode 100644 (file)
index 0000000..a608d74
--- /dev/null
@@ -0,0 +1,1185 @@
+/*
+ * arch/ubicom32/kernel/ldsr.c
+ *   Ubicom32 architecture Linux Device Services Driver Interface
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *
+ * NOTES:
+ *
+ * The LDSR is a programmable interrupt controller that is written in software.
+ * It emulates the behavior of an pic by fielding the interrupts, choosing a
+ * victim thread to take the interrupt and forcing that thread to take a context
+ * switch to the appropriate interrupt handler.
+ *
+ * Because traps are treated as just a special class of interrupts, the LDSR
+ * also handles the processing of traps.
+ *
+ * Because we compile Linux both UP and SMP, we need the LDSR to use
+ * architectural locking that is not "compiled out" when compiling UP.  For now,
+ * we use the single atomic bit lock.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/cpumask.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <asm/ip5000.h>
+#include <asm/atomic.h>
+#include <asm/machdep.h>
+#include <asm/asm-offsets.h>
+#include <asm/traps.h>
+#include <asm/thread.h>
+#include <asm/range-protect.h>
+
+/*
+ * One can not print from the LDSR so the best we can do is
+ * check a condition and stall all of the threads.
+ */
+
+// #define DEBUG_LDSR 1
+#if defined(DEBUG_LDSR)
+#define DEBUG_ASSERT(cond) \
+       if (!(cond)) { \
+               THREAD_STALL; \
+       }
+#else
+#define DEBUG_ASSERT(cond)
+#endif
+
+/*
+ * Make global so that we can use it in the RFI code in assembly.
+ */
+unsigned int ldsr_soft_irq_mask;
+EXPORT_SYMBOL(ldsr_soft_irq_mask);
+
+static unsigned int ldsr_suspend_mask;
+static unsigned int ldsr_soft_irq;
+static unsigned int ldsr_stack_space[1024];
+
+static struct ldsr_register_bank {
+       volatile unsigned int enabled0;
+       volatile unsigned int enabled1;
+       volatile unsigned int mask0;
+       volatile unsigned int mask1;
+       unsigned int total;
+       unsigned int retry;
+       unsigned int backout;
+} ldsr_interrupt;
+
+/*
+ * Which thread/cpu are we?
+ */
+static int ldsr_tid = -1;
+
+#if defined(CONFIG_IRQSTACKS)
+/*
+ * per-CPU IRQ stacks (thread information and stack)
+ *
+ * NOTE: Do not use DEFINE_PER_CPU() as it makes it harder
+ * to find the location of ctx from assembly language.
+ */
+union irq_ctx {
+       struct thread_info      tinfo;
+       u32                     stack[THREAD_SIZE/sizeof(u32)];
+};
+static union irq_ctx *percpu_irq_ctxs[NR_CPUS];
+
+/*
+ *  Storage for the interrupt stack.
+ */
+#if !defined(CONFIG_IRQSTACKS_USEOCM)
+static char percpu_irq_stacks[(NR_CPUS * THREAD_SIZE) + (THREAD_SIZE - 1)];
+#else
+/*
+ *  For OCM, the linker will ensure that space is allocated for the stack
+ *  see (vmlinux.lds.S)
+ */
+static char percpu_irq_stacks[];
+#endif
+
+#endif
+
+/*
+ * Save trap IRQ because we need to un-suspend if it gets set.
+ */
+static unsigned int ldsr_trap_irq_mask;
+static unsigned int ldsr_trap_irq;
+
+/*
+ * ret_from_interrupt_to_kernel
+ *     Just restore the context and do nothing else.
+ */
+asmlinkage void ret_from_interrupt_to_kernel(void)__attribute__((naked));
+
+/*
+ * ret_from_interrupt_to_user
+ *     Call scheduler if needed. Just restore the context.
+ */
+asmlinkage void ret_from_interrupt_to_user(void)__attribute__((naked));
+
+#ifdef DEBUG_LDSR
+u32_t old_sp, old_pc, old_a0, old_a5, old_a3;
+struct pt_regs copy_regs, *copy_save_area;
+#endif
+
+int __user_mode(unsigned long sp)
+{
+
+       u32_t saved_stack_base = sp & ~(ASM_THREAD_SIZE - 1);
+#if defined(CONFIG_IRQSTACKS_USEOCM)
+       if ((union irq_ctx *)saved_stack_base == percpu_irq_ctxs[smp_processor_id()]) {
+               /*
+                *  On the interrupt stack.
+                */
+               return 0;
+       }
+#endif
+
+       if (!(u32_t)current) {
+               return 0;
+       }
+       return saved_stack_base != ((u32_t)current->stack);
+}
+
+/*
+ * ldsr_lock_release()
+ *     Release the LDSR lock.
+ */
+static void ldsr_lock_release(void)
+{
+       UBICOM32_UNLOCK(LDSR_LOCK_BIT);
+}
+
+/*
+ * ldsr_lock_acquire()
+ *     Acquire the LDSR lock, spin if not available.
+ */
+static void ldsr_lock_acquire(void)
+{
+       UBICOM32_LOCK(LDSR_LOCK_BIT);
+}
+
+/*
+ * ldsr_thread_irq_disable()
+ *     Disable interrupts for the specified thread.
+ */
+static void ldsr_thread_irq_disable(unsigned int tid)
+{
+       unsigned int mask = (1 << tid);
+
+       asm volatile (
+       "       or.4    scratchpad1, scratchpad1, %0    \n\t"
+               :
+               : "d"(mask)
+               : "cc"
+       );
+}
+
+/*
+ * ldsr_thread_get_interrupts()
+ *     Get the interrupt state for all threads.
+ */
+static unsigned long ldsr_thread_get_interrupts(void)
+{
+       unsigned long ret = 0;
+       asm volatile (
+       "       move.4  %0, scratchpad1 \n\t"
+               : "=r" (ret)
+               :
+       );
+       return ret;
+}
+
+/*
+ * ldsr_emulate_and_run()
+ *     Emulate the instruction and then set the thread to run.
+ */
+static void ldsr_emulate_and_run(unsigned int tid)
+{
+       unsigned int thread_mask = (1 << tid);
+       u32_t write_csr = (tid << 15) | (1 << 14);
+
+       /*
+        * Emulate the unaligned access.
+        */
+       unaligned_emulate(tid);
+
+       /*
+        * Get the thread back in a running state.
+        */
+       asm volatile (
+       "       setcsr  %0                      \n\t"
+       "       setcsr_flush 0                  \n\t"
+       "       move.4  trap_cause, #0          \n\t" /* Clear the trap cause
+                                                      * register */
+       "       setcsr  #0                      \n\t"
+       "       setcsr_flush 0                  \n\t"
+       "       move.4  mt_dbg_active_set, %1   \n\t" /* Activate thread even if
+                                                      * in dbg/fault state */
+       "       move.4  mt_active_set, %1       \n\t" /* Restart target
+                                                      * thread. */
+               :
+               : "r" (write_csr), "d" (thread_mask)
+               : "cc"
+       );
+       thread_enable_mask(thread_mask);
+}
+
+/*
+ * ldsr_preemptive_context_save()
+ *     save thread context from another hardware thread.  The other thread must
+ *     be stalled.
+ */
+static inline void ldsr_preemptive_context_save(u32_t thread,
+                                               struct pt_regs *regs)
+{
+       /*
+        * Save the current state of the specified thread
+        */
+       asm volatile (
+       "       move.4  a3, %0                                  \n\t"
+
+               /* set src1 from the target thread */
+       "       move.4  csr, %1                                 \n\t"
+       "       setcsr_flush 0                                  \n\t"
+       "       setcsr_flush 0                                  \n\t"
+
+               /* copy state from the other thread */
+       "       move.4  "D(PT_D0)"(a3), d0                      \n\t"
+       "       move.4  "D(PT_D1)"(a3), d1                      \n\t"
+       "       move.4  "D(PT_D2)"(a3), d2                      \n\t"
+       "       move.4  "D(PT_D3)"(a3), d3                      \n\t"
+       "       move.4  "D(PT_D4)"(a3), d4                      \n\t"
+       "       move.4  "D(PT_D5)"(a3), d5                      \n\t"
+       "       move.4  "D(PT_D6)"(a3), d6                      \n\t"
+       "       move.4  "D(PT_D7)"(a3), d7                      \n\t"
+       "       move.4  "D(PT_D8)"(a3), d8                      \n\t"
+       "       move.4  "D(PT_D9)"(a3), d9                      \n\t"
+       "       move.4  "D(PT_D10)"(a3), d10                    \n\t"
+       "       move.4  "D(PT_D11)"(a3), d11                    \n\t"
+       "       move.4  "D(PT_D12)"(a3), d12                    \n\t"
+       "       move.4  "D(PT_D13)"(a3), d13                    \n\t"
+       "       move.4  "D(PT_D14)"(a3), d14                    \n\t"
+       "       move.4  "D(PT_D15)"(a3), d15                    \n\t"
+       "       move.4  "D(PT_A0)"(a3), a0                      \n\t"
+       "       move.4  "D(PT_A1)"(a3), a1                      \n\t"
+       "       move.4  "D(PT_A2)"(a3), a2                      \n\t"
+       "       move.4  "D(PT_A3)"(a3), a3                      \n\t"
+       "       move.4  "D(PT_A4)"(a3), a4                      \n\t"
+       "       move.4  "D(PT_A5)"(a3), a5                      \n\t"
+       "       move.4  "D(PT_A6)"(a3), a6                      \n\t"
+       "       move.4  "D(PT_SP)"(a3), a7                      \n\t"
+       "       move.4  "D(PT_ACC0HI)"(a3), acc0_hi             \n\t"
+       "       move.4  "D(PT_ACC0LO)"(a3), acc0_lo             \n\t"
+       "       move.4  "D(PT_MAC_RC16)"(a3), mac_rc16          \n\t"
+       "       move.4  "D(PT_ACC1HI)"(a3), acc1_hi             \n\t"
+       "       move.4  "D(PT_ACC1LO)"(a3), acc1_lo             \n\t"
+       "       move.4  "D(PT_SOURCE3)"(a3), source3            \n\t"
+       "       move.4  "D(PT_INST_CNT)"(a3), inst_cnt          \n\t"
+       "       move.4  "D(PT_CSR)"(a3), csr                    \n\t"
+       "       move.4  "D(PT_DUMMY_UNUSED)"(a3), #0            \n\t"
+       "       move.4  "D(PT_INT_MASK0)"(a3), int_mask0        \n\t"
+       "       move.4  "D(PT_INT_MASK1)"(a3), int_mask1        \n\t"
+       "       move.4  "D(PT_TRAP_CAUSE)"(a3), trap_cause      \n\t"
+       "       move.4  "D(PT_PC)"(a3), pc                      \n\t"
+       "       move.4  "D(PT_PREVIOUS_PC)"(a3), previous_pc    \n\t"
+               /* disable csr thread select */
+       "       movei   csr, #0                                 \n\t"
+       "       setcsr_flush 0                                  \n\t"
+       :
+       : "r" (regs->dn), "d" ((thread << 9) | (1 << 8))
+       : "a3"
+       );
+}
+
+/*
+ * ldsr_rotate_threads()
+ *     Simple round robin algorithm for choosing the next cpu
+ */
+static int ldsr_rotate_threads(unsigned long cpus)
+{
+       static unsigned char ldsr_bits[8] = {
+               3, 0, 1, 0, 2, 0, 1, 0
+       };
+
+       static int nextbit;
+       int thisbit;
+
+       /*
+        * Move the interrupts down so that we consider interrupts from where
+        * we left off, then take the interrupts we would lose and move them
+        * to the top half of the interrupts value.
+        */
+       cpus = (cpus >> nextbit) | (cpus << ((sizeof(cpus) * 8) - nextbit));
+
+       /*
+        * 50% of the time we won't take this at all and then of the cases where
+        * we do about 50% of those we only execute once.
+        */
+       if (!(cpus & 0xffff)) {
+               nextbit += 16;
+               cpus >>= 16;
+       }
+
+       if (!(cpus & 0xff)) {
+               nextbit += 8;
+               cpus >>= 8;
+       }
+
+       if (!(cpus & 0xf)) {
+               nextbit += 4;
+               cpus >>= 4;
+       }
+
+       nextbit += ldsr_bits[cpus & 0x7];
+       thisbit = (nextbit & ((sizeof(cpus) * 8) - 1));
+       nextbit = (thisbit + 1) & ((sizeof(cpus) * 8) - 1);
+       DEBUG_ASSERT(thisbit < THREAD_ARCHITECTURAL_MAX);
+       return thisbit;
+}
+
+/*
+ * ldsr_rotate_interrupts()
+ *     Get rotating next set bit value.
+ */
+static int ldsr_rotate_interrupts(unsigned long long interrupts)
+{
+       static unsigned char ldsr_bits[8] = {
+               3, 0, 1, 0, 2, 0, 1, 0
+       };
+
+       static int nextbit;
+       int thisbit;
+
+       /*
+        * Move the interrupts down so that we consider interrupts from where
+        * we left off, then take the interrupts we would lose and move them
+        * to the top half of the interrupts value.
+        */
+       interrupts = (interrupts >> nextbit) |
+               (interrupts << ((sizeof(interrupts) * 8) - nextbit));
+
+       /*
+        * 50% of the time we won't take this at all and then of the cases where
+        * we do about 50% of those we only execute once.
+        */
+       if (!(interrupts & 0xffffffff)) {
+               nextbit += 32;
+               interrupts >>= 32;
+       }
+
+       if (!(interrupts & 0xffff)) {
+               nextbit += 16;
+               interrupts >>= 16;
+       }
+
+       if (!(interrupts & 0xff)) {
+               nextbit += 8;
+               interrupts >>= 8;
+       }
+
+       if (!(interrupts & 0xf)) {
+               nextbit += 4;
+               interrupts >>= 4;
+       }
+
+       nextbit += ldsr_bits[interrupts & 0x7];
+       thisbit = (nextbit & ((sizeof(interrupts) * 8) - 1));
+       nextbit = (thisbit + 1) & ((sizeof(interrupts) * 8) - 1);
+
+       DEBUG_ASSERT(thisbit < (sizeof(interrupts) * 8));
+       return thisbit;
+}
+
+/*
+ * ldsr_backout_or_irq()
+ *
+ * One way or the other this interrupt is not being
+ * processed, make sure that it is reset.  We are
+ * not going to call irq_end_vector() so unmask the
+ * interrupt.
+ */
+static void ldsr_backout_of_irq(int vector, unsigned long tid_mask)
+{
+#if defined(CONFIG_SMP)
+       if (unlikely(vector == smp_ipi_irq)) {
+               smp_reset_ipi(tid_mask);
+       }
+#endif
+       ldsr_unmask_vector(vector);
+       ldsr_interrupt.backout++;
+}
+
+#if defined(CONFIG_IRQSTACKS)
+/*
+ * ldsr_choose_savearea_and_returnvec()
+ *     Test our current state (user, kernel, interrupt) and set things up.
+ *
+ * This version of the function uses 3 stacks and nests interrupts
+ * on the interrupt stack.
+ */
+static struct pt_regs *ldsr_choose_savearea_and_returnvec(thread_t tid, u32_t linux_sp, u32_t *pvec)
+{
+       struct pt_regs *save_area;
+       u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1);
+       struct thread_info * ti= (struct thread_info *)sw_ksp[tid];
+
+#if defined(CONFIG_SMP)
+       union irq_ctx *icp = percpu_irq_ctxs[tid];
+#else
+       union irq_ctx *icp = percpu_irq_ctxs[0];
+#endif
+
+       if (masked_linux_sp == (u32_t)icp) {
+               /*
+                * Fault/Interrupt occurred while on the interrupt stack.
+                */
+               save_area = (struct pt_regs *)((char *)linux_sp - sizeof(struct pt_regs) - 8);
+               *pvec = (u32_t)(&ret_from_interrupt_to_kernel);
+       } else {
+               /*
+                *  Fault/Interrupt occurred while on user/kernel stack.  This is a new
+                *  first use of the interrupt stack.
+                */
+               save_area = (struct pt_regs *) ((char *)icp + sizeof(icp->stack) - sizeof(struct pt_regs) - 8);
+               if (masked_linux_sp == (u32_t)ti) {
+                       *pvec  = (u32_t)(&ret_from_interrupt_to_kernel);
+               } else {
+                       *pvec  = (u32_t)(&ret_from_interrupt_to_user);
+               }
+
+               /*
+                * Because the softirq code will execute on the "interrupt" stack, we
+                * need to maintain the knowledge of what "task" was executing on the
+                * cpu.  This is done by copying the thread_info->task from the cpu
+                * we are about to context switch into the interrupt contexts thread_info
+                * structure.
+                */
+               icp->tinfo.task = ti->task;
+               icp->tinfo.preempt_count =
+                               (icp->tinfo.preempt_count & ~SOFTIRQ_MASK) |
+                               (ti->preempt_count & SOFTIRQ_MASK);
+               icp->tinfo.interrupt_nesting = 0;
+       }
+       save_area->nesting_level = icp->tinfo.interrupt_nesting;
+       return save_area;
+}
+
+#else
+/*
+ * ldsr_choose_savearea_and_returnvec()
+ *     Test our current state (user, kernel, interrupt) and set things up.
+ *
+ * The version of the function uses just the user & kernel stack and
+ * nests interrupts on the existing kernel stack.
+ */
+static struct pt_regs *ldsr_choose_savearea_and_returnvec(thread_t tid, u32_t linux_sp, u32_t *pvec)
+{
+       struct pt_regs *save_area;
+       u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1);
+       struct thread_info *ti = (struct thread_info *)sw_ksp[tid];
+
+       if (masked_linux_sp == (u32_t)ti) {
+               /*
+                * Fault/Interrupt occurred while on the kernel stack.
+                */
+               save_area = (struct pt_regs *)((char *)linux_sp - sizeof(struct pt_regs) - 8);
+               *pvec = (u32_t) (&ret_from_interrupt_to_kernel);
+       } else {
+               /*
+                *  Fault/Interrupt occurred while on user stack.
+                */
+               ti->interrupt_nesting = 0;
+               save_area = (struct pt_regs *)((u32_t)ti + THREAD_SIZE - sizeof(struct pt_regs) - 8);
+               *pvec  = (u32_t) (&ret_from_interrupt_to_user);
+       }
+       save_area->nesting_level = ti->interrupt_nesting;
+       return save_area;
+}
+#endif
+
+/*
+ * ldsr_ctxsw_thread()
+ *     Context switch a mainline thread to execute do_IRQ() for the specified
+ *     vector.
+ */
+static void ldsr_ctxsw_thread(int vector, thread_t tid)
+{
+       u32_t linux_sp;
+       u32_t return_vector;
+       struct pt_regs *save_area, *regs;
+       u32_t thread_mask = (1 << tid);
+       u32_t read_csr = ((tid << 9) | (1 << 8));
+       u32_t write_csr = (tid << 15) | (1 << 14);
+       u32_t interrupt_vector = (u32_t)(&do_IRQ);
+
+       unsigned int frame_type = UBICOM32_FRAME_TYPE_INTERRUPT;
+
+
+       DEBUG_ASSERT(!thread_is_enabled(tid));
+
+       /*
+        * Acquire the necessary global and per thread locks for tid.
+        * As a side effect, we ensure that the thread has not trapped
+        * and return true if it has.
+        */
+       if (unlikely(thread_is_trapped(tid))) {
+               /*
+                * Read the trap cause, the sp and clear the MT_TRAP bits.
+                */
+               unsigned int cause;
+               asm volatile (
+               "       setcsr  %3              \n\t"
+               "       setcsr_flush 0          \n\t"
+               "       setcsr_flush 0          \n\t"
+               "       move.4  %0, TRAP_CAUSE  \n\t"
+               "       move.4  %1, SP          \n\t"
+               "       setcsr  #0              \n\t"
+               "       setcsr_flush 0          \n\t"
+               "       move.4  MT_BREAK_CLR, %2\n\t"
+               "       move.4  MT_TRAP_CLR, %2 \n\t"
+                       : "=&r" (cause), "=&r" (linux_sp)
+                       : "r" (thread_mask), "m" (read_csr)
+               );
+
+               ldsr_backout_of_irq(vector, (1 << tid));
+
+#if !defined(CONFIG_UNALIGNED_ACCESS_DISABLED)
+               /*
+                * See if the unaligned trap handler can deal with this.
+                * If so, emulate the instruction and then just restart
+                * the thread.
+                */
+               if (unaligned_only(cause)) {
+#if defined(CONFIG_UNALIGNED_ACCESS_USERSPACE_ONLY)
+                       /*
+                        * Check if this is a kernel stack if so we will not
+                        * handle the trap
+                        */
+                       u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1);
+                       if ((masked_linux_sp != (u32_t)sw_ksp[tid]) &&
+                           unaligned_only(cause)) {
+                               ldsr_emulate_and_run(tid);
+                               return;
+                       }
+#else
+                       ldsr_emulate_and_run(tid);
+                       return;
+#endif
+
+               }
+#endif
+
+               interrupt_vector = (u32_t)(&trap_handler);
+               frame_type = UBICOM32_FRAME_TYPE_TRAP;
+       } else {
+               /*
+                * Read the target thread's SP
+                */
+               asm volatile (
+               "       setcsr  %1              \n\t"
+               "       setcsr_flush 0          \n\t"
+               "       setcsr_flush 0          \n\t"
+               "       move.4  %0, SP          \n\t"
+               "       setcsr  #0              \n\t"
+               "       setcsr_flush 0          \n\t"
+                       : "=m" (linux_sp)
+                       : "m" (read_csr)
+               );
+       }
+
+       /*
+        * We are delivering an interrupt, count it.
+        */
+       ldsr_interrupt.total++;
+
+       /*
+        * At this point, we will definitely force this thread to
+        * a new context, show its interrupts as disabled.
+        */
+       ldsr_thread_irq_disable(tid);
+
+       /*
+        * Test our current state (user, kernel, interrupt).  Save the
+        * appropriate data and setup for the return.
+        */
+       save_area = ldsr_choose_savearea_and_returnvec(tid, linux_sp, &return_vector);
+
+       /*
+        *  The pt_regs (save_area) contains the type of thread that we are dealing
+        *  with (KERNEL/NORMAL) and is copied into each pt_regs area.  We get this
+        *  from the current tasks kernel pt_regs area that always exists at the
+        *  top of the kernel stack.
+        */
+       regs = (struct pt_regs *)((u32_t)sw_ksp[tid] + THREAD_SIZE - sizeof(struct pt_regs) - 8);
+       save_area->thread_type = regs->thread_type;
+
+       /*
+        * Preserve the context of the Linux thread.
+        */
+       ldsr_preemptive_context_save(tid, save_area);
+
+       /*
+        * Load the fram_type into the save_area.
+        */
+       save_area->frame_type = frame_type;
+
+#ifdef CONFIG_STOP_ON_TRAP
+       /*
+        * Before we get backtrace and showing stacks working well, it sometimes
+        * helps to enter the debugger when a trap occurs before we change the
+        * thread to handle the fault.  This optional code causes all threads to
+        * stop on every trap frame.  One assumes that GDB connected via the
+        * mailbox interface will be used to recover from this state.
+        */
+       if (frame_type == UBICOM32_FRAME_TYPE_TRAP) {
+               THREAD_STALL;
+       }
+#endif
+
+#ifdef DEBUG_LDSR
+       copy_regs = *save_area;
+       copy_save_area = save_area;
+
+       old_a0 = save_area->an[0];
+       old_a3 = save_area->an[3];
+       old_sp = save_area->an[7];
+       old_a5 = save_area->an[5];
+       old_pc = save_area->pc;
+#endif
+
+       /*
+        * Now we have to switch the kernel thread to run do_IRQ function.
+        *      Set pc to do_IRQ
+        *      Set d0 to vector
+        *      Set d1 to save_area.
+        *      Set a5 to the proper return vector.
+        */
+       asm volatile (
+       "       setcsr  %0                      \n\t"
+       "       setcsr_flush 0                  \n\t"
+       "       move.4  d0, %5                  \n\t" /* d0 = 0 vector # */
+       "       move.4  d1, %1                  \n\t" /* d1 = save_area */
+       "       move.4  sp, %1                  \n\t" /* sp = save_area */
+       "       move.4  a5, %2                  \n\t" /* a5 = return_vector */
+       "       move.4  pc, %3                  \n\t" /* pc = do_IRQ routine. */
+       "       move.4  trap_cause, #0          \n\t" /* Clear the trap cause
+                                                      * register */
+       "       setcsr  #0                      \n\t"
+       "       setcsr_flush 0                  \n\t"
+       "       enable_kernel_ranges %4         \n\t"
+       "       move.4  mt_dbg_active_set, %4   \n\t" /* Activate thread even if
+                                                      * in dbg/fault state */
+       "       move.4  mt_active_set, %4       \n\t" /* Restart target
+                                                      * thread. */
+               :
+               : "r" (write_csr), "r" (save_area),
+                 "r" (return_vector), "r" (interrupt_vector),
+                 "d" (thread_mask), "r" (vector)
+               : "cc"
+       );
+       thread_enable_mask(thread_mask);
+}
+
+/*
+ * ldsr_deliver_interrupt()
+ *     Deliver the interrupt to one of the threads or all of the threads.
+ */
+static void ldsr_deliver_interrupt(int vector,
+                                  unsigned long deliver_to,
+                                  int all)
+{
+       unsigned long disabled_threads;
+       unsigned long possible_threads;
+       unsigned long trapped_threads;
+       unsigned long global_locks;
+
+       /*
+        * Disable all of the threads that we might want to send
+        * this interrupt to.
+        */
+retry:
+       DEBUG_ASSERT(deliver_to);
+       thread_disable_mask(deliver_to);
+
+       /*
+        * If any threads are in the trap state, we have to service the
+        * trap for those threads first.
+        */
+       asm volatile (
+               "move.4 %0, MT_TRAP             \n\t"
+               : "=r" (trapped_threads)
+               :
+       );
+
+       trapped_threads &= deliver_to;
+       if (unlikely(trapped_threads)) {
+               /*
+                * all traps will be handled, so clear the trap bit before restarting any threads
+                */
+               ubicom32_clear_interrupt(ldsr_trap_irq);
+
+               /*
+                * Let the remaining untrapped threads, continue.
+                */
+               deliver_to &= ~trapped_threads;
+               if (deliver_to) {
+                       thread_enable_mask(deliver_to);
+               }
+
+               /*
+                * For the trapped threads force them to handle
+                * a trap.
+                */
+               while (trapped_threads) {
+                       unsigned long which = ffz(~trapped_threads);
+                       trapped_threads &= ~(1 << which);
+                       ldsr_ctxsw_thread(vector, which);
+               }
+               return;
+       }
+
+       /*
+        * Can we deliver an interrupt to any of the threads?
+        */
+       disabled_threads = ldsr_thread_get_interrupts();
+       possible_threads = deliver_to & ~disabled_threads;
+       if (unlikely(!possible_threads)) {
+#if defined(CONFIG_SMP)
+               /*
+                * In the SMP case, we can not wait because 1 cpu might be
+                * sending an IPI to another cpu which is currently blocked.
+                * The only way to ensure IPI delivery is to backout and
+                * keep trying.  For SMP, we don't sleep until the interrupts
+                * are delivered.
+                */
+               thread_enable_mask(deliver_to);
+               ldsr_backout_of_irq(vector, deliver_to);
+               return;
+#else
+               /*
+                * In the UP case, we have nothing to do so we should wait.
+                *
+                * Since the INT_MASK0 and INT_MASK1 are "re-loaded" before we
+                * suspend in the outer loop, we do not need to save them here.
+                *
+                * We test that we were awakened for our specific interrupts
+                * because the ldsr mask/unmask operations will force the ldsr
+                * awake even if the interrupt on the mainline thread is not
+                * completed.
+                */
+               unsigned int scratch = 0;
+               thread_enable_mask(deliver_to);
+               asm volatile (
+               "       move.4  INT_MASK0, %1           \n\t"
+               "       move.4  INT_MASK1, #0           \n\t"
+
+               "1:     suspend                         \n\t"
+               "       move.4  %0, INT_STAT0           \n\t"
+               "       and.4   %0, %0, %1              \n\t"
+               "       jmpeq.f 1b                      \n\t"
+
+               "       move.4  INT_CLR0, %2            \n\t"
+                       : "+r" (scratch)
+                       : "d" (ldsr_suspend_mask), "r" (ldsr_soft_irq_mask)
+                       : "cc"
+               );
+
+               /*
+                * This delay is sized to coincide with the time it takes a
+                * thread to complete the exit (see return_from_interrupt).
+                */
+               ldsr_interrupt.retry++;
+               __delay(10);
+               goto retry;
+#endif
+       }
+
+       /*
+        * If any of the global locks are held, we can not deliver any
+        * interrupts, we spin delay(10) and then try again.  If our
+        * spinning becomes a bottle neck, we will need to suspend but for
+        * now lets just spin.
+        */
+       asm volatile (
+               "move.4 %0, scratchpad1         \n\t"
+               : "=r" (global_locks)
+               :
+       );
+       if (unlikely(global_locks & 0xffff0000)) {
+               thread_enable_mask(deliver_to);
+
+               /*
+                * This delay is sized to coincide with the average time it
+                * takes a thread to release a global lock.
+                */
+               ldsr_interrupt.retry++;
+               __delay(10);
+               goto retry;
+       }
+
+       /*
+        * Deliver to one cpu.
+        */
+       if (!all) {
+               /*
+                * Find our victim and then enable everyone else.
+                */
+               unsigned long victim = ldsr_rotate_threads(possible_threads);
+               DEBUG_ASSERT((deliver_to & (1 << victim)));
+               DEBUG_ASSERT((possible_threads & (1 << victim)));
+
+               deliver_to &= ~(1 << victim);
+               if (deliver_to) {
+                       thread_enable_mask(deliver_to);
+               }
+               ldsr_ctxsw_thread(vector, victim);
+               return;
+       }
+
+       /*
+        * If we can't deliver to some threads, wake them
+        * back up and reset things to deliver to them.
+        */
+       deliver_to &= ~possible_threads;
+       if (unlikely(deliver_to)) {
+               thread_enable_mask(deliver_to);
+               ldsr_backout_of_irq(vector, deliver_to);
+       }
+
+       /*
+        * Deliver to all possible threads(s).
+        */
+       while (possible_threads) {
+               unsigned long victim = ffz(~possible_threads);
+               possible_threads &= ~(1 << victim);
+               ldsr_ctxsw_thread(vector, victim);
+       }
+}
+
+/*
+ * ldsr_thread()
+ *     This thread acts as the interrupt controller for Linux.
+ */
+static void ldsr_thread(void *arg)
+{
+       int stat0;
+       int stat1;
+       int interrupt0;
+       int interrupt1;
+       long long interrupts;
+       unsigned long cpus;
+
+#if !defined(CONFIG_SMP)
+       /*
+        * In a non-smp configuration, we can not use the cpu(s) arrays because
+        * there is not a 1-1 correspondence between cpus(s) and our threads.
+        * Thus we must get a local idea of the mainline threads and use the
+        * one and only 1 set as the victim.  We do this once before the ldsr
+        * loop.
+        *
+        * In the SMP case, we will use the cpu(s) map to determine which cpu(s)
+        * are valid to send interrupts to.
+        */
+       int victim = 0;
+       unsigned int mainline = thread_get_mainline();
+       if (mainline == 0) {
+               panic("no mainline Linux threads to interrupt");
+               return;
+       }
+       victim = ffz(~mainline);
+       cpus = (1 << victim);
+#endif
+
+       while (1) {
+               /*
+                * If one changes this code not to reload the INT_MASK(s), you
+                * need to know that code in the lock waiting above does not
+                * reset the MASK registers back; so that code will need to be
+                * changed.
+                */
+               ldsr_lock_acquire();
+               asm volatile (
+               "       move.4 INT_MASK0, %0    \n\t"
+               "       move.4 INT_MASK1, %1    \n\t"
+                       :
+                       : "U4" (ldsr_interrupt.mask0), "U4" (ldsr_interrupt.mask1)
+               );
+               ldsr_lock_release();
+               thread_suspend();
+
+               /*
+                * Read the interrupt status registers
+                */
+               asm volatile (
+                       "move.4 %0, INT_STAT0   \n\t"
+                       "move.4 %1, INT_STAT1   \n\t"
+                       : "=r" (stat0), "=r" (stat1)
+                       :
+               );
+
+               /*
+                * We only care about interrupts that we have been told to care
+                * about.  The interrupt must be enabled, unmasked, and have
+                * occurred in the hardware.
+                */
+               ldsr_lock_acquire();
+               interrupt0 = ldsr_interrupt.enabled0 &
+                       ldsr_interrupt.mask0 & stat0;
+               interrupt1 = ldsr_interrupt.enabled1 &
+                       ldsr_interrupt.mask1 & stat1;
+               ldsr_lock_release();
+
+               /*
+                * For each interrupt in the "snapshot" we will mask the
+                * interrupt handle the interrupt (typically calling do_IRQ()).
+                *
+                * The interrupt is unmasked by desc->chip->end() function in
+                * the per chip generic interrupt handling code
+                * (arch/ubicom32/kernel/irq.c).8
+                */
+               interrupts = ((unsigned long long)interrupt1 << 32) |
+                       interrupt0;
+               while (interrupts) {
+                       int all = 0;
+                       int vector = ldsr_rotate_interrupts(interrupts);
+                       interrupts &= ~((unsigned long long)1 << vector);
+
+                       /*
+                        * Now mask off this vector so that the LDSR ignores
+                        * it until it is acknowledged.
+                        */
+                       ldsr_mask_vector(vector);
+#if !defined(CONFIG_SMP)
+                       ldsr_deliver_interrupt(vector, cpus, all);
+#else
+                       cpus = smp_get_affinity(vector, &all);
+                       if (!cpus) {
+                               /*
+                                * No CPU to deliver to so just leave
+                                * the interrupt unmasked and increase
+                                * the backout count.  We will eventually
+                                * return and deliver it again.
+                                */
+                               ldsr_unmask_vector(vector);
+                               ldsr_interrupt.backout++;
+                               continue;
+                       }
+                       ldsr_deliver_interrupt(vector, cpus, all);
+#endif
+               }
+       }
+
+       /* NOTREACHED */
+}
+
+/*
+ * ldsr_mask_vector()
+ *     Temporarily mask the interrupt vector, turn off the bit in the mask
+ *     register.
+ */
+void ldsr_mask_vector(unsigned int vector)
+{
+       unsigned int mask;
+       if (vector < 32) {
+               mask = ~(1 << vector);
+               ldsr_lock_acquire();
+               ldsr_interrupt.mask0 &= mask;
+               ldsr_lock_release();
+               thread_resume(ldsr_tid);
+               return;
+       }
+
+       mask = ~(1 << (vector - 32));
+       ldsr_lock_acquire();
+       ldsr_interrupt.mask1 &= mask;
+       ldsr_lock_release();
+       thread_resume(ldsr_tid);
+}
+
+/*
+ * ldsr_unmask_vector()
+ *     Unmask the interrupt vector so that it can be used, turn on the bit in
+ *     the mask register.
+ *
+ * Because it is legal for the interrupt path to disable an interrupt,
+ * the unmasking code must ensure that disabled interrupts are not
+ * unmasked.
+ */
+void ldsr_unmask_vector(unsigned int vector)
+{
+       unsigned int mask;
+       if (vector < 32) {
+               mask = (1 << vector);
+               ldsr_lock_acquire();
+               ldsr_interrupt.mask0 |= (mask & ldsr_interrupt.enabled0);
+               ldsr_lock_release();
+               thread_resume(ldsr_tid);
+               return;
+       }
+
+       mask = (1 << (vector - 32));
+       ldsr_lock_acquire();
+       ldsr_interrupt.mask1 |= (mask & ldsr_interrupt.enabled1);
+       ldsr_lock_release();
+       thread_resume(ldsr_tid);
+}
+
+/*
+ * ldsr_enable_vector()
+ *     The LDSR implements an interrupt controller and has a local (to the
+ *     LDSR) copy of its interrupt mask.
+ */
+void ldsr_enable_vector(unsigned int vector)
+{
+       unsigned int mask;
+       if (vector < 32) {
+               mask = (1 << vector);
+               ldsr_lock_acquire();
+               ldsr_interrupt.enabled0 |= mask;
+               ldsr_interrupt.mask0 |= mask;
+               ldsr_lock_release();
+               thread_resume(ldsr_tid);
+               return;
+       }
+
+       mask = (1 << (vector - 32));
+       ldsr_lock_acquire();
+       ldsr_interrupt.enabled1 |= mask;
+       ldsr_interrupt.mask1 |= mask;
+       ldsr_lock_release();
+       thread_resume(ldsr_tid);
+}
+
+/*
+ * ldsr_disable_vector()
+ *     The LDSR implements an interrupt controller and has a local (to the
+ *     LDSR) copy of its interrupt mask.
+ */
+void ldsr_disable_vector(unsigned int vector)
+{
+       unsigned int mask;
+
+       if (vector < 32) {
+               mask = ~(1 << vector);
+               ldsr_lock_acquire();
+               ldsr_interrupt.enabled0 &= mask;
+               ldsr_interrupt.mask0 &= mask;
+               ldsr_lock_release();
+               thread_resume(ldsr_tid);
+               return;
+       }
+
+       mask = ~(1 << (vector - 32));
+       ldsr_lock_acquire();
+       ldsr_interrupt.enabled1 &= mask;
+       ldsr_interrupt.mask1 &= mask;
+       ldsr_lock_release();
+       thread_resume(ldsr_tid);
+}
+
+/*
+ * ldsr_get_threadid()
+ *     Return the threadid of the LDSR thread.
+ */
+thread_t ldsr_get_threadid(void)
+{
+       return ldsr_tid;
+}
+
+/*
+ * ldsr_set_trap_irq()
+ *     Save away the trap Soft IRQ
+ *
+ * See the per thread lock suspend code above for an explination.
+ */
+void ldsr_set_trap_irq(unsigned int irq)
+{
+       ldsr_trap_irq = irq;
+       ldsr_trap_irq_mask = (1 << irq);
+       ldsr_suspend_mask |= ldsr_trap_irq_mask;
+}
+
+/*
+ * ldsr_init()
+ *     Initialize the LDSR (Interrupt Controller)
+ */
+void ldsr_init(void)
+{
+#if defined(CONFIG_IRQSTACKS)
+       int i;
+       union irq_ctx *icp;
+#endif
+
+       void *stack_high = (void *)ldsr_stack_space;
+       stack_high += sizeof(ldsr_stack_space);
+       stack_high -= 8;
+
+
+       /*
+        * Obtain a soft IRQ to use
+        */
+       if (irq_soft_alloc(&ldsr_soft_irq) < 0) {
+               panic("no software IRQ is available\n");
+               return;
+       }
+       ldsr_soft_irq_mask |= (1 << ldsr_soft_irq);
+       ldsr_suspend_mask |= ldsr_soft_irq_mask;
+
+       /*
+        * Now allocate and start the LDSR thread.
+        */
+       ldsr_tid = thread_alloc();
+       if (ldsr_tid < 0) {
+               panic("no thread available to run LDSR");
+               return;
+       }
+
+#if defined(CONFIG_IRQSTACKS)
+       /*
+        * Initialize the per-cpu irq thread_info structure that
+        * is at the top of each per-cpu irq stack.
+        */
+       icp = (union irq_ctx *)
+               (((unsigned long)percpu_irq_stacks + (THREAD_SIZE - 1)) & ~(THREAD_SIZE - 1));
+       for (i = 0; i < NR_CPUS; i++) {
+               struct thread_info *ti = &(icp->tinfo);
+               ti->task = NULL;
+               ti->exec_domain = NULL;
+               ti->cpu = i;
+               ti->preempt_count = 0;
+               ti->interrupt_nesting = 0;
+               percpu_irq_ctxs[i] = icp++;
+       }
+#endif
+       thread_start(ldsr_tid, ldsr_thread, NULL,
+                    stack_high, THREAD_TYPE_NORMAL);
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/module.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/module.c
new file mode 100644 (file)
index 0000000..3d29dc2
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * arch/ubicom32/kernel/module.c
+ *   Ubicom32 architecture loadable module support.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/moduleloader.h>
+#include <linux/bug.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <asm/ocm-alloc.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+static void _module_free_ocm(struct module *mod)
+{
+       printk(KERN_INFO "module arch cleanup %s: OCM instruction memory free "
+              " of %d @%p\n", mod->name, mod->arch.ocm_inst_size,
+              mod->arch.ocm_inst);
+
+       if (mod->arch.ocm_inst) {
+               ocm_inst_free(mod->arch.ocm_inst);
+               mod->arch.ocm_inst = 0;
+               mod->arch.ocm_inst_size = 0;
+       }
+}
+
+void *module_alloc(unsigned long size)
+{
+       if (size == 0)
+               return NULL;
+       return vmalloc(size);
+}
+
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+       vfree(module_region);
+       /* FIXME: If module_region == mod->init_region, trim exception
+          table entries. */
+
+       /*
+        * This is expected to be final module free, use this to prune the
+        * ocm
+        */
+       if (module_region && module_region == mod->module_core)
+               _module_free_ocm(mod);
+
+}
+
+/*
+ * module_frob_arch_sections()
+ *     Called from kernel/module.c allowing arch specific handling of
+ *     sections/headers.
+ */
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+                             Elf_Shdr *sechdrs,
+                             char *secstrings,
+                             struct module *mod)
+{
+       Elf_Shdr *s, *sechdrs_end;
+       void *ocm_inst = NULL;
+       int ocm_inst_size = 0;
+
+       /*
+        * Ubicom32 v3 and v4 are almost binary compatible but not completely.
+        * To be safe check that the module was compiled with the correct -march
+        * which is flags.
+        */
+#ifdef CONFIG_UBICOM32_V4
+       if ((hdr->e_flags & 0xFFFF) != EF_UBICOM32_V4) {
+               printk(KERN_WARNING "Module %s was not compiled for "
+                      "ubicom32v4, elf_flags:%x,\n",
+                      mod->name, hdr->e_flags);
+               return -ENOEXEC;
+       }
+#elif defined CONFIG_UBICOM32_V3
+       if ((hdr->e_flags & 0xFFFF) != EF_UBICOM32_V3) {
+               printk(KERN_WARNING "Module %s was not compiled for "
+                      "ubicom32v3, elf_flags:%x\n",
+                      mod->name, hdr->e_flags);
+               return -ENOEXEC;
+       }
+#else
+#error Unknown/Unsupported ubicom32 architecture.
+#endif
+
+       /*
+        * XXX: sechdrs are vmalloced in kernel/module.c
+        * and would be vfreed just after module is loaded,
+        * so we hack to keep the only information we needed
+        * in mod->arch to correctly free L1 I/D sram later.
+        * NOTE: this breaks the semantic of mod->arch structure.
+        */
+       sechdrs_end = sechdrs + hdr->e_shnum;
+       for (s = sechdrs; s < sechdrs_end; ++s) {
+               if (strncmp(".ocm_text", secstrings + s->sh_name, 9) == 0)
+                       ocm_inst_size += s->sh_size;
+       }
+
+       if (!ocm_inst_size)
+               return 0;
+
+       ocm_inst = ocm_inst_alloc(ocm_inst_size, 0 /* internal */);
+       if (ocm_inst == NULL) {
+#ifdef CONFIG_OCM_MODULES_FALLBACK_TO_DDR
+               printk(KERN_WARNING
+                      "module %s: OCM instruction memory allocation of %d"
+                      "failed, fallback to DDR\n", mod->name, ocm_inst_size);
+               return 0;
+#else
+               printk(KERN_ERR
+                      "module %s: OCM instruction memory allocation of %d"
+                      "failed.\n", mod->name, ocm_inst_size);
+               return -ENOMEM;
+#endif
+       }
+
+       mod->arch.ocm_inst = ocm_inst;
+       mod->arch.ocm_inst_size = ocm_inst_size;
+
+       printk(KERN_INFO
+              "module %s: OCM instruction memory allocation of %d @%p\n",
+              mod->name, mod->arch.ocm_inst_size, mod->arch.ocm_inst);
+
+       for (s = sechdrs; s < sechdrs_end; ++s) {
+               if (strncmp(".ocm_text", secstrings + s->sh_name, 9) == 0) {
+                       memcpy(ocm_inst, (void *)s->sh_addr, s->sh_size);
+                       s->sh_flags &= ~SHF_ALLOC;
+                       s->sh_addr = (unsigned long)ocm_inst;
+                       ocm_inst += s->sh_size;
+               }
+       }
+
+       return 0;
+}
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+                  const char *strtab,
+                  unsigned int symindex,
+                  unsigned int relsec,
+                  struct module *me)
+{
+       DEBUGP("Invalid Applying relocate section %u to %u\n", relsec,
+              sechdrs[relsec].sh_info);
+       return -EINVAL;
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+                      const char *strtab,
+                      unsigned int symindex,
+                      unsigned int relsec,
+                      struct module *me)
+{
+       unsigned int i;
+       Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+       Elf32_Sym *sym;
+       uint32_t *location;
+       uint32_t insn;
+
+       DEBUGP("Applying relocate_add section %u to %u\n", relsec,
+              sechdrs[relsec].sh_info);
+       for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+               uint32_t v;
+               const int elf32_rtype = ELF32_R_TYPE(rel[i].r_info);
+
+               /* This is where to make the change */
+               location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+                       + rel[i].r_offset;
+               /* This is the symbol it is referring to.  Note that all
+                  undefined symbols have been resolved.  */
+               sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+                       + ELF32_R_SYM(rel[i].r_info);
+
+               v = rel[i].r_addend + sym->st_value;
+
+
+               switch (elf32_rtype) {
+               case R_UBICOM32_32:
+               {
+                       /*
+                        * Store the 32 bit relocation as is.
+                        */
+                       *location = v;
+                       break;
+               }
+               case R_UBICOM32_HI24:
+               {
+                       /*
+                        * 24 bit relocation that is part of the MOVEAI
+                        * instruction. The 24 bits come from bits 7 - 30 of the
+                        * relocation. Theses bits eventually get split into 2
+                        * fields in the instruction encoding.
+                        *
+                        * - Bits 7 - 27 of the relocation are encoded into bits
+                        * 0 - 20 of the instruction.
+                        *
+                        *  - Bits 28 - 30 of the relocation are encoded into
+                        *  bit 24 - 26 of the instruction.
+                        */
+                       uint32_t valid24 = (v >> 7) & 0xffffff;
+                       insn = *location;
+
+                       insn &= ~(0x1fffff | (0x7 << 24));
+                       insn |= (valid24 & 0x1fffff);
+                       insn |= ((valid24 & 0xe00000) << 3);
+                       *location = insn;
+               }
+               break;
+               case R_UBICOM32_LO7_S:
+               case R_UBICOM32_LO7_2_S:
+               case R_UBICOM32_LO7_4_S:
+               {
+                       /*
+                        * Bits 0 - 6 of the relocation are encoded into the
+                        * 7bit unsigned immediate fields of the SOURCE-1 field
+                        * of the instruction.  The immediate value is left
+                        * shifted by (0, 1, 2) based on the operand size.
+                        */
+                       uint32_t valid7 = v & 0x7f;
+                       insn = *location;
+
+                       if (elf32_rtype == R_UBICOM32_LO7_2_S) {
+                               valid7 >>= 1;
+                       } else if (elf32_rtype == R_UBICOM32_LO7_4_S) {
+                               valid7 >>= 2;
+                       }
+
+                       insn &= ~(0x1f | (0x3 << 8));
+                       insn |= (valid7 & 0x1f);
+                       insn |= ((valid7 & 0x60) << 3);
+                       *location = insn;
+               }
+               break;
+               case R_UBICOM32_LO7_D:
+               case R_UBICOM32_LO7_2_D:
+               case R_UBICOM32_LO7_4_D:
+               {
+                       /*
+                        * Bits 0 - 6 of the relocation are encoded into the
+                        * 7bit unsigned immediate fields of the DESTINATION
+                        * field of the instruction.  The immediate value is
+                        * left shifted by (0, 1, 2) based on the operand size.
+                        */
+                       uint32_t valid7 = v & 0x7f;
+                       insn = *location;
+
+                       if (elf32_rtype == R_UBICOM32_LO7_2_D) {
+                               valid7 >>= 1;
+                       } else if (elf32_rtype == R_UBICOM32_LO7_4_D) {
+                               valid7 >>= 2;
+                       }
+
+                       insn &= ~((0x1f | (0x3 << 8)) << 16);
+                       insn |= ((valid7 & 0x1f) << 16);
+                       insn |= ((valid7 & 0x60) << 19);
+                       *location = insn;
+               }
+               break;
+               case R_UBICOM32_LO7_CALLI:
+               case R_UBICOM32_LO16_CALLI:
+               {
+                       /*
+                        * Extract the offset for a CALLI instruction. The
+                        * offsets can be either 7 bits or 18 bits. Since all
+                        * instructions in ubicom32 architecture are at work
+                        * aligned addresses the truncated offset is right
+                        * shifted by 2 before being encoded in the instruction.
+                        */
+                       uint32_t val;
+                       if (elf32_rtype == R_UBICOM32_LO7_CALLI) {
+                               val  = v & 0x7f;
+                       } else {
+                               val  = v & 0x3ffff;
+                       }
+
+                       val >>= 2;
+
+                       insn = *location;
+
+                       insn &= ~0x071f071f;
+                       insn |= (val & 0x1f) << 0;
+                       val >>= 5;
+                       insn |= (val & 0x07) << 8;
+                       val >>= 3;
+                       insn |= (val & 0x1f) << 16;
+                       val >>= 5;
+                       insn |= (val & 0x07) << 24;
+                       *location = insn;
+               }
+               break;
+               case R_UBICOM32_24_PCREL:
+               {
+                       /*
+                        * Extract 26 bit signed PC relative offset for CALL
+                        * instructions. Since instruction addresses are word
+                        * aligned the offset is right shited by 2 before
+                        * encoding into instruction.
+                        */
+                       int32_t val = v - (int32_t)location;
+
+                       /*
+                        * Check that the top 7 bits are all equal to the sign
+                        * bit (26), i.e all 0's or all 1's.  If they are not then
+                        * the absolute difference is greater than 25 bits.
+                        */
+                       if (((uint32_t)val & 0xFE000000) != 0xFE000000 &&
+                               ((uint32_t)val & 0xFE000000) != 0x0) {
+                               /*
+                                * The relocation is beyond our addressable
+                                * range with a 26 bit call.
+                                */
+                               printk(KERN_ERR "module %s: PC Relative "
+                                       "relocation out of range: "
+                                       "%u (%x->%x, %x)\n",
+                                       me->name, elf32_rtype,
+                                       v, (uint32_t) location, val);
+                               return -ENOEXEC;
+                       }
+
+                       val = (val & 0x3ffffff) >> 2;
+                       insn = *location;
+                       insn = insn & 0xf8e00000;
+
+                       insn |= (val >> 21) << 24;
+                       insn |= (val & 0x1fffff);
+                       *location = insn;
+               }
+               break;
+               case R_UBICOM32_LO16:
+               case R_UBICOM32_HI16:
+               {
+                       /*
+                        * 16 bit immediate value that is encoded into bit 0 -
+                        * 15 of the instruction.
+                        */
+                       uint32_t val;
+
+                       if (elf32_rtype == R_UBICOM32_LO16) {
+                               val  = v & 0xffff;
+                       } else {
+                               val  = (v >> 16) & 0xffff;
+                       }
+
+                       insn = *location;
+                       insn &= 0xffff0000;
+
+                       insn |= val;
+                       *location = insn;
+               }
+               break;
+               case R_UBICOM32_21_PCREL:
+               {
+                       /*
+                        * Extract 23 bit signed PC relative offset for JMP<cc>
+                        * instructions. Since instruction addresses are word
+                        * aligned the offset is right shited by 2 before
+                        * encoding into instruction.
+                        */
+                       int32_t val = v - (int32_t)location;
+
+                       val = (val & 0x7fffff) >> 2;
+                       insn = *location;
+                       insn = insn & 0xffe00000;
+
+                       insn |= (val >> 21) << 24;
+                       insn |= val;
+                       *location = insn;
+               }
+               break;
+               default:
+                       BUG();
+                       printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+                              me->name, elf32_rtype);
+                       return -ENOEXEC;
+               }
+       }
+       return 0;
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+                   const Elf_Shdr *sechdrs,
+                   struct module *mod)
+{
+       unsigned int i, strindex = 0, symindex = 0;
+       char *secstrings;
+       int err;
+
+       err = module_bug_finalize(hdr, sechdrs, mod);
+       if (err)
+               return err;
+
+       if (!mod->arch.ocm_inst) {
+               /*
+                * No OCM code, so nothing more to do.
+                */
+               return 0;
+       }
+
+       secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+       for (i = 1; i < hdr->e_shnum; i++) {
+               /* Internal symbols and strings. */
+               if (sechdrs[i].sh_type == SHT_SYMTAB) {
+                       symindex = i;
+                       strindex = sechdrs[i].sh_link;
+               }
+       }
+
+       for (i = 1; i < hdr->e_shnum; i++) {
+               const char *strtab = (char *)sechdrs[strindex].sh_addr;
+               unsigned int info = sechdrs[i].sh_info;
+
+               /* Not a valid relocation section? */
+               if (info >= hdr->e_shnum)
+                       continue;
+
+               if ((sechdrs[i].sh_type == SHT_RELA) &&
+                   (strncmp(".rela.ocm_text",
+                            secstrings + sechdrs[i].sh_name, 5 + 9) == 0)) {
+                       err = apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
+                                                symindex, i, mod);
+                       if (err)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+       module_bug_cleanup(mod);
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/os_node.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/os_node.c
new file mode 100644 (file)
index 0000000..9e014d5
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * arch/ubicom32/kernel/os_node.c
+ *   <TODO: Replace with short file description>
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "linux/types.h"
+#include "linux/linkage.h"
+#include "linux/uts.h"
+#include "linux/utsrelease.h"
+#include "linux/version.h"
+#include <asm/ocm_size.h>
+#include <asm/devtree.h>
+#include <asm/ip5000.h>
+
+extern asmlinkage void *_start;
+
+/*
+ * This file provides static information to the boot code allowing it to decide
+ * if the os is compatible. Thus hopefully enabling the boot code to prevent
+ * accidentally booting a kernel that has no hope of running.
+ */
+struct os_node {
+       struct devtree_node node;
+       unsigned long version; /* Always 1 */
+       unsigned long entry_point;
+       const char    os_name[32]; /* For diagnostic purposes only */
+       const char    os_version_str[32];
+       unsigned long os_version_num;
+       unsigned long expected_ocm_code_start;/* OS Code */
+       unsigned long expected_ocm_data_end;  /* OS Data */
+       unsigned long expected_ram_start;
+       unsigned long expected_ram_end;
+       unsigned long arch_version;
+       unsigned long expected_os_syscall_begin;
+       unsigned long expected_os_syscall_end;
+};
+
+
+extern void __os_syscall_begin;
+extern void __os_syscall_end;
+/*
+ * The os_node is only referenced by head.S and should never be modified at
+ * run-time.
+ */
+asmlinkage const struct os_node _os_node = {
+       .node = {
+               .next = NULL,
+               .name = { "OS" },
+               .magic = 0x10203040,
+       },
+       .version = 0x10002,
+       .entry_point = (unsigned long)&_start,
+#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE
+       .expected_ocm_code_start = OCMSTART + APP_OCM_CODE_SIZE,
+       .expected_ocm_data_end   = OCMEND   - APP_OCM_DATA_SIZE,
+#else
+       .expected_ocm_code_start = OCMEND,
+       .expected_ocm_data_end   = OCMEND,
+#endif
+       .os_name = { UTS_SYSNAME },
+       .os_version_str = { UTS_RELEASE },
+       .os_version_num = LINUX_VERSION_CODE,
+       .expected_ram_start = KERNELSTART,
+       .expected_ram_end = SDRAMSTART + CONFIG_MIN_RAMSIZE,
+       .arch_version = UBICOM32_ARCH_VERSION,
+       .expected_os_syscall_begin = (unsigned long)&__os_syscall_begin,
+       .expected_os_syscall_end = (unsigned long)&__os_syscall_end,
+
+
+};
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/process.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/process.c
new file mode 100644 (file)
index 0000000..23872fe
--- /dev/null
@@ -0,0 +1,634 @@
+/*
+ * arch/ubicom32/kernel/process.c
+ *   Ubicom32 architecture-dependent process handling.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 1995  Hamish Macdonald
+ *
+ * 68060 fixes by Jesper Skov
+ *
+ * uClinux changes
+ * Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com>
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/fs.h>
+#include <linux/pm.h>
+
+#include <linux/uaccess.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/machdep.h>
+#include <asm/setup.h>
+#include <asm/pgtable.h>
+#include <asm/ip5000.h>
+#include <asm/range-protect.h>
+
+#define DUMP_RANGE_REGISTER(REG, IDX) asm volatile ( \
+        "       move.4          %0, "REG"_RANGE"IDX"_EN \n\t" \
+        "       move.4          %1, "REG"_RANGE"IDX"_LO \n\t" \
+        "       move.4          %2, "REG"_RANGE"IDX"_HI \n\t" \
+                : "=d"(en), "=d"(lo), "=d"(hi) \
+        ); \
+        printk(KERN_NOTICE REG"Range"IDX": en:%08x, range: %08x-%08x\n", \
+                (unsigned int)en, \
+                (unsigned int)lo, \
+                (unsigned int)hi)
+
+asmlinkage void ret_from_fork(void);
+
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
+/* machine-dependent / hardware-specific power functions */
+void (*mach_reset)(void);
+void (*mach_halt)(void);
+void (*mach_power_off)(void);
+
+/*
+ * cpu_idle()
+ *     The idle thread.
+ *
+ * Our idle loop suspends and is woken up by a timer interrupt.
+ */
+void cpu_idle(void)
+{
+       while (1) {
+               local_irq_disable();
+               while (!need_resched()) {
+                       local_irq_enable();
+                       thread_suspend();
+                       local_irq_disable();
+               }
+               local_irq_enable();
+               preempt_enable_no_resched();
+               schedule();
+               preempt_disable();
+       }
+}
+
+/*
+ * dump_fpu()
+ *
+ *     Fill in the fpu structure for a core dump. (just a stub as we don't have
+ *     an fpu)
+ */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs)
+{
+       return 1;
+}
+
+/*
+ * machine_restart()
+ *     Resets the system.
+ */
+void machine_restart(char *__unused)
+{
+       /*
+        * Disable all threads except myself. We can do this
+        * directly without needing to call smp_send_stop
+        * because we have a unique architecture where
+        * one thread can disable one or more other threads.
+        */
+       thread_disable_others();
+
+       /*
+        * Call the hardware-specific machine reset function.
+        */
+       if (mach_reset) {
+               mach_reset();
+       }
+
+       printk(KERN_EMERG "System Restarting\n");
+
+       /*
+        * Set watchdog to trigger (after 1ms delay) (12 Mhz is the fixed OSC)
+        */
+       UBICOM32_IO_TIMER->tkey = TIMER_TKEYVAL;
+       UBICOM32_IO_TIMER->wdcom = UBICOM32_IO_TIMER->mptval +
+               (12000000 / 1000);
+       UBICOM32_IO_TIMER->wdcfg = 0;
+       UBICOM32_IO_TIMER->tkey = 0;
+
+       /*
+        * Wait for watchdog
+        */
+       asm volatile (
+               "       move.4          MT_EN, #0               \n\t"
+               "       pipe_flush      0                       \n\t"
+       );
+
+       local_irq_disable();
+       for (;;) {
+               thread_suspend();
+       }
+}
+
+/*
+ * machine_halt()
+ *     Halt the machine.
+ *
+ * Similar to machine_power_off, but don't shut off power.  Add code
+ * here to freeze the system for e.g. post-mortem debug purpose when
+ * possible.  This halt has nothing to do with the idle halt.
+ */
+void machine_halt(void)
+{
+       /*
+        * Disable all threads except myself. We can do this
+        * directly without needing to call smp_send_stop
+        * because we have a unique architecture where
+        * one thread can disable one or more other threads.
+        */
+       thread_disable_others();
+
+       /*
+        * Call the hardware-specific machine halt function.
+        */
+       if (mach_halt) {
+               mach_halt();
+       }
+
+       printk(KERN_EMERG "System Halted, OK to turn off power\n");
+       local_irq_disable();
+       for (;;) {
+               thread_suspend();
+       }
+}
+
+/*
+ * machine_power_off()
+ *     Turn the power off, if a power off handler is defined, otherwise, spin
+ *     endlessly.
+ */
+void machine_power_off(void)
+{
+       /*
+        * Disable all threads except myself. We can do this
+        * directly without needing to call smp_send_stop
+        * because we have a unique architecture where
+        * one thread can disable one or more other threads.
+        */
+       thread_disable_others();
+
+       /*
+        * Call the hardware-specific machine power off function.
+        */
+       if (mach_power_off) {
+               mach_power_off();
+       }
+
+       printk(KERN_EMERG "System Halted, OK to turn off power\n");
+       local_irq_disable();
+       for (;;) {
+               thread_suspend();
+       }
+}
+
+/*
+ * address_is_valid()
+ *     check if an address is valid -- (for read access)
+ */
+static bool address_is_valid(const void *address)
+{
+       int addr = (int)address;
+       unsigned long socm, eocm, sdram, edram;
+
+       if (addr & 3)
+               return false;
+
+       processor_ocm(&socm, &eocm);
+       processor_dram(&sdram, &edram);
+       if (addr >= socm && addr < eocm)
+               return true;
+
+       if (addr >= sdram && addr < edram)
+               return true;
+
+       return false;
+}
+
+/*
+ * vma_path_name_is_valid()
+ *     check if path_name of a vma is a valid string
+ */
+static bool vma_path_name_is_valid(const char *str)
+{
+#define MAX_NAME_LEN 256
+       int i = 0;
+       if (!address_is_valid(str))
+               return false;
+
+       for (; i < MAX_NAME_LEN; i++, str++) {
+               if (*str == '\0')
+                       return true;
+       }
+
+       return false;
+}
+
+/*
+ * show_vmas()
+ *     show vma info of a process
+ */
+void show_vmas(struct task_struct *task)
+{
+#ifdef CONFIG_DEBUG_VERBOSE
+#define UBICOM32_MAX_VMA_COUNT 1024
+
+       struct vm_area_struct *vma;
+       struct file *file;
+       char *name = "";
+       int flags, loop = 0;
+
+       printk(KERN_NOTICE "Start of vma list\n");
+
+       if (!address_is_valid(task) || !address_is_valid(task->mm))
+               goto error;
+
+       vma = task->mm->mmap;
+       while (vma) {
+               if (!address_is_valid(vma))
+                       goto error;
+
+               flags = vma->vm_flags;
+               file = vma->vm_file;
+
+               if (file) {
+                       /* seems better to use dentry op here, but sanity check is easier this way */
+                       if (!address_is_valid(file) || !address_is_valid(file->f_path.dentry) || !vma_path_name_is_valid(file->f_path.dentry->d_name.name))
+                               goto error;
+
+                       name = (char *)file->f_path.dentry->d_name.name;
+               }
+
+               /* Similar to /proc/pid/maps format */
+               printk(KERN_NOTICE "%08lx-%08lx %c%c%c%c %08lx %s\n",
+                       vma->vm_start,
+                       vma->vm_end,
+                       flags & VM_READ ? 'r' : '-',
+                       flags & VM_WRITE ? 'w' : '-',
+                       flags & VM_EXEC ? 'x' : '-',
+                       flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
+                       vma->vm_pgoff << PAGE_SHIFT,
+                       name);
+
+               vma = vma->vm_next;
+
+               if (loop++ > UBICOM32_MAX_VMA_COUNT)
+                       goto error;
+       }
+
+       printk(KERN_NOTICE "End of vma list\n");
+       return;
+
+error:
+       printk(KERN_NOTICE "\nCorrupted vma list, abort!\n");
+#endif
+}
+
+/*
+ * show_regs()
+ *     Print out all of the registers.
+ */
+void show_regs(struct pt_regs *regs)
+{
+       unsigned int i;
+       unsigned int en, lo, hi;
+
+       printk(KERN_NOTICE "regs: %p, tid: %d\n",
+               (void *)regs,
+               thread_get_self());
+
+       printk(KERN_NOTICE "pc: %08x, previous_pc: %08x\n\n",
+               (unsigned int)regs->pc,
+               (unsigned int)regs->previous_pc);
+
+       printk(KERN_NOTICE "Data registers\n");
+       for (i = 0; i < 16; i++) {
+               printk("D%02d: %08x, ", i, (unsigned int)regs->dn[i]);
+               if ((i % 4) == 3) {
+                       printk("\n");
+               }
+       }
+       printk("\n");
+
+       printk(KERN_NOTICE "Address registers\n");
+       for (i = 0; i < 8; i++) {
+               printk("A%02d: %08x, ", i, (unsigned int)regs->an[i]);
+               if ((i % 4) == 3) {
+                       printk("\n");
+               }
+       }
+       printk("\n");
+
+       printk(KERN_NOTICE "acc0: %08x-%08x, acc1: %08x-%08x\n",
+               (unsigned int)regs->acc0[1],
+               (unsigned int)regs->acc0[0],
+               (unsigned int)regs->acc1[1],
+               (unsigned int)regs->acc1[0]);
+
+       printk(KERN_NOTICE "mac_rc16: %08x, source3: %08x\n",
+               (unsigned int)regs->mac_rc16,
+               (unsigned int)regs->source3);
+
+       printk(KERN_NOTICE "inst_cnt: %08x, csr: %08x\n",
+               (unsigned int)regs->inst_cnt,
+               (unsigned int)regs->csr);
+
+       printk(KERN_NOTICE "int_mask0: %08x, int_mask1: %08x\n",
+               (unsigned int)regs->int_mask0,
+               (unsigned int)regs->int_mask1);
+
+       /*
+        * Dump range registers
+        */
+       DUMP_RANGE_REGISTER("I", "0");
+       DUMP_RANGE_REGISTER("I", "1");
+       DUMP_RANGE_REGISTER("I", "2");
+       DUMP_RANGE_REGISTER("I", "3");
+       DUMP_RANGE_REGISTER("D", "0");
+       DUMP_RANGE_REGISTER("D", "1");
+       DUMP_RANGE_REGISTER("D", "2");
+       DUMP_RANGE_REGISTER("D", "3");
+       DUMP_RANGE_REGISTER("D", "4");
+
+       printk(KERN_NOTICE "frame_type: %d, nesting_level: %d, thread_type %d\n\n",
+               (int)regs->frame_type,
+               (int)regs->nesting_level,
+               (int)regs->thread_type);
+}
+
+/*
+ * kernel_thread_helper()
+ *     On execution d0 will be 0, d1 will be the argument to be passed to the
+ *     kernel function.  d2 contains the kernel function that needs to get
+ *     called. d3 will contain address to do_exit which need to get moved
+ *     into a5. On return from fork the child thread d0 will be 0. We call
+ *     this dummy function which in turn loads the argument
+ */
+asmlinkage void kernel_thread_helper(void);
+
+/*
+ * kernel_thread()
+ *     Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+       struct pt_regs regs;
+
+       memset(&regs, 0, sizeof(regs));
+
+       regs.dn[1] = (unsigned long)arg;
+       regs.dn[2] = (unsigned long)fn;
+       regs.dn[3] = (unsigned long)do_exit;
+       regs.an[5] = (unsigned long)kernel_thread_helper;
+       regs.pc = (unsigned long)kernel_thread_helper;
+       regs.nesting_level = 0;
+       regs.thread_type = KERNEL_THREAD;
+
+       return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
+                      0, &regs, 0, NULL, NULL);
+}
+EXPORT_SYMBOL(kernel_thread);
+
+/*
+ * flush_thread()
+ *     XXX todo
+ */
+void flush_thread(void)
+{
+       /* XXX todo */
+}
+
+/*
+ * sys_fork()
+ *     Not implemented on no-mmu.
+ */
+asmlinkage int sys_fork(struct pt_regs *regs)
+{
+       /* fork almost works, enough to trick you into looking elsewhere :-( */
+       return -EINVAL;
+}
+
+/*
+ * sys_vfork()
+ *     By the time we get here, the non-volatile registers have also been saved
+ *     on the stack. We do some ugly pointer stuff here.. (see also copy_thread
+ *     which does context copy).
+ */
+asmlinkage int sys_vfork(struct pt_regs *regs)
+{
+       unsigned long old_sp = regs->an[7];
+       unsigned long old_a5 = regs->an[5];
+       unsigned long old_return_address;
+       long do_fork_return;
+
+       /*
+        * Read the old retrun address from the stack.
+        */
+       if (copy_from_user(&old_return_address,
+                          (void *)old_sp, sizeof(unsigned long))) {
+               force_sig(SIGSEGV, current);
+               return 0;
+       }
+
+       /*
+        * Pop the vfork call frame by setting a5 and pc to the old_return
+        * address and incrementing the stack pointer by 4.
+        */
+       regs->an[5] = old_return_address;
+       regs->pc = old_return_address;
+       regs->an[7] += 4;
+
+       do_fork_return = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
+                                regs->an[7], regs, 0, NULL, NULL);
+
+       /*
+        * Now we have to test if the return code is an error. If it is an error
+        * then restore the frame and we will execute error processing in user
+        * space. Other wise the child and the parent will return to the correct
+        * places.
+        */
+       if ((unsigned long)(do_fork_return) >= (unsigned long)(-125)) {
+               /*
+                * Error case. We need to restore the frame.
+                */
+               regs->an[5] = old_a5;
+               regs->pc = old_a5;
+               regs->an[7] = old_sp;
+       }
+
+       return do_fork_return;
+}
+
+/*
+ * sys_clone()
+ *     creates a child thread.
+ */
+asmlinkage int sys_clone(unsigned long clone_flags,
+                        unsigned long newsp,
+                        struct pt_regs *regs)
+{
+       if (!newsp)
+               newsp = regs->an[7];
+       return do_fork(clone_flags, newsp, regs, 0,
+                      NULL, NULL);
+}
+
+/*
+ * copy_thread()
+ *     low level thread copy, only used by do_fork in kernel/fork.c
+ */
+int copy_thread(unsigned long clone_flags,
+               unsigned long usp, unsigned long topstk,
+               struct task_struct *p, struct pt_regs *regs)
+
+{
+       struct pt_regs *childregs;
+
+       childregs = (struct pt_regs *)
+               (task_stack_page(p) + THREAD_SIZE - 8) - 1;
+
+       *childregs = *regs;
+
+       /*
+        * Set return value for child to be 0.
+        */
+       childregs->dn[0] = 0;
+
+       if (usp)
+               childregs->an[7] = usp;
+       else
+               childregs->an[7] = (unsigned long)task_stack_page(p) +
+                       THREAD_SIZE - 8;
+
+       /*
+        * Set up the switch_to frame to return to "ret_from_fork"
+        */
+       p->thread.a5 = (unsigned long)ret_from_fork;
+       p->thread.sp = (unsigned long)childregs;
+
+       return 0;
+}
+
+/*
+ * sys_execve()
+ *     executes a new program.
+ */
+asmlinkage int sys_execve(char *name, char **argv,
+                         char **envp, struct pt_regs *regs)
+{
+       int error;
+       char *filename;
+
+       lock_kernel();
+       filename = getname(name);
+       error = PTR_ERR(filename);
+       if (IS_ERR(filename))
+               goto out;
+       error = do_execve(filename, argv, envp, regs);
+       putname(filename);
+       asm ("       .global sys_execve_complete\n"
+            "       sys_execve_complete:");
+out:
+       unlock_kernel();
+       return error;
+}
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+unsigned long thread_saved_pc(struct task_struct *tsk)
+{
+       return tsk->thread.a5;
+}
+
+
+unsigned long get_wchan(struct task_struct *p)
+{
+       unsigned long pc;
+
+       /*
+        * If we don't have a process, or it is not the current
+        * one or not RUNNING, it makes no sense to ask for a
+        * wchan.
+        */
+       if (!p || p == current || p->state == TASK_RUNNING)
+               return 0;
+
+       /*
+        * TODO: If the process is in the middle of schedule, we
+        * are supposed to do something different but for now we
+        * will return the same thing in both situations.
+        */
+       pc = thread_saved_pc(p);
+       if (in_sched_functions(pc))
+               return pc;
+       return pc;
+}
+
+
+/*
+ * Infrequently used interface to dump task registers to core files.
+ */
+int dump_task_regs(struct task_struct *task, elf_gregset_t *elfregs)
+{
+       struct pt_regs *regs = task_pt_regs(task);
+       *(struct pt_regs *)elfregs = *regs;
+
+       return 1;
+}
+
+/*
+ * __switch_to is the function that implements the contex save and
+ * switch within the kernel. Since this is a function call very few
+ * registers have to be saved to pull this off. d0 holds prev and we
+ * want to preserve it. prev_switch is a pointer to task->thread
+ * structure. This is where we will save the register state. next_switch
+ * is pointer to the next task's thread structure that holds the
+ * registers.
+ */
+asmlinkage void *__switch_to(struct task_struct *prev,
+                            struct thread_struct *prev_switch,
+                            struct thread_struct *next_switch)
+       __attribute__((naked));
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/processor.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/processor.c
new file mode 100644 (file)
index 0000000..55d1bdf
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * arch/ubicom32/kernel/processor.c
+ *   Ubicom32 architecture processor info implementation.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
+#include <linux/types.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+#include <linux/cpu.h>
+#include <asm/devtree.h>
+#include <asm/processor.h>
+#include <asm/cpu.h>
+#include <asm/ocm_size.h>
+
+struct procnode {
+       struct devtree_node dn;
+       unsigned int threads;
+       unsigned int timers;
+       unsigned int frequency;
+       unsigned int ddr_frequency;
+       unsigned int interrupt0;
+       unsigned int interrupt1;
+       void *socm;
+       void *eocm;
+       void *sdram;
+       void *edram;
+       unsigned int arch_version;
+       void *os_syscall_begin;
+       void *os_syscall_end;
+};
+
+struct procnode *pn;
+
+/*
+ * show_processorinfo()
+ *     Print the actual processor information.
+ */
+static void show_processorinfo(struct seq_file *m)
+{
+       char *cpu, *mmu, *fpu;
+       unsigned int clockfreq;
+       unsigned int chipid;
+
+       cpu = CPU;
+       mmu = "none";
+       fpu = "none";
+
+       asm volatile (
+       "move.4         %0, CHIP_ID     \n\t"
+       : "=r" (chipid)
+       );
+
+       /*
+        * General Processor Information.
+        */
+       seq_printf(m, "Vendor:\t\t%s\n", "Ubicom");
+       seq_printf(m, "CPU:\t\t%s\n", cpu);
+       seq_printf(m, "MMU:\t\t%s\n", mmu);
+       seq_printf(m, "FPU:\t\t%s\n", fpu);
+       seq_printf(m, "Arch:\t\t%hx\n", chipid >> 16);
+       seq_printf(m, "Rev:\t\t%hx\n", (chipid & 0xffff));
+
+       /*
+        * Now compute the clock frequency in Mhz.
+        */
+       clockfreq = processor_frequency();
+       seq_printf(m, "Clock Freq:\t%u.0 MHz\n",
+                  clockfreq / 1000000);
+       seq_printf(m, "DDR Freq:\t%u.0 MHz\n",
+                  pn ? pn->ddr_frequency / 1000000 : 0);
+       seq_printf(m, "BogoMips:\t%lu.%02lu\n",
+                  (loops_per_jiffy * HZ) / 500000,
+                  ((loops_per_jiffy * HZ) / 5000) % 100);
+       seq_printf(m, "Calibration:\t%lu loops\n", (loops_per_jiffy * HZ));
+}
+
+/*
+ * show_cpuinfo()
+ *     Get CPU information for use by the procfs.
+ */
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+       unsigned long n = (unsigned long)v - 1;
+
+#if defined(CONFIG_SMP)
+       struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, n);
+#endif
+
+       /*
+        * Print the general processor information on the first
+        * call.
+        */
+       if (n == 0) {
+               show_processorinfo(m);
+       }
+
+#if defined(CONFIG_SMP)
+       /*
+        * For each hwthread, print if this hwthread is running Linux
+        * or is an I/O thread.
+        */
+       if (cpu_isset(n, cpu_online_map)) {
+               seq_printf(m, "cpu[%02lu]:\tthread id - %lu\n", n, p->tid);
+       } else {
+               seq_printf(m, "cpu[%02lu]:\toff-line\n", n);
+       }
+#endif
+       return 0;
+
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+       unsigned long i = *pos;
+
+       return i < NR_CPUS ? (void *)(i + 1) : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       ++*pos;
+       return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+const struct seq_operations cpuinfo_op = {
+       .start  = c_start,
+       .next   = c_next,
+       .stop   = c_stop,
+       .show   = show_cpuinfo,
+};
+
+/*
+ * processor_timers()
+ *     Returns the timers available to Linux.
+ */
+unsigned int processor_timers(void)
+{
+       if (!pn) {
+               return 0;
+       }
+       return pn->timers;
+}
+
+/*
+ * processor_threads()
+ *     Returns the threads available to Linux.
+ */
+unsigned int processor_threads(void)
+{
+       if (!pn) {
+               return 0;
+       }
+       return pn->threads;
+}
+
+/*
+ * processor_frequency()
+ *     Returns the frequency of the system clock.
+ */
+unsigned int processor_frequency(void)
+{
+       if (!pn) {
+               return 0;
+       }
+       return pn->frequency;
+}
+EXPORT_SYMBOL(processor_frequency);
+
+/*
+ * processor_interrupts()
+ *     Return the interrupts that are setup at boot time.
+ */
+int processor_interrupts(unsigned int *int0, unsigned int *int1)
+{
+       if (!pn) {
+               return -EFAULT;
+       }
+
+       if (int0) {
+               *int0 = pn->interrupt0;
+       }
+
+       if (int1) {
+               *int1 = pn->interrupt1;
+       }
+       return 0;
+}
+
+/*
+ * processor_ocm()
+ *     Returns the start and end of OCM available to Linux.
+ */
+void processor_ocm(unsigned long *socm, unsigned long *eocm)
+{
+       *socm = (unsigned long)pn->socm;
+       *eocm = (unsigned long)pn->eocm;
+}
+
+/*
+ * processor_dram()
+ *     Returns the start and end of dram available to Linux.
+ */
+void processor_dram(unsigned long *sdram, unsigned long *edram)
+{
+       *sdram = (unsigned long)pn->sdram;
+       *edram = (unsigned long)pn->edram;
+}
+
+/*
+ * processor_validate_failed()
+ *     Returns the dram available to Linux.
+ */
+static noinline void processor_validate_failed(void)
+{
+       while (1)
+               THREAD_STALL;
+}
+
+/*
+ * processor_validate()
+ *     Validates the procnode against limitations of this link/built.
+ */
+static void processor_validate(void)
+{
+       void *dram_start = (void *)(KERNELSTART);
+       void *dram_end   = (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE);
+#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE
+       void *ocm_code_start = (void *)(OCMSTART + APP_OCM_CODE_SIZE);
+       void *ocm_data_end   = (void *)(OCMEND   - APP_OCM_DATA_SIZE);
+#endif
+       extern void __os_syscall_begin;
+       extern void __os_syscall_end;
+       int proc_node_valid = 1;
+
+       if (!pn) {
+               printk(KERN_ERR "ERROR: processor node not found\n");
+               goto error;
+       }
+
+
+       if (dram_start < pn->sdram || dram_end > pn->edram) {
+               printk(KERN_ERR "ERROR: processor dram mismatch %p-%p "
+                      "available but we are expecting %p-%p\n",
+                      pn->sdram, pn->edram, dram_start, dram_end);
+               proc_node_valid = 0;
+       } else {
+               printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n",
+                      pn->sdram, pn->edram, dram_start, dram_end);
+       }
+       if (&__os_syscall_begin < pn->os_syscall_begin ||
+           &__os_syscall_end > pn->os_syscall_end) {
+               printk(KERN_ERR "ERROR: processor syscall area mismatch "
+                      "%p-%p available but we are expecting %p-%p\n",
+                      pn->os_syscall_begin, pn->os_syscall_end,
+                      &__os_syscall_begin, &__os_syscall_end);
+               proc_node_valid = 0;
+       } else {
+               printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n",
+                      pn->sdram, pn->edram, dram_start, dram_end);
+       }
+#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE
+       if (ocm_code_start < pn->socm ||  ocm_data_end > pn->eocm) {
+               printk(KERN_ERR "ERROR: processor ocm mismatch %p-%p "
+                      "available but we are expecting %p-%p\n",
+                      pn->socm, pn->eocm, ocm_code_start, ocm_data_end);
+               proc_node_valid = 0;
+       } else {
+               printk(KERN_INFO "processor ocm %p-%p, expecting %p-%p\n",
+                      pn->socm, pn->eocm, ocm_code_start, ocm_data_end);
+
+       }
+#endif
+
+       if (UBICOM32_ARCH_VERSION != pn->arch_version) {
+               printk(KERN_ERR "ERROR: processor arch mismatch, kernel"
+                      "compiled for %d found %d\n",
+                      UBICOM32_ARCH_VERSION, pn->arch_version);
+               proc_node_valid = 0;
+       }
+
+       if (proc_node_valid)
+               return;
+error:
+       processor_validate_failed();
+}
+
+void __init processor_init(void)
+{
+       /*
+        * If we do not have a trap node in the device tree, we leave the fault
+        * handling to the underlying hardware.
+        */
+       pn = (struct procnode *)devtree_find_node("processor");
+
+       processor_validate();
+
+       /*
+        * If necessary correct the initial range registers to cover the
+        * complete physical space
+        */
+       if (pn->edram > (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE)) {
+               printk(KERN_INFO "updating range registers for expanded dram\n");
+               asm volatile (
+                       "       move.4 D_RANGE1_HI, %0          \t\n"
+                       "       move.4 I_RANGE0_HI, %0          \t\n"
+#ifdef CONFIG_PROTECT_KERNEL
+                       "       move.4 D_RANGE2_HI, %0          \t\n"
+                       "       move.4 I_RANGE2_HI, %0          \t\n"
+#endif
+               : : "a"((unsigned long)pn->edram - 4)
+                       );
+       }
+
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ptrace.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/ptrace.c
new file mode 100644 (file)
index 0000000..18bb39e
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * arch/ubicom32/kernel/ptrace.c
+ *   Ubicom32 architecture ptrace implementation.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * (C) 1994 by Hamish Macdonald
+ * Taken from linux/kernel/ptrace.c and modified for M680x0.
+ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/signal.h>
+#include <linux/uaccess.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/cacheflush.h>
+#include <asm/processor.h>
+
+/*
+ * ptrace_getregs()
+ *
+ *     Get all user integer registers.
+ */
+static inline int ptrace_getregs(struct task_struct *task, void __user *uregs)
+{
+       struct pt_regs *regs = task_pt_regs(task);
+       return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
+}
+
+/*
+ * ptrace_get_reg()
+ *
+ *     Get contents of register REGNO in task TASK.
+ */
+static unsigned long ptrace_get_reg(struct task_struct *task, int regno)
+{
+       if (regno < sizeof(struct pt_regs)) {
+               struct pt_regs *pt_regs = task_pt_regs(task);
+               return *(unsigned long *)((long) pt_regs + regno);
+       }
+
+       return -EIO;
+}
+
+/*
+ * ptrace_put_reg()
+ *     Write contents of register REGNO in task TASK.
+ */
+static int ptrace_put_reg(struct task_struct *task, int regno,
+                         unsigned long data)
+{
+       if (regno <= sizeof(struct pt_regs) && regno != PT_FRAME_TYPE) {
+               struct pt_regs *pt_regs = task_pt_regs(task);
+               *(unsigned long *)((long) pt_regs + regno) = data;
+               return 0;
+       }
+       return -EIO;
+}
+
+/*
+ * ptrace_disable_single_step()
+ *     Disable Single Step
+ */
+static int ptrace_disable_single_step(struct task_struct *task)
+{
+       /*
+        * Single Step not yet implemented, so must always be disabled
+        */
+       return 0;
+}
+
+/*
+ * ptrace_disable()
+ *     Make sure the single step bit is not set.
+ * Called by kernel/ptrace.c when detaching..
+ */
+void ptrace_disable(struct task_struct *child)
+{
+       ptrace_disable_single_step(child);
+}
+
+/*
+ * arch_ptrace()
+ *     architecture specific ptrace routine.
+ */
+long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+{
+       int ret;
+       switch (request) {
+       /* when I and D space are separate, these will need to be fixed. */
+       case PTRACE_PEEKTEXT: /* read word at location addr. */
+       case PTRACE_PEEKDATA:
+               ret = generic_ptrace_peekdata(child, addr, data);
+               break;
+
+       /* read the word at location addr in the USER area. */
+       case PTRACE_PEEKUSR: {
+               unsigned long tmp;
+
+               ret = -EIO;
+               if (((unsigned long) addr > PT_INTERP_FDPIC_LOADMAP)
+                   || (addr & 3))
+                       break;
+
+               tmp = 0;  /* Default return condition */
+
+               ret = -EIO;
+               if (addr < sizeof(struct pt_regs)) {
+                       tmp = ptrace_get_reg(child, addr);
+               } else if (addr == PT_TEXT_ADDR) {
+                       tmp = child->mm->start_code;
+               } else if (addr == PT_TEXT_END_ADDR) {
+                       tmp = child->mm->end_code;
+               } else if (addr == PT_DATA_ADDR) {
+                       tmp = child->mm->start_data;
+               } else if (addr == PT_EXEC_FDPIC_LOADMAP) {
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+                       tmp = child->mm->context.exec_fdpic_loadmap;
+#endif
+               } else if (addr == PT_INTERP_FDPIC_LOADMAP) {
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+                       tmp = child->mm->context.interp_fdpic_loadmap;
+#endif
+               } else {
+                       break;
+               }
+
+               ret = put_user(tmp, (unsigned long *)data);
+               break;
+       }
+
+       case PTRACE_POKETEXT: /* write the word at location addr. */
+       case PTRACE_POKEDATA:
+               ret = generic_ptrace_pokedata(child, addr, data);
+
+               /*
+                * If we just changed some code so we need to
+                * correct the caches
+                */
+               if (request == PTRACE_POKETEXT && ret == 0) {
+                       flush_icache_range(addr, addr + 4);
+               }
+               break;
+
+       case PTRACE_POKEUSR: /* write the word at location addr
+                             * in the USER area */
+               ret = -EIO;
+
+               if (((unsigned long) addr > PT_DATA_ADDR) || (addr & 3))
+                       break;
+
+               if (addr < sizeof(struct pt_regs)) {
+                       ret = ptrace_put_reg(child, addr, data);
+               }
+               break;
+
+       case PTRACE_SYSCALL: /* continue and stop at next (return from)
+                             * syscall */
+       case PTRACE_CONT: { /* restart after signal. */
+
+               ret = -EIO;
+               if (!valid_signal(data))
+                       break;
+               if (request == PTRACE_SYSCALL)
+                       set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               else
+                       clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               child->exit_code = data;
+               /* make sure the single step bit is not set. */
+               ptrace_disable_single_step(child);
+               wake_up_process(child);
+               ret = 0;
+               break;
+       }
+
+       /*
+        * make the child exit.  Best I can do is send it a sigkill.
+        * perhaps it should be put in the status that it wants to exit.
+        */
+       case PTRACE_KILL: {
+               ret = 0;
+               if (child->exit_state == EXIT_ZOMBIE) /* already dead */
+                       break;
+               child->exit_code = SIGKILL;
+               /* make sure the single step bit is not set. */
+               ptrace_disable_single_step(child);
+               wake_up_process(child);
+               break;
+       }
+
+       case PTRACE_DETACH:     /* detach a process that was attached. */
+               ret = ptrace_detach(child, data);
+               break;
+
+       case PTRACE_GETREGS:    /* Get all gp regs from the child. */
+               ptrace_getregs(child, (unsigned long *)data);
+               ret = 0;
+               break;
+
+       case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+               int i;
+               unsigned long tmp;
+               int count = sizeof(struct pt_regs) / sizeof(unsigned long);
+               for (i = 0; i < count; i++) {
+                       if (get_user(tmp, (unsigned long *) data)) {
+                               ret = -EFAULT;
+                               break;
+                       }
+                       ptrace_put_reg(child, sizeof(unsigned long) * i, tmp);
+                       data += sizeof(long);
+               }
+               ret = 0;
+               break;
+       }
+
+       default:
+               return ptrace_request(child, request, addr, data);
+               break;
+       }
+       return ret;
+}
+/*
+ * syscall_trace
+ *
+ * called by syscall enter/exit when the TIF_SYSCALL_TRACE bit is set.
+ */
+asmlinkage void syscall_trace(void)
+{
+       struct task_struct *cur = current;
+       if (!test_thread_flag(TIF_SYSCALL_TRACE))
+               return;
+       if (!(cur->ptrace & PT_PTRACED))
+               return;
+       ptrace_notify(SIGTRAP | ((cur->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 (cur->exit_code) {
+               send_sig(cur->exit_code, current, 1);
+               current->exit_code = 0;
+       }
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/semaphore.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/semaphore.c
new file mode 100644 (file)
index 0000000..d996ac2
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * arch/ubicom32/kernel/semaphore.c
+ *   Ubicom32 architecture semaphore implementation.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+/*
+ *  Generic semaphore code. Buyer beware. Do your own
+ * specific changes in <asm/semaphore-helper.h>
+ */
+
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <asm/semaphore-helper.h>
+
+#ifndef CONFIG_RMW_INSNS
+spinlock_t semaphore_wake_lock;
+#endif
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to sleep, while the "waking" variable is
+ * incremented when the "up()" code goes to wake up waiting
+ * processes.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * waking_non_zero() (from asm/semaphore.h) must execute
+ * atomically.
+ *
+ * When __up() is called, the count was negative before
+ * incrementing it, and we need to wake up somebody.
+ *
+ * This routine adds one to the count of processes that need to
+ * wake up and exit.  ALL waiting processes actually wake up but
+ * only the one that gets to the "waking" field first will gate
+ * through and acquire the semaphore.  The others will go back
+ * to sleep.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+void __up(struct semaphore *sem)
+{
+       wake_one_more(sem);
+       wake_up(&sem->wait);
+}
+
+/*
+ * Perform the "down" function.  Return zero for semaphore acquired,
+ * return negative for signalled out of the function.
+ *
+ * If called from __down, the return is ignored and the wait loop is
+ * not interruptible.  This means that a task waiting on a semaphore
+ * using "down()" cannot be killed until someone does an "up()" on
+ * the semaphore.
+ *
+ * If called from __down_interruptible, the return value gets checked
+ * upon return.  If the return value is negative then the task continues
+ * with the negative value in the return register (it can be tested by
+ * the caller).
+ *
+ * Either form may be used in conjunction with "up()".
+ *
+ */
+
+
+#define DOWN_HEAD(task_state)                                          \
+                                                                       \
+                                                                       \
+       current->state = (task_state);                                  \
+       add_wait_queue(&sem->wait, &wait);                              \
+                                                                       \
+       /*                                                              \
+        * Ok, we're set up.  sem->count is known to be less than zero  \
+        * so we must wait.                                             \
+        *                                                              \
+        * We can let go the lock for purposes of waiting.              \
+        * We re-acquire it after awaking so as to protect              \
+        * all semaphore operations.                                    \
+        *                                                              \
+        * If "up()" is called before we call waking_non_zero() then    \
+        * we will catch it right away.  If it is called later then     \
+        * we will have to go through a wakeup cycle to catch it.       \
+        *                                                              \
+        * Multiple waiters contend for the semaphore lock to see       \
+        * who gets to gate through and who has to wait some more.      \
+        */                                                             \
+       for (;;) {
+
+#define DOWN_TAIL(task_state)                  \
+               current->state = (task_state);  \
+       }                                       \
+       current->state = TASK_RUNNING;          \
+       remove_wait_queue(&sem->wait, &wait);
+
+void __sched __down(struct semaphore *sem)
+{
+       DECLARE_WAITQUEUE(wait, current);
+
+       DOWN_HEAD(TASK_UNINTERRUPTIBLE)
+       if (waking_non_zero(sem))
+               break;
+       schedule();
+       DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+}
+
+int __sched __down_interruptible(struct semaphore *sem)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       int ret = 0;
+
+       DOWN_HEAD(TASK_INTERRUPTIBLE)
+
+       ret = waking_non_zero_interruptible(sem, current);
+       if (ret) {
+               if (ret == 1)
+                       /* ret != 0 only if we get interrupted -arca */
+                       ret = 0;
+               break;
+       }
+       schedule();
+       DOWN_TAIL(TASK_INTERRUPTIBLE)
+       return ret;
+}
+
+int __down_trylock(struct semaphore *sem)
+{
+       return waking_non_zero_trylock(sem);
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/setup.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/setup.c
new file mode 100644 (file)
index 0000000..7357f4e
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * arch/ubicom32/kernel/setup.c
+ *   Ubicom32 architecture-dependent parts of system setup.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 1999-2007  Greg Ungerer (gerg@snapgear.com)
+ * Copyright (C) 1998,1999  D. Jeff Dionne <jeff@uClinux.org>
+ * Copyleft  ()) 2000       James D. Schettine {james@telos-systems.com}
+ * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
+ * Copyright (C) 1995       Hamish Macdonald
+ * Copyright (C) 2000       Lineo Inc. (www.lineo.com)
+ * Copyright (C) 2001      Lineo, Inc. <www.lineo.com>
+ * 68VZ328 Fixes/support    Evan Stawnyczy <e@lineo.ca>
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+
+#include <asm/devtree.h>
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/ubicom32-common.h>
+#include <asm/processor.h>
+#include <asm/bootargs.h>
+#include <asm/thread.h>
+
+unsigned long memory_start;
+EXPORT_SYMBOL(memory_start);
+
+unsigned long memory_end;
+EXPORT_SYMBOL(memory_end);
+
+static char __initdata command_line[COMMAND_LINE_SIZE];
+#ifdef CONFIG_CMDLINE_BOOL
+static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
+#endif
+
+extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
+
+/*
+ * setup_arch()
+ *     Setup the architecture dependent portions of the system.
+ */
+void __init setup_arch(char **cmdline_p)
+{
+       int bootmap_size;
+       unsigned long ram_start;
+
+       processor_init();
+       bootargs_init();
+
+       /*
+        * Use the link for memory_start from the link and the processor
+        * node for memory_end.
+        */
+       memory_start = PAGE_ALIGN(((unsigned long)&_end));
+       processor_dram(&ram_start, &memory_end);
+
+       init_mm.start_code = (unsigned long) &_stext;
+       init_mm.end_code = (unsigned long) &_etext;
+       init_mm.end_data = (unsigned long) &_edata;
+       init_mm.brk = (unsigned long) 0;
+
+       /*
+        * bootexec copies the original default command line to end of memory.
+        * u-boot can modify it there (i.e. to enable network boot) and the
+        * kernel picks up the modified version.
+        *
+        * mainexec creates a `new default' command_line which is in the
+        * bootargs devnode. It is updated on every firmware update but
+        * not used at the moment.
+        */
+       strlcpy(boot_command_line, (char *)(memory_end - COMMAND_LINE_SIZE), COMMAND_LINE_SIZE);
+
+#ifdef CONFIG_CMDLINE_BOOL
+#ifdef CONFIG_CMDLINE_OVERRIDE
+       strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+#else
+       if (builtin_cmdline[0]) {
+               /* append boot loader cmdline to builtin */
+               strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
+               strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+               strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+       }
+#endif
+#endif
+
+       strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
+       *cmdline_p = command_line;
+
+       parse_early_param();
+
+       printk(KERN_INFO "%s Processor, Ubicom, Inc. <www.ubicom.com>\n", CPU);
+
+#if defined(DEBUG)
+       printk(KERN_DEBUG "KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
+               "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext,
+               (int) &_sdata, (int) &_edata,
+               (int) &_sbss, (int) &_ebss);
+       printk(KERN_DEBUG "MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ",
+               (int) &_ebss, (int) memory_start,
+               (int) memory_start, (int) memory_end);
+#endif
+
+#ifdef DEBUG
+       if (strlen(*cmdline_p))
+               printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p);
+#endif
+
+#if defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE)
+       conswitchp = &dummy_con;
+#endif
+
+       /*
+        * If we have a device tree, see if we have the nodes we need.
+        */
+       if (devtree) {
+               devtree_print();
+       }
+
+       /*
+        * From the arm initialization comment:
+        *
+        * This doesn't seem to be used by the Linux memory manager any
+        * more, but is used by ll_rw_block.  If we can get rid of it, we
+        * also get rid of some of the stuff above as well.
+        *
+        * Note: max_low_pfn and max_pfn reflect the number of _pages_ in
+        * the system, not the maximum PFN.
+        */
+       max_pfn = max_low_pfn = (memory_end - PAGE_OFFSET) >> PAGE_SHIFT;
+
+       /*
+        * Give all the memory to the bootmap allocator, tell it to put the
+        * boot mem_map at the start of memory.
+        */
+       bootmap_size = init_bootmem_node(
+                       NODE_DATA(0),
+                       memory_start >> PAGE_SHIFT,     /* map goes here */
+                       PAGE_OFFSET >> PAGE_SHIFT,      /* 0 on coldfire */
+                       memory_end >> PAGE_SHIFT);
+       /*
+        * Free the usable memory, we have to make sure we do not free
+        * the bootmem bitmap so we then reserve it after freeing it :-)
+        */
+       free_bootmem(memory_start, memory_end - memory_start);
+       reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
+
+       /*
+        * Get kmalloc into gear.
+        */
+       paging_init();
+
+       /*
+        * Fix up the thread_info structure, indicate this is a mainline Linux
+        * thread and setup the sw_ksp().
+        */
+       sw_ksp[thread_get_self()] = (unsigned int) current_thread_info();
+       thread_set_mainline(thread_get_self());
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/signal.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/signal.c
new file mode 100644 (file)
index 0000000..f6ccbe3
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * arch/ubicom32/kernel/signal.c
+ *   Ubicom32 architecture signal handling implementation.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 1991, 1992  Linus Torvalds
+ * Linux/m68k support by Hamish Macdonald
+ * 68060 fixes by Jesper Skov
+ * 1997-12-01  Modified for POSIX.1b signals by Andreas Schwab
+ * mathemu support by Roman Zippel
+ * ++roman (07/09/96): implemented signal stacks
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *
+ * mathemu support by Roman Zippel
+ *  (Note: fpstate in the signal context is completely ignored for the emulator
+ *         and the internal floating point format is put on stack)
+ *
+ * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
+ * Atari :-) Current limitation: Only one sigstack can be active at one time.
+ * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
+ * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
+ * signal handlers!
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/syscalls.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/highuid.h>
+#include <linux/tty.h>
+#include <linux/personality.h>
+#include <linux/binfmts.h>
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/traps.h>
+#include <asm/ucontext.h>
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+/*
+ * asm signal return handlers.
+ */
+void ret_from_user_signal(void);
+void ret_from_user_rt_signal(void);
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
+
+/*
+ * Common signal suspend implementation
+ */
+static int signal_suspend(sigset_t *saveset, struct pt_regs *regs)
+{
+       regs->dn[0] = -EINTR;
+       while (1) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule();
+               if (!do_signal(saveset, regs)) {
+                       continue;
+               }
+               /*
+                * If the current frame type is a signal trampoline we are
+                * actually going to call the signal handler so we return the
+                * desired d0 as the return value.
+                */
+               if (regs->frame_type == UBICOM32_FRAME_TYPE_SIGTRAMP) {
+                       return regs->dn[0];
+               }
+               return -EINTR;
+       }
+       /*
+        * Should never get here
+        */
+       BUG();
+       return 0;
+}
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+asmlinkage int do_sigsuspend(struct pt_regs *regs)
+{
+       old_sigset_t mask = regs->dn[0];
+       sigset_t saveset;
+
+       mask &= _BLOCKABLE;
+       spin_lock_irq(&current->sighand->siglock);
+       saveset = current->blocked;
+       siginitset(&current->blocked, mask);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       /*
+        * Call common handler
+        */
+       return signal_suspend(&saveset, regs);
+}
+
+asmlinkage int
+do_rt_sigsuspend(struct pt_regs *regs)
+{
+       sigset_t *unewset = (sigset_t *)regs->dn[0];
+       size_t sigsetsize = (size_t)regs->dn[1];
+       sigset_t saveset, 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);
+
+       spin_lock_irq(&current->sighand->siglock);
+       saveset = current->blocked;
+       current->blocked = newset;
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       /*
+        * Call common handler
+        */
+       return signal_suspend(&saveset, regs);
+}
+
+asmlinkage int
+sys_sigaction(int sig, const struct old_sigaction *act,
+             struct old_sigaction *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;
+}
+
+asmlinkage int
+do_sys_sigaltstack(struct pt_regs *regs)
+{
+       const stack_t *uss = (stack_t *) regs->dn[0];
+       stack_t *uoss = (stack_t *)regs->dn[1];
+       return do_sigaltstack(uss, uoss, regs->an[7]);
+}
+
+/*
+ * fdpic_func_descriptor describes sa_handler when the application is FDPIC
+ */
+struct fdpic_func_descriptor {
+       unsigned long   text;
+       unsigned long   GOT;
+};
+
+/*
+ * rt_sigframe is stored on the user stack immediately before (above)
+ * the signal handlers stack.
+ */
+struct rt_sigframe
+{
+       unsigned long syscall_number;   /* This holds __NR_rt_sigreturn. */
+       unsigned long restore_all_regs; /* This field gets set to 1 if the frame
+                                        * type is TRAP or INTERRUPT. */
+       siginfo_t *info;
+       struct ucontext uc;
+       int sig;
+       void *pretcode;
+};
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+asmlinkage int do_sigreturn(unsigned long __unused)
+{
+       BUG();
+       return 0;
+}
+
+asmlinkage int do_rt_sigreturn(struct pt_regs *regs)
+{
+       unsigned long usp = regs->an[7];
+       struct rt_sigframe *frame = (struct rt_sigframe *)(usp);
+       sigset_t set;
+
+       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(&current->sighand->siglock);
+       current->blocked = set;
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+
+       if (copy_from_user(regs, &frame->uc.uc_mcontext, sizeof(struct pt_regs)))
+               goto badframe;
+       return regs->dn[0];
+
+badframe:
+       force_sig(SIGSEGV, current);
+       return 0;
+}
+
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
+{
+       unsigned long usp;
+
+       /* Default to using normal stack.  */
+       usp = regs->an[7];
+
+       /* This is the X/Open sanctioned signal stack switching.  */
+       if (ka->sa.sa_flags & SA_ONSTACK) {
+               if (!sas_ss_flags(usp))
+                       usp = current->sas_ss_sp + current->sas_ss_size;
+       }
+       return (void *)((usp - frame_size) & ~0x3);
+}
+
+/*
+ * signal_trampoline:  Defined in ubicom32_syscall.S
+ */
+asmlinkage void signal_trampoline(void)__attribute__((naked));
+
+static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
+                           sigset_t *set, struct pt_regs *regs)
+{
+       struct rt_sigframe *frame;
+       int err = 0;
+
+       frame = (struct rt_sigframe *) get_sigframe(ka, regs, sizeof(*frame));
+
+       /*
+        * The 'err |=' have been may criticized as bad code style, but I
+        * strongly suspect that we want this code to be fast.  So for
+        * now it stays as is.
+        */
+       err |= __put_user( (  (current_thread_info()->exec_domain)
+                          && (current_thread_info()->exec_domain->signal_invmap)
+                          && (sig < 32) )
+                          ? current_thread_info()->exec_domain->signal_invmap[sig]
+                          : sig, &frame->sig);
+       err |= __put_user(info, &frame->info);
+
+       /* Create the ucontext.  */
+       err |= __put_user(0, &frame->uc.uc_flags);
+       err |= __put_user(0, &frame->uc.uc_link);
+       err |= __put_user((void *)current->sas_ss_sp,
+                         &frame->uc.uc_stack.ss_sp);
+       err |= __put_user(sas_ss_flags(regs->an[7]),
+                         &frame->uc.uc_stack.ss_flags);
+       err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+       err |= __put_user(__NR_rt_sigreturn, &frame->syscall_number);
+       if ((regs->frame_type == UBICOM32_FRAME_TYPE_TRAP) ||
+           (regs->frame_type == UBICOM32_FRAME_TYPE_INTERRUPT)) {
+               err |= __put_user(1, &frame->restore_all_regs);
+       } else {
+               err |= __put_user(0, &frame->restore_all_regs);
+       }
+       err |= copy_to_user (&frame->uc.uc_mcontext.sc_regs, regs, sizeof(struct pt_regs));
+       err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
+
+       if (err)
+               goto give_sigsegv;
+
+       /*
+        * Set up registers for signal handler NOTE: Do not modify dn[14], it
+        * contains the userspace tls pointer, so it important that it carries
+        * over to the signal handler.
+        */
+       regs->an[7] = (unsigned long)frame;
+       regs->pc = (unsigned long) signal_trampoline;
+       regs->an[5] = (unsigned long) signal_trampoline;
+       regs->dn[0] = sig;
+       regs->dn[1] = (unsigned long) frame->info;
+       regs->dn[2] = (unsigned int) &frame->uc;
+
+       /*
+        * If this is FDPIC then the signal handler is actually a function
+        * descriptor.
+        */
+       if (current->personality & FDPIC_FUNCPTRS) {
+               struct fdpic_func_descriptor __user *funcptr =
+                       (struct fdpic_func_descriptor *) ka->sa.sa_handler;
+               err |= __get_user(regs->dn[3], &funcptr->text);
+               err |= __get_user(regs->an[0], &funcptr->GOT);
+               if (err)
+                       goto give_sigsegv;
+
+               /*
+                * The funcdesc must be in a3 as this is required for the lazy
+                * resolver in ld.so, if the application is not FDPIC a3 is not
+                * used.
+                */
+               regs->an[3] = (unsigned long) funcptr;
+
+       } else {
+               regs->dn[3] = (unsigned long)ka->sa.sa_handler;
+               regs->an[0] = 0;
+       }
+
+       regs->frame_type =  UBICOM32_FRAME_TYPE_SIGTRAMP;
+
+       return;
+
+give_sigsegv:
+       /* user space exception */
+       force_sigsegv(sig, current);
+}
+
+static inline void
+handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
+{
+       switch (regs->dn[0]) {
+       case -ERESTARTNOHAND:
+               if (!has_handler)
+                       goto do_restart;
+               regs->dn[0] = -EINTR;
+               break;
+
+       case -ERESTARTSYS:
+               if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
+                       regs->dn[0] = -EINTR;
+                       break;
+               }
+       /* fallthrough */
+       case -ERESTARTNOINTR:
+       do_restart:
+               regs->dn[0] = regs->original_dn_0;
+               regs->pc -= 8;
+               regs->an[5] -= 8;
+               break;
+       }
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+static void
+handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
+             sigset_t *oldset, struct pt_regs *regs)
+{
+       /* are we from a system call? */
+       if (regs->frame_type == -1)
+               /* If so, check system call restarting.. */
+               handle_restart(regs, ka, 1);
+
+       /* set up the stack frame */
+       setup_rt_frame(sig, ka, info, oldset, regs);
+
+       if (ka->sa.sa_flags & SA_ONESHOT)
+               ka->sa.sa_handler = SIG_DFL;
+
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
+               sigaddset(&current->blocked,sig);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+}
+
+/*
+ * 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.
+ */
+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
+{
+       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 1;
+
+       if (!oldset)
+               oldset = &current->blocked;
+
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+       if (signr > 0) {
+               /* Whee!  Actually deliver the signal.  */
+               handle_signal(signr, &ka, &info, oldset, regs);
+               return 1;
+       }
+
+       /* Did we come from a system call? */
+       if (regs->frame_type == -1) {
+               /* Restart the system call - no handlers present */
+               handle_restart(regs, NULL, 0);
+       }
+
+       return 0;
+}
+
+/*
+ * sys_sigreturn()
+ *     Return handler for signal clean-up.
+ *
+ * NOTE: Ubicom32 does not use this syscall.  Instead we rely
+ * on do_rt_sigreturn().
+ */
+asmlinkage long sys_sigreturn(void)
+{
+       return -ENOSYS;
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/smp.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/smp.c
new file mode 100644 (file)
index 0000000..4aa27eb
--- /dev/null
@@ -0,0 +1,806 @@
+/*
+ * arch/ubicom32/kernel/smp.c
+ *   SMP implementation for Ubicom32 processors.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 2001,2004 Grant Grundler <grundler@parisc-linux.org>
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+#include <linux/kernel.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/kernel_stat.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/cpu.h>
+#include <linux/profile.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/current.h>
+#include <asm/tlbflush.h>
+#include <asm/timex.h>
+#include <asm/cpu.h>
+#include <asm/irq.h>
+#include <asm/processor.h>
+#include <asm/thread.h>
+#include <asm/sections.h>
+#include <asm/ip5000.h>
+
+/*
+ * Mask the debug printout for IPI because they are too verbose
+ * for regular debugging.
+ */
+
+// #define DEBUG_SMP 1
+#if !defined(DEBUG_SMP)
+#define smp_debug(lvl, ...)
+#else
+static unsigned int smp_debug_lvl = 50;
+#define smp_debug(lvl, printargs...)           \
+       if (lvl >= smp_debug_lvl) {             \
+                       printk(printargs);      \
+       }
+#endif
+
+#if !defined(DEBUG_SMP)
+#define DEBUG_ASSERT(cond)
+#else
+#define DEBUG_ASSERT(cond) \
+       if (!(cond)) { \
+               THREAD_STALL; \
+       }
+#endif
+
+/*
+ * List of IPI Commands (more than one can be set at a time).
+ */
+enum ipi_message_type {
+       IPI_NOP,
+       IPI_RESCHEDULE,
+       IPI_CALL_FUNC,
+       IPI_CALL_FUNC_SINGLE,
+       IPI_CPU_STOP,
+       IPI_CPU_TIMER,
+};
+
+/*
+ * We maintain a hardware thread oriented view of online threads
+ * and those involved or needing IPI.
+ */
+static volatile unsigned long smp_online_threads = 0;
+static volatile unsigned long smp_needs_ipi = 0;
+static volatile unsigned long smp_inside_ipi = 0;
+static unsigned long smp_irq_affinity[NR_IRQS];
+
+/*
+ * What do we need to track on a per cpu/thread basis?
+ */
+DEFINE_PER_CPU(struct cpuinfo_ubicom32, cpu_data);
+
+/*
+ * Each thread cpuinfo IPI information is guarded by a lock
+ * that is kept local to this file.
+ */
+DEFINE_PER_CPU(spinlock_t, ipi_lock) = SPIN_LOCK_UNLOCKED;
+
+/*
+ * The IPI(s) are based on a software IRQ through the LDSR.
+ */
+unsigned int smp_ipi_irq;
+
+/*
+ * Define a spinlock so that only one cpu is able to modify the
+ * smp_needs_ipi and to set/clear the IRQ at a time.
+ */
+DEFINE_SPINLOCK(smp_ipi_lock);
+
+/*
+ * smp_halt_processor()
+ *     Halt this hardware thread.
+ */
+static void smp_halt_processor(void)
+{
+       int cpuid = thread_get_self();
+       cpu_clear(smp_processor_id(), cpu_online_map);
+       local_irq_disable();
+       printk(KERN_EMERG "cpu[%d] has halted. It is not OK to turn off power \
+               until all cpu's are off.\n", cpuid);
+       for (;;) {
+               thread_suspend();
+       }
+}
+
+/*
+ * ipi_interrupt()
+ *     Handle an Interprocessor Interrupt.
+ */
+static irqreturn_t ipi_interrupt(int irq, void *dev_id)
+{
+       int cpuid = smp_processor_id();
+       struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid);
+       unsigned long ops;
+
+       /*
+        * Count this now; we may make a call that never returns.
+        */
+       p->ipi_count++;
+
+       /*
+        * We are about to process all ops.  If another cpu has stated
+        * that we need an IPI, we will have already processed it.  By
+        * clearing our smp_needs_ipi, and processing all ops,
+        * we reduce the number of IPI interrupts.  However, this introduces
+        * the possibility that smp_needs_ipi will be clear and the soft irq
+        * will have gone off; so we need to make the get_affinity() path
+        * tolerant of spurious interrupts.
+        */
+       spin_lock(&smp_ipi_lock);
+       smp_needs_ipi &= ~(1 << p->tid);
+       spin_unlock(&smp_ipi_lock);
+
+       for (;;) {
+               /*
+                * Read the set of IPI commands we should handle.
+                */
+               spinlock_t *lock = &per_cpu(ipi_lock, cpuid);
+               spin_lock(lock);
+               ops = p->ipi_pending;
+               p->ipi_pending = 0;
+               spin_unlock(lock);
+
+               /*
+                * If we have no IPI commands to execute, break out.
+                */
+               if (!ops) {
+                       break;
+               }
+
+               /*
+                * Execute the set of commands in the ops word, one command
+                * at a time in no particular order.  Strip of each command
+                * as we execute it.
+                */
+               while (ops) {
+                       unsigned long which = ffz(~ops);
+                       ops &= ~(1 << which);
+
+                       BUG_ON(!irqs_disabled());
+                       switch (which) {
+                       case IPI_NOP:
+                               smp_debug(100, KERN_INFO "cpu[%d]: "
+                                         "IPI_NOP\n", cpuid);
+                               break;
+
+                       case IPI_RESCHEDULE:
+                               /*
+                                * Reschedule callback.  Everything to be
+                                * done is done by the interrupt return path.
+                                */
+                               smp_debug(200, KERN_INFO "cpu[%d]: "
+                                         "IPI_RESCHEDULE\n", cpuid);
+                               break;
+
+                       case IPI_CALL_FUNC:
+                               smp_debug(100, KERN_INFO "cpu[%d]: "
+                                         "IPI_CALL_FUNC\n", cpuid);
+                               generic_smp_call_function_interrupt();
+                               break;
+
+                       case IPI_CALL_FUNC_SINGLE:
+                               smp_debug(100, KERN_INFO "cpu[%d]: "
+                                         "IPI_CALL_FUNC_SINGLE\n", cpuid);
+                               generic_smp_call_function_single_interrupt();
+                               break;
+
+                       case IPI_CPU_STOP:
+                               smp_debug(100, KERN_INFO "cpu[%d]: "
+                                         "IPI_CPU_STOP\n", cpuid);
+                               smp_halt_processor();
+                               break;
+
+#if !defined(CONFIG_LOCAL_TIMERS)
+                       case IPI_CPU_TIMER:
+                               smp_debug(100, KERN_INFO "cpu[%d]: "
+                                         "IPI_CPU_TIMER\n", cpuid);
+#if defined(CONFIG_GENERIC_CLOCKEVENTS)
+                               local_timer_interrupt();
+#else
+                               update_process_times(user_mode(get_irq_regs()));
+                               profile_tick(CPU_PROFILING);
+#endif
+#endif
+                               break;
+
+                       default:
+                               printk(KERN_CRIT "cpu[%d]: "
+                                         "Unknown IPI: %lu\n", cpuid, which);
+
+                               return IRQ_NONE;
+                       }
+
+                       /*
+                        * Let in any pending interrupts
+                        */
+                       BUG_ON(!irqs_disabled());
+                       local_irq_enable();
+                       local_irq_disable();
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+/*
+ * ipi_send()
+ *     Send an Interprocessor Interrupt.
+ */
+static void ipi_send(int cpu, enum ipi_message_type op)
+{
+       struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpu);
+       spinlock_t *lock = &per_cpu(ipi_lock, cpu);
+       unsigned long flags;
+
+       /*
+        * We protect the setting of the ipi_pending field and ensure
+        * that the ipi delivery mechanism and interrupt are atomically
+        * handled.
+        */
+       spin_lock_irqsave(lock, flags);
+       p->ipi_pending |= 1 << op;
+       spin_unlock_irqrestore(lock, flags);
+
+       spin_lock_irqsave(&smp_ipi_lock, flags);
+       smp_needs_ipi |= (1 << p->tid);
+       ubicom32_set_interrupt(smp_ipi_irq);
+       spin_unlock_irqrestore(&smp_ipi_lock, flags);
+       smp_debug(100, KERN_INFO "cpu[%d]: send: %d\n", cpu, op);
+}
+
+/*
+ * ipi_send_mask
+ *     Send an IPI to each cpu in mask.
+ */
+static inline void ipi_send_mask(unsigned int op, const struct cpumask mask)
+{
+       int cpu;
+       for_each_cpu_mask(cpu, mask) {
+               ipi_send(cpu, op);
+       }
+}
+
+/*
+ * ipi_send_allbutself()
+ *     Send an IPI to all threads but ourselves.
+ */
+static inline void ipi_send_allbutself(unsigned int op)
+{
+       int self = smp_processor_id();
+       struct cpumask result;
+       cpumask_copy(&result, &cpu_online_map);
+       cpu_clear(self, result);
+       ipi_send_mask(op, result);
+}
+
+/*
+ * smp_enable_vector()
+ */
+static void smp_enable_vector(unsigned int irq)
+{
+       ubicom32_clear_interrupt(smp_ipi_irq);
+       ldsr_enable_vector(irq);
+}
+
+/*
+ * smp_disable_vector()
+ *     Disable the interrupt by clearing the appropriate bit in the
+ *     LDSR Mask Register.
+ */
+static void smp_disable_vector(unsigned int irq)
+{
+       ldsr_disable_vector(irq);
+}
+
+/*
+ * smp_mask_vector()
+ */
+static void smp_mask_vector(unsigned int irq)
+{
+       ldsr_mask_vector(irq);
+}
+
+/*
+ * smp_unmask_vector()
+ */
+static void smp_unmask_vector(unsigned int irq)
+{
+       ldsr_unmask_vector(irq);
+}
+
+/*
+ * smp_end_vector()
+ *     Called once an interrupt is completed (reset the LDSR mask).
+ */
+static void smp_end_vector(unsigned int irq)
+{
+       struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, smp_processor_id());
+       spin_lock(&smp_ipi_lock);
+       smp_inside_ipi &= ~(1 << p->tid);
+       if (smp_inside_ipi) {
+               spin_unlock(&smp_ipi_lock);
+               return;
+       }
+       spin_unlock(&smp_ipi_lock);
+       ldsr_unmask_vector(irq);
+       smp_debug(100, KERN_INFO "cpu[%d]: unamesk vector\n", smp_processor_id());
+}
+
+/*
+ * Special hanlder functions for SMP.
+ */
+static struct irq_chip ubicom32_smp_chip = {
+       .name           = "UbicoIPI",
+       .startup        = NULL,
+       .shutdown       = NULL,
+       .enable         = smp_enable_vector,
+       .disable        = smp_disable_vector,
+       .ack            = NULL,
+       .mask           = smp_mask_vector,
+       .unmask         = smp_unmask_vector,
+       .end            = smp_end_vector,
+};
+
+/*
+ * smp_reset_ipi()
+ *     None of these cpu(s) got their IPI, turn it back on.
+ *
+ * Note: This is called by the LDSR which is not a full
+ * Linux cpu.  Thus you must use the raw form of locks
+ * because lock debugging will not work on the partial
+ * cpu nature of the LDSR.
+ */
+void smp_reset_ipi(unsigned long mask)
+{
+       __raw_spin_lock(&smp_ipi_lock.raw_lock);
+       smp_needs_ipi |= mask;
+       smp_inside_ipi &= ~mask;
+       ubicom32_set_interrupt(smp_ipi_irq);
+       __raw_spin_unlock(&smp_ipi_lock.raw_lock);
+       smp_debug(100, KERN_INFO "smp: reset IPIs for: 0x%x\n", mask);
+}
+
+/*
+ * smp_get_affinity()
+ *     Choose the thread affinity for this interrupt.
+ *
+ * Note: This is called by the LDSR which is not a full
+ * Linux cpu.  Thus you must use the raw form of locks
+ * because lock debugging will not work on the partial
+ * cpu nature of the LDSR.
+ */
+unsigned long smp_get_affinity(unsigned int irq, int *all)
+{
+       unsigned long mask = 0;
+
+       /*
+        * Most IRQ(s) are delivered in a round robin fashion.
+        */
+       if (irq != smp_ipi_irq) {
+               unsigned long result = smp_irq_affinity[irq] & smp_online_threads;
+               DEBUG_ASSERT(result);
+               *all = 0;
+               return result;
+       }
+
+       /*
+        * This is an IPI request.  Return all cpu(s) scheduled for an IPI.
+        * We also track those cpu(s) that are going to be "receiving" IPI this
+        * round.  When all CPU(s) have called smp_end_vector(),
+        * we will unmask the IPI interrupt.
+        */
+       __raw_spin_lock(&smp_ipi_lock.raw_lock);
+       ubicom32_clear_interrupt(smp_ipi_irq);
+       if (smp_needs_ipi) {
+               mask = smp_needs_ipi;
+               smp_inside_ipi |= smp_needs_ipi;
+               smp_needs_ipi = 0;
+       }
+       __raw_spin_unlock(&smp_ipi_lock.raw_lock);
+       *all = 1;
+       return mask;
+}
+
+/*
+ *  smp_set_affinity()
+ *     Set the affinity for this irq but store the value in tid(s).
+ */
+void smp_set_affinity(unsigned int irq, const struct cpumask *dest)
+{
+       int cpuid;
+       unsigned long *paffinity = &smp_irq_affinity[irq];
+
+       /*
+        *  If none specified, all cpus are allowed.
+        */
+       if (cpus_empty(*dest)) {
+               *paffinity = 0xffffffff;
+               return;
+       }
+
+       /*
+        * Make sure to clear the old value before setting up the
+        * list.
+        */
+       *paffinity = 0;
+       for_each_cpu_mask(cpuid, *dest) {
+               struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid);
+               *paffinity |= (1 << p->tid);
+       }
+}
+
+/*
+ * smp_send_stop()
+ *     Send a stop request to all CPU but this one.
+ */
+void smp_send_stop(void)
+{
+       ipi_send_allbutself(IPI_CPU_STOP);
+}
+
+/*
+ * smp_send_timer_all()
+ *     Send all cpu(s) but this one, a request to update times.
+ */
+void smp_send_timer_all(void)
+{
+       ipi_send_allbutself(IPI_CPU_TIMER);
+}
+
+/*
+ * smp_timer_broadcast()
+ *     Use an IPI to broadcast a timer message
+ */
+void smp_timer_broadcast(const struct cpumask *mask)
+{
+       ipi_send_mask(IPI_CPU_TIMER, *mask);
+}
+
+/*
+ * smp_send_reschedule()
+ *     Send a reschedule request to the specified cpu.
+ */
+void smp_send_reschedule(int cpu)
+{
+       ipi_send(cpu, IPI_RESCHEDULE);
+}
+
+/*
+ * arch_send_call_function_ipi()
+ *     Cause each cpu in the mask to call the generic function handler.
+ */
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
+{
+       int cpu;
+       for_each_cpu_mask(cpu, *mask) {
+               ipi_send(cpu, IPI_CALL_FUNC);
+       }
+}
+
+/*
+ * arch_send_call_function_single_ipi()
+ *     Cause the specified cpu to call the generic function handler.
+ */
+void arch_send_call_function_single_ipi(int cpu)
+{
+       ipi_send(cpu, IPI_CALL_FUNC_SINGLE);
+}
+
+/*
+ * setup_profiling_timer()
+ *     Dummy function created to keep Oprofile happy in the SMP case.
+ */
+int setup_profiling_timer(unsigned int multiplier)
+{
+       return 0;
+}
+
+/*
+ * smp_mainline_start()
+ *     Start a slave thread executing a mainline Linux context.
+ */
+static void __init smp_mainline_start(void *arg)
+{
+       int cpuid = smp_processor_id();
+       struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid);
+
+       BUG_ON(p->tid != thread_get_self());
+
+       /*
+        * Well, support 2.4 linux scheme as well.
+        */
+       if (cpu_test_and_set(cpuid, cpu_online_map)) {
+               printk(KERN_CRIT "cpu[%d]: already initialized!\n", cpuid);
+               smp_halt_processor();
+               return;
+       }
+
+       /*
+        * Initialise the idle task for this CPU
+        */
+       atomic_inc(&init_mm.mm_count);
+       current->active_mm = &init_mm;
+       if (current->mm) {
+               printk(KERN_CRIT "cpu[%d]: idle task already has memory "
+                      "management\n", cpuid);
+               smp_halt_processor();
+               return;
+       }
+
+       /*
+        * TODO: X86 does this prior to calling notify, try to understand why?
+        */
+       preempt_disable();
+
+#if defined(CONFIG_GENERIC_CLOCKEVENTS)
+       /*
+        * Setup a local timer event so that this cpu will get timer interrupts
+        */
+       if (local_timer_setup(cpuid) == -1) {
+               printk(KERN_CRIT "cpu[%d]: timer alloc failed\n", cpuid);
+               smp_halt_processor();
+               return;
+       }
+#endif
+
+       /*
+        * Notify those interested that we are up and alive.  This must
+        * be done before interrupts are enabled.  It must also be completed
+        * before the bootstrap cpu returns from __cpu_up() (see comment
+        * above cpu_set() of the cpu_online_map).
+        */
+       notify_cpu_starting(cpuid);
+
+       /*
+        * Indicate that this thread is now online and present.   Setting
+        * cpu_online_map has the side effect of allowing the bootstrap
+        * cpu to continue along; so anything that MUST be done prior to the
+        * bootstrap cpu returning from __cpu_up() needs to go above here.
+        */
+       cpu_set(cpuid, cpu_online_map);
+       cpu_set(cpuid, cpu_present_map);
+
+       /*
+        * Maintain a thread mapping in addition to the cpu mapping.
+        */
+       smp_online_threads |= (1 << p->tid);
+
+       /*
+        * Enable interrupts for this thread.
+        */
+       local_irq_enable();
+
+       /*
+        * Enter the idle loop and wait for a timer to schedule some work.
+        */
+       printk(KERN_INFO "cpu[%d]: entering cpu_idle()\n", cpuid);
+       cpu_idle();
+
+       /* Not Reached */
+}
+
+/*
+ * smp_cpus_done()
+ *     Called once the kernel_init() has brought up all cpu(s).
+ */
+void smp_cpus_done(unsigned int cpu_max)
+{
+       /* Do Nothing */
+}
+
+/*
+ * __cpu_up()
+ *     Called to startup a sepcific cpu.
+ */
+int __cpuinit __cpu_up(unsigned int cpu)
+{
+       struct task_struct *idle;
+       unsigned int *stack;
+       long timeout;
+       struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpu);
+
+       /*
+        * Create an idle task for this CPU.
+        */
+       idle = fork_idle(cpu);
+       if (IS_ERR(idle)) {
+               panic("cpu[%d]: fork failed\n", cpu);
+               return -ENOSYS;
+       }
+       task_thread_info(idle)->cpu = cpu;
+
+       /*
+        * Setup the sw_ksp[] to point to this new task.
+        */
+       sw_ksp[p->tid] = (unsigned int)idle->stack;
+       stack = (unsigned int *)(sw_ksp[p->tid] + PAGE_SIZE - 8);
+
+       /*
+        * Cause the specified thread to execute our smp_mainline_start
+        * function as a TYPE_NORMAL thread.
+        */
+       printk(KERN_INFO "cpu[%d]: launching mainline Linux thread\n", cpu);
+       if (thread_start(p->tid, smp_mainline_start, (void *)NULL, stack,
+                        THREAD_TYPE_NORMAL) == -1) {
+               printk(KERN_WARNING "cpu[%d]: failed thread_start\n", cpu);
+               return -ENOSYS;
+       }
+
+       /*
+        * Wait for the thread to start up.  The thread will set
+        * the online bit when it is running.  Our caller execpts the
+        * cpu to be online if we return 0.
+        */
+       for (timeout = 0; timeout < 10000; timeout++) {
+               if (cpu_online(cpu)) {
+                       break;
+               }
+
+               udelay(100);
+               barrier();
+               continue;
+       }
+
+       if (!cpu_online(cpu)) {
+               printk(KERN_CRIT "cpu[%d]: failed to live after %ld us\n",
+                      cpu, timeout * 100);
+               return -ENOSYS;
+       }
+
+       printk(KERN_INFO "cpu[%d]: came alive after %ld us\n",
+              cpu, timeout * 100);
+       return 0;
+}
+
+/*
+ * Data used by setup_irq for the IPI.
+ */
+static struct irqaction ipi_irq = {
+       .name    = "ipi",
+       .flags   = IRQF_DISABLED | IRQF_PERCPU,
+       .handler = ipi_interrupt,
+};
+
+/*
+ * smp_prepare_cpus()
+ *     Mark threads that are available to Linux as possible cpus(s).
+ */
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+       int i;
+
+       /*
+        * We will need a software IRQ to send IPI(s).  We will use
+        * a single software IRQ for all IPI(s).
+        */
+       if (irq_soft_alloc(&smp_ipi_irq) < 0) {
+               panic("no software IRQ is available\n");
+               return;
+       }
+
+       /*
+        * For the IPI interrupt, we want to use our own chip definition.
+        * This allows us to define what happens in SMP IPI without affecting
+        * the performance of the other interrupts.
+        *
+        * Next, Register the IPI interrupt function against the soft IRQ.
+        */
+       set_irq_chip(smp_ipi_irq, &ubicom32_smp_chip);
+       setup_irq(smp_ipi_irq, &ipi_irq);
+
+       /*
+        * We use the device tree node to determine how many
+        * free cpus we will have (up to NR_CPUS) and we indicate
+        * that those cpus are present.
+        *
+        * We need to do this very early in the SMP case
+        * because the Linux init code uses the cpu_present_map.
+        */
+       for_each_possible_cpu(i) {
+               thread_t tid;
+               struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, i);
+
+               /*
+                *  Skip the bootstrap cpu
+                */
+               if (i == 0) {
+                       continue;
+               }
+
+               /*
+                * If we have a free thread left in the mask,
+                * indicate that the cpu is present.
+                */
+               tid = thread_alloc();
+               if (tid == (thread_t)-1) {
+                       break;
+               }
+
+               /*
+                * Save the hardware thread id for this cpu.
+                */
+               p->tid = tid;
+               cpu_set(i, cpu_present_map);
+               printk(KERN_INFO "cpu[%d]: added to cpu_present_map - tid: %d\n", i, tid);
+       }
+}
+
+/*
+ * smp_prepare_boot_cpu()
+ *     Copy the per_cpu data into the appropriate spot for the bootstrap cpu.
+ *
+ * The code in boot_cpu_init() has already set the boot cpu's
+ * state in the possible, present, and online maps.
+ */
+void __devinit smp_prepare_boot_cpu(void)
+{
+       struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, 0);
+
+       smp_online_threads |= (1 << p->tid);
+       printk(KERN_INFO "cpu[%d]: bootstrap CPU online - tid: %ld\n",
+                       current_thread_info()->cpu, p->tid);
+}
+
+/*
+ * smp_setup_processor_id()
+ *     Set the current_thread_info() structure cpu value.
+ *
+ * We set the value to the true hardware thread value that we are running on.
+ * NOTE: this function overrides the weak alias function in main.c
+ */
+void __init smp_setup_processor_id(void)
+{
+       struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, 0);
+       int i;
+       for_each_cpu_mask(i, CPU_MASK_ALL)
+               set_cpu_possible(i, true);
+
+       current_thread_info()->cpu = 0;
+       p->tid = thread_get_self();
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/stacktrace.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/stacktrace.c
new file mode 100644 (file)
index 0000000..2a10e3f
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * arch/ubicom32/kernel/stacktrace.c
+ *   Ubicom32 architecture stack back trace implementation.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/module.h>
+#include <asm/stacktrace.h>
+#include <asm/thread.h>
+#include <asm/ip5000.h>
+
+/*
+ * These symbols are filled in by the linker.
+ */
+extern unsigned long _stext;
+extern unsigned long _etext;
+
+extern unsigned long __ocm_text_run_begin;
+extern unsigned long __data_begin;
+
+/*
+ * stacktrace_iterate()
+ *     Walk the stack looking for call and calli instructions on an aligned
+ *     boundary.
+ *
+ * Trace must point to the top of the current stack frame.
+ */
+unsigned long stacktrace_iterate(unsigned long **trace,
+                                unsigned long stext,
+                                unsigned long etext,
+                                unsigned long ocm_stext,
+                                unsigned long ocm_etext,
+                                unsigned long sstack,
+                                unsigned long estack)
+{
+       unsigned int thread_trap_en, instruction;
+       unsigned long address;
+       unsigned int limit = 0;
+       unsigned long result = 0;
+       unsigned long *sp = *trace;
+
+       /*
+        * Exclude the current thread from being monitored for traps.
+        */
+       asm volatile(
+               "       thread_get_self_mask d15                \n\t"
+                       /* save current trap status */
+               "       and.4   %0, MT_TRAP_EN, d15             \n\t"
+               "       not.4   d15, d15                        \n\t"
+                       /* disable trap */
+               "       and.4   MT_TRAP_EN, MT_TRAP_EN, d15     \n\t"
+               "       pipe_flush 0                            \n\t"
+               : "=r" (thread_trap_en)
+               :
+               : "d15", "cc"
+       );
+
+       while (limit++ < 256) {
+               /*
+                * See if we have a valid stack.
+                */
+               if (!between((unsigned long)sp, sstack, estack)) {
+#ifdef TRAP_DEBUG_STACK_TRACE
+                       printk(KERN_EMERG "stack address is out of range - "
+                              "sp: %x, sstack: %x, estack: %x\n",
+                              (unsigned int)sp, (unsigned int)sstack,
+                              (unsigned int)estack);
+#endif
+                       result = 0;
+                       *trace = 0;
+                       break;
+               }
+
+               /*
+                * Get the value off the stack and back up 4 bytes to what
+                * should be the address of a call or calli.
+                */
+               address = (*sp++) - 4;
+
+               /*
+                * If the address is not within the text segment, skip this
+                * value.
+                */
+               if (!between(address, stext, etext) &&
+                   !between(address, ocm_stext, ocm_etext)) {
+#ifdef TRAP_DEBUG_STACK_TRACE
+                       printk(KERN_EMERG "not a text address - "
+                              "address: %08x, stext: %08x, etext: %08x\n"
+                              "ocm_stext: %08x, ocm_etext: %08x\n",
+                              (unsigned int)address,
+                              (unsigned int)stext,
+                              (unsigned int)etext,
+                              (unsigned int)ocm_stext,
+                              (unsigned int)ocm_etext);
+#endif
+                       continue;
+
+               }
+
+               /*
+                * If the address is not on an aligned boundary it can not be a
+                * return address.
+                */
+               if (address & 0x3) {
+                       continue;
+               }
+
+               /*
+                * Read the probable instruction.
+                */
+               instruction = *(unsigned int *)address;
+
+               /*
+                * Is this a call instruction?
+                */
+               if ((instruction & 0xF8000000) == (u32_t)(0x1B << 27)) {
+#ifdef TRAP_DEBUG_STACK_TRACE
+                       printk(KERN_EMERG "call inst. result: %x, "
+                              "test: %x\n", (unsigned int)address,
+                              (unsigned int)instruction);
+#endif
+                       *trace = sp;
+                       result = address;
+                       break;
+               }
+
+               /*
+                * Is this a calli instruction?
+                */
+               if ((instruction & 0xF8000000) == (u32_t)(0x1E << 27)) {
+#ifdef TRAP_DEBUG_STACK_TRACE
+                       printk(KERN_EMERG "calli inst. result: %x, "
+                              "test: %x\n", (unsigned int)address,
+                              (unsigned int)instruction);
+#endif
+                       *trace = sp;
+                       result = address;
+                       break;
+               }
+       }
+
+       /*
+        * Restore the current thread to be monitored for traps.
+        */
+       if (thread_trap_en) {
+               asm volatile(
+               "       thread_get_self_mask d15                \n\t"
+               "       or.4    MT_TRAP_EN, MT_TRAP_EN, d15     \n\t"
+                       :
+                       :
+                       : "d15", "cc"
+               );
+       }
+       return result;
+}
+
+#ifdef CONFIG_STACKTRACE
+/*
+ * stacktrace_save_entries()
+ *     Save stack back trace information into the provided trace structure.
+ */
+void stacktrace_save_entries(struct task_struct *tsk,
+                            struct stack_trace *trace,
+                            unsigned long sp)
+{
+       unsigned long code_start = (unsigned long)&_stext;
+       unsigned long code_end = (unsigned long)&_etext;
+       unsigned long ocm_code_start = (unsigned long)&__ocm_text_run_begin;
+       unsigned long ocm_code_end = (unsigned long)&__data_begin;
+       unsigned long stack_end = (unsigned long)(tsk->stack + THREAD_SIZE - 8);
+       unsigned long stack = (unsigned long)sp;
+       unsigned int idx = 0;
+       unsigned long *handle;
+       int skip = trace->skip;
+
+       handle = (unsigned long *)stack;
+       while (idx < trace->max_entries) {
+               if (skip) {
+                       skip--;
+                       continue;
+               }
+               trace->entries[idx] = stacktrace_iterate(&handle,
+                                       code_start, code_end,
+                                       ocm_code_start, ocm_code_end,
+                                       (unsigned long)stack, stack_end);
+               if (trace->entries[idx] == 0) {
+                       break;
+               }
+               idx++;
+       }
+}
+
+/*
+ * save_stack_trace()
+ *     Save the specified amount of the kernel stack trace information
+ *     for the current task.
+ */
+void save_stack_trace(struct stack_trace *trace)
+{
+       unsigned long sp = 0;
+       asm volatile (
+       "       move.4  %0, SP          \n\t"
+               : "=r" (sp)
+       );
+       stacktrace_save_entries(current, trace, sp);
+}
+EXPORT_SYMBOL_GPL(save_stack_trace);
+
+/*
+ * save_stack_trace_tsk()
+ *     Save the specified amount of the kernel stack trace information
+ *     for the specified task.
+ *
+ * Note: We assume the specified task is not currently running.
+ */
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+       stacktrace_save_entries(tsk, trace, tsk->thread.sp);
+}
+EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
+#endif /* CONFIG_STACKTRACE */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/sys_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/sys_ubicom32.c
new file mode 100644 (file)
index 0000000..b06f3f3
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * arch/ubicom32/kernel/sys_ubicom32.c
+ *   Ubicom32 architecture system call support implementation.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/ubicom32
+ * platform.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/utsname.h>
+#include <linux/ipc.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/unistd.h>
+
+#include <asm/setup.h>
+#include <asm/traps.h>
+#include <asm/cacheflush.h>
+
+/* common code for old and new mmaps */
+static inline long do_mmap2(
+       unsigned long addr, unsigned long len,
+       unsigned long prot, unsigned long flags,
+       unsigned long fd, unsigned long pgoff)
+{
+       int error = -EBADF;
+       struct file *file = NULL;
+
+       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+       if (!(flags & MAP_ANONYMOUS)) {
+               file = fget(fd);
+               if (!file)
+                       goto out;
+       }
+
+       down_write(&current->mm->mmap_sem);
+       error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+       up_write(&current->mm->mmap_sem);
+
+       if (file)
+               fput(file);
+out:
+       return error;
+}
+
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+       unsigned long prot, unsigned long flags,
+       unsigned long fd, unsigned long pgoff)
+{
+       return do_mmap2(addr, len, prot, flags, fd, pgoff);
+}
+
+/*
+ * Perform the select(nd, in, out, ex, tv) and mmap() system
+ * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to
+ * handle more than 4 system call parameters, so these system calls
+ * used a memory block for parameter passing..
+ */
+
+struct mmap_arg_struct {
+       unsigned long addr;
+       unsigned long len;
+       unsigned long prot;
+       unsigned long flags;
+       unsigned long fd;
+       unsigned long offset;
+};
+
+asmlinkage int old_mmap(struct mmap_arg_struct *arg)
+{
+       struct mmap_arg_struct a;
+       int error = -EFAULT;
+
+       if (copy_from_user(&a, arg, sizeof(a)))
+               goto out;
+
+       error = -EINVAL;
+       if (a.offset & ~PAGE_MASK)
+               goto out;
+
+       a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+       error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd,
+                        a.offset >> PAGE_SHIFT);
+out:
+       return error;
+}
+
+struct sel_arg_struct {
+       unsigned long n;
+       fd_set *inp, *outp, *exp;
+       struct timeval *tvp;
+};
+
+asmlinkage int old_select(struct sel_arg_struct *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 int sys_ipc(uint call, int first, int second,
+                       int third, void *ptr, long fifth)
+{
+       int version, ret;
+
+       version = call >> 16; /* hack for backward compatibility */
+       call &= 0xffff;
+
+       if (call <= SEMCTL)
+               switch (call) {
+               case SEMOP:
+                       return sys_semop(first, (struct sembuf *)ptr, second);
+               case SEMGET:
+                       return sys_semget(first, second, third);
+               case SEMCTL: {
+                       union semun fourth;
+                       if (!ptr)
+                               return -EINVAL;
+                       if (get_user(fourth.__pad, (void **) ptr))
+                               return -EFAULT;
+                       return sys_semctl(first, second, third, fourth);
+                       }
+               default:
+                       return -EINVAL;
+               }
+       if (call <= MSGCTL)
+               switch (call) {
+               case MSGSND:
+                       return sys_msgsnd(first, (struct msgbuf *) 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 *)ptr,
+                                                  sizeof(tmp)))
+                                       return -EFAULT;
+                               return sys_msgrcv(first, tmp.msgp, second,
+                                                  tmp.msgtyp, third);
+                               }
+                       default:
+                               return sys_msgrcv(first,
+                                                 (struct msgbuf *) ptr,
+                                                 second, fifth, third);
+                       }
+               case MSGGET:
+                       return sys_msgget((key_t) first, second);
+               case MSGCTL:
+                       return sys_msgctl(first, second,
+                                          (struct msqid_ds *) ptr);
+               default:
+                       return -EINVAL;
+               }
+       if (call <= SHMCTL)
+               switch (call) {
+               case SHMAT:
+                       switch (version) {
+                       default: {
+                               ulong raddr;
+                               ret = do_shmat(first, ptr, second, &raddr);
+                               if (ret)
+                                       return ret;
+                               return put_user(raddr, (ulong __user *) third);
+                       }
+                       }
+               case SHMDT:
+                       return sys_shmdt(ptr);
+               case SHMGET:
+                       return sys_shmget(first, second, third);
+               case SHMCTL:
+                       return sys_shmctl(first, second, ptr);
+               default:
+                       return -ENOSYS;
+               }
+
+       return -EINVAL;
+}
+
+/* sys_cacheflush -- flush (part of) the processor cache.  */
+asmlinkage int
+sys_cacheflush(unsigned long addr, int scope, int cache, unsigned long len)
+{
+       flush_cache_all();
+       return 0;
+}
+
+asmlinkage int sys_getpagesize(void)
+{
+       return PAGE_SIZE;
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/syscalltable.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/syscalltable.S
new file mode 100644 (file)
index 0000000..8921fb8
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * arch/ubicom32/kernel/syscalltable.S
+ *     <TODO: Replace with short file description>
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+/*
+ *
+ *  Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com)
+ *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>, Kenneth Albanowski <kjahds@kjahds.com>,
+ *  Copyright (C) 2000  Lineo Inc. (www.lineo.com)
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/unistd.h>
+
+.text
+ALIGN
+       .global sys_call_table
+sys_call_table:
+       .long sys_ni_syscall    /* 0  -  old "setup()" system call*/
+       .long sys_exit
+       .long sys_fork
+       .long sys_read
+       .long sys_write
+       .long sys_open          /* 5 */
+       .long sys_close
+       .long sys_waitpid
+       .long sys_creat
+       .long sys_link
+       .long sys_unlink        /* 10 */
+       .long execve_intercept
+       .long sys_chdir
+       .long sys_time
+       .long sys_mknod
+       .long sys_chmod         /* 15 */
+       .long sys_chown16
+       .long sys_ni_syscall    /* old break syscall holder */
+       .long sys_stat
+       .long sys_lseek
+       .long sys_getpid        /* 20 */
+       .long sys_mount
+       .long sys_oldumount
+       .long sys_setuid16
+       .long sys_getuid16
+       .long sys_stime         /* 25 */
+       .long sys_ptrace
+       .long sys_alarm
+       .long sys_fstat
+       .long sys_pause
+       .long sys_utime         /* 30 */
+       .long sys_ni_syscall    /* old stty syscall holder */
+       .long sys_ni_syscall    /* old gtty syscall holder */
+       .long sys_access
+       .long sys_nice
+       .long sys_ni_syscall    /* 35 */ /* old ftime syscall holder */
+       .long sys_sync
+       .long sys_kill
+       .long sys_rename
+       .long sys_mkdir
+       .long sys_rmdir         /* 40 */
+       .long sys_dup
+       .long sys_pipe
+       .long sys_times
+       .long sys_ni_syscall    /* old prof syscall holder */
+       .long sys_brk           /* 45 */
+       .long sys_setgid16
+       .long sys_getgid16
+       .long sys_signal
+       .long sys_geteuid16
+       .long sys_getegid16     /* 50 */
+       .long sys_acct
+       .long sys_umount        /* recycled never used phys() */
+       .long sys_ni_syscall    /* old lock syscall holder */
+       .long sys_ioctl
+       .long sys_fcntl         /* 55 */
+       .long sys_ni_syscall    /* old mpx syscall holder */
+       .long sys_setpgid
+       .long sys_ni_syscall    /* old ulimit syscall holder */
+       .long sys_ni_syscall
+       .long sys_umask         /* 60 */
+       .long sys_chroot
+       .long sys_ustat
+       .long sys_dup2
+       .long sys_getppid
+       .long sys_getpgrp       /* 65 */
+       .long sys_setsid
+       .long sys_sigaction
+       .long sys_sgetmask
+       .long sys_ssetmask
+       .long sys_setreuid16    /* 70 */
+       .long sys_setregid16
+       .long sys_sigsuspend
+       .long sys_sigpending
+       .long sys_sethostname
+       .long sys_setrlimit     /* 75 */
+       .long sys_old_getrlimit
+       .long sys_getrusage
+       .long sys_gettimeofday
+       .long sys_settimeofday
+       .long sys_getgroups16   /* 80 */
+       .long sys_setgroups16
+       .long old_select
+       .long sys_symlink
+       .long sys_lstat
+       .long sys_readlink      /* 85 */
+       .long sys_uselib
+       .long sys_ni_syscall    /* _sys_swapon */
+       .long sys_reboot
+       .long sys_old_readdir
+       .long old_mmap          /* 90 */
+       .long sys_munmap
+       .long sys_truncate
+       .long sys_ftruncate
+       .long sys_fchmod
+       .long sys_fchown16      /* 95 */
+       .long sys_getpriority
+       .long sys_setpriority
+       .long sys_ni_syscall    /* old profil syscall holder */
+       .long sys_statfs
+       .long sys_fstatfs       /* 100 */
+       .long sys_ni_syscall    /* ioperm for i386 */
+       .long sys_socketcall
+       .long sys_syslog
+       .long sys_setitimer
+       .long sys_getitimer     /* 105 */
+       .long sys_newstat
+       .long sys_newlstat
+       .long sys_newfstat
+       .long sys_ni_syscall
+       .long sys_ni_syscall    /* iopl for i386 */ /* 110 */
+       .long sys_vhangup
+       .long sys_ni_syscall    /* obsolete idle() syscall */
+       .long sys_ni_syscall    /* vm86old for i386 */
+       .long sys_wait4
+       .long sys_ni_syscall    /* 115 */ /* _sys_swapoff */
+       .long sys_sysinfo
+       .long sys_ipc
+       .long sys_fsync
+       .long sys_sigreturn
+       .long clone_intercept   /* 120 */
+       .long sys_setdomainname
+       .long sys_newuname
+       .long sys_cacheflush    /* modify_ldt for i386 */
+       .long sys_adjtimex
+       .long sys_ni_syscall    /* 125 */ /* _sys_mprotect */
+       .long sys_sigprocmask
+       .long sys_ni_syscall    /* old "creat_module" */
+       .long sys_init_module
+       .long sys_delete_module
+       .long sys_ni_syscall    /* 130: old "get_kernel_syms" */
+       .long sys_quotactl
+       .long sys_getpgid
+       .long sys_fchdir
+       .long sys_bdflush
+       .long sys_sysfs         /* 135 */
+       .long sys_personality
+       .long sys_ni_syscall    /* for afs_syscall */
+       .long sys_setfsuid16
+       .long sys_setfsgid16
+       .long sys_llseek        /* 140 */
+       .long sys_getdents
+       .long sys_select
+       .long sys_flock
+       .long sys_ni_syscall    /* _sys_msync */
+       .long sys_readv         /* 145 */
+       .long sys_writev
+       .long sys_getsid
+       .long sys_fdatasync
+       .long sys_sysctl
+       .long sys_ni_syscall    /* 150 */ /* _sys_mlock */
+       .long sys_ni_syscall    /* _sys_munlock */
+       .long sys_ni_syscall    /* _sys_mlockall */
+       .long sys_ni_syscall    /* _sys_munlockall */
+       .long sys_sched_setparam
+       .long sys_sched_getparam /* 155 */
+       .long sys_sched_setscheduler
+       .long sys_sched_getscheduler
+       .long sys_sched_yield
+       .long sys_sched_get_priority_max
+       .long sys_sched_get_priority_min  /* 160 */
+       .long sys_sched_rr_get_interval
+       .long sys_nanosleep
+       .long sys_ni_syscall    /* _sys_mremap */
+       .long sys_setresuid16
+       .long sys_getresuid16   /* 165 */
+       .long sys_getpagesize   /* _sys_getpagesize */
+       .long sys_ni_syscall    /* old "query_module" */
+       .long sys_poll
+       .long sys_ni_syscall    /* _sys_nfsservctl */
+       .long sys_setresgid16   /* 170 */
+       .long sys_getresgid16
+       .long sys_prctl
+       .long sys_rt_sigreturn
+       .long sys_rt_sigaction
+       .long sys_rt_sigprocmask /* 175 */
+       .long sys_rt_sigpending
+       .long sys_rt_sigtimedwait
+       .long sys_rt_sigqueueinfo
+       .long sys_rt_sigsuspend
+       .long sys_pread64       /* 180 */
+       .long sys_pwrite64
+       .long sys_lchown16
+       .long sys_getcwd
+       .long sys_capget
+       .long sys_capset        /* 185 */
+       .long sys_sigaltstack
+       .long sys_sendfile
+       .long sys_ni_syscall    /* streams1 */
+       .long sys_ni_syscall    /* streams2 */
+       .long vfork_intercept           /* 190 */
+       .long sys_getrlimit
+       .long sys_mmap2
+       .long sys_truncate64
+       .long sys_ftruncate64
+       .long sys_stat64        /* 195 */
+       .long sys_lstat64
+       .long sys_fstat64
+       .long sys_chown
+       .long sys_getuid
+       .long sys_getgid        /* 200 */
+       .long sys_geteuid
+       .long sys_getegid
+       .long sys_setreuid
+       .long sys_setregid
+       .long sys_getgroups     /* 205 */
+       .long sys_setgroups
+       .long sys_fchown
+       .long sys_setresuid
+       .long sys_getresuid
+       .long sys_setresgid     /* 210 */
+       .long sys_getresgid
+       .long sys_lchown
+       .long sys_setuid
+       .long sys_setgid
+       .long sys_setfsuid      /* 215 */
+       .long sys_setfsgid
+       .long sys_pivot_root
+       .long sys_ni_syscall
+       .long sys_ni_syscall
+       .long sys_getdents64    /* 220 */
+       .long sys_gettid
+       .long sys_tkill
+       .long sys_setxattr
+       .long sys_lsetxattr
+       .long sys_fsetxattr     /* 225 */
+       .long sys_getxattr
+       .long sys_lgetxattr
+       .long sys_fgetxattr
+       .long sys_listxattr
+       .long sys_llistxattr    /* 230 */
+       .long sys_flistxattr
+       .long sys_removexattr
+       .long sys_lremovexattr
+       .long sys_fremovexattr
+       .long sys_futex         /* 235 */
+       .long sys_sendfile64
+       .long sys_ni_syscall    /* _sys_mincore */
+       .long sys_ni_syscall    /* _sys_madvise */
+       .long sys_fcntl64
+       .long sys_readahead     /* 240 */
+       .long sys_io_setup
+       .long sys_io_destroy
+       .long sys_io_getevents
+       .long sys_io_submit
+       .long sys_io_cancel     /* 245 */
+       .long sys_fadvise64
+       .long sys_exit_group
+       .long sys_lookup_dcookie
+       .long sys_epoll_create
+       .long sys_epoll_ctl     /* 250 */
+       .long sys_epoll_wait
+       .long sys_ni_syscall    /* _sys_remap_file_pages */
+       .long sys_set_tid_address
+       .long sys_timer_create
+       .long sys_timer_settime /* 255 */
+       .long sys_timer_gettime
+       .long sys_timer_getoverrun
+       .long sys_timer_delete
+       .long sys_clock_settime
+       .long sys_clock_gettime /* 260 */
+       .long sys_clock_getres
+       .long sys_clock_nanosleep
+       .long sys_statfs64
+       .long sys_fstatfs64
+       .long sys_tgkill        /* 265 */
+       .long sys_utimes
+       .long sys_fadvise64_64
+       .long sys_mbind
+       .long sys_get_mempolicy
+       .long sys_set_mempolicy /* 270 */
+       .long sys_mq_open
+       .long sys_mq_unlink
+       .long sys_mq_timedsend
+       .long sys_mq_timedreceive
+       .long sys_mq_notify     /* 275 */
+       .long sys_mq_getsetattr
+       .long sys_waitid
+       .long sys_ni_syscall    /* for _sys_vserver */
+       .long sys_add_key
+       .long sys_request_key   /* 280 */
+       .long sys_keyctl
+       .long sys_ioprio_set
+       .long sys_ioprio_get
+       .long sys_inotify_init
+       .long sys_inotify_add_watch     /* 285 */
+       .long sys_inotify_rm_watch
+       .long sys_migrate_pages
+       .long sys_openat
+       .long sys_mkdirat
+       .long sys_mknodat               /* 290 */
+       .long sys_fchownat
+       .long sys_futimesat
+       .long sys_fstatat64
+       .long sys_unlinkat
+       .long sys_renameat              /* 295 */
+       .long sys_linkat
+       .long sys_symlinkat
+       .long sys_readlinkat
+       .long sys_fchmodat
+       .long sys_faccessat             /* 300 */
+       .long sys_ni_syscall            /* Reserved for pselect6 */
+       .long sys_ni_syscall            /* Reserved for ppoll */
+       .long sys_unshare
+       .long sys_set_robust_list
+       .long sys_get_robust_list       /* 305 */
+       .long sys_splice
+       .long sys_sync_file_range
+       .long sys_tee
+       .long sys_vmsplice
+       .long sys_move_pages            /* 310 */
+       .long sys_sched_setaffinity
+       .long sys_sched_getaffinity
+       .long sys_kexec_load
+       .long sys_getcpu
+       .long sys_epoll_pwait           /* 315 */
+       .long sys_utimensat
+       .long sys_signalfd
+       .long sys_timerfd_create
+       .long sys_eventfd
+       .long sys_fallocate             /* 320 */
+       .long sys_timerfd_settime
+       .long sys_timerfd_gettime
+       .long sys_ni_syscall            /* sys_signalfd4 */
+       .long sys_ni_syscall            /* sys_eventfd2 */
+       .long sys_ni_syscall            /* sys_epoll_create1 */
+                                       /* 325 */
+       .long sys_ni_syscall            /* sys_dup3 */
+       .long sys_ni_syscall            /* sys_pipe2 */
+       .long sys_ni_syscall            /* sys_inotify_init1 */
+       .rept NR_syscalls-(.-sys_call_table)/4
+               .long sys_ni_syscall
+       .endr
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/thread.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/thread.c
new file mode 100644 (file)
index 0000000..aaa5fbe
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * arch/ubicom32/kernel/thread.c
+ *   Ubicom32 architecture hardware thread support.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
+#include <linux/types.h>
+#include <asm/ip5000.h>
+#include <asm/machdep.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread.h>
+
+/*
+ * TODO: At some point change the name here to be thread_ksp
+ */
+unsigned int sw_ksp[THREAD_ARCHITECTURAL_MAX];
+
+static unsigned int thread_mask = -1;
+static unsigned int thread_mainline_mask;
+
+/*
+ * thread_entry()
+ *     Returning from the called function will disable the thread.
+ *
+ * This could be a naked call to allow for hwthreads that do not have stacks.
+ * However, with -O0, the code still writes to thex stack, and this was
+ * corrupting memory just after the callers stack.
+ */
+static void thread_entry(void *arg, thread_exec_fn_t exec)
+{
+       /*
+        * Call thread function
+        */
+       exec(arg);
+
+       /*
+        * Complete => Disable self
+        */
+       thread_disable(thread_get_self());
+}
+
+/*
+ * thread_start()
+ *     Start the specified function on the specified hardware thread.
+ */
+thread_t thread_start(thread_t thread,
+                     thread_exec_fn_t exec,
+                     void *arg,
+                     unsigned int *sp_high,
+                     thread_type_t type)
+{
+       /*
+        * Sanity check
+        */
+       unsigned int enabled, mask, csr;
+       asm volatile (
+               "move.4         %0, MT_EN\n\t"
+               : "=m" (enabled)
+       );
+
+       mask = 1 << thread;
+       if (enabled & mask) {
+               printk(KERN_WARNING "request to enable a previously enabled thread\n");
+               return (thread_t)-1;
+       }
+
+       /*
+        * Update thread state
+        */
+       csr = (thread << 15) | (1 << 14);
+       asm volatile (
+               "setcsr         %0              \n\t"
+               "setcsr_flush   0               \n\t"
+
+               "move.4         A0, #0          \n\t"
+               "move.4         A1, #0          \n\t"
+               "move.4         A2, #0          \n\t"
+               "move.4         A3, #0          \n\t"
+               "move.4         A4, #0          \n\t"
+               "move.4         A5, #0          \n\t"
+               "move.4         A6, #0          \n\t"
+               "move.4         SP, %4          \n\t"   /* A7 is SP */
+
+               "move.4         D0, %3          \n\t"
+               "move.4         D1, %2          \n\t"
+               "move.4         D2, #0          \n\t"
+               "move.4         D3, #0          \n\t"
+               "move.4         D4, #0          \n\t"
+               "move.4         D5, #0          \n\t"
+               "move.4         D6, #0          \n\t"
+               "move.4         D7, #0          \n\t"
+               "move.4         D8, #0          \n\t"
+               "move.4         D9, #0          \n\t"
+               "move.4         D10, #0         \n\t"
+               "move.4         D11, #0         \n\t"
+               "move.4         D12, #0         \n\t"
+               "move.4         D13, #0         \n\t"
+               "move.4         D14, #0         \n\t"
+               "move.4         D15, #0         \n\t"
+
+               "move.4         INT_MASK0, #0   \n\t"
+               "move.4         INT_MASK1, #0   \n\t"
+               "move.4         PC, %1          \n\t"
+               "setcsr         #0              \n\t"
+               "setcsr_flush   0               \n\t"
+               :
+               : "r" (csr), "r" (thread_entry), "r" (exec),
+                 "r" (arg), "r" (sp_high)
+       );
+
+       /*
+        * Apply HRT state
+        */
+       if (type & THREAD_TYPE_HRT) {
+               asm volatile (
+                       "or.4           MT_HRT, MT_HRT, %0\n\t"
+                       :
+                       : "d" (mask)
+                       : "cc"
+               );
+       } else {
+               asm volatile (
+                       "and.4          MT_HRT, MT_HRT, %0\n\t"
+                       :
+                       : "d" (~mask)
+                       : "cc"
+               );
+       }
+
+       /*
+        * Set priority
+        */
+       asm volatile (
+               "or.4           MT_HPRI, MT_HPRI, %0\n\t"
+               :
+               : "d" (mask)
+               : "cc"
+       );
+
+       /*
+        * Enable thread
+        */
+       asm volatile (
+               "move.4         MT_ACTIVE_SET, %0       \n\t"
+               :
+               : "d" (mask)
+       );
+       thread_enable_mask(mask);
+       return thread;
+}
+
+/*
+ * thread_get_mainline()
+ *     Return a mask of those threads that are Linux mainline threads.
+ */
+unsigned int thread_get_mainline(void)
+{
+       return thread_mainline_mask;
+}
+
+/*
+ * thread_set_mainline()
+ *     Indicate that the specified thread is a Linux mainline thread.
+ */
+void thread_set_mainline(thread_t tid)
+{
+       thread_mainline_mask |= (1 << tid);
+}
+
+/*
+ * thread_alloc()
+ *     Allocate an unused hardware thread.
+ */
+thread_t thread_alloc(void)
+{
+       thread_t tid;
+
+       /*
+        * If this is the first time we are here get the list of unused
+        * threads from the processor device tree node.
+        */
+       if (thread_mask == -1) {
+               thread_mask = processor_threads();
+       }
+
+       if (!thread_mask) {
+               return (thread_t)-1;
+       }
+
+       tid = ffs(thread_mask);
+       if (tid != 0) {
+               tid--;
+               thread_mask &= ~(1 << tid);
+               return tid;
+       }
+
+       return (thread_t)-1;
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/time.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/time.c
new file mode 100644 (file)
index 0000000..4a99284
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * arch/ubicom32/kernel/time.c
+ *     Initialize the timer list and start the appropriate timers.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/profile.h>
+#include <linux/smp.h>
+#include <asm/ip5000.h>
+#include <asm/machdep.h>
+
+/*
+ * A bitmap of the timers on the processor indicates
+ * that the timer is free or in-use.
+ */
+static unsigned int timers;
+
+/*
+ * timer_set()
+ *     Init the specified compare register to go off <n> cycles from now.
+ */
+void timer_set(int timervector, unsigned int cycles)
+{
+       int idx = UBICOM32_VECTOR_TO_TIMER_INDEX(timervector);
+       UBICOM32_IO_TIMER->syscom[idx] =
+                       UBICOM32_IO_TIMER->sysval + cycles;
+       ldsr_enable_vector(timervector);
+}
+
+/*
+ * timer_reset()
+ *     Set/reset the timer to go off again.
+ *
+ * Because sysval is a continuous timer, this function is able
+ * to ensure that we do not have clock sku by using the previous
+ * value in syscom to set the next value for syscom.
+ *
+ * Returns the number of ticks that transpired since the last event.
+ */
+int timer_reset(int timervector, unsigned int cycles)
+{
+       /*
+        * Reset the timer in the LDSR thread to go off appropriately.
+        *
+        * Use the previous value of the timer to calculate the new stop
+        * time.  This allows us to account for it taking an
+        * indeterminate amount of time to get here.
+        */
+       const int timer_index = UBICOM32_VECTOR_TO_TIMER_INDEX(timervector);
+       unsigned int prev = UBICOM32_IO_TIMER->syscom[timer_index];
+       unsigned int next = prev + cycles;
+       int scratchpad3;
+       int diff;
+       int ticks = 1;
+
+       /*
+        * If the difference is negative, we have missed at least one
+        * timer tick.
+        *
+        * TODO: Decide if we want to "ignore" time (as done below) or
+        * if we want to process time (unevenly) by calling timer_tick()
+        * lost_ticks times.
+        */
+       while (1) {
+               /*
+                * Set our future time first.
+                */
+               UBICOM32_IO_TIMER->syscom[timer_index] = next;
+
+               /*
+                * Then check if we are really set time in the futrue.
+                */
+               diff = (int)next - (int)UBICOM32_IO_TIMER->sysval;
+               if (diff >= 0) {
+                       break;
+               }
+
+               /*
+                * Oops, we are too slow. Playing catch up.
+                *
+                * If the debugger is connected the there is a good
+                * chance that we lost time because we were in a
+                * break-point, so in this case we do not print out
+                * diagnostics.
+                */
+               asm volatile ("move.4 %0, scratchpad3"
+                             : "=r" (scratchpad3));
+               if ((scratchpad3 & 0x1) == 0) {
+                       /*
+                        * No debugger attached, print to the console
+                        */
+                       printk(KERN_EMERG "diff: %d, timer has lost %u "
+                              "ticks [rounded up]\n",
+                              -diff,
+                              (unsigned int)((-diff + cycles - 1) / cycles));
+               }
+
+               do {
+                       next += cycles;
+                       diff = (int)next - (int)UBICOM32_IO_TIMER->sysval;
+                       ticks++;
+               } while (diff < 0);
+       }
+       return ticks;
+}
+
+/*
+ * sched_clock()
+ *     Returns current time in nano-second units.
+ *
+ * Notes:
+ * 1) This is an override for the weak alias in
+ * kernel/sched_clock.c.
+ * 2) Do not use xtime_lock as this function is
+ * sometimes called with xtime_lock held.
+ * 3) We use a retry algorithm to ensure that
+ * we get a consistent value.
+ * 4) sched_clock must be overwritten if IRQ tracing
+ * is enabled because the default implementation uses
+ * the xtime_lock sequence while holding xtime_lock.
+ */
+unsigned long long sched_clock(void)
+{
+       unsigned long long my_jiffies;
+       unsigned long jiffies_top;
+       unsigned long jiffies_bottom;
+
+       do {
+               jiffies_top = jiffies_64 >> 32;
+               jiffies_bottom = jiffies_64 & 0xffffffff;
+       } while (unlikely(jiffies_top != (unsigned long)(jiffies_64 >> 32)));
+
+       my_jiffies = ((unsigned long long)jiffies_top << 32) | (jiffies_bottom);
+       return (my_jiffies - INITIAL_JIFFIES) * (NSEC_PER_SEC / HZ);
+}
+
+/*
+ * timer_free()
+ *     Free a hardware timer.
+ */
+void timer_free(int interrupt)
+{
+       unsigned int bit = interrupt - TIMER_INT(0);
+
+       /*
+        * The timer had not been allocated.
+        */
+       BUG_ON(timers & (1 << bit));
+       timers |= (1 << bit);
+}
+
+/*
+ * timer_alloc()
+ *     Allocate a hardware timer.
+ */
+int timer_alloc(void)
+{
+       unsigned int bit = find_first_bit((unsigned long *)&timers, 32);
+       if (!bit) {
+               printk(KERN_WARNING "no more free timers\n");
+               return -1;
+       }
+
+       timers &= ~(1 << bit);
+       return bit + TIMER_INT(0);
+}
+
+/*
+ * time_init()
+ *     Time init function.
+ */
+void time_init(void)
+{
+       /*
+        * Find the processor node and determine what timers are
+        * available for us.
+        */
+       timers = processor_timers();
+       if (timers == 0) {
+               printk(KERN_WARNING "no timers are available for Linux\n");
+               return;
+       }
+
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
+       timer_device_init();
+#else
+       timer_tick_init();
+#endif
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_broadcast.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_broadcast.c
new file mode 100644 (file)
index 0000000..8f0cdc4
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * arch/ubicom32/kernel/timer_broadcast.c
+ *   Implements a dummy clock event for each cpu.
+ *
+ * Copyright (C) 2008  Paul Mundt
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *   arch/arm
+ *   arch/sh
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/smp.h>
+#include <linux/jiffies.h>
+#include <linux/percpu.h>
+#include <linux/clockchips.h>
+#include <linux/irq.h>
+
+static DEFINE_PER_CPU(struct clock_event_device, local_clockevent);
+
+/*
+ *  The broadcast trick only works when the timer will be used in a periodic mode.
+ *  If the user has configured either NO_HZ or HIGH_RES_TIMERS they must have
+ *  a per cpu timer.
+ */
+#if defined(CONFIG_NO_HZ) || defined(CONFIG_HIGH_RES_TIMERS)
+#error "Tickless and High Resolution Timers require per-CPU local timers: CONFIG_LOCAL_TIMERS"
+#endif
+
+/*
+ * local_timer_interrupt()
+ *     Used on SMP for local timer interrupt sent via an IPI.
+ */
+void local_timer_interrupt(void)
+{
+       struct clock_event_device *dev = &__get_cpu_var(local_clockevent);
+
+       dev->event_handler(dev);
+}
+
+/*
+ * dummy_timer_set_next_event()
+ *     Cause the timer to go off "cycles" from now.
+ */
+static int dummy_timer_set_next_event(unsigned long cycles, struct clock_event_device *dev)
+{
+       return 0;
+}
+
+/*
+ * dummy_timer_set_mode()
+ *     Do Nothing.
+ */
+static void dummy_timer_set_mode(enum clock_event_mode mode,
+                                struct clock_event_device *clk)
+{
+}
+
+/*
+ * local_timer_setup()
+ *     Adds a clock event for the specified cpu.
+ */
+int __cpuinit local_timer_setup(unsigned int cpu)
+{
+       struct clock_event_device *dev = &per_cpu(local_clockevent, cpu);
+
+       dev->name               = "timer-dummy";
+       dev->features           = CLOCK_EVT_FEAT_DUMMY;
+       dev->rating             = 200;
+       dev->mult               = 1;
+       dev->set_mode           = dummy_timer_set_mode;
+       dev->set_next_event     = dummy_timer_set_next_event;
+       dev->broadcast          = smp_timer_broadcast;
+       dev->cpumask            = cpumask_of_cpu(cpu);
+       dev->irq                = -1;
+       printk(KERN_NOTICE "timer[%d]: %s - created\n", dev->irq, dev->name);
+
+       clockevents_register_device(dev);
+       return 0;
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_device.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_device.c
new file mode 100644 (file)
index 0000000..d2d094d
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * arch/ubicom32/kernel/timer_device.c
+ *   Implements a Ubicom32 clock device and event devices.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/types.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/spinlock.h>
+#include <asm/ip5000.h>
+#include <asm/machdep.h>
+
+#if defined(CONFIG_SMP)
+#include <asm/smp.h>
+#endif
+
+#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+#define MAX_TIMERS (2 + CONFIG_TIMER_EXTRA_ALLOC)
+#else
+#define MAX_TIMERS (NR_CPUS + CONFIG_TIMER_EXTRA_ALLOC)
+#endif
+
+#if (MAX_TIMERS > 10)
+#error "Ubicom32 only has 10 timers"
+#endif
+
+static unsigned int frequency;
+static struct clock_event_device timer_device_devs[MAX_TIMERS];
+static struct irqaction timer_device_irqs[MAX_TIMERS];
+static int timer_device_next_timer = 0;
+
+DEFINE_SPINLOCK(timer_device_lock);
+
+/*
+ * timer_device_set_next_event()
+ *     Cause the timer to go off "cycles" from now.
+ */
+static int timer_device_set_next_event(unsigned long cycles, struct clock_event_device *dev)
+{
+       timer_set(dev->irq, cycles);
+       return 0;
+}
+
+/*
+ * timer_device_set_mode()
+ *     Handle the mode switch for a clock event device.
+ */
+static void timer_device_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
+{
+       switch (mode) {
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               /*
+                * Make sure the vector is disabled
+                * until the next event is set.
+                */
+               printk(KERN_NOTICE "timer[%d]: shutdown\n", dev->irq);
+               ldsr_disable_vector(dev->irq);
+               break;
+
+       case CLOCK_EVT_MODE_ONESHOT:
+               /*
+                * Make sure the vector is disabled
+                * until the next event is set.
+                */
+               printk(KERN_NOTICE "timer[%d]: oneshot\n", dev->irq);
+               ldsr_disable_vector(dev->irq);
+               break;
+
+       case CLOCK_EVT_MODE_PERIODIC:
+               /*
+                * The periodic request is 1 per jiffies
+                */
+               printk(KERN_NOTICE "timer[%d]: periodic: %d cycles\n",
+                       dev->irq, frequency / CONFIG_HZ);
+               timer_set(dev->irq, frequency / CONFIG_HZ);
+               break;
+
+       case CLOCK_EVT_MODE_UNUSED:
+       case CLOCK_EVT_MODE_RESUME:
+               printk(KERN_WARNING "timer[%d]: unimplemented mode: %d\n",
+                       dev->irq, mode);
+               break;
+       };
+}
+
+/*
+ * timer_device_event()
+ *     Call the device's event handler.
+ *
+ * The pointer is initialized by the generic Linux code
+ * to the function to be called.
+ */
+static irqreturn_t timer_device_event(int irq, void *dev_id)
+{
+       struct clock_event_device *dev = (struct clock_event_device *)dev_id;
+
+       if (dev->mode == CLOCK_EVT_MODE_PERIODIC) {
+               /*
+                * The periodic request is 1 per jiffies
+                */
+               timer_reset(dev->irq, frequency / CONFIG_HZ);
+       } else {
+               /*
+                * The timer will go off again at the rollover
+                * point.  We must disable the IRQ to prevent
+                * getting a spurious interrupt.
+                */
+               ldsr_disable_vector(dev->irq);
+       }
+
+       if (!dev->event_handler) {
+               printk(KERN_CRIT "no registered event handler\n");
+               return IRQ_HANDLED;
+       }
+
+       dev->event_handler(dev);
+       return IRQ_HANDLED;
+}
+
+/*
+ * timer_device_clockbase_read()
+ *     Provide a primary clocksource around the sysval timer.
+ */
+static cycle_t timer_device_clockbase_read(void)
+{
+       return (cycle_t)UBICOM32_IO_TIMER->sysval;
+}
+
+/*
+ * Primary Clock Source Description
+ *
+ * We use 24 for the shift factor because we want
+ * to ensure there are less than 2^24 clocks
+ * in a jiffie of 10 ms.
+ */
+static struct clocksource timer_device_clockbase = {
+       .name   = "sysval",
+       .rating = 400,
+       .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
+       .mask   = CLOCKSOURCE_MASK(32),
+       .shift  = 24,
+       .mult   = 0,
+       .read   = timer_device_clockbase_read,
+};
+
+/*
+ * timer_device_alloc_event()
+ *     Allocate a timer device event.
+ */
+static int timer_device_alloc_event(const char *name, int cpuid, const cpumask_t *mask)
+{
+       struct clock_event_device *dev;
+       struct irqaction *action;
+
+       /*
+        * Are we out of configured timers?
+        */
+       spin_lock(&timer_device_lock);
+       if (timer_device_next_timer >= MAX_TIMERS) {
+               spin_unlock(&timer_device_lock);
+               printk(KERN_WARNING "out of timer event entries\n");
+               return -1;
+       }
+       dev = &timer_device_devs[timer_device_next_timer];
+       action = &timer_device_irqs[timer_device_next_timer];
+       timer_device_next_timer++;
+       spin_unlock(&timer_device_lock);
+
+       /*
+        * Now allocate a timer to ourselves.
+        */
+       dev->irq = timer_alloc();
+       if (dev->irq == -1) {
+               spin_lock(&timer_device_lock);
+               timer_device_next_timer--;
+               spin_unlock(&timer_device_lock);
+               printk(KERN_WARNING "out of hardware timers\n");
+               return -1;
+       }
+
+       /*
+        * Init the IRQ action structure.  Make sure
+        * this in place before you register the clock
+        * event device.
+        */
+       action->name = name;
+       action->flags = IRQF_DISABLED | IRQF_TIMER;
+       action->handler = timer_device_event;
+       cpumask_copy(&action->mask, mask);
+       action->dev_id = dev;
+       setup_irq(dev->irq, action);
+       irq_set_affinity(dev->irq, mask);
+       ldsr_disable_vector(dev->irq);
+
+       /*
+        * init clock dev structure.
+        *
+        * The min_delta_ns is chosen to ensure that setting next
+        * event will never be requested with too small of value.
+        */
+       dev->name = name;
+       dev->rating = timer_device_clockbase.rating;
+       dev->shift = timer_device_clockbase.shift;
+       dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+       dev->set_mode = timer_device_set_mode;
+       dev->set_next_event = timer_device_set_next_event;
+       dev->mult = div_sc(frequency, NSEC_PER_SEC, dev->shift);
+       dev->max_delta_ns = clockevent_delta2ns(0xffffffff, dev);
+       dev->min_delta_ns = clockevent_delta2ns(100, dev);
+       dev->cpumask = mask;
+       printk(KERN_NOTICE "timer[%d]: %s - created\n", dev->irq, dev->name);
+
+       /*
+        * Now register the device.
+        */
+       clockevents_register_device(dev);
+       return dev->irq;
+}
+
+#if defined(CONFIG_LOCAL_TIMERS)
+/*
+ * local_timer_setup()
+ *     Allocation function for creating a per cpu local timer.
+ */
+int __cpuinit local_timer_setup(unsigned int cpu)
+{
+       return timer_device_alloc_event("timer-cpu", cpu, cpumask_of(cpu));
+}
+#endif
+
+/*
+ * timer_device_init()
+ *     Create and init a generic clock driver for Ubicom32.
+ */
+void timer_device_init(void)
+{
+       int i;
+
+       /*
+        * Get the frequency from the processor device tree node or use
+        * the default if not available. We will store this as the frequency
+        * of the timer to avoid future calculations.
+        */
+       frequency = processor_frequency();
+       if (frequency == 0) {
+               frequency = CLOCK_TICK_RATE;
+       }
+
+       /*
+        * Setup the primary clock source around sysval.  Linux does not
+        * supply a Mhz multiplier so convert down to khz.
+        */
+       timer_device_clockbase.mult =
+               clocksource_khz2mult(frequency / 1000,
+                       timer_device_clockbase.shift);
+       if (clocksource_register(&timer_device_clockbase)) {
+               printk(KERN_ERR "timer: clocksource failed to register\n");
+               return;
+       }
+
+       /*
+        * Always allocate a primary timer.
+        */
+       timer_device_alloc_event("timer-primary", -1, CPU_MASK_ALL_PTR);
+
+#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+       /*
+        * If BROADCAST is selected we need to add a broadcast timer.
+        */
+       timer_device_alloc_event("timer-broadcast", -1, CPU_MASK_ALL_PTR);
+#endif
+
+       /*
+        * Allocate extra timers that are requested.
+        */
+       for (i = 0; i < CONFIG_TIMER_EXTRA_ALLOC; i++) {
+               timer_device_alloc_event("timer-extra", -1, CPU_MASK_ALL_PTR);
+       }
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_tick.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_tick.c
new file mode 100644 (file)
index 0000000..7a2ad49
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * arch/ubicom32/kernel/timer_tick.c
+ *     Impelemets a perodic timer.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/profile.h>
+
+#include <asm/ip5000.h>
+#include <asm/machdep.h>
+#if defined(CONFIG_SMP)
+#include <asm/smp.h>
+#endif
+
+static unsigned int timervector;
+static unsigned int frequency;
+
+/*
+ * timer_tick()
+ *     Kernel system timer support. Needs to keep up the real-time clock,
+ *     as well as call the "do_timer()" routine every clocktick.
+ */
+static irqreturn_t timer_tick(int irq, void *dummy)
+{
+       int ticks;
+
+       BUG_ON(!irqs_disabled());
+       ticks = timer_reset(timervector, frequency);
+
+       write_seqlock(&xtime_lock);
+       do_timer(ticks);
+       write_sequnlock(&xtime_lock);
+
+       update_process_times(user_mode(get_irq_regs()));
+       profile_tick(CPU_PROFILING);
+
+#if defined(CONFIG_SMP)
+       smp_send_timer_all();
+#endif
+       return(IRQ_HANDLED);
+}
+
+/*
+ * Data used by setup_irq for the timer.
+ */
+static struct irqaction timer_irq = {
+       .name    = "timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+       .handler = timer_tick,
+};
+
+/*
+ * timer_tick_init()
+ *     Implements a periodic timer
+ *
+ * This implementation directly calls the timer_tick() and move
+ * the Linux kernel forward.  This is used when the user has not
+ * selected GENERIC_CLOCKEVENTS.
+ */
+void timer_tick_init(void)
+{
+       /*
+        * Now allocate a timer to ourselves.
+        */
+       timervector = timer_alloc();
+       if (timervector == -1) {
+               printk(KERN_WARNING "where did the timer go?\n");
+               return;
+       }
+
+       setup_irq(timervector, &timer_irq);
+
+       /*
+        * Get the frequency from the processor device tree node or use
+        * the default if not available. We will store this as the frequency
+        * of the timer to avoid future calculations.
+        */
+       frequency = processor_frequency();
+       if (frequency == 0) {
+               frequency = CLOCK_TICK_RATE;
+       }
+       frequency /= CONFIG_HZ;
+
+       printk(KERN_NOTICE "timer will interrupt every: %d cycles\n", frequency);
+       timer_set(timervector, frequency);
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/topology.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/topology.c
new file mode 100644 (file)
index 0000000..0676a16
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * arch/ubicom32/kernel/topology.c
+ *   Ubicom32 architecture sysfs topology information.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/cache.h>
+
+static struct cpu cpu_devices[NR_CPUS] __read_mostly;
+
+static int __init topology_init(void)
+{
+       int num;
+
+       for_each_present_cpu(num) {
+               cpu_devices[num].hotpluggable = 0;
+               register_cpu(&cpu_devices[num], num);
+       }
+       return 0;
+}
+
+subsys_initcall(topology_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/traps.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/traps.c
new file mode 100644 (file)
index 0000000..8cb22e2
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * arch/ubicom32/kernel/traps.c
+ *   Ubicom32 architecture trap handling support.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+/*
+ * Sets up all exception vectors
+ */
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/a.out.h>
+#include <linux/user.h>
+#include <linux/string.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+#include <linux/kallsyms.h>
+#include <linux/compiler.h>
+#include <linux/stacktrace.h>
+#include <linux/personality.h>
+
+#include <asm/uaccess.h>
+#include <asm/stacktrace.h>
+#include <asm/devtree.h>
+#include <asm/setup.h>
+#include <asm/fpu.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/siginfo.h>
+#include <asm/ip5000.h>
+#include <asm/thread.h>
+
+#define TRAP_MAX_STACK_DEPTH 20
+
+/*
+ * These symbols are filled in by the linker.
+ */
+extern unsigned long _stext;
+extern unsigned long _etext;
+
+extern unsigned long __ocm_text_run_begin;
+extern unsigned long __data_begin;
+
+extern void show_vmas(struct task_struct *task);
+
+const char *trap_cause_strings[] = {
+       /*0*/   "inst address decode error",
+       /*1*/   "inst sync error",
+       /*2*/   "inst illegal",
+       /*3*/   "src1 address decode error",
+       /*4*/   "dst address decode error",
+       /*5*/   "src1 alignment error",
+       /*6*/   "dst alignment error",
+       /*7*/   "src1 sync error",
+       /*8*/   "dst sync error",
+       /*9*/   "DCAPT error",
+       /*10*/  "inst range error",
+       /*11*/  "src1 range error",
+       /*12*/  "dst range error",
+};
+
+/*
+ * The device tree trap node definition.
+ */
+struct trapnode {
+       struct devtree_node dn;
+       unsigned int intthread;
+};
+
+static struct trapnode *tn;;
+
+/*
+ * trap_interrupt_handler()
+ *     Software Interrupt to ensure that a trap is serviced.
+ */
+static irqreturn_t trap_interrupt_handler(int irq, void *dummy)
+{
+       /* Do Nothing */
+       return IRQ_HANDLED;
+}
+
+/*
+ * Data used by setup_irq for the timer.
+ */
+static struct irqaction trap_irq = {
+       .name    = "trap",
+       .flags   = IRQF_DISABLED,
+       .handler = trap_interrupt_handler,
+};
+
+/*
+ * trap_cause_to_str()
+ *     Convert a trap_cause into a series of printk
+ */
+static void trap_cause_to_str(long status)
+{
+       int bit;
+
+       if ((status & ((1 << TRAP_CAUSE_TOTAL) - 1)) == 0) {
+               printk(KERN_NOTICE "decode: UNKNOWN CAUSES\n");
+               return;
+       }
+
+       for (bit = 0; bit < TRAP_CAUSE_TOTAL; bit++) {
+               if (status & (1 << bit)) {
+                       printk(KERN_NOTICE "\tdecode: %08x %s\n",
+                              1 << bit, trap_cause_strings[bit]);
+               }
+       }
+}
+
+/*
+ * trap_print_information()
+ *     Print the cause of the trap and additional info.
+ */
+static void trap_print_information(const char *str, struct pt_regs *regs)
+{
+       printk(KERN_WARNING "\n");
+
+       if (current) {
+               printk(KERN_WARNING "Process %s (pid: %d)\n",
+                       current->comm, current->pid);
+       }
+
+       if (current && current->mm) {
+               printk(KERN_NOTICE "text = 0x%p-0x%p  data = 0x%p-0x%p\n"
+                       KERN_NOTICE "bss = 0x%p-0x%p   user-stack = 0x%p\n"
+                       KERN_NOTICE "\n",
+                       (void *)current->mm->start_code,
+                       (void *)current->mm->end_code,
+                       (void *)current->mm->start_data,
+                       (void *)current->mm->end_data,
+                       (void *)current->mm->end_data,
+                       (void *)current->mm->brk,
+                       (void *)current->mm->start_stack);
+       }
+
+       printk(KERN_WARNING "%s: Causes: 0x%08x\n", str,
+                       (unsigned int)regs->trap_cause);
+       trap_cause_to_str(regs->trap_cause);
+       show_regs(regs);
+       show_stack(NULL, (unsigned long *)regs->an[7]);
+       printk(KERN_NOTICE "--- End Trap --- \n");
+}
+
+/*
+ * dump_stack()
+ *     Dump the stack of the current task.
+ */
+void dump_stack(void)
+{
+       show_stack(NULL, NULL);
+}
+EXPORT_SYMBOL(dump_stack);
+
+/*
+ * show_stack()
+ *     Print out information from the current stack.
+ */
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+       /*
+        *  Allocate just enough entries on the stack.
+        */
+       unsigned int calls[TRAP_MAX_STACK_DEPTH];
+       unsigned long code_start;
+       unsigned long code_end;
+       unsigned long ocm_code_start = (unsigned long)&__ocm_text_run_begin;
+       unsigned long ocm_code_end = (unsigned long)&__data_begin;
+       unsigned long stack_end = (unsigned long)(current->stack + THREAD_SIZE - 8);
+       unsigned long stack = (unsigned long)sp;
+       int kernel_stack = 1;
+
+       processor_dram(&code_start, &code_end);
+
+       /*
+        * Which task are we talking about.
+        */
+       if (!task) {
+               task = current;
+       }
+
+       /*
+        * Find the stack for the task if one was not specified.  Otherwise
+        * use the specified stack.
+        */
+       if (!stack) {
+               if (task != current) {
+                       stack = task->thread.sp;
+                       stack_end = (unsigned long)task->stack + THREAD_SIZE - 8;
+               } else {
+                       asm volatile (
+                               "move.4         %0, SP          \n\t"
+                               : "=r" (stack)
+                       );
+               }
+       }
+
+       printk(KERN_NOTICE "Starting backtrace: PID %d '%s'\n",
+                       task->pid, task->comm);
+
+       /*
+        * We do 2 passes the first pass is Kernel stack is the second
+        * User stack.
+        */
+       while (kernel_stack) {
+               unsigned long *handle;
+               unsigned int i, idx = 0;
+               struct pt_regs *pt = task_pt_regs(task);
+
+               /*
+                * If the task is in user mode, reset the start
+                * and end values for text.
+                */
+               if (__user_mode(stack)) {
+                       if (!(task->personality & FDPIC_FUNCPTRS)) {
+                               printk(KERN_NOTICE "  User Stack:\n");
+                               code_start = task->mm->start_code;
+                               code_end = task->mm->end_code;
+                       } else {
+                               printk(KERN_NOTICE "  User Stack (fdpic):\n");
+                               show_vmas(task);
+                       }
+                       stack_end = task->mm->start_stack;
+                       ocm_code_end = ocm_code_start = 0;
+                       kernel_stack = 0;
+               } else {
+                       printk(KERN_NOTICE "  Kernel Stack:\n");
+               }
+
+               /*
+                * Collect the stack back trace information.
+                */
+               printk("    code[0x%lx-0x%lx]", code_start, code_end);
+               if (ocm_code_start) {
+                       printk(" ocm_code[0x%lx-0x%lx]",
+                              ocm_code_start, ocm_code_end);
+               }
+               printk("\n    stack[0x%lx-0x%lx]\n", stack, stack_end);
+
+               handle = (unsigned long*)stack;
+               while (idx < TRAP_MAX_STACK_DEPTH) {
+                       calls[idx] = stacktrace_iterate(&handle,
+                                       code_start, code_end,
+                                       ocm_code_start, ocm_code_end,
+                                       (unsigned long)stack, stack_end);
+                       if (calls[idx] == 0) {
+                               break;
+                       }
+                       idx++;
+               }
+
+               /*
+                * Now print out the data.
+                */
+               printk(KERN_NOTICE "  CALL && CALLI on stack:");
+               for (i = 0; i < idx; i++) {
+                       printk("%s0x%x, ", (i & 0x3) == 0 ?  "\n    " : "",
+                                       calls[i]);
+               }
+               printk(idx == TRAP_MAX_STACK_DEPTH ? "...\n" : "\n");
+
+               /*
+                * If we are doing user stack we are done
+                */
+               if (!kernel_stack) {
+                       break;
+               }
+
+               /*
+                * Does this kernel stack have a mm (i.e. is it user)
+                */
+               if (!task->mm) {
+                       printk("No mm for userspace stack.\n");
+                       break;
+               }
+               /*
+                * Get the user-mode stack (if any)
+                */
+               stack = pt->an[7];
+               printk(KERN_NOTICE "Userspace stack at 0x%lx frame type %d\n",
+                               stack, (int)pt->frame_type);
+               if (!__user_mode(stack)) {
+                       break;
+               }
+       }
+}
+
+/*
+ * die_if_kernel()
+ *     Determine if we are in kernel mode and if so print stuff out and die.
+ */
+void die_if_kernel(char *str, struct pt_regs *regs, long trap_cause)
+{
+       unsigned int s3value;
+
+       if (user_mode(regs)) {
+               return;
+       }
+
+       console_verbose();
+       trap_print_information(str, regs);
+
+       /*
+        * If the debugger is attached via the hardware mailbox protocol,
+        * go into an infinite loop and the debugger will figure things out.
+        */
+       asm volatile (
+             "move.4 %0, scratchpad3"
+             : "=r" (s3value)
+       );
+       if (s3value) {
+               asm volatile("1:        jmpt.t 1b");
+       }
+
+       /*
+        * Set the debug taint value.
+        */
+       add_taint(TAINT_DIE);
+       do_exit(SIGSEGV);
+}
+
+/*
+ * trap_handler()
+ *     Handle traps.
+ *
+ * Traps are treated as interrupts and registered with the LDSR.  When
+ * the LDSR takes the interrupt, it will determine if a trap has occurred
+ * and service the trap prior to servicing the interrupt.
+ *
+ * This function is directly called by the LDSR.
+ */
+void trap_handler(int irq, struct pt_regs *regs)
+{
+       int sig = SIGSEGV;
+       siginfo_t info;
+       unsigned int trap_cause = regs->trap_cause;
+
+       BUG_ON(!irqs_disabled());
+
+       /*
+        * test if in kernel and die.
+        */
+       die_if_kernel("Kernel Trap", regs, trap_cause);
+
+       /*
+        * User process problem, setup a signal for this process
+        */
+       if ((trap_cause & (1 << TRAP_CAUSE_DST_RANGE_ERR)) ||
+           (trap_cause & (1 << TRAP_CAUSE_SRC1_RANGE_ERR)) ||
+           (trap_cause & (1 << TRAP_CAUSE_I_RANGE_ERR))) {
+               sig = SIGSEGV;
+               info.si_code = SEGV_MAPERR;
+       } else if ((trap_cause & (1 << TRAP_CAUSE_DST_MISALIGNED)) ||
+                  (trap_cause & (1 << TRAP_CAUSE_SRC1_MISALIGNED))) {
+               sig = SIGBUS;
+               info.si_code = BUS_ADRALN;
+       } else if ((trap_cause & (1 << TRAP_CAUSE_DST_DECODE_ERR)) ||
+                  (trap_cause & (1 << TRAP_CAUSE_SRC1_DECODE_ERR))) {
+               sig = SIGILL;
+               info.si_code = ILL_ILLOPN;
+       } else if ((trap_cause & (1 << TRAP_CAUSE_ILLEGAL_INST))) {
+               /*
+                * Check for software break point and if found signal trap
+                * not illegal instruction.
+                */
+               unsigned long instruction;
+               if (between(regs->pc, KERNELSTART, memory_end) &&
+                       (regs->pc & 3) == 0 &&
+                       get_user(instruction, (unsigned long *)regs->pc) == 0) {
+
+                       /*
+                        * This used to be 0xaabbccdd but it turns out
+                        * that is now valid in ubicom32v4 isa so we
+                        * have switched to 0xfabbccdd
+                        */
+                       if ((instruction == 0xfabbccdd) ||
+                           (instruction == 0xaabbccdd)) {
+                               sig = SIGTRAP;
+                               info.si_code = TRAP_BRKPT;
+                               goto send_signal;
+                       }
+               }
+               sig = SIGILL;
+               info.si_code = ILL_ILLOPC;
+       } else if ((trap_cause & (1 << TRAP_CAUSE_I_DECODE_ERR))) {
+               sig = SIGILL;
+               info.si_code = ILL_ILLOPC;
+       } else if ((trap_cause & (1 << TRAP_CAUSE_DCAPT))) {
+               sig = SIGTRAP;
+               info.si_code = TRAP_TRACE;
+       }
+
+       /*
+        * Print a trap information block to the console, do not
+        * print this above the case because we don't want it
+        * printed for software break points.
+        */
+       trap_print_information("User Trap", regs);
+
+send_signal:
+
+       force_sig_info(sig, &info, current);
+
+       /*
+        * Interrupts are disabled, re-enable them now.
+        */
+       if (!irqs_disabled()) {
+               printk(KERN_EMERG "interrupts enabled on exit, irq=%d, regs=%p",
+                               irq, regs);
+               BUG();
+       }
+}
+
+/*
+ * trap_init_interrupt()
+ *     We need a 2nd trap handling init that will occur after init_IRQ().
+ */
+void __init trap_init_interrupt(void)
+{
+       int err;
+       unsigned char tirq;
+       struct devtree_node *dn = (struct devtree_node *)tn;
+
+       /*
+        * Now setup the Software IRQ so that if a trap occurs the LDSR
+        * is started.  The irq is there just to "force" the LDSR to run.
+        */
+       if (!tn) {
+               printk(KERN_WARNING "trap_init_interrupt skipped.\n");
+               return;
+       }
+
+       err = devtree_irq(dn, NULL, &tirq);
+       if (err) {
+               printk(KERN_WARNING "error obtaining trap irq value: %d\n",
+                       err);
+               return;
+       }
+
+       if (tirq == DEVTREE_IRQ_NONE) {
+               printk(KERN_WARNING "trap irq not available: %d\n", tirq);
+               return;
+       }
+
+       err = setup_irq(tirq, &trap_irq);
+       if (err) {
+               printk(KERN_WARNING "trap irq setup failed: %d\n", err);
+               return;
+       }
+
+       /*
+        * Let ultra know which thread is handling the traps and
+        * what the interrupt to use is.
+        */
+       tn->intthread = ldsr_get_threadid();
+
+       /*
+        * Tell the LDSR about our IRQ so that it will unsuspend
+        * if one occurs while waiting for the per thread lock.
+        */
+       ldsr_set_trap_irq(tirq);
+}
+
+/*
+ * trap_init()
+ *     init trap handling
+ *
+ * Trap handling is done through the ldsr.  Every time an interrupt
+ * occurs, the LDSR looks for threads that are listed in the TRAP
+ * register and forces a call to the trap handler.
+ */
+void __init trap_init(void)
+{
+       /*
+        * If we do not have a trap node in the device tree, we leave the fault
+        * handling to the underlying hardware.
+        */
+       tn = (struct trapnode *)devtree_find_node("traps");
+       if (!tn) {
+               printk(KERN_WARNING "traps are not handled by linux\n");
+               return;
+       }
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/uaccess.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/uaccess.c
new file mode 100644 (file)
index 0000000..2fe5f5f
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * arch/ubicom32/include/asm/uaccess.c
+ *   User space memory access functions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+
+extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
+
+/*
+ * __access_ok()
+ *     Check that the address is in the current processes.
+ *
+ * NOTE: The kernel uses "pretend" user addresses that wind
+ * up calling access_ok() so this approach has only marginal
+ * value because you wind up with lots of false positives.
+ */
+int __access_ok(unsigned long addr, unsigned long size)
+{
+       // struct vm_area_struct *vma;
+
+       /*
+        * Don't do anything if we are not a running system yet.
+        */
+       if (system_state != SYSTEM_RUNNING) {
+               return 1;
+       }
+
+       /*
+        * It appears that Linux will call this function even when we are not
+        * in the context of a user space application that has a VM address
+        * space.  So we must check that current and mm are valid before
+        * performing the check.
+        */
+       if ((!current) || (!current->mm)) {
+               return 1;
+       }
+
+       /*
+        * We perform some basic checks on the address to ensure that it
+        * is at least within the range of DRAM.
+        */
+       if ((addr < (int)&_etext) || (addr > memory_end)) {
+               printk(KERN_WARNING "pid=%d[%s]: range [%lx - %lx] not in memory area: [%lx - %lx]\n",
+                       current->pid, current->comm,
+                       addr, addr + size,
+                       memory_start, memory_end);
+               return 0;
+       }
+
+       /*
+        * For nommu Linux we can check this by looking at the allowed
+        * memory map for the process.
+        *
+        * TODO: Since the kernel passes addresses in it's own space as though
+        * they were user address, we can not validate the addresses this way.
+        */
+#if 0
+       if (!down_read_trylock(&current->mm->mmap_sem)) {
+               return 1;
+       }
+       vma = find_vma(current->mm, addr);
+       if (!vma) {
+               up_read(&current->mm->mmap_sem);
+               printk(KERN_WARNING "pid=%d[%s]: possible invalid acesss on range: [%lx - %lx]\n",
+                               current->pid, current->comm, addr, addr + size);
+               return 1;
+       }
+       if ((addr + size) > vma->vm_end) {
+               up_read(&current->mm->mmap_sem);
+               printk(KERN_WARNING "pid=%d[%s]: possible invalid length on range: [%lx - %lx]\n",
+                               current->pid, current->comm, addr, addr + size);
+               return 1;
+       }
+       up_read(&current->mm->mmap_sem);
+#endif
+       return 1;
+}
+
+EXPORT_SYMBOL(__access_ok);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_context_switch.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_context_switch.S
new file mode 100644 (file)
index 0000000..08db4c0
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * arch/ubicom32/kernel/ubicom32_context_switch.S
+ *     Implements context switch and return functions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/ubicom32-common.h>
+#include <asm/ip5000.h>
+#include <asm/range-protect.h>
+
+/*
+ * begin_restore_context()
+ *     Restore most of the context from sp (struct pt_reg *)
+ *
+ * This *can* be called without the global atomic lock. (because sp is
+ * not restored!)  Only d15 and a3 are allowed to be used after this
+ * before calling complete_restore_context
+ */
+.macro begin_restore_context
+       move.4  d0, PT_D0(sp)
+       move.4  d1, PT_D1(sp)
+       move.4  d2, PT_D2(sp)
+       move.4  d3, PT_D3(sp)
+       move.4  d4, PT_D4(sp)
+       move.4  d5, PT_D5(sp)
+       move.4  d6, PT_D6(sp)
+       move.4  d7, PT_D7(sp)
+       move.4  d8, PT_D8(sp)
+       move.4  d9, PT_D9(sp)
+       move.4  d10, PT_D10(sp)
+       move.4  d11, PT_D11(sp)
+       move.4  d12, PT_D12(sp)
+       move.4  d13, PT_D13(sp)
+       move.4  d14, PT_D14(sp)
+;;     move.4  d15, PT_D15(sp)
+       move.4  a0, PT_A0(sp)
+       move.4  a1, PT_A1(sp)
+       move.4  a2, PT_A2(sp)
+;;     move.4  a3, PT_A3(sp)
+       move.4  a4, PT_A4(sp)
+       move.4  a5, PT_A5(sp)
+       move.4  a6, PT_A6(sp)
+       move.4  acc0_hi, PT_ACC0HI(sp)
+       move.4  acc0_lo, PT_ACC0LO(sp)
+       move.4  mac_rc16, PT_MAC_RC16(sp)
+       move.4  acc1_hi, PT_ACC1HI(sp)
+       move.4  acc1_lo, PT_ACC1LO(sp)
+       move.4  source3, PT_SOURCE3(sp)
+       move.4  int_mask0, PT_INT_MASK0(sp)
+       move.4  int_mask1, PT_INT_MASK1(sp)
+.endm
+
+/*
+ * complete_restore_context()
+ *     Completely restore the context from sp (struct pt_reg *)
+ *
+ * Note: Recovered PC and CSR are saved on the stack and are to be
+ * popped off before returning.
+ */
+.macro complete_restore_context
+       move.4  a3, sp
+       move.4  d15, PT_D15(sp)
+       move.4  sp, PT_SP(a3)           ; Recover Stack pointer from save area
+       move.4  -4(sp)++, PT_PC(a3)     ; Recover saved PC and save to stack
+       move.4  -4(sp)++, PT_CSR(a3)    ; Recover saved csr and save to stack
+       move.4  a3, PT_A3(a3)
+.endm
+
+/*
+ * old restore_context macro
+ */
+.macro restore_context
+       begin_restore_context
+       complete_restore_context
+.endm
+
+/*
+ * ldsr_thread_enable_interrupts()
+ *     An assembly version of the enable interrupts function.
+ *
+ * The stack is fair game but all registers MUST be preserved.
+ *
+ */
+.macro ldsr_thread_enable_interrupts
+       move.4  -4(sp)++, d3    ; Push d3
+       move.4  -4(sp)++, a3    ; Push a3
+
+       /*
+        * Read the ROSR and obtain ~(1 << tid)
+        */
+       lsr.4   d3, rosr, #0x2  ; Move the thread portion of ROSR into d3
+       lsl.4   d3, #1, d3      ; perform a (1 << tid)
+       not.4   d3, d3          ; Negate the value of d3 == ~(1 << threadid)
+
+       /*
+        * Get the value of the ldsr_soft_irq_mask
+        */
+       moveai  a3, #%hi(ldsr_soft_irq_mask)
+       move.4  a3, %lo(ldsr_soft_irq_mask)(a3)
+
+       /*
+        * Now re-enable interrupts for this thread and then
+        * wakeup the LDSR.
+        */
+       and.4   scratchpad1, scratchpad1, d3
+       move.4  int_set0, a3
+
+       /*
+        * Restore the registers.
+        */
+       move.4  a3, (sp)4++
+       move.4  d3, (sp)4++
+.endm
+
+/*
+ * ret_from_interrupt_to_kernel()
+ *     RFI function that is where do_IRQ() returns to if the thread was
+ *     in kernel space.
+ */
+       .section .text.ret_from_interrupt_to_kernel, "ax", @progbits
+       .global ret_from_interrupt_to_kernel
+ret_from_interrupt_to_kernel:
+       begin_restore_context           ; Restore the thread context
+       atomic_lock_acquire             ; Enter critical section
+       complete_restore_context        ; Restore the thread context
+       atomic_lock_release             ; Leave critical section
+       ldsr_thread_enable_interrupts   ; enable the threads interrupts
+       move.4  csr, (sp)4++            ; Restore csr from the stack
+       ret     (sp)4++
+
+/*
+ * ret_from_interrupt_to_user()
+ *     RFI function that is where do_IRQ() returns to if the thread was
+ *     in user space.
+ *
+ * TODO: Do we really need the critical section handling in this code?
+ *
+ */
+       .section .text.ret_from_interrupt_to_user, "ax", @progbits
+       .global ret_from_interrupt_to_user
+ret_from_interrupt_to_user:
+       ldsr_thread_enable_interrupts                   ; enable the threads interrupts
+       /*
+        * Set a1 to the thread info pointer, no need to save it as we are
+        * restoring userspace and will never return
+        */
+       movei   d0, #(~(ASM_THREAD_SIZE-1))
+       and.4   a1, sp, d0
+
+       /*
+        * Test if the scheduler needs to be called.
+        */
+       btst    TI_FLAGS(a1), #ASM_TIF_NEED_RESCHED
+       jmpeq.t 2f
+       call    a5, schedule                    ; Call the scheduler. I will come back here.
+
+       /*
+        * See if we have pending signals and call do_signal
+        * if needed.
+        */
+2:
+       btst    TI_FLAGS(a1), #ASM_TIF_SIGPENDING       ; Any signals needed?
+       jmpeq.t 1f
+
+       /*
+        * Now call do_signal()
+        */
+       move.4  d0, #0                                  ; oldset pointer is NULL
+       move.4  d1, sp                                  ; d1 is the regs pointer
+       call    a5, do_signal                           ; Call do_signal()
+
+       /*
+        * Back from do_signal(), re-enter critical section.
+        */
+1:
+       begin_restore_context                           ; Restore the thread context
+       atomic_lock_acquire                             ; Enter critical section
+       call a3, __complete_and_return_to_userspace     ; jump to unprotected section
+
+/*
+ * restore_all_registers()
+ *
+ * restore_all_registers will be the alternate exit route for
+ * preempted processes that have called a signal handler
+ * and are returning back to user space.
+ */
+       .section .text.restore_all_registers, "ax", @progbits
+       .global restore_all_registers
+restore_all_registers:
+       begin_restore_context                   ; Restore the thread context
+       atomic_lock_acquire                     ; Enter critical section
+       call a3, __complete_and_return_to_userspace
+
+/*
+ * __complete_and_return_to_userspace
+ *
+ * restores the second half of the context and returns
+ * You must have the atomic lock when you call this function
+ */
+       .section .kernel_unprotected, "ax", @progbits
+__complete_and_return_to_userspace:
+       disable_kernel_ranges_for_current d15   ; disable kernel ranges
+       complete_restore_context                ; restore previous context
+       atomic_lock_release                     ; Leave critical section
+       move.4  csr, (sp)4++                    ; Restore csr from the stack
+       ret     (sp)4++
+
+/*
+ * ret_from_fork()
+ *     Called on the child's return from fork system call.
+ */
+       .section .text.ret_from_fork, "ax", @progbits
+       .global ret_from_fork
+ret_from_fork:
+       ;;;  d0 contains the arg for schedule_tail
+       ;;;  the others we don't care about as they are in PT_REGS (sp)
+       call   a5, schedule_tail
+
+       atomic_lock_acquire             ; Enter critical section
+
+       move.4  a3, sp
+       move.4  d0, PT_D0(a3)           ; Restore D0
+       move.4  d1, PT_D1(a3)           ; Restore D1
+       move.4  d2, PT_D2(a3)           ; Restore D2
+       move.4  d3, PT_D3(a3)           ; Restore D3
+       move.4  d10, PT_D10(a3)         ; Restore D10
+       move.4  d11, PT_D11(a3)         ; Restore D11
+       move.4  d12, PT_D12(a3)         ; Restore D12
+       move.4  d13, PT_D13(a3)         ; Restore D13
+       move.4  a1, PT_A1(a3)           ; Restore A1
+       move.4  a2, PT_A2(a3)           ; Restore A2
+       move.4  a5, PT_A5(a3)           ; Restore A5
+       move.4  a6, PT_A6(a3)           ; Restore A6
+       ;;  I think atomic_lock_acquire could be moved here..
+       move.4  sp, PT_SP(a3)           ; Restore sp
+       move.4  a4, PT_PC(a3)           ; Restore pc in register a4
+       move.4  PT_FRAME_TYPE(a3), #0   ; Clear frame_type to indicate it is invalid.
+
+#ifdef CONFIG_PROTECT_KERNEL
+       call a3, __ret_from_fork_bottom_half
+       .section .kernel_unprotected, "ax", @progbits
+__ret_from_fork_bottom_half:
+       disable_kernel_ranges_for_current d15
+#endif
+       atomic_lock_release             ; Leave critical section
+       calli   a4, 0(a4)               ; Return.
+
+/*
+ * __switch_to()
+ *
+ * Call with:
+ *     void *__switch_to(struct task_struct *prev, struct thread_struct *prev_switch,
+ *                             struct thread_struct *next_switch)
+ */
+       .section .text.__switch_to, "ax", @progbits
+       .global __switch_to
+__switch_to:
+
+       /*
+        * Set up register a3 to point to save area.
+        */
+       movea   a3, d1                  ; a3 now holds prev_switch
+       move.4  (a3)4++, d10
+       move.4  (a3)4++, d11
+       move.4  (a3)4++, d12
+       move.4  (a3)4++, d13
+       move.4  (a3)4++, a1
+       move.4  (a3)4++, a2
+       move.4  (a3)4++, a5
+       move.4  (a3)4++, a6
+       move.4  (a3)4++, a7
+
+       /*
+        * Set up register a3 to point to restore area.
+        */
+       movea   a3, d2                  ; a3 now holds next_switch
+       move.4  d10 , (a3)4++
+       move.4  d11 , (a3)4++
+       move.4  d12 , (a3)4++
+       move.4  d13 , (a3)4++
+       move.4  a1 , (a3)4++
+       move.4  a2 , (a3)4++
+       move.4  a5 , (a3)4++
+       move.4  a6 , (a3)4++
+       move.4  a7 , (a3)4++
+
+       /*
+        * Load the sw_ksp with the proper thread_info pointer.
+        */
+       movei   d15, #(~(ASM_THREAD_SIZE-1))
+       and.4   a3, sp, d15             ; a3 now has the thread info pointer
+       moveai  a4, #%hi(sw_ksp)
+       lea.1   a4, %lo(sw_ksp)(a4)     ; a4 now has the base address of sw_ksp array
+       lsr.4   d15, ROSR, #2           ; Thread number - bit's 6 through 31 are zeroes anyway.
+       move.4  (a4, d15), a3           ; Load the thread info pointer into the hw_ksp array..
+
+       /*
+        * We are done with context switch. Time to return..
+        */
+       calli   a5, 0(a5)
+       .size __switch_to, . - __switch_to
+
+/*
+ * ubicom32_emulate_insn()
+ *     Emulates the instruction.
+ *
+ * Call with:
+ *     unsigned int ubicom32_emulate_insn(int source1, int source2, int source3, int *save_acc, int *save_csr);
+ */
+       .section .text.ubicom32_emulate_insn, "ax", @progbits
+       .global ubicom32_emulate_insn
+       .global trap_emulate
+ubicom32_emulate_insn:
+       movea   a3, d3          ; a3 holds save_acc pointer
+       movea   a4, d4          ; a4 hods save_csr pointer
+       move.4  source3, d2
+       move.4  acc0_lo, (a3)
+       move.4  acc0_hi, 4(a3)
+       move.4  acc1_lo, 8(a3)
+       move.4  acc1_hi, 12(a3)
+       move.4  mac_rc16, 16(a3)
+       move.4  CSR, (a4)
+       setcsr_flush 0
+
+trap_emulate:
+       move.4  d0, d1
+       setcsr_flush 0
+       move.4  (a4), CSR       ; Save csr
+       move.4  (a3), acc0_lo
+       move.4  4(a3), acc0_hi
+       move.4  8(a3), acc1_lo
+       move.4  12(a3), acc1_hi
+       move.4  16(a3), mac_rc16
+       ret     a5
+       .size ubicom32_emulate_insn, . - ubicom32_emulate_insn
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_ksyms.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_ksyms.c
new file mode 100644 (file)
index 0000000..ea7eb15
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * arch/ubicom32/kernel/ubicom32_ksyms.c
+ *   Ubicom32 architecture compiler support and misc symbols.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/module.h>
+#include <linux/linkage.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
+#include <linux/in6.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/semaphore.h>
+
+#include <asm/setup.h>
+#include <asm/machdep.h>
+#include <asm/pgalloc.h>
+#include <asm/irq.h>
+#include <asm/checksum.h>
+#include <asm/current.h>
+
+/* platform dependent support */
+
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(iounmap);
+
+EXPORT_SYMBOL(ip_fast_csum);
+
+
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
+
+/* The following are special because they're not called
+   explicitly (the C compiler generates them).  Fortunately,
+   their interface isn't gonna change any time soon now, so
+   it's OK to leave it out of version control.  */
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memmove);
+
+#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4
+/*
+ * 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 __divdi3(void);
+extern void __lshrdi3(void);
+extern void __modsi3(void);
+extern void __muldi3(void);
+extern void __udivsi3(void);
+extern void __umodsi3(void);
+
+/* gcc lib functions */
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__divdi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
+#else
+extern void __libgcc_udivmodsi(void);
+extern void __libgcc_divmodsi(void);
+
+EXPORT_SYMBOL(__libgcc_udivmodsi);
+EXPORT_SYMBOL(__libgcc_divmodsi);
+#endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_syscall.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_syscall.S
new file mode 100644 (file)
index 0000000..870f66c
--- /dev/null
@@ -0,0 +1,694 @@
+/*
+ * arch/ubicom32/kernel/ubicom32_syscall.S
+ *     <TODO: Replace with short file description>
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <linux/unistd.h>
+
+#include <asm/ubicom32-common.h>
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm/range-protect.h>
+
+/*
+ * __old_system_call()
+ */
+       .section .old_syscall_entry.text, "ax", @progbits
+#ifdef CONFIG_OLD_40400010_SYSTEM_CALL
+__old_system_call:
+       call a3, system_call
+       .size __old_system_call, . - __old_system_call ;
+#else
+       /*
+        * something that will crash the userspace application, but
+        * should not take down the kernel, if protection is enabled
+        * this will never even get executed.
+        */
+       .long   0xFABBCCDE                      ; illegal instruction
+       bkpt #-1                                ; we will never get here
+#endif
+
+/*
+ * system_call()
+ */
+       .section .syscall_entry.text, "ax", @progbits
+       .global system_call
+system_call:
+       /*
+        * Regular ABI rules for function calls apply for syscall.  d8 holds
+        * the syscall number. We will use that to index into the syscall table.
+        * d0 - d5 hold the parameters.
+        *
+        * First we get the current thread_info and swap to the kernel stack.
+        * This is done by reading the current thread and looking up the ksp
+        * from the sw_ksp array and storing it in a3.
+        *
+        * Then we reserve space for the syscall context a struct pt_regs and
+        * save it using a4 initially and later as sp.
+        * Once sp is set to the kernel sp we can leave the critical section.
+        *
+        * For the user case the kernel stack will have the following layout.
+        *
+        *  a3           ksp[0] +-----------------------+
+        *                      | Thread info area      |
+        *                      | struct thread_info    |
+        *                      +-----------------------+
+        *                      :                       :
+        *                      |   Kernel Stack Area   |
+        *                      |                       |
+        *  a4 / sp >>>         +-----------------------+
+        *                      | Context save area     |
+        *                      | struct pt_reg         |
+        *  ksp[THREAD_SIZE-8]  +-----------------------+
+        *                      | 8 Byte Buffer Zone    |
+        *  ksp[THREAD_SIZE]    +-----------------------+
+
+        *
+        * For kernel syscalls the layout is as follows.
+        *
+        *  a3           ksp[0] +-----------------------+
+        *                      | Thread info area      |
+        *                      | struct thread_info    |
+        *                      +-----------------------+
+        *                      :                       :
+        *                      |   Kernel Stack Area   |
+        *                      |                       |
+        *  a4 / sp >>>         +-----------------------+
+        *                      | Context save area     |
+        *                      | struct pt_reg         |
+        * sp at syscall entry  +-----------------------+
+        *                      | Callers Kernel Stack  |
+        *                      :                       :
+        *
+        * Once the context is saved we optionally call syscall_trace and setup
+        * the exit routine and jump to the syscall.
+        */
+
+       /*
+        * load the base address for sw_ksp into a3
+        * Note.. we cannot access it just yet as protection is still on.
+        */
+       moveai  a3, #%hi(sw_ksp)
+       lea.1   a3, %lo(sw_ksp)(a3)
+
+       /*
+        * Enter critical section .
+        *
+        * The 'critical' aspects here are the switching the to the ksp and
+        * changing the protection registers, these both use per thread
+        * information so we need to protect from a context switch. For now this
+        * is done using the global atomic lock.
+        */
+       atomic_lock_acquire
+
+       thread_get_self d15                     ; Load current thread number
+#ifdef CONFIG_PROTECT_KERNEL
+       lsl.4   d9, #1, d15                     ; Convert to thread bit
+       enable_kernel_ranges d9
+#endif
+       /*
+        * in order to reduce the size of code in the syscall section we get
+        * out of it right now
+        */
+       call a4, __system_call_bottom_half
+       .size system_call, . - system_call
+
+       .section .text.__system_call_bottom_half, "ax", @progbits
+__system_call_bottom_half:
+
+       /*
+        * We need to Determine if this is a kernel syscall or user syscall.
+        * Start by loading the pointer for the thread_info structure for the
+        * current process in to a3.
+        */
+       move.4  a3, (a3, d15)                   ; a3 = sw_ksp[d15]
+
+       /*
+        * Now if this is a kernel thread the same value can be a acheived by
+        * masking off the lower bits on the current stack pointer.
+        */
+       movei   d9, #(~(ASM_THREAD_SIZE-1))     ; load mask
+       and.4   d9, sp, d9                      ; apply mask
+
+       /*
+        * d9 now has the masked version of the sp. If this is identical to
+        * what is in a3 then don't switch to ksp as we are already in the
+        * kernel.
+        */
+       sub.4   #0, a3, d9
+
+       /*
+        * if d9 and a3 are not equal. We are usespace and have to shift to
+        * ksp.
+        */
+       jmpne.t 1f
+
+       /*
+        * Kernel Syscall.
+        *
+        * The kernel has called this routine. We have to pdec space for pt_regs
+        * from sp.
+        */
+       pdec    a4, PT_SIZE(sp)                 ; a4 = ksp - PT_SIZE
+       jmpt.t  2f
+
+       /*
+        * Userspace Syscall.
+        *
+        * Add THREAD_SIZE and subtract PT_SIZE to create the proper ksp
+        */
+1:     movei   d15, #(ASM_THREAD_SIZE - 8 - PT_SIZE)
+       lea.1   a4, (a3, d15)                   ; a4 = ksp + d15
+
+       /*
+        * Replace user stack pointer with kernel stack pointer (a4)
+        * Load -1 into frame_type in save area to indicate this is system call
+        * frame.
+        */
+2:     move.4  PT_A7(a4), a7                   ; Save old sp/A7 on kernel stack
+       move.4  PT_FRAME_TYPE(a4), #-1          ; Set the frame type.
+       move.4  sp, a4                          ; Change to ksp.
+       /*
+        * We are now officially back in the kernel!
+        */
+
+       /*
+        * Now that we are on the ksp we can leave the critical section
+        */
+       atomic_lock_release
+
+       /*
+        * We need to save a0 because we need to be able to restore it in
+        * the event that we need to handle a signal.  It's not generally
+        * a callee-saved register but is the GOT pointer.
+        */
+       move.4  PT_A0(sp), a0                   ; Save A0 on kernel stack
+
+       /*
+        * We still need to save d10-d13, a1, a2, a5, a6 in the kernel frame
+        * for this process, we also save the system call params in the case of
+        * syscall restart. (note a7 was saved above)
+        */
+       move.4  PT_A1(sp), a1                   ; Save A1 on kernel stack
+       move.4  PT_A2(sp), a2                   ; Save A2 on kernel stack
+       move.4  PT_A5(sp), a5                   ; Save A5 on kernel stack
+       move.4  PT_A6(sp), a6                   ; Save A6 on kernel stack
+       move.4  PT_PC(sp), a5                   ; Save A5 at the PC location
+       move.4  PT_D10(sp), d10                 ; Save D10 on kernel stack
+       move.4  PT_D11(sp), d11                 ; Save D11 on kernel stack
+       move.4  PT_D12(sp), d12                 ; Save D12 on kernel stack
+       move.4  PT_D13(sp), d13                 ; Save D13 on kernel stack
+
+       /*
+        * Now save the syscall parameters
+        */
+       move.4  PT_D0(sp), d0                   ; Save d0 on kernel stack
+       move.4  PT_ORIGINAL_D0(sp), d0          ; Save d0 on kernel stack
+       move.4  PT_D1(sp), d1                   ; Save d1 on kernel stack
+       move.4  PT_D2(sp), d2                   ; Save d2 on kernel stack
+       move.4  PT_D3(sp), d3                   ; Save d3 on kernel stack
+       move.4  PT_D4(sp), d4                   ; Save d4 on kernel stack
+       move.4  PT_D5(sp), d5                   ; Save d5 on kernel stack
+       move.4  PT_D8(sp), d8                   ; Save d8 on kernel stack
+
+       /*
+        * Test if syscalls are being traced and if they are jump to syscall
+        * trace (it will comeback here)
+        */
+       btst    TI_FLAGS(a3), #ASM_TIF_SYSCALL_TRACE
+       jmpne.f .Lsystem_call__trace
+.Lsystem_call__trace_complete:
+       /*
+        * Check for a valid call number [ 0 <= syscall_number < NR_syscalls ]
+        */
+       cmpi    d8, #0
+       jmplt.f 3f
+       cmpi    d8, #NR_syscalls
+       jmplt.t 4f
+
+       /*
+        * They have passed an invalid number. Call sys_ni_syscall staring by
+        * load a4 with the base address of sys_ni_syscall
+        */
+3:     moveai  a4, #%hi(sys_ni_syscall)
+       lea.1   a4, %lo(sys_ni_syscall)(a4)
+       jmpt.t  5f                              ; Jump to regular processing
+
+       /*
+        * Validated syscall, load the syscall table base address into a3 and
+        * read the syscall ptr out.
+        */
+4:     moveai  a3, #%hi(sys_call_table)
+       lea.1   a3, %lo(sys_call_table)(a3)     ; a3 = sys_call_table
+       move.4  a4, (a3, d8)                    ; a4 = sys_call_table[d8]
+
+       /*
+        * Before calling the syscall, setup a5 so that syscall_exit is called
+        * on return from syscall
+        */
+5:     moveai  a5, #%hi(syscall_exit)          ; Setup return address
+       lea.1   a5, %lo(syscall_exit)(a5)       ; from system call
+
+       /*
+        * If the syscall is __NR_rt_rigreturn then we have to test d1 to
+        * figure out if we have to change change the return routine to restore
+        * all registers.
+        */
+       cmpi    d8, #__NR_rt_sigreturn
+       jmpeq.f 6f
+
+       /*
+        * Launch system call (it will return through a5 - syscall_exit)
+        */
+       calli   a3, 0(a4)
+
+       /*
+        * System call is rt_sigreturn. Test d1. If it is 1 we have to
+        * change the return address to restore_all_registers
+        */
+6:     cmpi    d1, #1
+       jmpne.t 7f
+
+       moveai  a5, #%hi(restore_all_registers)  ; Setup return address
+       lea.1   a5, %lo(restore_all_registers)(a5) ; to restore_all_registers.
+
+       /*
+        * Launch system call  (it will return through a5)
+        */
+7:     calli   a3, 0(a4)                        ; Launch system call
+
+.Lsystem_call__trace:
+       /*
+        * Syscalls are being traced.
+        * Call syscall_trace, (return here)
+        */
+       call    a5, syscall_trace
+
+       /*
+        * Restore syscall state (it would have been discarded during the
+        * syscall trace)
+        */
+       move.4  d0, PT_D0(sp)                   ; Restore d0 from kernel stack
+       move.4  d1, PT_D1(sp)                   ; Restore d1 from kernel stack
+       move.4  d2, PT_D2(sp)                   ; Restore d2 from kernel stack
+       move.4  d3, PT_D3(sp)                   ; Restore d3 from kernel stack
+       move.4  d4, PT_D4(sp)                   ; Restore d4 from kernel stack
+       move.4  d5, PT_D5(sp)                   ; Restore d5 from kernel stack
+       /* add this back if we ever have a syscall with 7 args */
+       move.4  d8, PT_D8(sp)                   ; Restore d8 from kernel stack
+
+       /*
+        * return to syscall
+        */
+       jmpt.t .Lsystem_call__trace_complete
+       .size __system_call_bottom_half, . - __system_call_bottom_half
+
+/*
+ * syscall_exit()
+ */
+       .section .text.syscall_exit
+       .global syscall_exit
+syscall_exit:
+       /*
+        * d0 contains the return value. We should move that into the kernel
+        * stack d0 location.  We will be transitioning from kernel to user
+        * mode. Test the flags and see if we have to call schedule. If we are
+        * going to truly exit then all that has to be done is that from the
+        * kernel stack we have to restore d0, a0, a1, a2, a5, a6 and sp (a7)bb
+        * and then return via a5.
+        */
+
+       /*
+        * Save d0 to pt_regs
+        */
+       move.4  PT_D0(sp), d0                   ; Save d0 into the kernel stack
+
+       /*
+        * load the thread_info structure by masking off the THREAD_SIZE
+        * bits.
+        *
+        * Note: we used to push a1, but now we don't as we are going
+        * to eventually restore it to the userspace a1.
+        */
+       movei   d9, #(~(ASM_THREAD_SIZE-1))
+       and.4   a1, sp, d9
+
+       /*
+        * Are any interesting bits set on TI flags, if there are jump
+        * aside to post_processing.
+        */
+       move.4  d9, #(_TIF_SYSCALL_TRACE | _TIF_NEED_RESCHED | _TIF_SIGPENDING)
+       and.4   #0, TI_FLAGS(a1), d9
+       jmpne.f .Lsyscall_exit__post_processing ; jump to handler
+.Lsyscall_exit__post_processing_complete:
+
+       move.4  d0, PT_D0(sp)                   ; Restore D0 from kernel stack
+       move.4  d1, PT_D1(sp)                   ; Restore d1 from kernel stack
+       move.4  d2, PT_D2(sp)                   ; Restore d2 from kernel stack
+       move.4  d3, PT_D3(sp)                   ; Restore d3 from kernel stack
+       move.4  d4, PT_D4(sp)                   ; Restore d4 from kernel stack
+       move.4  d5, PT_D5(sp)                   ; Restore d5 from kernel stack
+       move.4  d8, PT_D8(sp)                   ; Restore d8 from kernel stack
+       move.4  d10, PT_D10(sp)                 ; Restore d10 from kernel stack
+       move.4  d11, PT_D11(sp)                 ; Restore d11 from kernel stack
+       move.4  d12, PT_D12(sp)                 ; Restore d12 from kernel stack
+       move.4  d13, PT_D13(sp)                 ; Restore d13 from kernel stack
+       move.4  a1, PT_A1(sp)                   ; Restore A1 from kernel stack
+       move.4  a2, PT_A2(sp)                   ; Restore A2 from kernel stack
+       move.4  a5, PT_A5(sp)                   ; Restore A5 from kernel stack
+       move.4  a6, PT_A6(sp)                   ; Restore A6 from kernel stack
+       move.4  a0, PT_A0(sp)                   ; Restore A6 from kernel stack
+
+       /*
+        * this is only for debug, and could be removed for production builds
+        */
+       move.4  PT_FRAME_TYPE(sp), #0           ; invalidate frame_type
+
+#ifdef CONFIG_PROTECT_KERNEL
+
+       call a4, __syscall_exit_bottom_half
+
+       .section .kernel_unprotected, "ax", @progbits
+__syscall_exit_bottom_half:
+       /*
+        * Enter critical section
+        */
+       atomic_lock_acquire
+       disable_kernel_ranges_for_current d15
+#endif
+       /*
+        * Lastly restore userspace stack ptr
+        *
+        * Note: that when protection is on we need to hold the lock around the
+        * stack swap as well because otherwise the protection could get
+        * inadvertently disabled again at the end of a context switch.
+        */
+       move.4  a7, PT_A7(sp)                   ; Restore A7 from kernel stack
+
+       /*
+        * We are now officially back in userspace!
+        */
+
+#ifdef CONFIG_PROTECT_KERNEL
+       /*
+        * Leave critical section and return to user space.
+        */
+       atomic_lock_release
+#endif
+       calli   a5, 0(a5)                       ; Back to userspace code.
+
+       bkpt #-1                                ; we will never get here
+
+       /*
+        * Post syscall processing. (unlikely part of syscall_exit)
+        *
+        * Are we tracing syscalls. If TIF_SYSCALL_TRACE is set, call
+        * syscall_trace routine and return here.
+        */
+       .section .text.syscall_exit, "ax", @progbits
+.Lsyscall_exit__post_processing:
+       btst    TI_FLAGS(a1), #ASM_TIF_SYSCALL_TRACE
+       jmpeq.t 1f
+       call    a5, syscall_trace
+
+       /*
+        * Do we need to resched ie call schedule. If TIF_NEED_RESCHED is set,
+        * call the scheduler, it will come back here.
+        */
+1:     btst    TI_FLAGS(a1), #ASM_TIF_NEED_RESCHED
+       jmpeq.t 2f
+       call    a5, schedule
+
+       /*
+        * Do we need to post a signal, if TIF_SIGPENDING is set call the
+        * do_signal.
+        */
+2:     btst    TI_FLAGS(a1), #ASM_TIF_SIGPENDING
+       jmpeq.t .Lsyscall_exit__post_processing_complete
+
+       /*
+        * setup the do signal call
+        */
+       move.4  d0, #0                          ; oldset pointer is NULL
+       lea.1   d1, (sp)                        ; d1 is the regs pointer.
+       call    a5, do_signal
+
+       jmpt.t  .Lsyscall_exit__post_processing_complete
+
+/*     .size syscall_exit, . - syscall_exit */
+
+/*
+ * kernel_execve()
+ *     kernel_execv is called when we the kernel is starting a
+ *     userspace application.
+ */
+       .section .kernel_unprotected, "ax", @progbits
+       .global kernel_execve
+kernel_execve:
+       move.4  -4(sp)++, a5                    ; Save return address
+       /*
+        * Call execve
+        */
+       movei   d8, #__NR_execve                ; call execve
+       call    a5, system_call
+       move.4  a5, (sp)4++
+
+       /*
+        * protection was enabled again at syscall exit, but we want
+        * to return to kernel so we enable it again.
+        */
+#ifdef CONFIG_PROTECT_KERNEL
+       /*
+        * We are entering the kernel so we need to disable the protection.
+        * Enter critical section, disable ranges and leave critical section.
+        */
+       call a3, __enable_kernel_ranges ;  and jump back to kernel
+#else
+       ret a5                                  ; jump back to the kernel
+#endif
+
+       .size kernel_execve, . - kernel_execve
+
+/*
+ * signal_trampoline()
+ *
+ *     Deals with transitioning from to userspace signal handlers and returning
+ *     to userspace, only called from the kernel.
+ *
+ */
+       .section .kernel_unprotected, "ax", @progbits
+       .global signal_trampoline
+signal_trampoline:
+       /*
+        * signal_trampoline is called when we are jumping from the kernel to
+        * the userspace signal handler.
+        *
+        * The following registers are relevant. (set setup_rt_frame)
+        *   sp is the user space stack not the kernel stack
+        *  d0 = signal number
+        *  d1 = siginfo_t *
+        *  d2 = ucontext *
+        *  d3 = the user space signal handler
+        *  a0 is set to the GOT if userspace application is FDPIC, otherwise 0
+        *  a3 is set to the FD for the signal if userspace application is FDPIC
+        */
+#ifdef CONFIG_PROTECT_KERNEL
+       /*
+        * We are leaving the kernel so we need to enable the protection.
+        * Enter critical section, disable ranges and leave critical section.
+        */
+       atomic_lock_acquire                     ; Enter critical section
+       disable_kernel_ranges_for_current d15   ; disable kernel ranges
+       atomic_lock_release                     ; Leave critical section
+#endif
+       /*
+        * The signal handler pointer is in register d3 so tranfer it to a4 and
+        * call it
+        */
+       movea   a4, d3                          ; signal handler
+       calli   a5, 0(a4)
+
+       /*
+        * Return to userspace through rt_syscall which is stored on top of the
+        * stack d1 contains ret_via_interrupt status.
+        */
+       move.4  d8, (sp)                        ; d8 (syscall #) = rt_syscall
+       move.4  d1, 4(sp)                       ; d1 = ret_via_interrupt
+       call    a5, system_call         ; as we are 'in' the kernel
+                                               ; we can call kernel_syscall
+
+       bkpt #-1                                ; will never get here.
+       .size signal_trampoline, . - signal_trampoline
+
+/*
+ * kernel_thread_helper()
+ *
+ *     Entry point for kernel threads (only referenced by kernel_thread()).
+ *
+ *     On execution d0 will be 0, d1 will be the argument to be passed to the
+ *     kernel function.
+ *     d2 contains the kernel function that needs to get called.
+ *     d3 will contain address to do_exit which needs to get moved into a5.
+ *
+ *     On return from fork the child thread d0 will be 0. We call this dummy
+ *     function which in turn loads the argument
+ */
+       .section .kernel_unprotected, "ax", @progbits
+       .global kernel_thread_helper
+kernel_thread_helper:
+       /*
+        * Create a kernel thread. This is called from ret_from_vfork (a
+        * userspace return routine) so we need to put it in an unprotected
+        * section and re-enable protection before calling the vector in d2.
+        */
+
+#ifdef CONFIG_PROTECT_KERNEL
+       /*
+        * We are entering the kernel so we need to disable the protection.
+        * Enter critical section, disable ranges and leave critical section.
+        */
+       call a5, __enable_kernel_ranges
+#endif
+       /*
+        * Move argument for kernel function into d0, and set a5 return address
+        * (a5) to do_exit and return through a2
+        */
+       move.4  d0, d1                          ; d0 = arg
+       move.4  a5, d3                          ; a5 = do_exit
+       ret     d2                              ; call function ptr in d2
+       .size kernel_thread_helper, . - kernel_thread_helper
+
+#ifdef CONFIG_PROTECT_KERNEL
+       .section .kernel_unprotected, "ax", @progbits
+__enable_kernel_ranges:
+       atomic_lock_acquire                     ; Enter critical section
+       enable_kernel_ranges_for_current d15
+       atomic_lock_release                     ; Leave critical section
+       calli a5, 0(a5)
+       .size __enable_kernel_ranges, . - __enable_kernel_ranges
+
+#endif
+
+/*
+ * The following system call intercept functions where we setup the
+ * input to the real system call.  In all cases these are just taking
+ * the current sp which is pointing to pt_regs and pushing it into the
+ * last arg of the system call.
+ *
+ * i.e. the public definition of sys_execv is
+ *     sys_execve(     char *name,
+ *                     char **argv,
+ *                     char **envp )
+ * but process.c defines it as
+ *     sys_execve(     char *name,
+ *                     char **argv,
+ *                     char **envp,
+ *                     struct pt_regs *regs )
+ *
+ * so execve_intercept needs to populate the 4th arg with pt_regs*,
+ * which is the stack pointer as we know we must be coming out of
+ * system_call
+ *
+ * The intercept vectors are referenced by syscalltable.S
+ */
+
+/*
+ * execve_intercept()
+ */
+       .section .text.execve_intercept, "ax", @progbits
+       .global execve_intercept
+execve_intercept:
+       move.4  d3, sp  ; Save pt_regs address
+       call    a3, sys_execve
+
+       .size execve_intercept, . - execve_intercept
+
+/*
+ * vfork_intercept()
+ */
+       .section .text.vfork_intercept, "ax", @progbits
+       .global vfork_intercept
+vfork_intercept:
+       move.4  d0, sp  ; Save pt_regs address
+       call    a3, sys_vfork
+
+       .size vfork_intercept, . - vfork_intercept
+
+/*
+ * clone_intercept()
+ */
+       .section .text.clone_intercept, "ax", @progbits
+       .global clone_intercept
+clone_intercept:
+       move.4  d2, sp  ; Save pt_regs address
+       call    a3, sys_clone
+
+       .size clone_intercept, . - clone_intercept
+
+/*
+ * sys_sigsuspend()
+ */
+       .section .text.sigclone_intercept, "ax", @progbits
+       .global sys_sigsuspend
+sys_sigsuspend:
+       move.4  d0, sp  ; Pass pointer to pt_regs in d0
+       call    a3, do_sigsuspend
+
+       .size sys_sigsuspend, . - sys_sigsuspend
+
+/*
+ * sys_rt_sigsuspend()
+ */
+       .section .text.sys_rt_sigsuspend, "ax", @progbits
+       .global sys_rt_sigsuspend
+sys_rt_sigsuspend:
+       move.4  d0, sp  ; Pass pointer to pt_regs in d0
+       call    a3, do_rt_sigsuspend
+
+       .size sys_rt_sigsuspend, . - sys_rt_sigsuspend
+
+/*
+ * sys_rt_sigreturn()
+ */
+       .section .text.sys_rt_sigreturn, "ax", @progbits
+       .global sys_rt_sigreturn
+sys_rt_sigreturn:
+       move.4  d0, sp  ; Pass pointer to pt_regs in d0
+       call    a3, do_rt_sigreturn
+
+       .size sys_rt_sigreturn, . - sys_rt_sigreturn
+
+/*
+ * sys_sigaltstack()
+ */
+       .section .text.sys_sigaltstack, "ax", @progbits
+       .global sys_sigaltstack
+sys_sigaltstack:
+       move.4  d0, sp  ; Pass pointer to pt_regs in d0
+       call    a3, do_sys_sigaltstack
+
+       .size sys_sigaltstack, . - sys_sigaltstack
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/unaligned_trap.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/unaligned_trap.c
new file mode 100644 (file)
index 0000000..d856d06
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+ * arch/ubicom32/kernel/unaligned_trap.c
+ *   Handle unaligned traps in both user or kernel space.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/cacheflush.h>
+#include <asm/traps.h>
+
+#define FALSE 0
+#define TRUE 1
+
+/* no possible trap */
+#define UNUSED 0
+/* possible source operand trap */
+#define SRC 1
+#define SRC_2 2
+/* possible destination operand trap */
+#define DEST 3
+#define DEST_2 4
+/* can be either source or destination or both */
+#define TWO_OP 5
+#define TWO_OP_2 6
+
+/* TODO: What is the real value here, put something in to make it compile for
+ * now */
+#define MOVE_2 0x0d
+#define LSL_2  0x11
+#define LSR_2  0x13
+#define MOVEI  0x19
+#define CMPI   0x18
+
+static int op_format[32] =
+{
+       TWO_OP,         /* 0x00 */
+       UNUSED,
+       SRC,
+       UNUSED,
+       TWO_OP,         /* 0x04 */
+       TWO_OP,
+       SRC,
+       UNUSED,
+       TWO_OP_2,       /* 0x08 */
+       TWO_OP,
+       TWO_OP_2,
+       TWO_OP,
+       TWO_OP_2,       /* 0x0C */
+       TWO_OP,
+       TWO_OP_2,
+       TWO_OP,
+       TWO_OP,         /* 0x10 */
+       TWO_OP_2,
+       TWO_OP,
+       TWO_OP,
+       UNUSED,         /* 0x14 */
+       UNUSED,
+       UNUSED,
+       UNUSED,
+       SRC_2,          /* 0x18 */
+       DEST_2,
+       UNUSED,
+       UNUSED,
+       UNUSED,         /* 0x1C */
+       UNUSED,
+       UNUSED,         /* unaligned CALLI will not be fixed. */
+       UNUSED
+};
+
+static int op_0_format[32] =
+{
+       UNUSED,         /* 0x00 */
+       UNUSED,
+       UNUSED,
+       UNUSED,
+       UNUSED,         /* 0x04 - ret don't fix - bad ret is always wrong */
+       UNUSED,
+       UNUSED,
+       UNUSED,
+       UNUSED,         /* 0x08 */
+       UNUSED,
+       TWO_OP,
+       TWO_OP_2,
+       TWO_OP,         /* 0x0c */
+       TWO_OP_2,
+       TWO_OP,
+       UNUSED,         /* .1 can't trap */
+       UNUSED,         /* 0x10 */
+       UNUSED,
+       SRC,
+       UNUSED,
+       UNUSED,         /* 0x14 */
+       TWO_OP_2,
+       UNUSED,
+       UNUSED,
+       UNUSED,         /* 0x18 */
+       UNUSED,
+       UNUSED,
+       UNUSED,
+       DEST,           /* 0x1c */
+       DEST,
+       DEST,
+       DEST,           /* all lea have 32-bit destination */
+};
+
+static int op_2_format[32] =
+{
+       UNUSED,         /* 0x00 */
+       UNUSED,
+       UNUSED,
+       UNUSED,
+       UNUSED,         /* 0x04 */
+       UNUSED,
+       SRC,
+       UNUSED,
+       UNUSED,         /* 0x08 crcgen is .1 */
+       UNUSED,
+       UNUSED,
+       UNUSED,
+       UNUSED,         /* 0x0c */
+       UNUSED,
+       UNUSED,
+       UNUSED,
+       SRC,            /* 0x10 */
+       SRC_2,
+       SRC,
+       SRC_2,
+       SRC,            /* 0x14 */
+       SRC_2,
+       SRC,
+       UNUSED,
+       UNUSED,         /* 0x18 */
+       UNUSED,
+       SRC,
+       UNUSED,
+       SRC,            /* 0x1c */
+       UNUSED,
+       SRC_2,
+       UNUSED,
+};
+
+static int op_6_format[32] =
+{
+       SRC_2,          /* 0x00 */
+       SRC_2,
+       SRC_2,
+       SRC_2,
+       SRC_2,          /* 0x04 */
+       SRC_2,
+       UNUSED,
+       SRC_2,
+       SRC,            /* 0x08 MULS.4 */
+       SRC_2,
+       SRC,
+       UNUSED,
+       UNUSED,         /* 0x0c */
+       UNUSED,
+       UNUSED,
+       UNUSED,
+       SRC,            /* 0x10 */
+       SRC_2,
+       SRC,
+       SRC_2,
+       UNUSED,         /* 0x14 */
+       UNUSED,
+       UNUSED,
+       UNUSED,
+       UNUSED,         /* 0x18 */
+       UNUSED,
+       UNUSED,
+       UNUSED,
+       UNUSED,         /* 0x1c */
+       UNUSED,
+       UNUSED,
+       UNUSED,
+};
+
+/*
+ * unaligned_get_address()
+ *     get an address using save_an and save_dn registers, and updates save_an
+ *     with side effects
+ */
+unsigned char *unaligned_get_address(int thread, int specifier, int four_byte,
+                                    unsigned int save_an[],
+                                    unsigned int save_dn[], int *write_back_an)
+{
+       unsigned char *address;
+
+       int areg = (specifier >> 5) & 7;
+       if ((specifier >> 8) == 2) {
+               int offset = specifier & 0xf;
+               offset = ((offset << 28) >> 28);
+               if (likely(four_byte)) {
+                       offset <<= 2;
+               } else {
+                       offset <<= 1;
+               }
+               if (specifier & 0x10) {
+                       address = (unsigned char *)(save_an[areg] + offset);
+               } else {
+                       address = (unsigned char *)save_an[areg];
+               }
+               save_an[areg] = save_an[areg] + offset;
+
+               /*
+                * Let caller know An registers have been modified.
+                */
+               *write_back_an = 1;
+       } else if ((specifier >> 8) == 3) {
+               int dreg = specifier & 0xf;
+               if (likely(four_byte)) {
+                       address = (unsigned char *)(save_an[areg] +
+                                                   (save_dn[dreg] << 2));
+               } else {
+                       address = (unsigned char *)(save_an[areg] +
+                                                   (save_dn[dreg] << 1));
+               }
+       } else {
+               int offset = ((specifier >> 3) & 0x60) | (specifier & 0x1f);
+               if (likely(four_byte)) {
+                       address = (unsigned char *)(save_an[areg] +
+                                                   (offset << 2));
+               } else {
+                       address = (unsigned char *)(save_an[areg] +
+                                                   (offset << 1));
+               }
+       }
+
+       return address;
+}
+
+static int save_dn[16];
+static int save_an[8];
+static int save_acc[5];
+
+/*
+ * unaligned_emulate()
+ *     emulate the instruction at thread's pc that has taken an unaligned data
+ *     trap.
+ *
+ * source or destination or both might be unaligned
+ * the instruction must have a memory source or destination or both
+ * the emulated instruction is copied and executed in this thread
+ *
+ *     TODO: Protection is handled outside of this function
+ *     TODO: handling simultaneous unaligned and memory protection traps
+ *
+ *     Get thread state
+ *             the PC and instruction (and local copy, emulate_inst), and An
+ *             and Dn registers
+ *             All implicit soruce state (source3, CSR, accumulators)
+
+ *     if the instruction has a memory source
+ *             Use the instruction, An and Dn registers to form src_address
+ *             get unaligned source data from src_address (usually sign
+ *             extended)
+ *                     (2 bytes, with or without sign extension, or 4 bytes)
+ *             modify emulate_inst to use d0 as source
+ *     else
+ *             get the soure operand from one of thread's registers
+ *     if instruction has a memory destination
+ *             Use the instruction, An and Dn registers to form dest_address
+ *             modify emulate_inst to use d0 as destination
+ *     if there was a memory source
+ *             put the source data in thread's d0
+ *     get the source-2 Dn operand and source 3 operand from thread
+ *     execute modified inst
+ *             (save it, flush caches, set up local values for implicit
+ *             sources, execute, save explicit and implicit results)
+ *     if inst has destination address
+ *             copy result to dest_address, possibly unaligned, 1, 2, or 4
+ *             bytes
+ *     restore thread's implicit results (modified address registers, CSR,
+ *     accumulators) add 4 to thread's pc
+ */
+void unaligned_emulate(unsigned int thread)
+{
+       unsigned int pc;
+       unsigned int inst;
+       unsigned int op;
+       unsigned int subop;
+       int format;
+       unsigned int emulate_inst;
+       int four_byte;
+       int src_operand, dest_operand;
+       int save_csr;
+       int source3;
+       unsigned int source1;
+       unsigned int source_data;
+       unsigned char *dest_address = NULL;
+       int source2 = 0;
+       unsigned int result;
+       unsigned int write_back_an = 0;
+       unsigned int chip_id_copy;
+
+       extern unsigned int trap_emulate;
+       extern unsigned int ubicom32_emulate_insn(int source1, int source2,
+                                                 int source3, int *save_acc,
+                                                 int *save_csr);
+
+       /*
+        * get the chip_id
+        */
+       asm volatile (
+       "       move.4          %0, chip_id             \n\t" /* get chip_id. */
+               : "=r"(chip_id_copy)
+               :
+       );
+
+       /*
+        * get the pc
+        */
+       asm volatile (
+       "       move.4          CSR, %1         \n\t" /* set source thread in
+                                                      * CSR */
+       "       setcsr_flush    0               \n\t"
+       "       move.4          %0, pc          \n\t"
+       "       move.4          CSR, #0         \n\t" /* restore CSR */
+       "       setcsr_flush    0               \n\t"
+               : "=a"(pc)
+               : "d" ((1 << 8) | (thread << 9))
+               : "cc"
+       );
+
+       inst = *((unsigned int *)pc);
+       op = inst >> 27;
+       if (unlikely(op == 2 || op == 6)) {
+               subop = (inst >> 21) & 0x1f;
+       } else {
+               subop = (inst >> 11) & 0x1f;
+       }
+       format = op_format[op];
+       emulate_inst = inst;
+
+       if (op == 0) {
+               format = op_0_format[subop];
+       } else if (op == 2) {
+               format = op_2_format[subop];
+       } else if (op == 6) {
+               format = op_6_format[subop];
+       }
+
+       if (unlikely(format == UNUSED)) {
+               /*
+                * We are not going to emulate this. Bump PC by 4 and move on.
+                */
+               asm volatile (
+               "       move.4          CSR, %0                 \n\t"
+               "       setcsr_flush    0                       \n\t"
+               "       move.4          pc, %1                  \n\t"
+               "       setcsr          #0                      \n\t"
+               "       setcsr_flush    0                       \n\t"
+                       :
+                       : "d"((1 << 14) | (thread << 15)), "d"(pc + 4)
+                       : "cc"
+               );
+               return;
+       }
+
+       four_byte = (format == TWO_OP || format == DEST || format == SRC);
+
+       /*
+        * source or destination memory operand needs emulation
+        */
+       src_operand = (format == SRC ||
+                      format == SRC_2 ||
+                      format == TWO_OP ||
+                      format == TWO_OP_2) &&
+               ((inst >> 8) & 7) > 1;
+
+       dest_operand = (format == DEST ||
+                       format == DEST_2 ||
+                       format == TWO_OP ||
+                       format == TWO_OP_2) &&
+               ((inst >> 24) & 7) > 1;
+
+       /*
+        * get thread's implicit sources (not covered by source context select).
+        * data and address registers and CSR (for flag bits) and src3 and
+        * accumulators
+        */
+       asm volatile (
+       "       move.4          CSR, %2         \n\t"   /* set source thread in
+                                                        * CSR */
+       "       setcsr_flush    0               \n\t"
+       "       move.4          (%3), d0        \n\t"   /* get dn registers */
+       "       move.4          4(%3), d1       \n\t"
+       "       move.4          8(%3), d2       \n\t"
+       "       move.4          12(%3), d3      \n\t"
+       "       move.4          16(%3), d4      \n\t"
+       "       move.4          20(%3), d5      \n\t"
+       "       move.4          24(%3), d6      \n\t"
+       "       move.4          28(%3), d7      \n\t"
+       "       move.4          32(%3), d8      \n\t"
+       "       move.4          36(%3), d9      \n\t"
+       "       move.4          40(%3), d10     \n\t"
+       "       move.4          44(%3), d11     \n\t"
+       "       move.4          48(%3), d12     \n\t"
+       "       move.4          52(%3), d13     \n\t"
+       "       move.4          56(%3), d14     \n\t"
+       "       move.4          60(%3), d15     \n\t"
+       "       move.4          (%4), a0        \n\t"   /* get an registers */
+       "       move.4          4(%4), a1       \n\t"
+       "       move.4          8(%4), a2       \n\t"
+       "       move.4          12(%4), a3      \n\t"
+       "       move.4          16(%4), a4      \n\t"
+       "       move.4          20(%4), a5      \n\t"
+       "       move.4          24(%4), a6      \n\t"
+       "       move.4          28(%4), a7      \n\t"
+       "       move.4          %0, CSR         \n\t"   /* get csr and source3
+                                                        * implicit operands */
+       "       move.4          %1, source3     \n\t"
+       "       move.4          (%5), acc0_lo   \n\t"   /* get accumulators */
+       "       move.4          4(%5), acc0_hi  \n\t"
+       "       move.4          8(%5), acc1_lo  \n\t"
+       "       move.4          12(%5), acc1_hi \n\t"
+       "       move.4          16(%5), mac_rc16        \n\t"
+       "       move.4          CSR, #0         \n\t"   /* restore CSR */
+       "       setcsr_flush    0               \n\t"
+               : "=m"(save_csr), "=m"(source3)
+               : "d"((1 << 8) | (thread << 9)),
+                 "a"(save_dn), "a"(save_an), "a"(save_acc)
+               : "cc"
+       );
+
+       /*
+        * turn off thread select bits if they were on
+        */
+       BUG_ON((save_csr & 0x04100) != 0);
+       if (unlikely(save_csr & 0x04100)) {
+               /*
+                * Things are in funny state as thread select bits are on in
+                * csr. PANIC.
+                */
+               panic("In unaligned trap handler. Trap thread CSR has thread "
+                     "select bits on.\n");
+       }
+
+       save_csr = save_csr & 0x1000ff;
+
+       /*
+        * get the source1 operand
+        */
+       source1 = 0;
+       if (src_operand) {
+               unsigned char *src_address;
+
+               /*
+                * source1 comes from memory
+                */
+               BUG_ON(!(format == TWO_OP || format == TWO_OP_2 ||
+                        format == SRC || format == SRC_2));
+               src_address = unaligned_get_address(thread, inst & 0x7ff,
+                                                   four_byte, save_an,
+                                                   save_dn, &write_back_an);
+
+               /*
+                * get data (possibly unaligned)
+                */
+               if (likely(four_byte)) {
+                       source_data = (*src_address << 24) |
+                               (*(src_address + 1) << 16) |
+                               (*(src_address + 2) << 8) |
+                               *(src_address + 3);
+                       source1 = source_data;
+               } else {
+                       source1 = *src_address << 8 |
+                               *(src_address + 1);
+
+                       /*
+                        * Source is not extended if the instrution is MOVE.2 or
+                        * if the cpu CHIP_ID >= 0x30000 and the instruction is
+                        * either LSL.2 or LSR.2.  All other cases have to be
+                        * sign extended.
+                        */
+                       if ((!(op == 2 && subop == MOVE_2)) &&
+                           (!((chip_id_copy >= 0x30000) &&
+                              (subop == LSL_2 || subop == LSR_2)))) {
+                               /*
+                                * Have to sign extend the .2 entry.
+                                */
+                               source1 = ((unsigned int)
+                                          ((signed int)
+                                           ((signed short) source1)));
+                       }
+               }
+       } else if (likely(op != MOVEI)) {
+               /*
+                * source1 comes from a register, using move.4 d0, src1
+                * unaligned_emulate_get_source is pointer to code to insert remulated instruction
+                */
+               extern unsigned int unaligned_emulate_get_src;
+               *((int *)&unaligned_emulate_get_src) &= ~(0x7ff);
+               *((int *)&unaligned_emulate_get_src) |= (inst & 0x7ff);
+               flush_dcache_range((unsigned long)(&unaligned_emulate_get_src),
+                                  (unsigned long)(&unaligned_emulate_get_src) + 4);
+
+               asm volatile (
+                       /* source1 uses thread's registers */
+               "       move.4          CSR, %1                 \n\t"
+               "       setcsr_flush 0                          \n\t"
+               "unaligned_emulate_get_src:                     \n\t"
+               "       move.4  %0, #0                          \n\t"
+               "       setcsr          #0                      \n\t"
+               "       setcsr_flush    0                       \n\t"
+                       : "=d" (source1)
+                       : "d" ((1 << 8) | (thread << 9))
+                       : "cc"
+               );
+       }
+
+       /*
+        * get the destination address
+        */
+       if (dest_operand) {
+               BUG_ON(!(format == TWO_OP || format == TWO_OP_2 ||
+                        format == DEST || format == DEST_2));
+               dest_address = unaligned_get_address(thread,
+                                                    ((inst >> 16) & 0x7ff),
+                                                    four_byte, save_an,
+                                                    save_dn, &write_back_an);
+       }
+
+       if (write_back_an) {
+               /*
+                * restore any modified An registers
+                */
+               asm volatile (
+               "       move.4          CSR, %0                 \n\t"
+               "       setcsr_flush    0                       \n\t"
+               "       move.4          a0, (%1)                \n\t"
+               "       move.4          a1, 4(%1)               \n\t"
+               "       move.4          a2, 8(%1)               \n\t"
+               "       move.4          a3, 12(%1)              \n\t"
+               "       move.4          a4, 16(%1)              \n\t"
+               "       move.4          a5, 20(%1)              \n\t"
+               "       move.4          a6, 24(%1)              \n\t"
+               "       move.4          a7, 28(%1)              \n\t"
+               "       setcsr          #0                      \n\t"
+               "       setcsr_flush    0                       \n\t"
+                       :
+                       : "d" ((1 << 14) | (thread << 15)), "a" (save_an)
+                       : "cc"
+               );
+       }
+
+       /*
+        * get source 2 register if needed, and modify inst to use d1 for
+        * source-2 source-2 will come from this thread, not the trapping thread
+        */
+       source2 = 0;
+       if ((op >= 8 && op <= 0x17) ||
+           ((op == 2 || op == 6) && (inst & 0x4000000))) {
+               int src_dn = (inst >> 11) & 0xf;
+               source2 = save_dn[src_dn];
+               /*
+                * force the emulated instruction to use d1 for source2 operand
+                */
+               emulate_inst = (emulate_inst & 0xffff07ff) | 0x800;
+       }
+
+       if (likely(op != MOVEI)) {
+               /*
+                * change emulated instruction source1 to d0
+                */
+               emulate_inst &= ~0x7ff;
+               emulate_inst |= 1 << 8;
+       }
+
+       if (unlikely(op == 6 || op == 2)) {
+               /*
+                * Set destination to d0
+                */
+               emulate_inst &= ~(0xf << 16);
+       } else if (likely(op != CMPI)) {
+               /*
+                * Set general destination field to d0.
+                */
+               emulate_inst &= ~(0x7ff << 16);
+               emulate_inst |= 1 << 24;
+       }
+
+       /*
+        * execute emulated instruction d0, to d0, no memory access
+        * source2 if needed will be in d1
+        * source3, CSR, and accumulators are set up before execution
+        */
+       *((unsigned int *)&trap_emulate) = emulate_inst;
+       flush_dcache_range((unsigned long)(&trap_emulate),
+                          (unsigned long)(&trap_emulate) + 4);
+
+       result = ubicom32_emulate_insn(source1, source2, source3,
+                                      save_acc, &save_csr);
+
+       /*
+        * set the result value
+        */
+       if (dest_operand) {
+               /*
+                * copy result to memory
+                */
+               if (four_byte) {
+                       *dest_address++ =
+                               (unsigned char)((result >> 24) & 0xff);
+                       *dest_address++ =
+                               (unsigned char)((result >> 16) & 0xff);
+               }
+               *dest_address++ = (unsigned char)((result >> 8) & 0xff);
+               *dest_address = (unsigned char)(result & 0xff);
+       } else if (likely(op != CMPI)) {
+               /*
+                * copy result to a register, using move.4 dest, result
+                */
+               extern unsigned int unaligned_trap_set_result;
+               *((unsigned int *)&unaligned_trap_set_result) &= ~0x7ff0000;
+
+               if (op == 2 || op == 6) {
+                       *((unsigned int *)&unaligned_trap_set_result) |=
+                               ((inst & 0x000f0000) | 0x01000000);
+               } else {
+                       *((unsigned int *)&unaligned_trap_set_result) |=
+                               (inst & 0x7ff0000);
+               }
+               flush_dcache_range((unsigned long)&unaligned_trap_set_result,
+                                  ((unsigned long)(&unaligned_trap_set_result) + 4));
+
+               asm volatile (
+                       /* result uses thread's registers */
+               "       move.4          CSR, %1                 \n\t"
+               "       setcsr_flush 0                          \n\t"
+               "unaligned_trap_set_result:                     \n\t"
+               "       move.4 #0, %0                           \n\t"
+               "       setcsr          #0                      \n\t"
+               "       setcsr_flush    0                       \n\t"
+                       :
+                       : "d"(result), "d" ((1 << 14) | (thread << 15))
+                       : "cc"
+               );
+       }
+
+       /*
+        * bump PC in thread and restore implicit register changes
+        */
+       asm volatile (
+       "       move.4          CSR, %0                 \n\t"
+       "       setcsr_flush    0                       \n\t"
+       "       move.4          pc, %1                  \n\t"
+       "       move.4          acc0_lo, (%3)           \n\t"
+       "       move.4          acc0_hi, 4(%3)          \n\t"
+       "       move.4          acc1_lo, 8(%3)          \n\t"
+       "       move.4          acc1_hi, 12(%3)         \n\t"
+       "       move.4          mac_rc16, 16(%3)        \n\t"
+       "       move.4          CSR, %2                 \n\t"
+       "       setcsr          #0                      \n\t"
+       "       setcsr_flush    0                       \n\t"
+               :
+               : "d"((1 << 14) | (thread << 15)),
+                 "d"(pc + 4), "d"(save_csr), "a"(save_acc)
+               : "cc"
+       );
+}
+
+/*
+ * unaligned_only()
+ *     Return true if either of the unaligned causes are set (and no others).
+ */
+int unaligned_only(unsigned int cause)
+{
+       unsigned int unaligned_cause_mask =
+               (1 << TRAP_CAUSE_DST_MISALIGNED) |
+               (1 << TRAP_CAUSE_SRC1_MISALIGNED);
+
+       BUG_ON(cause == 0);
+       return (cause & unaligned_cause_mask) == cause;
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/vmlinux.lds.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/vmlinux.lds.S
new file mode 100644 (file)
index 0000000..cd64677
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * arch/ubicom32/kernel/vmlinux.lds.S
+ *     vmlinux primary linker script
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/ocm_size.h>
+#include <asm/memory_map.h>
+#include <asm/thread_info.h>
+#include <linux/threads.h>
+
+/*
+ * Sanity checks to prevent errors later on that are much harder to understand
+ */
+#if !defined APP_OCM_CODE_SIZE
+#error APP_OCM_CODE_SIZE has not been defined in ocm_size.h
+#endif
+
+#if !defined APP_OCM_DATA_SIZE
+#error APP_OCM_DATA_SIZE has not been defined in ocm_size.h
+#endif
+
+/*
+ * The `free' ocm area that ultra does not use.
+ */
+#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE
+#define OCM_FREE_START (OCMSTART + APP_OCM_CODE_SIZE)
+#define OCM_FREE_LENGTH        (OCMSIZE - APP_OCM_CODE_SIZE - APP_OCM_DATA_SIZE)
+#else
+#define OCM_FREE_START OCMEND
+#define OCM_FREE_LENGTH 0
+#endif
+
+/*
+ * If you want to limit OCM use for text/data or completely disable it
+ * you can change these values.
+ */
+#define OCM_TEXT_LENGTH        OCM_FREE_LENGTH
+#define OCM_DATA_LENGTH        OCM_FREE_LENGTH
+
+#define        RAM_START       KERNELSTART
+#define        RAM_LENGTH      ((SDRAMSTART + CONFIG_MIN_RAMSIZE) - RAM_START)
+#define        TEXT            ram
+#define        DATA            ram
+#define        INIT            ram
+#define        BSS             ram
+
+#ifndef DATA_ADDR
+#define        DATA_ADDR
+#endif
+
+#include <asm-generic/vmlinux.lds.h>
+
+OUTPUT_ARCH(ubicom32)
+ENTRY(_start)
+
+MEMORY {
+       ram             : ORIGIN = RAM_START, LENGTH = RAM_LENGTH
+       syscall         : ORIGIN = OS_SYSCALL_BEGIN, LENGTH = (OS_SYSCALL_END - OS_SYSCALL_BEGIN)
+       ocm             : ORIGIN = OCM_FREE_START, LENGTH = OCM_FREE_LENGTH
+}
+
+jiffies = jiffies_64 + 4;
+
+/*
+ * Fixed locations required by gdb coredumps.
+ *
+ * Note that the names are what gdb is expecting so renaming will break
+ * the toolchain.
+ */
+__ocm_begin            = OCMSTART;
+__ocm_limit            = __ocm_begin + OCMSIZE;
+__sdram_begin          = SDRAMSTART;
+__sdram_limit          = __sdram_begin + CONFIG_MIN_RAMSIZE;
+__filemedia_begin_addr = FLASHSTART;
+__filemedia_end_addr   = __filemedia_begin_addr + 0x00800000;
+
+/*
+ * For internal diagnostics
+ */
+__os_syscall_begin     = OS_SYSCALL_BEGIN;
+__os_syscall_end       = OS_SYSCALL_END;
+
+SECTIONS {
+
+       .fixed_text : {
+               _begin = .;
+               *(.skip_syscall)
+               *(.old_syscall_entry.text)
+               __fixed_text_end = .;
+       } > TEXT
+       . = _begin + SIZEOF(.fixed_text) ;
+
+       /*
+        * System call text in lower ocm (fixed location, can never change)
+        */
+       __syscall_text_load_begin = .;
+       __syscall_text_run_begin = OS_SYSCALL_BEGIN;
+
+       .syscall_text __syscall_text_run_begin : AT(__syscall_text_load_begin) {
+               *(.syscall_entry.text) /* Must be at OS_SYSCALL_BEGIN 0x3ffc0040 */
+               *(.kernel_unprotected)
+               . = ALIGN(4);
+               __syscall_text_run_end = .;
+       } > syscall /* .syscall_text */
+       . = __syscall_text_load_begin + __syscall_text_run_end - __syscall_text_run_begin ;
+       __ocm_text_load_begin = .;
+       __ocm_text_run_begin = OCM_FREE_START ;
+       .ocm_text __ocm_text_run_begin : AT(__ocm_text_load_begin) {
+#if OCM_TEXT_LENGTH
+               *(.ocm_text)
+               *(.sched.text)
+               *(.spinlock.text)
+#include <asm/ocm_text.lds.inc>
+               . = ALIGN(4);
+#endif
+               __ocm_text_run_end = .;
+               __data_begin = ALIGN(OCM_SECTOR_SIZE);
+       } > ocm /* .ocm_text */
+
+       .ocm_module_text __ocm_text_run_end (NOLOAD) : AT(__ocm_text_run_end) {
+               __ocm_inst_heap_begin = .;
+               /* Reserve the min requested */
+               . += (CONFIG_OCM_MODULES_RESERVATION) * 1024;
+#ifdef CONFIG_OCM_MODULES_MAY_CONSUME_REMAINING_CODESPACE
+               /* Round up to OCM sector size (we cannot use it for data) */
+               . = ALIGN(OCM_SECTOR_SIZE);
+#endif
+               __ocm_inst_heap_end = .;
+               /* update __data_begin */
+               __data_begin = ALIGN(OCM_SECTOR_SIZE);
+       } > ocm  /* .ocm_module_text */
+
+       . = __ocm_text_load_begin + __ocm_text_run_end - __ocm_text_run_begin ;
+       __ocm_text_load_end = .;
+
+       __ocm_data_load_begin = .;
+       __ocm_data_run_begin = __data_begin ;
+#if OCM_DATA_LENGTH
+       .ocm_data __ocm_data_run_begin : AT(__ocm_data_load_begin) {
+#if defined(CONFIG_IRQSTACKS_USEOCM)
+               percpu_irq_stacks = .;
+               . += NR_CPUS * THREAD_SIZE;
+#endif
+               *(.ocm_data)
+               . = ALIGN(4) ;
+               __ocm_data_run_end = .;
+       } > ocm
+       . = __ocm_data_load_begin + __ocm_data_run_end - __ocm_data_run_begin ;
+#else
+       __ocm_data_run_end = __ocm_data_run_begin;
+#endif
+       __ocm_data_load_end = .;
+
+       __ocm_free_begin = __ocm_data_run_end;
+       __ocm_free_end = OCM_FREE_START + OCM_FREE_LENGTH;
+
+       .text __ocm_data_load_end : AT(__ocm_data_load_end) {
+               . = ALIGN(4);
+               _stext = .;
+               _text = .;
+               TEXT_TEXT
+               SCHED_TEXT
+               LOCK_TEXT
+               *(.text.lock)
+               *(.text.__libgcc_udivmodsi)
+               *(.text.__libgcc_divmodsi)
+               *(.text.__libgcc_muldi3)
+               *(.text.__libgcc_udivmoddi)
+               *(.text.__libgcc_divmoddi)
+               *(.text.*)
+#if OCM_TEXT_LENGTH == 0
+               *(.ocm_text)
+               *(.sched.text)
+               *(.spinlock.text)
+#endif
+               . = ALIGN(16);          /* Exception table              */
+               __start___ex_table = .;
+               *(__ex_table)
+               __stop___ex_table = .;
+
+               *(.rodata) *(.rodata.*)
+               *(__vermagic)           /* Kernel version magic */
+               *(__markers_strings)
+               *(.rodata1)
+               *(.rodata.str1.1)
+               *(__tracepoints_strings)
+
+                /* PCI quirks */
+               __start_pci_fixups_early = . ;
+                       *(.pci_fixup_early)
+               __end_pci_fixups_early = . ;
+               __start_pci_fixups_header = . ;
+                       *(.pci_fixup_header)
+               __end_pci_fixups_header = . ;
+               __start_pci_fixups_final = . ;
+                       *(.pci_fixup_final)
+               __end_pci_fixups_final = . ;
+               __start_pci_fixups_enable = . ;
+                       *(.pci_fixup_enable)
+               __end_pci_fixups_enable = . ;
+               __start_pci_fixups_resume = . ;
+                      *(.pci_fixup_resume)
+               __end_pci_fixups_resume = . ;
+               __start_pci_fixups_resume_early = . ;
+                      *(.pci_fixup_resume_early)
+               __end_pci_fixups_resume_early = . ;
+               __start_pci_fixups_suspend  = . ;
+                      *(.pci_fixup_suspend)
+               __end_pci_fixups_suspend = . ;
+
+               __start_builtin_fw = . ;
+                       *(.builtin_fw)
+               __end_builtin_fw = . ;
+
+
+               /* Kernel symbol table: Normal symbols */
+               . = ALIGN(4);
+               __start___ksymtab = .;
+               *(__ksymtab)
+               __stop___ksymtab = .;
+
+               /* Kernel symbol table: GPL-only symbols */
+               __start___ksymtab_gpl = .;
+               *(__ksymtab_gpl)
+               __stop___ksymtab_gpl = .;
+
+               /* Kernel symbol table: Normal unused symbols */
+               __start___ksymtab_unused = .;
+               *(__ksymtab_unused)
+               __stop___ksymtab_unused = .;
+
+               /* Kernel symbol table: GPL-only unused symbols */
+               __start___ksymtab_unused_gpl = .;
+               *(__ksymtab_unused_gpl)
+               __stop___ksymtab_unused_gpl = .;
+
+               /* Kernel symbol table: GPL-future symbols */
+               __start___ksymtab_gpl_future = .;
+               *(__ksymtab_gpl_future)
+               __stop___ksymtab_gpl_future = .;
+
+               /* Kernel symbol table: Normal symbols */
+               __start___kcrctab = .;
+               *(__kcrctab)
+               __stop___kcrctab = .;
+
+               /* Kernel symbol table: GPL-only symbols */
+               __start___kcrctab_gpl = .;
+               *(__kcrctab_gpl)
+               __stop___kcrctab_gpl = .;
+
+               /* Kernel symbol table: GPL-future symbols */
+               __start___kcrctab_gpl_future = .;
+               *(__kcrctab_gpl_future)
+               __stop___kcrctab_gpl_future = .;
+
+               /* Kernel symbol table: strings */
+               *(__ksymtab_strings)
+
+               /* Built-in module parameters */
+               . = ALIGN(4) ;
+               __start___param = .;
+               *(__param)
+               __stop___param = .;
+
+               . = ALIGN(4) ;
+               _etext = . ;
+       } > TEXT
+
+       .data DATA_ADDR : {
+               . = ALIGN(4);
+               _sdata = . ;
+               DATA_DATA
+#if OCM_DATA_LENGTH == 0
+               *(.ocm_data)
+#endif
+               . = ALIGN(8192) ;
+               _data_protection_end = .;
+               *(.data.init_task)
+               . = ALIGN(4);
+               _edata = . ;
+       } > DATA
+
+       .init : {
+               . = ALIGN(4096);
+               __init_begin = .;
+               _sinittext = .;
+               INIT_TEXT
+               _einittext = .;
+               *(.init.rodata)
+               INIT_DATA
+               . = ALIGN(16);
+               __setup_start = .;
+               *(.init.setup)
+               __setup_end = .;
+               __initcall_start = .;
+               INITCALLS
+               __initcall_end = .;
+               __con_initcall_start = .;
+               *(.con_initcall.init)
+               __con_initcall_end = .;
+               ___security_initcall_start = .;
+               *(.security_initcall.init)
+               ___security_initcall_end = .;
+#ifdef CONFIG_BLK_DEV_INITRD
+               . = ALIGN(4);
+               __initramfs_start = .;
+               *(.init.ramfs)
+               __initramfs_end = .;
+#endif
+               . = ALIGN(4096);
+               __per_cpu_start = .;
+                       *(.data.percpu)
+                       *(.data.percpu.shared_aligned)
+               __per_cpu_end = .;
+
+               . = ALIGN(4096);
+               __init_end = .;
+       } > INIT
+
+         .eh_frame   :
+         {
+           PROVIDE (___eh_frame_begin = .);
+           *(.eh_frame)
+           LONG (0);
+           PROVIDE (___eh_frame_end = .);
+         } > INIT
+
+       /DISCARD/ : {
+               EXIT_TEXT
+               EXIT_DATA
+               *(.exitcall.exit)
+       }
+
+       .bss : {
+               . = ALIGN(4);
+               _sbss = . ;
+               *(.bss)
+               *(COMMON)
+               . = ALIGN(4) ;
+               _ebss = . ;
+               _end = . ;
+       } > BSS
+
+       NOTES > BSS
+
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/lib/Makefile b/target/linux/ubicom32/files/arch/ubicom32/lib/Makefile
new file mode 100644 (file)
index 0000000..e7f41cc
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# arch/ubicom32/lib/Makefile
+#      <TODO: Replace with short file description>
+#
+# (C) Copyright 2009, Ubicom, Inc.
+#
+# This file is part of the Ubicom32 Linux Kernel Port.
+#
+# The Ubicom32 Linux Kernel Port 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.
+#
+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+# see <http://www.gnu.org/licenses/>.
+#
+# Ubicom32 implementation derived from (with many thanks):
+#   arch/m68knommu
+#   arch/blackfin
+#   arch/parisc
+#
+#
+# Makefile for m68knommu specific library files..
+#
+
+lib-y  := checksum.o delay.o mem_ubicom32.o
diff --git a/target/linux/ubicom32/files/arch/ubicom32/lib/checksum.c b/target/linux/ubicom32/files/arch/ubicom32/lib/checksum.c
new file mode 100644 (file)
index 0000000..c93920f
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * arch/ubicom32/lib/checksum.c
+ *   Optimized checksum utilities for IP.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+/*
+ * 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.
+ *
+ *             IP/TCP/UDP checksumming routines
+ *
+ * Authors:    Jorge Cwik, <jorge@laser.satlink.net>
+ *             Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ *             Tom May, <ftom@netcom.com>
+ *             Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
+ *             Lots of code moved from tcp.c and ip.c; see those files
+ *             for more names.
+ *
+ * 03/02/96    Jes Sorensen, Andreas Schwab, Roman Hodek:
+ *             Fixed some nasty bugs, causing some horrible crashes.
+ *             A: At some points, the sum (%0) was used as
+ *             length-counter instead of the length counter
+ *             (%1). Thanks to Roman Hodek for pointing this out.
+ *             B: GCC seems to mess up if one uses too many
+ *             data-registers to hold input values and one tries to
+ *             specify d0 and d1 as scratch registers. Letting gcc choose these
+ *             registers itself solves the problem.
+ *
+ *             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.
+ */
+
+/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access kills, so most
+   of the assembly has to go. */
+
+#include <linux/module.h>
+#include <net/checksum.h>
+
+static unsigned long do_csum(const unsigned char * buff, int len)
+{
+       int count;
+       unsigned long result = 0;
+
+       /*
+        * The following optimized assembly code cannot handle data length less than 7 bytes!
+        */
+       if (likely(len >= 7)) {
+               len -= (4 - (int)buff) & 3;
+               count = len >> 2;
+               asm (
+               "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
+               "       and.4           d15, #(32-1), d15       \n\t"   // d15 = (-m) & (32 - 1)
+
+               "       bfextu          d14, %0, #2             \n\t"   // test 2 LSB of buff
+               "       jmpne.w.f       100f                    \n\t"
+               "       add.4           %1, #0, %1              \n\t"   // clear C
+               "       moveai          a3, #%%hi(1f)           \n\t"   // table jump
+               "       lea.1           a3, %%lo(1f)(a3)        \n\t"
+               "       lea.4           a3, (a3,d15)            \n\t"
+               "       calli           a3, 0(a3)               \n\t"
+
+               "100:   sub.4           %0, %0, d14             \n\t"
+               "       sub.4           d14, #4, d14            \n\t"
+               "       lsl.4           d14, d14, #3            \n\t"
+               "       add.4           %1, #0, %1              \n\t"   // clear C
+               "       moveai          a3, #%%hi(1f)           \n\t"   // table jump
+               "       lea.1           a3, %%lo(1f)(a3)        \n\t"
+               "       lea.4           a3, (a3,d15)            \n\t"
+               "       bfextu          %1, (%0)4++, d14        \n\t"   // read first partial word
+               "       calli           a3, 0(a3)               \n\t"
+#if 1
+               "200:   lsl.4           %3, %3, #3              \n\t"
+               "       bfrvrs          d15, (%0), #0           \n\t"   // read last word (partial)
+               "       bfextu          d15, d15, %3            \n\t"
+               "       bfrvrs          d15, d15, #0            \n\t"
+               "       add.4           %1, d15, %1             \n\t"
+               "       addc            %1, #0, %1              \n\t"   // sample C again
+               "       jmpt.w.t        2f                      \n\t"
+#else
+               "200:   move.1          d15, 0(%0)              \n\t"
+               "       lsl.4           d15, d15, #8            \n\t"
+               "       add.4           %1, d15, %1             \n\t"
+               "       addc            %1, #0, %1              \n\t"   // sample C again
+               "       add.4           %3, #-1, %3             \n\t"
+               "       jmpeq.w.t       2f                      \n\t"
+
+               "       move.1          d15, 1(%0)              \n\t"
+               "       add.4           %1, d15, %1             \n\t"
+               "       addc            %1, #0, %1              \n\t"   // sample C again
+               "       add.4           %3, #-1, %3             \n\t"
+               "       jmpeq.w.t       2f                      \n\t"
+
+               "       move.1          d15, 2(%0)              \n\t"
+               "       lsl.4           d15, d15, #8            \n\t"
+               "       add.4           %1, d15, %1             \n\t"
+               "       addc            %1, #0, %1              \n\t"   // sample C again
+               "       jmpt.w.t        2f                      \n\t"
+#endif
+#if defined(IP7000) || defined(IP7000_REV2)
+               "300:   swapb.2         %1, %1                  \n\t"
+#else
+               "300:   shmrg.2         %1, %1, %1              \n\t"
+               "       lsr.4           %1, %1, #8              \n\t"
+               "       bfextu          %1, %1, #16             \n\t"
+#endif
+               "       jmpt.w.t        3f                      \n\t"
+
+               "1:     add.4           %1, (%0)4++, %1         \n\t"   // first add without C
+               "       .rept           31                      \n\t"
+               "       addc            %1, (%0)4++, %1         \n\t"
+               "       .endr                                   \n\t"
+               "       addc            %1, #0, %1              \n\t"   // sample C again
+               "       add.4           %2, #-32, %2            \n\t"
+               "       jmpgt.w.t       1b                      \n\t"
+
+               "       and.4           %3, #3, %3              \n\t"   // check n
+               "       jmpne.w.f       200b                    \n\t"
+
+               "2:     .rept           2                       \n\t"
+               "       lsr.4           d15, %1, #16            \n\t"
+               "       bfextu          %1, %1, #16             \n\t"
+               "       add.4           %1, d15, %1             \n\t"
+               "       .endr                                   \n\t"
+               "       btst            d14, #3                 \n\t"   // start from odd address (<< 3)?
+               "       jmpne.w.f       300b                    \n\t"
+               "3:                                             \n\t"
+
+                       : "+a"(buff), "+d"(result), "+d"(count), "+d"(len)
+                       :
+                       : "d15", "d14", "a3", "cc"
+               );
+
+               return result;
+       }
+
+       /*
+        * handle a few bytes and fold result into 16-bit
+        */
+       while (len-- > 0) {
+               result += (*buff++ << 8);
+               if (len) {
+                       result += *buff++;
+                       len--;
+               }
+       }
+       asm (
+       "       .rept           2                       \n\t"
+       "       lsr.4           d15, %0, #16            \n\t"
+       "       bfextu          %0, %0, #16             \n\t"
+       "       add.4           %0, d15, %0             \n\t"
+       "       .endr                                   \n\t"
+               : "+d" (result)
+               :
+               : "d15", "cc"
+       );
+
+       return result;
+}
+
+/*
+ *     This is a version of ip_compute_csum() optimized for IP headers,
+ *     which always checksum on 4 octet boundaries.
+ */
+__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+{
+       return (__force __sum16)~do_csum(iph,ihl*4);
+}
+
+/*
+ * 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
+ */
+__wsum csum_partial(const void *buff, int len, __wsum sum)
+{
+       unsigned int result = do_csum(buff, len);
+
+       /* add in old sum, and carry.. */
+       result += (__force u32)sum;
+       if ((__force u32)sum > result)
+               result += 1;
+       return (__force __wsum)result;
+}
+
+EXPORT_SYMBOL(csum_partial);
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+__sum16 ip_compute_csum(const void *buff, int len)
+{
+       return (__force __sum16)~do_csum(buff,len);
+}
+
+/*
+ * copy from fs while checksumming, otherwise like csum_partial
+ */
+
+__wsum
+csum_partial_copy_from_user(const void __user *src, void *dst,
+                           int len, __wsum sum, int *csum_err)
+{
+       if (csum_err) *csum_err = 0;
+       memcpy(dst, (__force const void *)src, len);
+       return csum_partial(dst, len, sum);
+}
+
+/*
+ * copy from ds while checksumming, otherwise like csum_partial
+ */
+
+__wsum
+csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
+{
+       memcpy(dst, src, len);
+       return csum_partial(dst, len, sum);
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/lib/delay.c b/target/linux/ubicom32/files/arch/ubicom32/lib/delay.c
new file mode 100644 (file)
index 0000000..d19f97f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * arch/ubicom32/lib/delay.c
+ *   Ubicom32 implementation of udelay()
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/module.h>
+#include <asm/param.h>
+#include <asm/delay.h>
+#include <asm/ip5000.h>
+
+/*
+ * read_current_timer()
+ *     Return the current value of sysval.
+ */
+int __devinit read_current_timer(unsigned long *timer_val)
+{
+       *timer_val = (long)(UBICOM32_IO_TIMER->sysval);
+       return 0;
+}
+
+
+void udelay(unsigned long usecs)
+{
+       _udelay(usecs);
+}
+EXPORT_SYMBOL(udelay);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/lib/mem_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/lib/mem_ubicom32.c
new file mode 100644 (file)
index 0000000..d9c302e
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * arch/ubicom32/lib/mem_ubicom32.c
+ *   String functions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/compiler.h>
+
+#define LIKELY likely
+#define UNLIKELY unlikely
+
+typedef u32_t addr_t;
+
+/*
+ * memcpy()
+ */
+void *memcpy(void *dest, const void *src, size_t n)
+{
+       void *dest_ret = dest;
+
+       if (LIKELY((((addr_t)dest ^ (addr_t)src) & 3) == 0) && LIKELY(n > 6)) {
+               size_t m;
+               n -= (4 - (addr_t)dest) & 0x03;
+               m = n >> 2;
+               asm volatile (
+               "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
+               "       and.4           d15, #(32-1), d15       \n\t"   // d15 = (-m) & (32 - 1)
+               "       moveai          a3, #%%hi(1f)           \n\t"
+               "       lea.1           a3, %%lo(1f)(a3)        \n\t"
+               "       lea.4           a3, (a3,d15)            \n\t"
+
+               "       bfextu          d15, %0, #2             \n\t"   // d15 = (dest & 3)
+               "       jmpne.w.f       100f                    \n\t"
+               "       calli           a3, 0(a3)               \n\t"   // 4-byte alignment
+
+               "100:   cmpi            d15, #2                 \n\t"
+               "       jmpne.s.f       101f                    \n\t"
+               "       move.2          (%0)2++, (%1)2++        \n\t"
+               "       calli           a3, 0(a3)               \n\t"   // 2-byte alignment
+
+               "101:   move.1          (%0)1++, (%1)1++        \n\t"
+               "       jmpgt.s.f       102f                    \n\t"   // 3-byte alignment
+               "       move.2          (%0)2++, (%1)2++        \n\t"   // 1-byte alignment
+               "102:   calli           a3, 0(a3)               \n\t"
+
+               "200:   cmpi            %3, #2                  \n\t"
+               "       jmplt.s.f       201f                    \n\t"
+               "       move.2          (%0)2++, (%1)2++        \n\t"
+               "       jmpeq.s.t       2f                      \n\t"
+               "201:   move.1          (%0)1++, (%1)1++        \n\t"
+               "       jmpt.w.t        2f                      \n\t"
+
+               "1:     .rept           25                      \n\t"
+               "       movea           (%0)4++, (%1)4++        \n\t"
+               "       .endr                                   \n\t"
+               "       .rept           7                       \n\t"
+               "       move.4          (%0)4++, (%1)4++        \n\t"
+               "       .endr                                   \n\t"
+               "       add.4           %2, #-32, %2            \n\t"
+               "       jmpgt.w.f       1b                      \n\t"
+
+               "       and.4           %3, #3, %3              \n\t"   // check n
+               "       jmpne.w.f       200b                    \n\t"
+               "2:                                             \n\t"
+                       : "+a" (dest), "+a" (src), "+d" (m), "+d" (n)
+                       :
+                       : "d15", "a3", "memory", "cc"
+               );
+
+               return dest_ret;
+       }
+
+       if (LIKELY((((addr_t)dest ^ (addr_t)src) & 1) == 0) && LIKELY(n > 2)) {
+               size_t m;
+               n -= (addr_t)dest & 0x01;
+               m = n >> 1;
+               asm volatile (
+               "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
+               "       and.4           d15, #(32-1), d15       \n\t"   // d15 = (-m) & (32 - 1)
+               "       moveai          a3, #%%hi(1f)           \n\t"
+               "       lea.1           a3, %%lo(1f)(a3)        \n\t"
+               "       lea.4           a3, (a3,d15)            \n\t"
+
+               "       btst            %0, #0                  \n\t"   // check bit 0
+               "       jmpne.w.f       100f                    \n\t"
+               "       calli           a3, 0(a3)               \n\t"   // 4-byte alignment
+
+               "100:   move.1          (%0)1++, (%1)1++        \n\t"
+               "       calli           a3, 0(a3)               \n\t"
+
+               "200:   move.1          (%0)1++, (%1)1++        \n\t"
+               "       jmpt.w.t        2f                      \n\t"
+
+               "1:     .rept           32                      \n\t"
+               "       move.2          (%0)2++, (%1)2++        \n\t"
+               "       .endr                                   \n\t"
+               "       add.4           %2, #-32, %2            \n\t"
+               "       jmpgt.w.f       1b                      \n\t"
+
+               "       and.4           %3, #1, %3              \n\t"   // check n
+               "       jmpne.w.f       200b                    \n\t"
+               "2:                                             \n\t"
+
+                       : "+a" (dest), "+a" (src), "+d" (m), "+d" (n)
+                       :
+                       : "d15", "a3", "memory", "cc"
+               );
+
+               return dest_ret;
+       }
+
+       asm volatile (
+       "       sub.4           d15, #0, %2             \n\t"
+       "       jmpeq.w.f       2f                      \n\t"
+       "       and.4           d15, #(16-1), d15       \n\t"   // d15 = (-n) & (16 - 1)
+       "       moveai          a3, #%%hi(1f)           \n\t"
+       "       lea.1           a3, %%lo(1f)(a3)        \n\t"
+       "       lea.4           a3, (a3,d15)            \n\t"
+       "       calli           a3, 0(a3)               \n\t"
+
+       "1:     .rept           16                      \n\t"
+       "       move.1          (%0)1++, (%1)1++        \n\t"
+       "       .endr                                   \n\t"
+       "       add.4           %2, #-16, %2            \n\t"
+       "       jmpgt.w.f       1b                      \n\t"
+       "2:                                             \n\t"
+
+               : "+a" (dest), "+a" (src), "+d" (n)
+               :
+               : "d15", "a3", "memory", "cc"
+       );
+
+       return dest_ret;
+}
+
+/*
+ * memset()
+ */
+void *memset(void *s, int c, size_t n)
+{
+       void *s_ret = s;
+
+       if (LIKELY(n > 6)) {
+               size_t m;
+               n -= (4 - (addr_t)s) & 0x03;
+               m = n >> 2;
+               asm volatile (
+               "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
+               "       and.4           d15, #(32-1), d15       \n\t"   // d15 = (-m) & (32 - 1)
+               "       shmrg.1         %1, %1, %1              \n\t"
+               "       shmrg.2         %1, %1, %1              \n\t"   // %1 = (c<<24)|(c<<16)|(c<<8)|c
+               "       moveai          a3, #%%hi(1f)           \n\t"
+               "       lea.1           a3, %%lo(1f)(a3)        \n\t"
+               "       lea.4           a3, (a3,d15)            \n\t"
+
+               "       bfextu          d15, %0, #2             \n\t"   // d15 = (s & 3)
+               "       jmpne.w.f       100f                    \n\t"
+               "       calli           a3, 0(a3)               \n\t"   // 4-byte alignment
+
+               "100:   cmpi            d15, #2                 \n\t"
+               "       jmpne.s.f       101f                    \n\t"
+               "       move.2          (%0)2++, %1             \n\t"
+               "       calli           a3, 0(a3)               \n\t"   // 2-byte alignment
+
+               "101:   move.1          (%0)1++, %1             \n\t"
+               "       jmpgt.s.f       102f                    \n\t"   // 3-byte alignment
+               "       move.2          (%0)2++, %1             \n\t"   // 1-byte alignment
+               "102:   calli           a3, 0(a3)               \n\t"
+
+               "200:   cmpi            %3, #2                  \n\t"
+               "       jmplt.s.f       201f                    \n\t"
+               "       move.2          (%0)2++, %1             \n\t"
+               "       jmpeq.s.t       2f                      \n\t"
+               "201:   move.1          (%0)1++, %1             \n\t"
+               "       jmpt.w.t        2f                      \n\t"
+
+               "1:     .rept           25                      \n\t"
+               "       movea           (%0)4++, %1             \n\t"
+               "       .endr                                   \n\t"
+               "       .rept           7                       \n\t"
+               "       move.4          (%0)4++, %1             \n\t"
+               "       .endr                                   \n\t"
+               "       add.4           %2, #-32, %2            \n\t"
+               "       jmpgt.w.f       1b                      \n\t"
+
+               "       and.4           %3, #3, %3              \n\t"   // test bit 1 of n
+               "       jmpne.w.f       200b                    \n\t"
+               "2:                                             \n\t"
+
+                       : "+a" (s), "+d" (c), "+d" (m), "+d" (n)
+                       :
+                       : "d15", "a3", "memory", "cc"
+               );
+
+               return s_ret;
+       }
+
+       asm volatile (
+       "       sub.4           d15, #0, %2             \n\t"
+       "       jmpeq.w.f       2f                      \n\t"
+       "       and.4           d15, #(8-1), d15        \n\t"   // d15 = (-%2) & (16 - 1)
+       "       moveai          a3, #%%hi(1f)           \n\t"
+       "       lea.1           a3, %%lo(1f)(a3)        \n\t"
+       "       lea.4           a3, (a3,d15)            \n\t"
+       "       calli           a3, 0(a3)               \n\t"
+
+       "1:     .rept           8                       \n\t"
+       "       move.1          (%0)1++, %1             \n\t"
+       "       .endr                                   \n\t"
+       "2:                                             \n\t"
+
+               : "+a" (s), "+d" (c), "+d" (n)
+               :
+               : "d15", "a3", "memory", "cc"
+       );
+
+       return s_ret;
+}
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+       char *tmp;
+       const char *s;
+
+       if (n == 0)
+               return dest;
+
+       tmp = dest;
+       s = src;
+
+       /*
+        * Will perform 16-bit move if possible
+        */
+       if (likely((((u32)dest | (u32)src | n) & 1) == 0)) {
+               if (dest <= src) {
+                       asm volatile (
+                       "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
+                       "       and.4           d15, #(32-2), d15       \n\t"   // d15 = (- count) & (32 - 2)
+                       "       moveai          a3, #%%hi(1f)           \n\t"
+                       "       lea.1           a3, %%lo(1f)(a3)        \n\t"
+                       "       lea.2           a3, (a3,d15)            \n\t"
+                       "       calli           a3, 0(a3)               \n\t"
+
+                       "1:     .rept           16                      \n\t"
+                       "       move.2          (%0)2++, (%1)2++        \n\t"
+                       "       .endr                                   \n\t"
+                       "       add.4           %2, #-32, %2            \n\t"
+                       "       jmpgt.w.f       1b                      \n\t"
+
+                       : "+a" (tmp), "+a" (s), "+d" (n)
+                       :
+                       : "d15", "a3", "memory", "cc"
+                       );
+               } else {
+                       tmp += n;
+                       s += n;
+                       asm volatile (
+                       "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
+                       "       and.4           d15, #(32-2), d15       \n\t"   // d15 = (- count) & (32 - 2)
+                       "       moveai          a3, #%%hi(1f)           \n\t"
+                       "       lea.1           a3, %%lo(1f)(a3)        \n\t"
+                       "       lea.2           a3, (a3,d15)            \n\t"
+                       "       calli           a3, 0(a3)               \n\t"
+
+                       "1:     .rept           16                      \n\t"
+                       "       move.2          -2(%0)++, -2(%1)++      \n\t"
+                       "       .endr                                   \n\t"
+                       "       add.4           %2, #-32, %2            \n\t"
+                       "       jmpgt.w.f       1b                      \n\t"
+
+                       : "+a" (tmp), "+a" (s), "+d" (n)
+                       :
+                       : "d15", "a3", "memory", "cc"
+                       );
+               }
+               return dest;
+       }
+
+       if (dest <= src) {
+               asm volatile (
+               "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
+               "       and.4           d15, #(16-1), d15       \n\t"   // d15 = (- count) & (16 - 1)
+               "       moveai          a3, #%%hi(1f)           \n\t"
+               "       lea.1           a3, %%lo(1f)(a3)        \n\t"
+               "       lea.4           a3, (a3,d15)            \n\t"
+               "       calli           a3, 0(a3)               \n\t"
+
+               "1:     .rept           16                      \n\t"
+               "       move.1          (%0)1++, (%1)1++        \n\t"
+               "       .endr                                   \n\t"
+               "       add.4           %2, #-16, %2            \n\t"
+               "       jmpgt.w.f       1b                      \n\t"
+               : "+a" (tmp), "+a" (s), "+d" (n)
+               :
+               : "d15", "a3", "memory", "cc"
+               );
+       } else {
+               tmp += n;
+               s += n;
+               asm volatile (
+               "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
+               "       and.4           d15, #(16-1), d15       \n\t"   // d15 = (- count) & (16 - 1)
+               "       moveai          a3, #%%hi(1f)           \n\t"
+               "       lea.1           a3, %%lo(1f)(a3)        \n\t"
+               "       lea.4           a3, (a3,d15)            \n\t"
+               "       calli           a3, 0(a3)               \n\t"
+
+               "1:     .rept           16                      \n\t"
+               "       move.1          -1(%0)++, -1(%1)++      \n\t"
+               "       .endr                                   \n\t"
+               "       add.4           %2, #-16, %2            \n\t"
+               "       jmpgt.w.f       1b                      \n\t"
+               : "+a" (tmp), "+a" (s), "+d" (n)
+               :
+               : "d15", "a3", "memory", "cc"
+               );
+       }
+       return dest;
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/Kconfig.switch b/target/linux/ubicom32/files/arch/ubicom32/mach-common/Kconfig.switch
new file mode 100644 (file)
index 0000000..0303e16
--- /dev/null
@@ -0,0 +1,12 @@
+menuconfig UBICOM_SWITCH
+       tristate "Switch devices"
+       help
+               This option provides Ethernet switch management options via proc fs
+
+if UBICOM_SWITCH
+config UBICOM_SWITCH_BCM539X
+       tristate "Broadcom BCM539X series (SPI)"
+       depends on SPI_MASTER
+       help
+               Supports Broadcom BCM539X Gigabit Ethernet Switches over SPI
+endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/Makefile b/target/linux/ubicom32/files/arch/ubicom32/mach-common/Makefile
new file mode 100644 (file)
index 0000000..8c645af
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# arch/ubicom32/mach-common/Makefile
+#      Makefile for Ubicom32 generic drivers/code.
+#
+# (C) Copyright 2009, Ubicom, Inc.
+#
+# This file is part of the Ubicom32 Linux Kernel Port.
+#
+# The Ubicom32 Linux Kernel Port 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.
+#
+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+# see <http://www.gnu.org/licenses/>.
+#
+# Ubicom32 implementation derived from (with many thanks):
+#   arch/m68knommu
+#   arch/blackfin
+#   arch/parisc
+#
+
+obj-y += cachectl.o common.o usb_tio.o usb.o ubi32-gpio.o board.o bootargs.o profile.o
+obj-$(CONFIG_PCI) += pci.o io.o
+
+obj-$(CONFIG_FB_UBICOM32) += vdc_tio.o
+obj-$(CONFIG_UBICOM_HID) += ubicom32hid.o
+obj-$(CONFIG_UBICOM_INPUT) += ubicom32input.o
+obj-$(CONFIG_UBICOM_INPUT_I2C) += ubicom32input_i2c.o
+obj-$(CONFIG_UBICOM_SWITCH) += switch-core.o
+obj-$(CONFIG_UBICOM_SWITCH_BCM539X) += switch-bcm539x.o
+obj-$(CONFIG_UIO_UBICOM32RING) += ring_tio.o
+obj-$(CONFIG_SND_UBI32) += audio.o
+obj-$(CONFIG_UBICOM32_PLIO) += plio.o
+
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/audio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/audio.c
new file mode 100644 (file)
index 0000000..37db890
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * arch/ubicom32/mach-common/audio.c
+ *   Generic initialization for Ubicom32 Audio
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include <asm/devtree.h>
+#include <asm/audio.h>
+#include <asm/ubi32-pcm.h>
+
+/*
+ * The number of audio devices currently allocated, used for .id
+ */
+static int __initdata audio_device_count;
+
+/*
+ * The maximum number of resources (cards) that the audio will have.
+ * Currently 3, a register space, and up to 2 interrupts.
+ */
+#define AUDIO_MAX_RESOURCES    3
+
+/*
+ * audio_device_alloc
+ *     Checks the device tree and allocates a platform_device if found
+ */
+struct platform_device * __init audio_device_alloc(const char *driver_name,
+               const char *node_name, const char *inst_name, int priv_bytes)
+{
+       struct platform_device *pdev;
+       struct resource *res;
+       struct audio_node *audio_node;
+       struct ubi32pcm_platform_data *pdata;
+       struct audio_dev_regs *adr;
+       int idx;
+
+       /*
+        * Check the device tree for the audio node
+        */
+       audio_node = (struct audio_node *)devtree_find_node(node_name);
+       if (!audio_node) {
+               printk(KERN_WARNING "audio device '%s' not found\n", node_name);
+               return NULL;
+       }
+
+       if (audio_node->version != AUDIONODE_VERSION) {
+               printk(KERN_WARNING "audio node not compatible\n");
+               return NULL;
+       }
+
+       /*
+        * Find the instance in this node
+        */
+       adr = audio_node->regs->adr;
+       for (idx = 0; idx < audio_node->regs->max_devs; idx++) {
+               if ((adr->version == AUDIO_DEV_REGS_VERSION) &&
+                  (strcmp(adr->name, inst_name) == 0)) {
+                       break;
+               }
+               adr++;
+       }
+       if (idx == audio_node->regs->max_devs) {
+               printk(KERN_WARNING "audio inst '%s' not found in device '%s'\n", inst_name, node_name);
+               return NULL;
+       }
+
+       /*
+        * Dynamically create the platform_device structure and resources
+        */
+       pdev = kzalloc(sizeof(struct platform_device) +
+                      sizeof(struct ubi32pcm_platform_data) +
+                      priv_bytes , GFP_KERNEL);
+       if (!pdev) {
+               printk(KERN_WARNING "audio could not alloc pdev\n");
+               return NULL;
+       }
+
+       res = kzalloc(sizeof(struct resource) * AUDIO_MAX_RESOURCES,
+                       GFP_KERNEL);
+       if (!res) {
+               kfree(pdev);
+               printk(KERN_WARNING "audio could not alloc res\n");
+               return NULL;
+       }
+
+       pdev->name = driver_name;
+       pdev->id = audio_device_count++;
+       pdev->resource = res;
+
+       /*
+        * Fill in the resources and platform data from devtree information
+        */
+       res[0].start = (u32_t)(audio_node->regs);
+       res[0].end = (u32_t)(audio_node->regs);
+       res[0].flags = IORESOURCE_MEM;
+       res[1 + AUDIO_TX_IRQ_RESOURCE].start = audio_node->dn.sendirq;
+       res[1 + AUDIO_TX_IRQ_RESOURCE].flags = IORESOURCE_IRQ;
+       res[1 + AUDIO_RX_IRQ_RESOURCE].start = audio_node->dn.recvirq;
+       res[1 + AUDIO_RX_IRQ_RESOURCE].flags = IORESOURCE_IRQ;
+       pdev->num_resources = 3;
+
+       printk(KERN_INFO "Audio.%d '%s':'%s' found irq=%d/%d.%d regs=%p pdev=%p/%p\n",
+               pdev->id, node_name, inst_name, audio_node->dn.sendirq,
+               audio_node->dn.recvirq, idx, audio_node->regs, pdev, res);
+       pdata = (struct ubi32pcm_platform_data *)(pdev + 1);
+       pdev->dev.platform_data = pdata;
+       pdata->node_name = node_name;
+       pdata->inst_name = inst_name;
+       pdata->inst_num = idx;
+       if (priv_bytes) {
+               pdata->priv_data = pdata + 1;
+       }
+
+       return pdev;
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/board.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/board.c
new file mode 100644 (file)
index 0000000..9634e34
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * arch/ubicom32/mach-common/board.c
+ *   Board init and support code.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/cpu.h>
+#include <asm/devtree.h>
+
+struct boardnode {
+       struct devtree_node dn;
+       const char *revision;
+};
+
+static const struct boardnode *bn;
+
+/*
+ * board_get_revision()
+ *     Returns revision string of the board.
+ */
+const char *board_get_revision(void)
+{
+       if (!bn) {
+               return "NULL";
+       }
+
+       return bn->revision;
+}
+
+/*
+ * board_init
+ */
+void __init board_init(void)
+{
+       bn = (struct boardnode *)devtree_find_node("board");
+       if (!bn) {
+               printk(KERN_WARNING "board node not found\n");
+               return;
+       }
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/bootargs.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/bootargs.c
new file mode 100644 (file)
index 0000000..2967150
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * arch/ubicom32/mach-common/bootargs.c
+ *   Board init and support code.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/cpu.h>
+#include <asm/devtree.h>
+
+struct bootargsnode {
+       struct devtree_node dn;
+       const char cmdline[512];
+};
+
+static const struct bootargsnode *ban;
+
+/*
+ * bootargs_get_cmdline()
+ *     Returns kernel boot arguments set by the bootloader.
+ */
+const char *bootargs_get_cmdline(void)
+{
+       if (!ban) {
+               return "";
+       }
+
+       return ban->cmdline;
+}
+
+/*
+ * bootargs_init
+ */
+void __init bootargs_init(void)
+{
+       ban = (struct bootargsnode *)devtree_find_node("bootargs");
+       if (!ban) {
+               printk(KERN_WARNING "bootargs node not found\n");
+               return;
+       }
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/cachectl.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/cachectl.c
new file mode 100644 (file)
index 0000000..afb9dc4
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * arch/ubicom32/mach-common/cachectl.c
+ *   Architecture cache control support
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <asm/cachectl.h>
+
+/*
+ * The write queue flush procedure in mem_cache_control needs to make
+ * DCACHE_WRITE_QUEUE_LENGTH writes to DDR (not OCM). Here we reserve some
+ * memory for this operation.
+ * Allocate array of cache lines of least DCACHE_WRITE_QUEUE_LENGTH + 1 words in
+ * length rounded up to the nearest cache line.
+ */
+#define CACHE_WRITE_QUEUE_FLUSH_AREA_SIZE \
+       ALIGN(sizeof(int) * (DCACHE_WRITE_QUEUE_LENGTH + 1), CACHE_LINE_SIZE)
+
+static char cache_write_queue_flush_area[CACHE_WRITE_QUEUE_FLUSH_AREA_SIZE]
+       __attribute__((aligned(CACHE_LINE_SIZE)));
+
+/*
+ * ONE_CCR_ADDR_OP is a helper macro that executes a single CCR operation.
+ */
+#define ONE_CCR_ADDR_OP(cc, op_addr, op)                               \
+       do {                                                            \
+               asm volatile (                                          \
+               "       btst    "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_VALID)"                         \n\t" \
+               "       jmpne.f .-4                                                             \n\t" \
+               "       move.4  "D(CCR_ADDR)"(%0), %1                                           \n\t" \
+               "       move.1  "D(CCR_CTRL+3)"(%0), %2                                         \n\t" \
+               "       bset    "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_VALID)"      \n\t" \
+               "       cycles  2                                                               \n\t" \
+               "       btst    "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_DONE)"                          \n\t" \
+               "       jmpeq.f .-4                                                             \n\t" \
+                       :                                               \
+                       : "a"(cc), "r"(op_addr), "r"(op & 0xff)         \
+                       : "cc"                                          \
+               );                                                      \
+       } while (0)
+
+/*
+ * mem_cache_control()
+ *     Special cache control operation
+ */
+void mem_cache_control(unsigned long cc, unsigned long begin_addr,
+                      unsigned long end_addr, unsigned long op)
+{
+       unsigned long op_addr;
+       int dccr = cc == DCCR_BASE;
+       if (dccr && op == CCR_CTRL_FLUSH_ADDR) {
+               /*
+                * We ensure all previous writes have left the data cache write
+                * queue by sending DCACHE_WRITE_QUEUE_LENGTH writes (to
+                * different words) down the queue.  If this is not done it's
+                * possible that the data we are trying to flush hasn't even
+                * entered the data cache.
+                * The +1 ensure that the final 'flush' is actually a flush.
+                */
+               int *flush_area = (int *)cache_write_queue_flush_area;
+               asm volatile(
+                       "       .rept "D(DCACHE_WRITE_QUEUE_LENGTH + 1)"        \n\t"
+                       "       move.4 (%0)4++, d0                              \n\t"
+                       "       .endr                                           \n\t"
+                       : "+a"(flush_area)
+                       );
+       }
+
+       if (dccr)
+               UBICOM32_LOCK(DCCR_LOCK_BIT);
+       else
+               UBICOM32_LOCK(ICCR_LOCK_BIT);
+
+       /*
+        * Calculate the cache lines we need to operate on that include
+        * begin_addr though end_addr.
+        */
+       begin_addr = begin_addr & ~(CACHE_LINE_SIZE - 1);
+       end_addr = (end_addr + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1);
+       op_addr = begin_addr;
+
+       do {
+               ONE_CCR_ADDR_OP(cc, op_addr, op);
+               op_addr += CACHE_LINE_SIZE;
+       } while (likely(op_addr < end_addr));
+
+       if (dccr && op == CCR_CTRL_FLUSH_ADDR) {
+               /*
+                * It turns out that when flushing the data cache the last flush
+                * isn't actually complete at this point. This is because there
+                * is another write buffer on the DDR side of the cache that is
+                * arbitrated with the I-Cache.
+                *
+                * The only foolproof method that ensures that the last data
+                * cache flush *actually* completed is to do another flush on a
+                * dirty cache line. This flush will block until the DDR write
+                * buffer is empty.
+                *
+                * Rather than creating a another dirty cache line, we use the
+                * flush_area above as we know that it is dirty from previous
+                * writes.
+                */
+               ONE_CCR_ADDR_OP(cc, cache_write_queue_flush_area, op);
+       }
+
+       if (dccr)
+               UBICOM32_UNLOCK(DCCR_LOCK_BIT);
+       else
+               UBICOM32_UNLOCK(ICCR_LOCK_BIT);
+
+}
+EXPORT_SYMBOL(mem_cache_control);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/common.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/common.c
new file mode 100644 (file)
index 0000000..2f183bd
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * arch/ubicom32/mach-common/common.c
+ *   Common platform support.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+
+/* Minimum CLK support */
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
+
+int clk_enable(struct clk *clk)
+{
+       return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/io.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/io.c
new file mode 100644 (file)
index 0000000..3c55ba7
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * arch/ubicom32/mach-common/io.c
+ *   PCI I/O memory read/write support functions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#ifdef CONFIG_PCI
+unsigned char  ioread8(void __iomem *addr)
+{
+       if (IS_PCI_ADDRESS(addr))
+               return ubi32_pci_read_u8(addr);
+       else
+               return (unsigned char)(*(volatile unsigned char *)addr);
+}
+EXPORT_SYMBOL(ioread8);
+
+unsigned short  ioread16(void __iomem *addr)
+{
+       if (IS_PCI_ADDRESS(addr))
+               return ubi32_pci_read_u16(addr);
+       else
+               return (unsigned short)(*(volatile unsigned short *)addr);
+}
+EXPORT_SYMBOL(ioread16);
+
+unsigned int  ioread32(void __iomem *addr)
+{
+       if (IS_PCI_ADDRESS(addr))
+               return ubi32_pci_read_u32(addr);
+       else
+               return (unsigned int)(*(volatile unsigned int *)addr);
+}
+EXPORT_SYMBOL(ioread32);
+
+void iowrite32(unsigned int val, void __iomem *addr)
+{
+       if (IS_PCI_ADDRESS(addr))
+               ubi32_pci_write_u32(val, addr);
+       else
+               *(volatile unsigned int *)addr = val;
+}
+EXPORT_SYMBOL(iowrite32);
+
+void iowrite16(unsigned short val, void __iomem *addr)
+{
+       if (IS_PCI_ADDRESS(addr))
+               ubi32_pci_write_u16(val, addr);
+       else
+               *(volatile unsigned short *)addr = val;
+}
+EXPORT_SYMBOL(iowrite16);
+
+void iowrite8(unsigned char val, void __iomem *addr)
+{
+       if (IS_PCI_ADDRESS(addr))
+               ubi32_pci_write_u8(val, addr);
+       else
+               *(volatile unsigned char *)addr = val;
+}
+EXPORT_SYMBOL(iowrite8);
+
+void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned len)
+{
+       if (IS_PCI_ADDRESS(from)) {
+               if ((((u32_t)from & 0x3) == 0) && (((u32_t)to & 0x3) == 0)) {
+                       while ((int)len >= 4) {
+                               *(u32_t *)to = ubi32_pci_read_u32(from);
+                               to += 4;
+                               from += 4;
+                               len -= 4;
+                       }
+               } else if ((((u32_t)from & 0x1) == 0) &&
+                          (((u32_t)to & 0x1) == 0)) {
+                       while ((int)len >= 2) {
+                                *(u16_t *)to = ubi32_pci_read_u16(from);
+                                to += 2;
+                                from += 2;
+                                len -= 2;
+                       }
+               }
+
+               while (len) {
+                       *(u8_t *)to = ubi32_pci_read_u8(from);
+                       to++;
+                       from++;
+                       len--;
+               }
+       } else
+               memcpy(to, (void *)from, len);
+}
+EXPORT_SYMBOL(memcpy_fromio);
+
+void memcpy_toio(volatile void __iomem *to, const void *from, unsigned len)
+{
+       if (IS_PCI_ADDRESS(to)) {
+               if ((((u32_t)from & 0x3) == 0) && (((u32_t)to & 0x3) == 0)) {
+                       while ((int)len >= 4) {
+                               ubi32_pci_write_u32(*(u32_t *)from, to);
+                               to += 4;
+                               from += 4;
+                               len -= 4;
+                       }
+               } else if ((((u32_t)from & 0x1) == 0) &&
+                          (((u32_t)to & 0x1) == 0)) {
+                       while ((int)len >= 2) {
+                               ubi32_pci_write_u16(*(u16_t *)from, to);
+                               to += 2;
+                               from += 2;
+                               len -= 2;
+                       }
+               }
+
+               while (len) {
+                       ubi32_pci_write_u8(*(u8_t *)from, to);
+                       from++;
+                       to++;
+                       len--;
+               }
+       } else
+               memcpy((void *)to, from, len);
+
+}
+EXPORT_SYMBOL(memcpy_toio);
+
+void memset_io(volatile void __iomem *addr, int val, size_t len)
+{
+       if (IS_PCI_ADDRESS(addr)) {
+               while (len) {
+                       ubi32_pci_write_u8((unsigned char)val, addr);
+                       addr++;
+                       len--;
+               }
+       } else
+               memset((void *)addr, val, len);
+
+}
+EXPORT_SYMBOL(memset_io);
+
+void ioread8_rep(void __iomem *port, void *buf, unsigned long count)
+{
+       if (IS_PCI_ADDRESS(port)) {
+               while (count) {
+                       *(u8_t *)buf = ioread8(port);
+                       buf++;
+                       count--;
+               }
+       } else {
+               insb((unsigned int)port, buf, count);
+       }
+
+}
+EXPORT_SYMBOL(ioread8_rep);
+
+void ioread16_rep(void __iomem *port, void *buf, unsigned long count)
+{
+       if (IS_PCI_ADDRESS(port)) {
+               while (count) {
+                       *(u16_t *)buf = ioread16(port);
+                       buf += 2;
+                       count--;
+               }
+       } else {
+               insw((unsigned int)port, buf, count);
+       }
+}
+EXPORT_SYMBOL(ioread16_rep);
+
+void ioread32_rep(void __iomem *port, void *buf, unsigned long count)
+{
+        if (IS_PCI_ADDRESS(port)) {
+               while (count) {
+                       *(u32_t *)buf = ioread32(port);
+                       buf += 4;
+                       count--;
+               }
+       } else {
+               insl((unsigned int)port, buf, count);
+       }
+}
+EXPORT_SYMBOL(ioread32_rep);
+
+void  iowrite8_rep(void __iomem *port, const void *buf, unsigned long count)
+{
+         if (IS_PCI_ADDRESS(port)) {
+               while (count) {
+                       iowrite8(*(u8_t *)buf, port);
+                       buf++;
+                       count--;
+               }
+       } else {
+               outsb((unsigned int)port, buf, count);
+       }
+
+}
+EXPORT_SYMBOL(iowrite8_rep);
+
+void  iowrite16_rep(void __iomem *port, const void *buf, unsigned long count)
+{
+       if (IS_PCI_ADDRESS(port)) {
+               while (count) {
+                       iowrite16(*(u16_t *)buf, port);
+                       buf += 2;
+                       count--;
+               }
+       } else {
+               outsw((unsigned int)port, buf, count);
+       }
+}
+EXPORT_SYMBOL(iowrite16_rep);
+
+void  iowrite32_rep(void __iomem *port, const void *buf, unsigned long count)
+{
+       if (IS_PCI_ADDRESS(port)) {
+               while (count) {
+                       iowrite32(*(u32_t *)buf, port);
+                       buf += 4;
+                       count--;
+               }
+       } else {
+               outsl((unsigned int)port, buf, count);
+       }
+}
+EXPORT_SYMBOL(iowrite32_rep);
+
+#endif /* CONFIG_PCI */
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/pci.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/pci.c
new file mode 100644 (file)
index 0000000..a3a0712
--- /dev/null
@@ -0,0 +1,1157 @@
+/*
+ * arch/ubicom32/mach-common/pci.c
+ *     PCI interface management.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+
+#include <asm/devtree.h>
+#include <asm/ip5000.h>
+#include <asm/ubicom32-common.h>
+
+static int debug_pci = 1 ;
+
+/* #define PCI_USE_INTERNAL_LOCK 1 */
+
+#ifdef PCI_USE_INTERNAL_LOCK
+#define PCI_LOCK(lock, irqflag)        pci_lock_acquire(irqflag)
+#define PCI_UNLOCK(lock, irqflag) pci_lock_release(irqflag)
+#elif defined(CONFIG_SMP)
+static DEFINE_SPINLOCK(pci_master_lock);
+#define PCI_LOCK(lock, irqflag)        spin_lock_irqsave(lock, irqflag)
+#define PCI_UNLOCK(lock, irqflag) spin_unlock_irqrestore(lock, irqflag)
+#else
+#define PCI_LOCK(lock, irqflag)                local_irq_save(irqflag)
+#define PCI_UNLOCK(lock, irqflag)      local_irq_restore(irqflag)
+#endif
+
+#define PCI_DEV0_IDSEL CONFIG_PCI_DEV0_IDSEL
+#define PCI_DEV1_IDSEL CONFIG_PCI_DEV1_IDSEL
+
+/*
+ * PCI commands
+ */
+#define PCI_CMD_INT_ACK                0x00    /* not supported */
+#define PCI_CMD_SPECIAL                0x01    /* not supported */
+#define PCI_CMD_IO_READ                0x02
+#define PCI_CMD_IO_WRITE       0x03
+#define PCI_CMD_MEM_READ       0x06
+#define PCI_CMD_MEM_WRITE      0x07
+#define PCI_CMD_CFG_READ       0x0a
+#define PCI_CMD_CFG_WRITE      0x0b
+#define PCI_CMD_MEM_READ_MULT  0x0c    /* not supported */
+#define PCI_CMD_DUAL_ADDR      0x0d    /* not supported */
+#define PCI_CMD_MEM_READ_LINE  0x0e    /* not supported */
+#define PCI_CMD_MEM_WRITE_INVAL        0x0f    /* not supported */
+/*
+ * Status codes, returned by pci_read_u32() and pci_write_u32()
+ */
+#define PCI_RESP_IN_PROGRESS   0xff  /* request still in queue */
+#define PCI_RESP_OK            0
+/*
+ * The following codes indicate that the request has completed
+ */
+#define PCI_RESP_NO_DEVSEL             1  /* timeout before target asserted
+                                           * DEVSEL! */
+#define PCI_RESP_LOST_DEVSEL           2  /* had DEVSEL, but went away before
+                                           * transfer completed! */
+#define PCI_RESP_BAD_TRDY              3  /* target asserted TRDY without
+                                           * DEVSEL! */
+#define PCI_RESP_NO_TRDY               4  /* timeout before target asserted
+                                           * TRDY! */
+#define PCI_RESP_BAD_STOP              5  /* target asserted STOP and TRDY
+                                           * without DEVSEL! */
+#define PCI_RESP_TARGET_ABORT          6
+#define PCI_RESP_TARGET_RETRY          7
+#define        PCI_RESP_TARGET_DISCONNECT      8
+#define PCI_RESP_MISMATCH              9  /* data read back doesn't match data
+                                           * written - debug only, the core PCI
+                                           * routines never return this */
+#define PCI_RESP_DET_SERR              10
+#define PCI_RESP_DET_PERR              11
+#define PCI_RESP_MALFORMED_REQ         12 /* Could be due to misaligned
+                                           * requests or invalid address */
+#define PCI_RESP_NO_RESOURCE           13 /* Could be memory or other resourse
+                                           * like queue space */
+#define PCI_RESP_ERROR                 14 /* All emcompassing error */
+
+/* registers in PCI config space */
+#define PCI_DEVICE_VENDOR_ID_REG       0x00
+#define PCI_STATUS_COMMAND_REG         0x04
+#define PCI_CLASS_REVISION_REG         0x08
+#define PCI_BHLC_REG                   0x0c  /* BIST, Header type, Latency
+                                              * timer, Cache line size */
+#define PCI_BASE_ADDR_REG              0x10
+#define PCI_BASE_REG_COUNT             6
+#define CARDBUS_CIS_PTR_REG            0x28
+#define PCI_SUB_SYSTEM_ID_REG          0x2c
+#define PCI_EXP_ROM_ADDR_REG           0x30
+#define PCI_CAP_PTR_REG                        0x34
+#define PCI_LGPL_REG                   0x3C  /* max Latency, min Gnt, interrupt
+                                              * Pin, interrupt Line */
+
+struct pci_master_request {
+       volatile u32_t pci_address;     /* must be 4-byte aligned */
+       volatile u32_t data;            /* must be 4-byte aligned */
+       volatile u8_t cmd;
+       volatile u8_t byte_valid;
+       volatile u8_t status;
+};
+
+struct pci_devnode {
+       struct devtree_node dn;
+       u32_t pci_idsel_0;
+       u32_t pci_idsel_1;
+       u32_t pci_cpu_address;
+       struct pci_master_request volatile *volatile req;
+};
+
+static struct pci_master_request req;  /* globally used for faster master write
+                                        * (discarding result when possible) */
+static struct pci_devnode *pci_node;
+
+#if !defined(CONFIG_DEBUG_PCIMEASURE)
+#define PCI_DECLARE_MEASUREMENT
+#define PCI_MEASUREMENT_START()
+#define PCI_MEASUREMENT_END(idx)
+#else
+#define PCI_DECLARE_MEASUREMENT \
+       int __diff;             \
+       unsigned int __tstart;
+
+#define PCI_MEASUREMENT_START() \
+       __tstart = UBICOM32_IO_TIMER->sysval;
+
+#define PCI_MEASUREMENT_END(idx) \
+       __diff = (int)UBICOM32_IO_TIMER->sysval - (int)__tstart; \
+       pci_measurement_update((idx), __diff);
+
+#define PCI_WEIGHT 32
+
+struct pci_measurement {
+       volatile unsigned int min;
+       volatile unsigned int avg;
+       volatile unsigned int max;
+};
+
+enum pci_measurement_list {
+       PCI_MEASUREMENT_READ32,
+       PCI_MEASUREMENT_WRITE32,
+       PCI_MEASUREMENT_READ16,
+       PCI_MEASUREMENT_WRITE16,
+       PCI_MEASUREMENT_READ8,
+       PCI_MEASUREMENT_WRITE8,
+       PCI_MEASUREMENT_LAST,
+};
+
+static const char *pci_measurement_name_list[PCI_MEASUREMENT_LAST] = {
+       "READ32",
+       "WRITE32",
+       "READ16",
+       "WRITE16",
+       "READ8",
+       "WRITE8"
+};
+static struct pci_measurement pci_measurements[PCI_MEASUREMENT_LAST];
+
+/*
+ * pci_measurement_update()
+ *     Update an entry in the measurement array for this idx.
+ */
+static void pci_measurement_update(int idx, int sample)
+{
+       struct pci_measurement *pm = &pci_measurements[idx];
+       if ((pm->min == 0) || (pm->min > sample)) {
+               pm->min = sample;
+       }
+       if (pm->max < sample) {
+               pm->max = sample;
+       }
+       pm->avg = ((pm->avg * (PCI_WEIGHT - 1)) + sample) / PCI_WEIGHT;
+}
+#endif
+
+#if defined(PCI_USE_INTERNAL_LOCK)
+/*
+ * pci_lock_release()
+ *     Release the PCI lock.
+ */
+static void pci_lock_release(unsigned long irqflag)
+{
+       UBICOM32_UNLOCK(PCI_LOCK_BIT);
+}
+
+/*
+ * pci_lock_acquire()
+ *     Acquire the PCI lock, spin if not available.
+ */
+static void pci_lock_acquire(unsigned long irqflag)
+{
+       UBICOM32_LOCK(PCI_LOCK_BIT);
+}
+#endif
+
+/*
+ * pci_set_hrt_interrupt()
+ */
+static inline void pci_set_hrt_interrupt(struct pci_devnode *pci_node)
+{
+       ubicom32_set_interrupt(pci_node->dn.sendirq);
+}
+
+/*
+ * pci_read_u32()
+ *     Synchronously read 32 bits from PCI space.
+ */
+u8 pci_read_u32(u8 pci_cmd, u32 address, u32 *data)
+{
+       u8 status;
+       unsigned long irqflag;
+
+
+       /*
+        * Fill in the request.
+        */
+       volatile struct pci_master_request lreq;
+       PCI_DECLARE_MEASUREMENT;
+
+       lreq.pci_address = address;
+       lreq.cmd = pci_cmd;
+       lreq.byte_valid = 0xf;          /* enable all bytes */
+
+       /*
+        * Wait for any previous request to complete and then make this request.
+        */
+       PCI_MEASUREMENT_START();
+       PCI_LOCK(&pci_master_lock, irqflag);
+       while (unlikely(pci_node->req == &req))
+               ;
+       pci_node->req = &lreq;
+       pci_set_hrt_interrupt(pci_node);
+       PCI_UNLOCK(&pci_master_lock, irqflag);
+
+       /*
+        * Wait for the result to show up.
+        */
+       while (unlikely(pci_node->req == &lreq))
+               ;
+       status = lreq.status;
+       if (likely(status == PCI_RESP_OK))
+               *data = le32_to_cpu(lreq.data);
+       else
+               *data = 0;
+       PCI_MEASUREMENT_END(PCI_MEASUREMENT_READ32);
+       return status;
+}
+
+/*
+ * pci_write_u32()
+ *     Asyncrhnously or synchronously write 32 bits to PCI master space.
+ */
+u8 pci_write_u32(u8 pci_cmd, u32 address, u32 data)
+{
+       unsigned long irqflag;
+       PCI_DECLARE_MEASUREMENT;
+
+       /*
+        * Wait for any previous write or pending read to complete.
+        *
+        * We use a global data block because once we write the request
+        * we do not wait for it to complete before exiting.
+        */
+       PCI_MEASUREMENT_START();
+       PCI_LOCK(&pci_master_lock, irqflag);
+       while (unlikely(pci_node->req == &req))
+               ;
+       req.pci_address = address;
+       req.data = cpu_to_le32(data);
+       req.cmd = pci_cmd;
+       req.byte_valid = 0xf;           /* enable all bytes */
+       pci_node->req = &req;
+       pci_set_hrt_interrupt(pci_node);
+       PCI_UNLOCK(&pci_master_lock, irqflag);
+       PCI_MEASUREMENT_END(PCI_MEASUREMENT_WRITE32);
+       return PCI_RESP_OK;
+}
+
+/*
+ * pci_read_u16()
+ *     Synchronously read 16 bits from PCI space.
+ */
+u8 pci_read_u16(u8 pci_cmd, u32 address, u16 *data)
+{
+       u8 status;
+       unsigned long irqflag;
+
+       /*
+        * Fill in the request.
+        */
+       volatile struct pci_master_request lreq;
+       PCI_DECLARE_MEASUREMENT;
+
+       lreq.pci_address = address & ~2;
+       lreq.cmd = pci_cmd;
+       lreq.byte_valid = (address & 2) ? 0xc : 0x3;
+
+       /*
+        * Wait for any previous request to complete and then make this request.
+        */
+       PCI_MEASUREMENT_START();
+       PCI_LOCK(&pci_master_lock, irqflag);
+       while (unlikely(pci_node->req == &req))
+               ;
+       pci_node->req = &lreq;
+       pci_set_hrt_interrupt(pci_node);
+       PCI_UNLOCK(&pci_master_lock, irqflag);
+
+       /*
+        * Wait for the result to show up.
+        */
+       while (unlikely(pci_node->req == &lreq))
+               ;
+       status = lreq.status;
+       if (likely(status == PCI_RESP_OK)) {
+               lreq.data = le32_to_cpu(lreq.data);
+               *data = (u16)((address & 2) ? (lreq.data >> 16) : lreq.data);
+       } else
+               *data = 0;
+       PCI_MEASUREMENT_END(PCI_MEASUREMENT_READ16);
+       return status;
+}
+
+/*
+ * pci_write_u16()
+ *     Asyncrhnously or synchronously write 16 bits to PCI master space.
+ */
+u8 pci_write_u16(u8 pci_cmd, u32 address, u16 data)
+{
+       unsigned long irqflag;
+       PCI_DECLARE_MEASUREMENT;
+
+       /*
+        * Wait for any previous write or pending read to complete.
+        *
+        * We use a global data block because once we write the request
+        * we do not wait for it to complete before exiting.
+        */
+       PCI_MEASUREMENT_START();
+       PCI_LOCK(&pci_master_lock, irqflag);
+       while (unlikely(pci_node->req == &req))
+               ;
+       req.pci_address = address & ~2;
+       req.data = (u32)data;
+       req.data = cpu_to_le32((address & 2) ? (req.data << 16) : req.data);
+       req.cmd = pci_cmd;
+       req.byte_valid = (address & 2) ? 0xc : 0x3;
+       pci_node->req = &req;
+       pci_set_hrt_interrupt(pci_node);
+       PCI_UNLOCK(&pci_master_lock, irqflag);
+       PCI_MEASUREMENT_END(PCI_MEASUREMENT_WRITE16);
+       return PCI_RESP_OK;
+}
+
+/*
+ * pci_read_u8()
+ *     Synchronously read 8 bits from PCI space.
+ */
+u8 pci_read_u8(u8 pci_cmd, u32 address, u8 *data)
+{
+       u8 status;
+       unsigned long irqflag;
+
+       /*
+        * Fill in the request.
+        */
+       volatile struct pci_master_request lreq;
+       PCI_DECLARE_MEASUREMENT;
+
+       lreq.pci_address = address & ~3;
+       lreq.cmd = pci_cmd;
+       lreq.byte_valid = 1 << (address & 0x3);
+
+       /*
+        * Wait for any previous request to complete and then make this request.
+        */
+       PCI_MEASUREMENT_START();
+       PCI_LOCK(&pci_master_lock, irqflag);
+       while (unlikely(pci_node->req == &req))
+               ;
+       pci_node->req = &lreq;
+       pci_set_hrt_interrupt(pci_node);
+       PCI_UNLOCK(&pci_master_lock, irqflag);
+
+       /*
+        * Wait for the result to show up.
+        */
+       while (unlikely(pci_node->req == &lreq))
+               ;
+       status = lreq.status;
+       if (likely(status == PCI_RESP_OK)) {
+               *data = (u8)(lreq.data >> (24 - ((address & 0x3) << 3)));
+       } else
+               *data = 0;
+       PCI_MEASUREMENT_END(PCI_MEASUREMENT_READ8);
+       return status;
+}
+
+/*
+ * pci_write_u8()
+ *     Asyncrhnously or synchronously write 8 bits to PCI master space.
+ */
+u8 pci_write_u8(u8 pci_cmd, u32 address, u8 data)
+{
+       unsigned long irqflag;
+       PCI_DECLARE_MEASUREMENT;
+
+       /*
+        * Wait for any previous write or pending read to complete.
+        *
+        * We use a global data block because once we write the request
+        * we do not wait for it to complete before exiting.
+        */
+       PCI_MEASUREMENT_START();
+       PCI_LOCK(&pci_master_lock, irqflag);
+       while (unlikely(pci_node->req == &req))
+               ;
+       req.pci_address = address & ~3;
+       req.data = ((u32)data << (24 - ((address & 0x3) << 3)));
+       req.cmd = pci_cmd;
+       req.byte_valid = 1 << (address & 0x3);
+       pci_node->req = &req;
+       pci_set_hrt_interrupt(pci_node);
+       PCI_UNLOCK(&pci_master_lock, irqflag);
+       PCI_MEASUREMENT_END(PCI_MEASUREMENT_WRITE8);
+       return PCI_RESP_OK;
+}
+
+unsigned int ubi32_pci_read_u32(const volatile void __iomem *addr)
+{
+       unsigned int data;
+       pci_read_u32(PCI_CMD_MEM_READ, (u32)addr, &data);
+       return data;
+}
+EXPORT_SYMBOL(ubi32_pci_read_u32);
+
+unsigned short ubi32_pci_read_u16(const volatile void __iomem *addr)
+{
+       unsigned short data;
+       pci_read_u16(PCI_CMD_MEM_READ, (u32)addr, &data);
+       return data;
+}
+EXPORT_SYMBOL(ubi32_pci_read_u16);
+
+unsigned char  ubi32_pci_read_u8(const volatile void __iomem *addr)
+{
+       unsigned char  data;
+       pci_read_u8(PCI_CMD_MEM_READ, (u32)addr, &data);
+       return data;
+}
+EXPORT_SYMBOL(ubi32_pci_read_u8);
+
+void ubi32_pci_write_u32(unsigned int val, const volatile void __iomem *addr)
+{
+       pci_write_u32(PCI_CMD_MEM_WRITE, (u32)addr, val);
+}
+EXPORT_SYMBOL(ubi32_pci_write_u32);
+
+void ubi32_pci_write_u16(unsigned short val, const volatile void __iomem *addr)
+{
+       pci_write_u16(PCI_CMD_MEM_WRITE, (u32)addr, val);
+}
+EXPORT_SYMBOL(ubi32_pci_write_u16);
+
+void ubi32_pci_write_u8(unsigned char val, const void volatile __iomem *addr)
+{
+       pci_write_u8(PCI_CMD_MEM_WRITE, (u32)addr, val);
+}
+EXPORT_SYMBOL(ubi32_pci_write_u8);
+
+#if defined(CONFIG_DEBUG_PCIMEASURE)
+static unsigned int pci_cycles_to_nano(unsigned int cycles, unsigned int frequency)
+{
+       unsigned int nano = ((cycles * 1000) / (frequency / 1000000));
+       return nano;
+}
+
+/*
+ * pci_measurement_show()
+ *     Print out the min, avg, max values for each PCI transaction type.
+ *
+ * By request, the max value is reset after each dump.
+ */
+static int pci_measurement_show(struct seq_file *p, void *v)
+{
+       unsigned int min, avg, max;
+       unsigned int freq = processor_frequency();
+       int trans = *((loff_t *) v);
+
+       if (trans == 0) {
+               seq_puts(p, "min\tavg\tmax\t(nano-seconds)\n");
+       }
+
+       if (trans >= PCI_MEASUREMENT_LAST) {
+               return 0;
+       }
+
+       min = pci_cycles_to_nano(pci_measurements[trans].min, freq);
+       avg = pci_cycles_to_nano(pci_measurements[trans].avg, freq);
+       max = pci_cycles_to_nano(pci_measurements[trans].max, freq);
+       pci_measurements[trans].max = 0;
+       seq_printf(p, "%u\t%u\t%u\t%s\n", min, avg, max, pci_measurement_name_list[trans]);
+       return 0;
+}
+
+static void *pci_measurement_start(struct seq_file *f, loff_t *pos)
+{
+       return (*pos < PCI_MEASUREMENT_LAST) ? pos : NULL;
+}
+
+static void *pci_measurement_next(struct seq_file *f, void *v, loff_t *pos)
+{
+       (*pos)++;
+       if (*pos >= PCI_MEASUREMENT_LAST)
+               return NULL;
+       return pos;
+}
+
+static void pci_measurement_stop(struct seq_file *f, void *v)
+{
+       /* Nothing to do */
+}
+
+static const struct seq_operations pci_measurement_seq_ops = {
+       .start = pci_measurement_start,
+       .next  = pci_measurement_next,
+       .stop  = pci_measurement_stop,
+       .show  = pci_measurement_show,
+};
+
+static int pci_measurement_open(struct inode *inode, struct file *filp)
+{
+       return seq_open(filp, &pci_measurement_seq_ops);
+}
+
+static const struct file_operations pci_measurement_fops = {
+       .open           = pci_measurement_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+static int __init pci_measurement_init(void)
+{
+       proc_create("pci_measurements", 0, NULL, &pci_measurement_fops);
+       return 0;
+}
+module_init(pci_measurement_init);
+#endif
+
+static int ubi32_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+                                int where, int size, u32 *value)
+{
+       u8 cmd;
+       u32 addr;
+       u8  data8;
+       u16 data16;
+
+       u8 slot = PCI_SLOT(devfn);
+       u8 fn = PCI_FUNC(devfn);
+
+       if (slot > 1) {
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       } else if (slot == 0) {
+               addr = PCI_DEV0_IDSEL + where;
+       } else {
+               addr = PCI_DEV1_IDSEL + where;
+       }
+
+       addr += (fn << 8);
+
+       cmd = PCI_CMD_CFG_READ;
+       if (size == 1) {
+               pci_read_u8(cmd, addr, &data8);
+               *value = (u32)data8;
+       } else if (size == 2) {
+               pci_read_u16(cmd, addr, &data16);
+               *value = (u32)data16;
+       } else {
+               pci_read_u32(cmd, addr, value);
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int ubi32_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+                                 int where, int size, u32 value)
+{
+       u8 cmd;
+       u32 addr;
+       u8 slot = PCI_SLOT(devfn);
+       u8 fn = PCI_FUNC(devfn);
+
+       if (slot > 1) {
+               return PCIBIOS_DEVICE_NOT_FOUND;
+       } else if (slot == 0) {
+               addr = PCI_DEV0_IDSEL + where;
+       } else {
+               addr = PCI_DEV1_IDSEL + where;
+       }
+
+       addr += (fn << 8);
+
+       cmd = PCI_CMD_CFG_WRITE;
+       if (size == 1) {
+               pci_write_u8(cmd, addr, (u8)value);
+       } else if (size == 2) {
+               pci_write_u16(cmd, addr, (u16)value);
+       } else {
+               pci_write_u32(cmd, addr, value);
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size)
+{
+       return -EIO;
+}
+EXPORT_SYMBOL(pci_set_dma_max_seg_size);
+
+int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
+{
+       return -EIO;
+}
+EXPORT_SYMBOL(pci_set_dma_seg_boundary);
+
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+{
+       resource_size_t start = pci_resource_start(dev, bar);
+       resource_size_t len   = pci_resource_len(dev, bar);
+       unsigned long flags = pci_resource_flags(dev, bar);
+
+       if (!len || !start) {
+               return NULL;
+       }
+
+       if (maxlen && len > maxlen) {
+               len = maxlen;
+       }
+
+       if (flags & IORESOURCE_IO) {
+               return ioport_map(start, len);
+       }
+
+       if (flags & IORESOURCE_MEM) {
+               if (flags & IORESOURCE_CACHEABLE) {
+                       return ioremap(start, len);
+               }
+               return ioremap_nocache(start, len);
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(pci_iomap);
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+       if ((unsigned long)addr >= VMALLOC_START &&
+           (unsigned long)addr < VMALLOC_END) {
+               iounmap(addr);
+       }
+}
+EXPORT_SYMBOL(pci_iounmap);
+
+/*
+ *  From arch/arm/kernel/bios32.c
+ *
+ *  PCI bios-type initialisation for PCI machines
+ *
+ *  Bits taken from various places.
+ */
+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 = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL);
+               if (!sys)
+                       panic("PCI: unable to allocate sys data!");
+
+               sys->hw      = hw;
+               sys->busnr   = busnr;
+               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;
+               }
+       }
+}
+
+/*
+ * 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;
+}
+
+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;
+               /*
+                * 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 * __init pcibios_setup(char *str)
+{
+       if (!strcmp(str, "debug")) {
+               debug_pci = 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);
+}
+
+
+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)) ||
+               (dev->vendor == PCI_VENDOR_ID_ITE &&
+                dev->device == PCI_DEVICE_ID_ITE_8152);
+
+}
+
+/*
+ * 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 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) {
+               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
+
+/**
+ * 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;
+}
+
+
+struct pci_ops ubi32_pci_ops = {
+       .read   = ubi32_pci_read_config,
+       .write  = ubi32_pci_write_config,
+};
+
+static struct pci_bus *ubi32_pci_scan_bus(int nr, struct pci_sys_data *sys)
+{
+       return pci_scan_bus(sys->busnr, &ubi32_pci_ops, sys);
+}
+
+#define UBI32_PCI_MEM_BASE PCI_DEV_REG_BASE
+#define UBI32_PCI_MEM_LEN  0x80000000
+
+#define UBI32_PCI_IO_BASE 0x0
+#define UBI32_PCI_IO_END  0x0
+
+static struct resource ubi32_pci_mem = {
+       .name   = "PCI memory space",
+       .start  = UBI32_PCI_MEM_BASE,
+       .end    = UBI32_PCI_MEM_BASE + UBI32_PCI_MEM_LEN - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct resource ubi32_pci_io = {
+       .name   = "PCI IO space",
+       .start  = UBI32_PCI_IO_BASE,
+       .end    = UBI32_PCI_IO_END,
+       .flags  = IORESOURCE_IO,
+};
+
+static int __init ubi32_pci_setup(int nr, struct pci_sys_data *sys)
+{
+       if (nr > 0)
+               return 0;
+
+       request_resource(&iomem_resource, &ubi32_pci_mem);
+       request_resource(&ioport_resource, &ubi32_pci_io);
+
+       sys->resource[0] = &ubi32_pci_io;
+       sys->resource[1] = &ubi32_pci_mem;
+       sys->resource[2] = NULL;
+
+       return 1;
+}
+
+static void __init ubi32_pci_preinit(void)
+{
+}
+
+static int __init ubi32_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+       return pci_node->dn.recvirq;
+}
+
+struct hw_pci ubi32_pci __initdata = {
+       .nr_controllers = 1,
+       .preinit        = ubi32_pci_preinit,
+       .setup          = ubi32_pci_setup,
+       .scan           = ubi32_pci_scan_bus,
+       .map_irq        = ubi32_pci_map_irq,
+};
+
+static int __init ubi32_pci_init(void)
+{
+       pci_node = (struct pci_devnode *)devtree_find_node("pci");
+       if (pci_node == NULL) {
+               printk(KERN_WARNING "PCI init failed\n");
+               return -ENOSYS;
+       }
+       pci_common_init(&ubi32_pci);
+       return 0;
+}
+
+subsys_initcall(ubi32_pci_init);
+
+/*
+ * workaround for dual PCI card interrupt
+ */
+#define PCI_COMMON_INT_BIT (1 << 19)
+void ubi32_pci_int_wr(void)
+{
+       volatile unsigned int pci_int_line;
+       pci_int_line = UBICOM32_IO_PORT(RB)->gpio_in;
+       if (!(pci_int_line & PCI_COMMON_INT_BIT))
+       {
+               ubicom32_set_interrupt(pci_node->dn.recvirq);
+       }
+}
+EXPORT_SYMBOL(ubi32_pci_int_wr);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/plio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/plio.c
new file mode 100644 (file)
index 0000000..ac26a1e
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * plio.c
+ *     PLIO state machine support functions
+ *
+ * Copyright Â© 2009 Ubicom Inc. <www.ubicom.com>.  All rights reserved.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <asm/plio.h>
+
+/*
+ * plio_reset
+ *     Select and reset PLIO function
+ */
+static void plio_reset(const plio_fctl_t *plio_fctl) {
+       plio_io_function_t plio_function = {
+               .fn_sel         = PLIO_FN,
+               .fn_reset       = 1,
+       };
+
+       /*
+        * enable extension port
+        */
+       PEXT_NBR->function = plio_function;
+
+       /*
+        * program clock dividers
+        */
+       PLIO_NBR->fctl2 = plio_fctl->fctl2;
+
+       /*
+        * select plio function and assert function reset
+        */
+       plio_function.br_thread = thread_get_self();
+       plio_function.fn_reset = 1;
+       PLIO_NBR->function = plio_function;
+
+       /*
+        * program plio controls
+        */
+       PLIO_NBR->fctl0 = plio_fctl->fctl0;
+       PLIO_NBR->fctl1 = plio_fctl->fctl1;
+
+       /*
+        * deassert function reset
+        */
+       plio_function.fn_reset = 0;
+       PLIO_NBR->function = plio_function;
+}
+
+/*
+ * plio_init
+ *     configure and initialize PLIO.
+ */
+void plio_init(const plio_fctl_t *plio_fctl, const plio_config_t *plio_config, const plio_sram_t plio_sram_cfg[], int sram_cfg_size){
+       /*
+        * first reset to start plio clock
+        */
+       plio_reset(plio_fctl);
+
+       udelay(1);
+
+       /*
+        * configure pfsm
+        */
+       PLIO_NBR->fctl0.pfsm_prog = 1;
+       memcpy(PLIO_BR->pfsm_sram, plio_sram_cfg, sram_cfg_size);
+       PLIO_NBR->fctl0.pfsm_prog = 0;
+
+       /*
+        * program rest of plio
+        */
+       memcpy(&PLIO_BR->config, plio_config, sizeof(plio_config_t));
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/profile.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/profile.c
new file mode 100644 (file)
index 0000000..c95de6b
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ * arch/ubicom32/mach-common/profile.c
+ *   Implementation for Ubicom32 Profiler
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/platform_device.h>
+#include "profile.h"
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/fs.h>
+#include <linux/page-flags.h>
+#include <asm/uaccess.h>
+#include <asm/devtree.h>
+#include <asm/profilesample.h>
+#include <asm/memory_map.h>
+#include <asm/page.h>
+#include <asm/ip5000.h>
+
+/*
+ * spacs for all memory blocks so we can hold locks for short time when walking tables
+ */
+#define PROFILE_NUM_MAPS 5000
+static struct profile_map profile_pm[PROFILE_NUM_MAPS];
+
+static struct profilenode *node = NULL;
+static int profile_first_packet = 1;
+
+static int profile_open(struct inode *inode, struct file *filp)
+{
+       if (!node) {
+               return -ENOENT;
+       }
+       node->busy = 1;
+       if (!node->enabled) {
+               node->enabled = 1;
+               node->busy = 0;
+               profile_first_packet = 1;
+               return 0;
+       }
+       node->busy = 0;
+       return -EBUSY;
+}
+
+static int profile_sequence_num;
+
+/*
+ * make a packet full of sample data
+ */
+static int profile_make_data_packet(char *buf, int count)
+{
+       int samples;            /* number of samples requested */
+       int i;
+       struct profile_header ph;
+       char *ptr;
+
+       if (count < sizeof(struct profile_header) + sizeof(struct profile_sample)) {
+               return -EINVAL;
+       }
+
+       /*
+        * fill in the packet header
+        */
+       memset(&ph, 0, sizeof(struct profile_header));
+       ph.magic = PROF_MAGIC + PROFILE_VERSION;
+       ph.header_size = sizeof(struct profile_header);
+       ph.clocks = node->clocks;
+       for (i = 0; i < PROFILE_MAX_THREADS; ++i) {
+               ph.instruction_count[i] = node->inst_count[i];
+       }
+       ph.profile_instructions = 0;
+       ph.enabled = node->enabled_threads;
+       ph.hrt = node->hrt;
+       ph.high = 0;
+       ph.profiler_thread = node->profiler_thread;
+       ph.clock_freq = node->clock_freq;
+       ph.seq_num = profile_sequence_num++;
+       ph.cpu_id = node->cpu_id;
+       ph.perf_counters[0] = node->stats[0];
+       ph.perf_counters[1] = node->stats[1];
+       ph.perf_counters[2] = node->stats[2];
+       ph.perf_counters[3] = node->stats[3];
+       ph.ddr_freq = node->ddr_freq;
+
+       ptr = buf + sizeof(struct profile_header);
+
+       samples = (count - sizeof(struct profile_header)) / sizeof(struct profile_sample);
+       for (i = 0; i < samples && node->count; ++i) {
+               if (copy_to_user(ptr, &node->samples[node->tail], sizeof(struct profile_sample)) != 0) {
+                       return -EFAULT;
+               }
+               node->count--;
+               node->tail++;
+               if (node->tail >= node->max_samples) {
+                       node->tail = 0;
+               }
+               ptr += sizeof(struct profile_sample);
+       }
+       ph.sample_count = i;
+       if (copy_to_user(buf, &ph, sizeof(struct profile_header)) != 0) {
+               return -EFAULT;
+       }
+       if (ph.sample_count == 0)
+               return 0;
+       else
+               return sizeof(struct profile_header) + ph.sample_count * sizeof(struct profile_sample);
+}
+
+static void profile_get_memory_stats(unsigned int *total_free, unsigned int *max_free)
+{
+       struct list_head *p;
+       struct zone *zone;
+       unsigned int size;
+
+       *total_free = 0;
+       *max_free = 0;
+
+       /*
+        * get all the free regions.  In each zone, the array of free_area lists contains the first page of each frame of size 1 << order
+        */
+       for_each_zone(zone) {
+               unsigned long order, flags, i;
+
+               if (!populated_zone(zone))
+                       continue;
+
+               if (!is_normal(zone))
+                       continue;
+
+               spin_lock_irqsave(&zone->lock, flags);
+               for_each_migratetype_order(order, i) {
+                       size = ((1 << order) << PAGE_SHIFT) >> 10;
+                       list_for_each(p, &(zone->free_area[order].free_list[i])) {
+                               if (size > *max_free) {
+                                       *max_free = size;
+                               }
+                               *total_free += size;
+                       }
+               }
+               spin_unlock_irqrestore(&zone->lock, flags);
+       }
+}
+
+struct profile_counter_pkt profile_builtin_stats[] =
+{
+       {
+       "Free memory(KB)", 0
+       },
+       {
+       "Max free Block(KB)", 0
+       }
+};
+
+/*
+ * make a packet full of performance counters
+ */
+static char prof_pkt[PROFILE_MAX_PACKET_SIZE];
+static int profile_make_stats_packet(char *buf, int count)
+{
+       char *ptr = prof_pkt;
+       struct profile_header_counters hdr;
+       int stat_count = 0;
+       int i;
+       unsigned int total_free, max_free;
+       int builtin_count = sizeof(profile_builtin_stats) / sizeof(struct profile_counter_pkt);
+
+       if (count > PROFILE_MAX_PACKET_SIZE) {
+               count = PROFILE_MAX_PACKET_SIZE;
+       }
+       stat_count = (count - sizeof(struct profile_header_counters)) / sizeof (struct profile_counter_pkt);
+       stat_count -= builtin_count;
+
+       if (stat_count <= 0) {
+               return 0;
+       }
+
+       if (stat_count > node->num_counters) {
+               stat_count = node->num_counters;
+       }
+
+       hdr.magic = PROF_MAGIC_COUNTERS;
+       hdr.ultra_sample_time = node->clocks;
+       hdr.ultra_count = stat_count;
+       hdr.linux_sample_time = UBICOM32_IO_TIMER->sysval;
+       hdr.linux_count = builtin_count;
+       memcpy(ptr, (void *)&hdr, sizeof(struct profile_header_counters));
+       ptr += sizeof(struct profile_header_counters);
+
+
+       for (i = 0; i < stat_count; ++i) {
+               memcpy(ptr, (void *)(&(node->counters[i])), sizeof(struct profile_counter));
+               ptr += sizeof(struct profile_counter);
+       }
+
+       /*
+        * built in statistics
+        */
+       profile_get_memory_stats(&total_free, &max_free);
+       profile_builtin_stats[0].value = total_free;
+       profile_builtin_stats[1].value = max_free;
+       memcpy(ptr, (void *)profile_builtin_stats, sizeof(profile_builtin_stats));
+       ptr += sizeof(profile_builtin_stats);
+
+       if (copy_to_user(buf, prof_pkt, ptr - prof_pkt) != 0) {
+               return -EFAULT;
+       }
+       return ptr - prof_pkt;
+}
+
+/*
+ * return a udp packet ready to send to the profiler tool
+ * when there are no packets left to make, return 0
+ */
+static int profile_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
+{
+       int result = 0;
+       if (!node) {
+               return -ENOENT;
+       }
+       node->busy = 1;
+       if (!node->enabled) {
+               node->busy = 0;
+               return -EPERM;
+       }
+       if (!node->samples) {
+               node->busy = 0;
+               return -ENOMEM;
+       }
+
+       if (profile_first_packet) {
+               result = profile_make_stats_packet(buf, count);
+               profile_first_packet = 0;
+       }
+       if (result == 0) {
+               result = profile_make_data_packet(buf, count);
+               if (result == 0) {
+                       profile_first_packet = 1;
+               }
+       }
+       node->busy = 0;
+       return result;
+
+}
+
+static int profile_release(struct inode *inode, struct file *filp)
+{
+       if (!node) {
+               return -ENOENT;
+       }
+       node->busy = 1;
+       if (node->enabled) {
+               node->enabled = 0;
+               node->count = 0;
+               node->tail = node->head;
+               node->busy = 0;
+               return 0;
+       }
+       node->busy = 0;
+       profile_first_packet = 1;
+       return -EBADF;
+}
+
+static const struct file_operations profile_fops = {
+       .open           = profile_open,
+       .read           = profile_read,
+       .release        = profile_release,
+};
+
+static int page_aligned(void *x)
+{
+       return !((unsigned int)x & ((1 << PAGE_SHIFT) - 1));
+}
+
+static int profile_maps_open(struct inode *inode, struct file *filp)
+{
+       struct rb_node *rb;
+       int num = 0;
+       int slab_start;
+       struct vm_area_struct *vma;
+       int type = PROFILE_MAP_TYPE_UNKNOWN;
+       int flags, i;
+       struct list_head *p;
+       struct zone *zone;
+
+       /*
+        * get the slab data (first so dups will show up as vmas)
+        */
+       slab_start = num;
+       num += kmem_cache_block_info("size-512", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
+       num += kmem_cache_block_info("size-1024", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
+       num += kmem_cache_block_info("size-2048", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
+       num += kmem_cache_block_info("size-4096", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
+       num += kmem_cache_block_info("size-8192", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
+
+       for (i = slab_start; i < num; ++i) {
+               profile_pm[i].type_size |= PROFILE_MAP_TYPE_SMALL << PROFILE_MAP_TYPE_SHIFT;
+       }
+
+       slab_start = num;
+       num += kmem_cache_block_info("dentry", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
+       num += kmem_cache_block_info("inode_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
+       num += kmem_cache_block_info("sysfs_dir_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
+       num += kmem_cache_block_info("proc_inode_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
+
+       for (i = slab_start; i < num; ++i) {
+               profile_pm[i].type_size |= PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT;
+       }
+
+       /*
+        * get all the vma regions (allocated by mmap, most likely
+        */
+#if 0
+       down_read(&nommu_vma_sem);
+       for (rb = rb_first(&nommu_vma_tree); rb && num < PROFILE_NUM_MAPS; rb = rb_next(rb)) {
+               vma = rb_entry(rb, struct vm_area_struct, vm_rb);
+               profile_pm[num].start = (vma->vm_start - SDRAMSTART) >> PAGE_SHIFT;
+               profile_pm[num].type_size = (vma->vm_end - vma->vm_start + (1 << PAGE_SHIFT) - 1) >> PAGE_SHIFT;
+               flags = vma->vm_flags & 0xf;
+               if (flags == (VM_READ | VM_EXEC)) {
+                       type = PROFILE_MAP_TYPE_TEXT;
+               } else if (flags == (VM_READ | VM_WRITE | VM_EXEC)) {
+                       type = PROFILE_MAP_TYPE_STACK;
+               } else if (flags == (VM_READ | VM_WRITE)) {
+                       type = PROFILE_MAP_TYPE_APP_DATA;
+               }
+               profile_pm[num].type_size |= type << PROFILE_MAP_TYPE_SHIFT;
+               num++;
+       }
+       up_read(&nommu_vma_sem);
+       if (rb) {
+               return -ENOMEM;
+       }
+#endif
+
+       /*
+        * get all the free regions.  In each zone, the array of free_area lists contains the first page of each frame of size 1 << order
+        */
+       for_each_zone(zone) {
+               unsigned long order, flags, i;
+               struct page *page;
+
+               if (!populated_zone(zone))
+                       continue;
+
+               if (!is_normal(zone))
+                       continue;
+
+               spin_lock_irqsave(&zone->lock, flags);
+               for_each_migratetype_order(order, i) {
+                       list_for_each(p, &(zone->free_area[order].free_list[i])) {
+                               page = list_entry(p, struct page, lru);
+                               profile_pm[num].start = ((page_to_phys(page) - SDRAMSTART) >> PAGE_SHIFT) - 0x40;
+                               profile_pm[num].type_size = (PROFILE_MAP_TYPE_FREE << PROFILE_MAP_TYPE_SHIFT) | order;
+                               num++;
+                               if (num >= PROFILE_NUM_MAPS) {
+                                       spin_unlock_irqrestore(&zone->lock, flags);
+                                       return -ENOMEM;
+                               }
+                       }
+               }
+               spin_unlock_irqrestore(&zone->lock, flags);
+       }
+
+       /*
+        * get the filesystem inodes
+        */
+       list_for_each(p, &(super_blocks)) {
+               struct super_block *sb;
+               struct list_head *q;
+               if (num >= PROFILE_NUM_MAPS)
+                       break;
+               sb = list_entry(p, struct super_block, s_list);
+               if (page_aligned(sb)) {
+                       profile_pm[num].start = ((unsigned int)sb - SDRAMSTART) >> PAGE_SHIFT;
+                       profile_pm[num].type_size = (PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT);
+                       num++;
+               }
+               list_for_each(q, &(sb->s_inodes)) {
+                       struct inode *in;
+                       if (num >= PROFILE_NUM_MAPS)
+                               break;
+                       in = list_entry(q, struct inode, i_sb_list);
+                       if (page_aligned(in)) {
+                               profile_pm[num].start = ((unsigned int)in - SDRAMSTART) >> PAGE_SHIFT;
+                               profile_pm[num].type_size = (PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT);
+                               num++;
+                       }
+               }
+       }
+
+       /*
+        * get the buffer cache pages
+        */
+       for (i = 0; i < num_physpages && num < PROFILE_NUM_MAPS; ++i) {
+               if ((mem_map + i)->flags & (1 << PG_lru)) {
+                       int start = i;
+                       while ((mem_map + i)->flags & (1 << PG_lru) && i < num_physpages)
+                               i++;
+                       profile_pm[num].start = start;
+                       profile_pm[num].type_size = (i - start) | (PROFILE_MAP_TYPE_CACHE << PROFILE_MAP_TYPE_SHIFT);
+                       num++;
+               }
+       }
+
+       filp->private_data = (void *)num;
+       return 0;
+}
+
+/*
+ * return one packet of map data, or 0 if all maps have been returned already
+ */
+static int profile_maps_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
+{
+       struct profile_header_maps header;
+       char *p = buf + sizeof(header);
+       int total = (int)filp->private_data;
+
+       header.count = (count - sizeof(header)) / sizeof(struct profile_map);
+       if (header.count > PROFILE_MAX_MAPS) {
+               header.count = PROFILE_MAX_MAPS;;
+       }
+       if (header.count > total - *f_pos) {
+               header.count = total - *f_pos;
+       }
+
+       if (header.count == 0) {
+               return 0;
+       }
+
+       header.magic = PROF_MAGIC_MAPS;
+       header.page_shift = PAGE_SHIFT;
+
+       if (copy_to_user(buf, &header, sizeof(header)) != 0) {
+               return -EFAULT;
+       }
+       if (copy_to_user(p, (void *)&profile_pm[*f_pos], sizeof(struct profile_map) * header.count) != 0) {
+               return -EFAULT;
+       }
+       *f_pos += header.count;
+
+       return sizeof(header) + sizeof(struct profile_map) * header.count;
+}
+
+static int profile_maps_release(struct inode *inode, struct file *filp)
+{
+       return 0;
+}
+
+static const struct file_operations profile_maps_fops = {
+       .open           = profile_maps_open,
+       .read           = profile_maps_read,
+       .release        = profile_maps_release,
+};
+
+static int profile_rate_show(struct seq_file *m, void *v)
+{
+       if (node) {
+               seq_printf(m, "%d samples per second.  %d virtual counters.\n", node->rate, node->num_counters);
+       } else {
+               seq_printf(m, "Profiler is not initialized.\n");
+       }
+       return 0;
+}
+
+static int profile_rate_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, profile_rate_show, NULL);
+}
+
+static int profile_rate_write(struct file *filp, const char *buf, size_t len, loff_t *off)
+{
+       *off = 0;
+       return 0;
+}
+
+static const struct file_operations profile_rate_fops = {
+       .open           = profile_rate_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = profile_rate_write,
+};
+
+int ubi32_profile_init_module(void)
+{
+       struct proc_dir_entry *pdir;
+
+       /*
+        * find the device
+        */
+       node = (struct profilenode *)devtree_find_node("profiler");
+       if (!node) {
+               printk(KERN_INFO "Profiler does not exist.\n");
+               return -ENODEV;
+       }
+
+       /*
+        * allocate the sample buffer
+        */
+       node->max_samples = PROFILE_MAX_SAMPLES;
+       node->samples = kmalloc(node->max_samples * sizeof(struct profile_sample), GFP_KERNEL);
+       if (!node->samples) {
+               printk(KERN_INFO "Profiler sample buffer kmalloc failed.\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * connect to the file system
+        */
+       pdir = proc_mkdir("profile", NULL);
+       if (!pdir) {
+               return -ENOMEM;
+       }
+       if (!proc_create("data", 0, pdir, &profile_fops)) {
+               return -ENOMEM;
+       }
+       if (!proc_create("rate", 0, pdir, &profile_rate_fops)) {
+               return -ENOMEM;
+       }
+       if (!proc_create("maps", 0, pdir, &profile_maps_fops)) {
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+
+module_init(ubi32_profile_init_module);
+
+MODULE_AUTHOR("David Fotland");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/profile.h b/target/linux/ubicom32/files/arch/ubicom32/mach-common/profile.h
new file mode 100644 (file)
index 0000000..e6ff7d9
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * arch/ubicom32/mach-common/profile.h
+ *   Private data for the profile module
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/types.h>
+#include <asm/devtree.h>
+#include "profpkt.h"
+
+#ifndef _PROFILE_H_
+#define _PROFILE_H_
+
+#define PROFILE_MAX_THREADS 16
+#define PROFILE_MAX_SAMPLES 1024
+
+struct profile_sample;
+struct oprofile_sample;
+
+/*
+ * values chosen so all counter values fit in a single UDP packet
+ */
+#define PROFILE_NODE_MAX_COUNTERS 32
+
+struct profile_counter {
+       char name[PROFILE_COUNTER_NAME_LENGTH];
+       unsigned int value;
+};
+
+struct profilenode {
+       struct devtree_node dn;
+       volatile u32_t enabled;                 /* Is the profiler enabled to take samples? */
+       volatile u32_t busy;                    /* set when the samples are being read by the driver */
+       volatile u32_t rate;                    /* What is the sampling rate? */
+       volatile u32_t enabled_threads;         /* which threads were enabled at the last sample time */
+       volatile u32_t hrt;                     /* HRT threads */
+       volatile u32_t profiler_thread;         /* thread running the profile sampler */
+       volatile u32_t clocks;                  /* system clock timer at last sample */
+       volatile u32_t clock_freq;              /* clock frequency in Hz */
+       volatile u32_t ddr_freq;                /* memory frequency */
+       volatile u32_t cpu_id;                  /* chip_id register */
+       volatile u32_t inst_count[PROFILE_MAX_THREADS];         /* sampled instruction counts at most recent sample */
+       volatile u32_t stats[4];                                /* contents of the cache statistics counters */
+       volatile u16_t head;                    /* sample taker puts samples here */
+       volatile u16_t tail;                    /* packet filler takes samples here */
+       volatile u16_t count;                   /* number of valid samples */
+       volatile u16_t max_samples;             /* how many samples can be in the samples array */
+       struct profile_sample *samples;         /* samples array allocated by the linux driver */
+       volatile u32_t num_counters;            /* how many registered performance counters */
+       volatile struct profile_counter counters[PROFILE_NODE_MAX_COUNTERS];
+
+       /* unimplemented interface for future oprofile work */
+       volatile u16_t oprofile_head;           /* sample taker puts samples here */
+       volatile u16_t oprofile_tail;           /* packet filler takes samples here */
+       volatile u16_t oprofile_count;          /* how many oprofile sampels are are in use */
+       volatile u16_t oprofile_max_samples;    /* samples array size for oprofile samples */
+       struct oprofile_sample *oprofile_samples;       /* oprofile sample buffer */
+};
+
+#endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/profpkt.h b/target/linux/ubicom32/files/arch/ubicom32/mach-common/profpkt.h
new file mode 100644 (file)
index 0000000..37d9219
--- /dev/null
@@ -0,0 +1,158 @@
+
+/*
+ * arch/ubicom32/mach-common/profpkt.c
+ *   Ubicom32 Profiler packet formats for communication between the linux proc driver and the profiler display tool
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#define PROFILE_PORT 51080
+#define PROFILE_POSIX_NAME_LENGTH 32
+
+/*
+ * profile UDP packet format for communicating between ip3k and host
+ *
+ * every packet starts with a header, followed by samples.
+ * samples are only taken for non-hrt threads that are
+ * active
+ */
+#define PROF_MAGIC 0x3ea0
+#define PROF_MAGIC_COUNTERS 0x9ea0
+#define PROF_MAGIC_MAPS 0xaea0
+
+/*
+ * Versions (31 max):
+ * 1 to 4 were before 6.0 release,  development versions
+ * 5 was forward compatible version, shipped with 6.0 and 6.1
+ * 6 adds heap packets, and clock_freq to header, shipped with 6.2
+ * 7 adds a sequence numbers to check for dropped packets, shipped with 6.3.5
+ * 8 adds mqueue timing information, shipped with 6.3.5
+ * 9 adds sdram heap size information, shipped with 6.4
+ * 10 adds heapmem heap callers and long latency stack traces.  shipped with 6.4
+ * 11 adds support for Mars (IP5K).  shipped with 6.10
+ * 12 adds more support for Mars.  Shipped with 7.0
+ * 13 adds per sample latency measurement.  Shipped with 7.2
+ * 14 changes the heap format and adds a string packet.  Shipped with 7.4
+ * 15 adds dsr stats and posix.  shipped with 7.6
+ * 16 corrects maximum packet count for Ares.  ships with 7.9
+ * 17 adds a5 register value to sample
+ */
+
+#define PROFILE_VERSION 17
+#define PROFILE_MAX_PACKET_SIZE 1440
+
+#define PROFILE_MAX_THREADS 16
+
+/*
+ * each packet starts with a profile_header, then sample_count samples
+ * samples are gprof samples of pc, the return address, condition codes, and
+ * active threads
+ */
+struct profile_header {
+       u16_t magic;                    /* magic number and version */
+       u8_t header_size;               /* number of bytes in profile header */
+       u8_t sample_count;              /* number of samples in the packet */
+       u32_t clocks;                   /* clock counter value */
+       u32_t instruction_count[PROFILE_MAX_THREADS];
+                                       /* instructions executed per thread */
+       u32_t profile_instructions;     /* instructions executed by profiler mainline */
+       u16_t enabled;                  /* which threads are enabled */
+       u16_t hrt;                      /* which threads are hrt */
+       u16_t high;                     /* which threads are high priority */
+       u16_t profiler_thread;          /* which thread runs the profiler */
+       u32_t heap_free;                /* current free on-cihp heap space in bytes */
+       u32_t heap_low_water;           /* on-chip heap low water mark */
+       u32_t netpage_free;             /* number of free on-chip net pages */
+       u32_t netpage_low_water;        /* low water mark on free on-chip netpages */
+       u32_t min_sp[PROFILE_MAX_THREADS];
+                                       /* stack pointer values per thread */
+       u32_t clock_freq;               /* clock frequency (Hz) of system being analyzed */
+       u32_t seq_num;                  /* to detect dropped profiler packets */
+       u32_t timing_sequence;          /* sample number since boot */
+       u32_t timing_interval;          /* second per sample timing interval */
+       u32_t timing_worst_time;        /* duration of longest finction called, in core clocks */
+       u32_t timing_function;          /* address of longest function */
+       u32_t timing_average;           /* average time of all functions in last interval */
+       u32_t timing_count;             /* number of functions called in last interval */
+       u32_t extheap_free;             /* current free extmem heap space in bytes */
+       u32_t extheap_low_water;        /* extmem heap low water mark */
+       u32_t cpu_id;                   /* CHIP_ID register contents */
+       u32_t perf_counters[4];         /* contents of the CPU performance counters */
+       u8_t perf_config[4];            /* what is being counted */
+       u32_t ddr_freq;                 /* DDR clock frequency */
+       u32_t extnetpage_free;          /* number of free off chip net pages */
+       u32_t extnetpage_low_water;     /* low water mark on off-chip free netpages */
+       u32_t dsr_max_latency;          /* max time to process a dsr interrupt, in clocks, since last packet */
+       u32_t dsr_ave_latency;          /* average dsr latency over last DSR_STATS_RECENT_COUNT interrupts */
+       u32_t dsr_count;                /* number of dsr interrupts since last packet */
+};
+
+struct profile_header_counters {
+       u16_t magic;
+       u16_t ultra_count;              /* how many ultra counters follow this */
+       u32_t ultra_sample_time;        /* in chip clocks */
+       u32_t linux_count;              /* how many linux counters follow this */
+       u32_t linux_sample_time;
+};
+
+/*
+ * values chosen so all counter values fit in a single 1400 byte UDP packet
+ */
+#define PROFILE_COUNTER_NAME_LENGTH 20
+#define PROFILE_MAX_COUNTERS ((PROFILE_MAX_PACKET_SIZE - sizeof(struct profile_header_counters)) / (PROFILE_COUNTER_NAME_LENGTH + 4))
+
+struct profile_counter_pkt {
+       char name[PROFILE_COUNTER_NAME_LENGTH];
+       unsigned int value;
+};
+
+/*
+ * send memory maps from linux to profiler tool
+ */
+
+struct profile_header_maps {
+       u16_t magic;
+       u16_t count;
+       u32_t page_shift;
+};
+
+#define PROFILE_MAP_NUM_TYPES 32
+
+/* types 0-15: size field is order.  True size is 2^order */
+#define PROFILE_MAP_TYPE_UNKNOWN 0
+#define PROFILE_MAP_TYPE_FREE 1
+#define PROFILE_MAP_TYPE_SMALL 2
+#define PROFILE_MAP_TYPE_FS 3
+/* types 16-31: size field is pages.  True size is (1 << PAGE_SHIFT) * size */
+#define PROFILE_MAP_SIZE_TYPE 16
+#define PROFILE_MAP_TYPE_TEXT 16
+#define PROFILE_MAP_TYPE_STACK 17
+#define PROFILE_MAP_TYPE_APP_DATA 18
+#define PROFILE_MAP_TYPE_CACHE 19
+#define PROFILE_MAP_RESERVED 24
+
+#define PROFILE_MAP_TYPE_SHIFT 11
+#define PROFILE_MAP_SIZE_MASK 0x7ff
+
+struct profile_map {
+       u16_t start;            /* start page number of segment, relative to start of DRAM */
+       u16_t type_size;        /* type (4 bits) of the segment and size in pages (12 bits) */
+};
+
+#define PROFILE_MAX_MAPS (PROFILE_MAX_PACKET_SIZE - sizeof(struct profile_header_maps)) / sizeof(struct profile_map)
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/ring_tio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ring_tio.c
new file mode 100644 (file)
index 0000000..9d0f8cd
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * arch/ubicom32/mach-common/ring_tio.c
+ *   Generic initialization for UIO Ubicom32 Ring
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include <asm/devtree.h>
+#include <asm/ring_tio.h>
+
+static const char *ring_tio_driver_name = "uio_ubicom32ring";
+
+/*
+ * The number of ring_tio's currently allocated, used for .id
+ */
+static int __initdata ring_tio_count;
+
+/*
+ * The maximum number of resources that the ring_tio will have.
+ * Currently 3, a register space, and up to 2 interrupts.
+ */
+#define RING_TIO_MAX_RESOURCES 3
+
+/*
+ * ring_tio_init
+ *     Checks the device tree and instantiates the driver if found
+ */
+void __init ring_tio_init(const char *node_name)
+{
+       struct platform_device *pdev;
+       struct resource *res;
+       int resource_idx = 0;
+       struct ring_tio_node *ring_node;
+
+       /*
+        * Check the device tree for the ring_tio
+        */
+       ring_node = (struct ring_tio_node *)devtree_find_node(node_name);
+       if (!ring_node) {
+               printk(KERN_WARNING "Ring TIO '%s' not found\n", node_name);
+               return;
+       }
+
+       if (ring_node->version != RING_TIO_NODE_VERSION) {
+               printk(KERN_WARNING "ring_tio not compatible\n");
+               return;
+       }
+
+       /*
+        * Dynamically create the platform_device structure and resources
+        */
+       pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
+       if (!pdev) {
+               printk(KERN_WARNING "ring_tio could not alloc pdev\n");
+               return;
+       }
+
+       res = kzalloc(sizeof(struct resource) * RING_TIO_MAX_RESOURCES,
+                       GFP_KERNEL);
+       if (!res) {
+               kfree(pdev);
+               printk(KERN_WARNING "ring_tio could not alloc res\n");
+               return;
+       }
+
+       pdev->name = ring_tio_driver_name;
+       pdev->id = ring_tio_count++;
+       pdev->resource = res;
+
+       /*
+        * Fill in the resources and platform data from devtree information
+        */
+       res[resource_idx].start = (u32_t)(ring_node->regs);
+       res[resource_idx].end = (u32_t)(ring_node->regs);
+       res[resource_idx].flags = IORESOURCE_MEM;
+       resource_idx++;
+
+       if (ring_node->dn.sendirq != 0xFF) {
+               res[resource_idx].start = ring_node->dn.sendirq;
+               res[resource_idx].flags = IORESOURCE_IRQ;
+               resource_idx++;
+       }
+
+       if (ring_node->dn.recvirq != 0xFF) {
+               res[resource_idx].start = ring_node->dn.recvirq;
+               res[resource_idx].flags = IORESOURCE_IRQ;
+               resource_idx++;
+       }
+       pdev->num_resources = resource_idx;
+
+       printk(KERN_INFO "RingTIO.%d '%s' found irq=%d/%d regs=%p pdev=%p/%p\n",
+               ring_tio_count - 1, node_name, ring_node->dn.sendirq,
+               ring_node->dn.recvirq, ring_node->regs, pdev, res);
+
+       /*
+        * Try to get the device registered
+        */
+       pdev->dev.platform_data = (void *)node_name;
+       if (platform_device_register(pdev) < 0) {
+               printk(KERN_WARNING "Ring failed to register\n");
+               kfree(pdev);
+               kfree(res);
+       }
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-bcm539x-reg.h b/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-bcm539x-reg.h
new file mode 100644 (file)
index 0000000..ca64eb1
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * arch/ubicom32/mach-common/switch-bcm539x-reg.h
+ *   Broadcom switch definitions for Ubicom32 architecture.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+/*
+ * Broadcom 53xx RoboSwitch device driver.
+ *
+ * Copyright 2007, Broadcom Corporation
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * $Id$
+ */
+
+#ifndef _SWITCH_BCM539X_REG_H_
+#define _SWITCH_BCM539X_REG_H_
+
+#define        BCM539X_CMD_READ                0x60
+#define        BCM539X_CMD_WRITE               0x61
+
+#define        BCM539X_GLOBAL_SPI_DATA0        0xf0
+
+#define        BCM539X_GLOBAL_SPI_STATUS       0xfe
+#define        BCM539X_GLOBAL_SPI_ST_SPIF      (1<<7)
+#define        BCM539X_GLOBAL_SPI_ST_RACK      (1<<5)
+
+#define        BCM539X_GLOBAL_PAGE             0xff
+
+#define PAGE_PORT_TC                   0x00            // Port Traffic Control Register
+
+#define PAGE_QOS_CTL                   0x30            // QoS Global Control Register
+#define PAGE_QOS_TAG                   0x34            // Default IEEE 802.1Q TAG Register
+
+#define PAGE_MII_CTL_PORT0             0x10            // Internal PHY MII Register
+#define PAGE_MII_CTL_PORT1             0x11
+#define PAGE_MII_CTL_PORT2             0x12
+#define PAGE_MII_CTL_PORT3             0x13
+#define PAGE_MII_CTL_PORT4             0x14
+
+#define PAGE_STATUS                    0x01            // Status Register Page
+#define PAGE_RATE_CONTROL              0x41            // Broadcast Storm Suppression Register
+
+#define REG_GRATE_CONTROL              0x00
+
+#define REG_LED_POWER                  0x12
+
+// Ingress Rate Control
+#define REG_IRATE_CONTROLP0            0x10
+#define REG_IRATE_CONTROLP1            0x14
+#define REG_IRATE_CONTROLP2            0x18
+#define REG_IRATE_CONTROLP3            0x1C
+#define REG_IRATE_CONTROLP4            0x20
+#define REG_IRATE_CONTROLP7            0x2C
+#define REG_IRATE_CONTROLPI            0x30
+
+// Egress Rate Control
+#define REG_ERATE_CONTROLP0            0x80
+#define REG_ERATE_CONTROLP1            0x82
+#define REG_ERATE_CONTROLP2            0x84
+#define REG_ERATE_CONTROLP3            0x86
+#define REG_ERATE_CONTROLP4            0x88
+#define REG_ERATE_CONTROLP5            0x8A
+#define REG_ERATE_CONTROLP6            0x8C
+#define REG_ERATE_CONTROLP7            0x8E
+#define REG_ERATE_CONTROLPI            0x90
+
+#define REG_LINK_STATUS                        0x00
+
+#define REG_TC_PORT0                   0x00
+#define REG_TC_PORT1                   0x01
+#define REG_TC_PORT2                   0x02
+#define REG_TC_PORT3                   0x03
+#define REG_TC_PORT4                   0x04
+#define REG_TC_PORT5                   0x05
+
+#define REG_SPEED_CTL                  0x00
+#define REG_SPEED_ADV100               0x08
+#define REG_SPEED_ADV1000              0x12
+
+#define REG_QOS_EN                     0x00
+#define REG_QOS_TAG_PORT1              0x12            // Default IEEE 802.1Q TAG, PORT 1
+#define REG_QOS_TAG_PORT2              0x14            // Default IEEE 802.1Q TAG, PORT 2
+#define REG_QOS_TAG_PORT3              0x16            // Default IEEE 802.1Q TAG, PORT 3
+#define REG_QOS_TAG_PORT4              0x18            // Default IEEE 802.1Q TAG, PORT 4
+#define REG_QOS_PID_PORT1              0x52            // Ingress Port Priority ID MAP, PORT 1
+#define REG_QOS_PID_PORT2              0x54            // Ingress Port Priority ID MAP, PORT 2
+#define REG_QOS_PID_PORT3              0x56            // Ingress Port Priority ID MAP, PORT 3
+#define REG_QOS_PID_PORT4              0x58            // Ingress Port Priority ID MAP, PORT 4
+#define REG_QOS_TXQ_CTL                        0x80            // Tx Queue Control Register
+#define REG_QOS_TXQ_WHTQ0              0x81            // Tx Queue Weight Register Queue 0
+#define REG_QOS_TXQ_WHTQ1              0x82            // Tx Queue Weight Register Queue 1
+#define REG_QOS_TXQ_WHTQ2              0x83            // Tx Queue Weight Register Queue 2
+#define REG_QOS_TXQ_WHTQ3              0x84            // Tx Queue Weight Register Queue 3
+
+#define REG_CTRL_PPSEL                 0x24            /* 5397: Protected port select register */
+
+#define RATE_CONTROL_ENABLED           (1 << 22)
+#define RATE_CONTROL_BSIZE             ((1 << 10) | (1 << 9) | (1 << 8))
+
+#define RATE_CONTROL_HIGH              ((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4))
+#define RATE_CONTROL_HIGH_N            ~((1 << 3) | (1 << 2) | (1 << 1) | (1 << 0))
+
+#define RATE_CONTROL_MEDIUM            ((1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0))
+#define RATE_CONTROL_MEDIUM_N          ~((1 << 7))
+
+#define RATE_CONTROL_NORMAL            ((1 << 5) | (1 << 2) | (1 << 0))
+#define RATE_CONTROL_NORMAL_N          ~((1 << 7) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1))
+
+#define RATE_CONTROL_LOW               ((1 << 4) | (1 << 3) | (1 << 0))
+#define RATE_CONTROL_LOW_N             ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2) | (1 << 1))
+
+// --- Gemtek, Configure the switch to support Ethernet Port QoS
+
+/* MII access registers */
+#define PSEUDO_PHYAD                   0x1E    /* MII Pseudo PHY address */
+#define REG_MII_PAGE                   0x10    /* MII Page register */
+#define REG_MII_ADDR                   0x11    /* MII Address register */
+#define REG_MII_DATA0                  0x18    /* MII Data register 0 */
+#define REG_MII_DATA1                  0x19    /* MII Data register 1 */
+#define REG_MII_DATA2                  0x1a    /* MII Data register 2 */
+#define REG_MII_DATA3                  0x1b    /* MII Data register 3 */
+
+/* Page numbers */
+#define PAGE_CTRL                      0x00    /* Control page */
+#define PAGE_MMR                       0x02    /* 5397 Management/Mirroring page */
+#define PAGE_VTBL                      0x05    /* ARL/VLAN Table access page */
+#define PAGE_VLAN                      0x34    /* VLAN page */
+
+/* Control page registers */
+#define REG_CTRL_PORT0                 0x00    /* Port 0 traffic control register */
+#define REG_CTRL_PORT1                 0x01    /* Port 1 traffic control register */
+#define REG_CTRL_PORT2                 0x02    /* Port 2 traffic control register */
+#define REG_CTRL_PORT3                 0x03    /* Port 3 traffic control register */
+#define REG_CTRL_PORT4                 0x04    /* Port 4 traffic control register */
+#define REG_CTRL_PORT5                 0x05    /* Port 5 traffic control register */
+#define REG_CTRL_PORT6                 0x06    /* Port 6 traffic control register */
+#define REG_CTRL_PORT7                 0x07    /* Port 7 traffic control register */
+#define REG_CTRL_MODE                  0x0B    /* Switch Mode register */
+#define REG_CTRL_MIIPO                 0x0E    /* 5325: MII Port Override register */
+#define REG_CTRL_SRST                  0x79    /* Software reset control register */
+
+#define REG_DEVICE_ID                  0x30    /* 539x Device id: */
+#define        DEVID5395                       0x95    /*  5395 */
+#define        DEVID5397                       0x97    /*  5397 */
+#define        DEVID5398                       0x98    /*  5398 */
+#define REG_REVISION_ID                        0x40    /* 539x Revision id: */
+
+/* VLAN page registers */
+#define REG_VLAN_CTRL0                 0x00    /* VLAN Control 0 register */
+#define REG_VLAN_CTRL1                 0x01    /* VLAN Control 1 register */
+#define REG_VLAN_CTRL2                 0x02    /* VLAN Control 2 register */
+#define REG_VLAN_CTRL3                 0x03    /* VLAN Control 3 register */
+#define REG_VLAN_CTRL4                 0x04    /* VLAN Control 4 register */
+#define REG_VLAN_CTRL5                 0x05    /* VLAN Control 5 register */
+#define REG_VLAN_ACCESS                        0x06    /* VLAN Table Access register */
+#define REG_VLAN_WRITE                 0x08    /* VLAN Write register */
+#define REG_VLAN_READ                  0x0C    /* VLAN Read register */
+#define REG_VLAN_PTAG0                 0x10    /* VLAN Default Port Tag register - port 0 */
+#define REG_VLAN_PTAG1                 0x12    /* VLAN Default Port Tag register - port 1 */
+#define REG_VLAN_PTAG2                 0x14    /* VLAN Default Port Tag register - port 2 */
+#define REG_VLAN_PTAG3                 0x16    /* VLAN Default Port Tag register - port 3 */
+#define REG_VLAN_PTAG4                 0x18    /* VLAN Default Port Tag register - port 4 */
+#define REG_VLAN_PTAG5                 0x1a    /* VLAN Default Port Tag register - port 5 */
+#define REG_VLAN_PTAG6                 0x1c    /* VLAN Default Port Tag register - port 6 */
+#define REG_VLAN_PTAG7                 0x1e    /* VLAN Default Port Tag register - port 7 */
+#define REG_VLAN_PTAG8                 0x20    /* 539x: VLAN Default Port Tag register - IMP port */
+#define REG_VLAN_PMAP                  0x20    /* 5325: VLAN Priority Re-map register */
+
+/* ARL/VLAN Table Access page registers */
+#define REG_VTBL_CTRL                  0x00    /* ARL Read/Write Control */
+#define REG_VTBL_MINDX                 0x02    /* MAC Address Index */
+#define REG_VTBL_VINDX                 0x08    /* VID Table Index */
+#define REG_VTBL_ARL_E0                        0x10    /* ARL Entry 0 */
+#define REG_VTBL_ARL_E1                        0x18    /* ARL Entry 1 */
+#define REG_VTBL_DAT_E0                        0x18    /* ARL Table Data Entry 0 */
+#define REG_VTBL_SCTRL                 0x20    /* ARL Search Control */
+#define REG_VTBL_SADDR                 0x22    /* ARL Search Address */
+#define REG_VTBL_SRES                  0x24    /* ARL Search Result */
+#define REG_VTBL_SREXT                 0x2c    /* ARL Search Result */
+#define REG_VTBL_VID_E0                        0x30    /* VID Entry 0 */
+#define REG_VTBL_VID_E1                        0x32    /* VID Entry 1 */
+#define REG_VTBL_PREG                  0xFF    /* Page Register */
+#define REG_VTBL_ACCESS                        0x60    /* VLAN table access register */
+#define REG_VTBL_INDX                  0x61    /* VLAN table address index register */
+#define REG_VTBL_ENTRY                 0x63    /* VLAN table entry register */
+#define REG_VTBL_ACCESS_5395           0x80    /* VLAN table access register */
+#define REG_VTBL_INDX_5395             0x81    /* VLAN table address index register */
+#define REG_VTBL_ENTRY_5395            0x83    /* VLAN table entry register */
+
+/* SPI registers */
+#define REG_SPI_PAGE                   0xff    /* SPI Page register */
+
+#endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-bcm539x.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-bcm539x.c
new file mode 100644 (file)
index 0000000..d9eca38
--- /dev/null
@@ -0,0 +1,1195 @@
+/*
+ * arch/ubicom32/mach-common/switch-bcm539x.c
+ *   BCM539X switch driver, SPI mode
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+
+#include <asm/switch-dev.h>
+#include <asm/ubicom32-spi-gpio.h>
+#include "switch-core.h"
+#include "switch-bcm539x-reg.h"
+
+#define DRIVER_NAME "bcm539x-spi"
+#define DRIVER_VERSION "1.0"
+
+#undef BCM539X_DEBUG
+#define BCM539X_SPI_RETRIES    100
+
+struct bcm539x_data {
+       struct switch_device                    *switch_dev;
+
+       /*
+        * Our private data
+        */
+       struct spi_device                       *spi;
+       struct switch_core_platform_data        *pdata;
+
+       /*
+        * Last page we accessed
+        */
+       u8_t                                    last_page;
+
+       /*
+        * 539x Device ID
+        */
+       u8_t                                    device_id;
+};
+
+/*
+ * bcm539x_wait_status
+ *     Waits for the specified bit in the status register to be set/cleared.
+ */
+static int bcm539x_wait_status(struct bcm539x_data *bd, u8_t mask, int set)
+{
+       u8_t txbuf[2];
+       u8_t rxbuf;
+       int i;
+       int ret;
+
+       txbuf[0] = BCM539X_CMD_READ;
+       txbuf[1] = BCM539X_GLOBAL_SPI_STATUS;
+       for (i = 0; i < BCM539X_SPI_RETRIES; i++) {
+               ret = spi_write_then_read(bd->spi, txbuf, 2, &rxbuf, 1);
+               rxbuf &= mask;
+               if ((set && rxbuf) || (!set && !rxbuf)) {
+                       return 0;
+               }
+               udelay(1);
+       }
+
+       return -EIO;
+}
+
+/*
+ * bcm539x_set_page
+ *     Sets the register page for access (only if necessary)
+ */
+static int bcm539x_set_page(struct bcm539x_data *bd, u8_t page)
+{
+       u8_t txbuf[3];
+
+       if (page == bd->last_page) {
+               return 0;
+       }
+
+       bd->last_page = page;
+
+       txbuf[0] = BCM539X_CMD_WRITE;
+       txbuf[1] = BCM539X_GLOBAL_PAGE;
+       txbuf[2] = page;
+
+       return spi_write(bd->spi, txbuf, 3);
+}
+
+/*
+ * bcm539x_write_bytes
+ *     Writes a number of bytes to a given page and register
+ */
+static int bcm539x_write_bytes(struct bcm539x_data *bd, u8_t page,
+                              u8_t reg, void *buf, u8_t len)
+{
+       int ret;
+       u8_t *txbuf;
+
+       txbuf = kmalloc(2 + len, GFP_KERNEL);
+       if (!txbuf) {
+               return -ENOMEM;
+       }
+
+       /*
+        * Make sure the chip has finished processing our previous request
+        */
+       ret = bcm539x_wait_status(bd, BCM539X_GLOBAL_SPI_ST_SPIF, 0);
+       if (ret) {
+               goto done;
+       }
+
+       /*
+        * Set the page
+        */
+       ret = bcm539x_set_page(bd, page);
+       if (ret) {
+               goto done;
+       }
+
+       /*
+        * Read the data
+        */
+       txbuf[0] = BCM539X_CMD_WRITE;
+       txbuf[1] = reg;
+       memcpy(&txbuf[2], buf, len);
+
+#ifdef BCM539X_DEBUG
+       {
+               int i;
+               printk("write page %02x reg %02x len=%d buf=", page, reg, len);
+               for (i = 0; i < len + 2; i++) {
+                       printk("%02x ", txbuf[i]);
+               }
+               printk("\n");
+       }
+#endif
+
+       ret = spi_write(bd->spi, txbuf, 2 + len);
+
+done:
+       kfree(txbuf);
+       return ret;
+}
+
+/*
+ * bcm539x_write_32
+ *     Writes 32 bits of data to the given page and register
+ */
+static inline int bcm539x_write_32(struct bcm539x_data *bd, u8_t page,
+                                  u8_t reg, u32_t data)
+{
+       data = cpu_to_le32(data);
+       return bcm539x_write_bytes(bd, page, reg, &data, 4);
+}
+
+/*
+ * bcm539x_write_16
+ *     Writes 16 bits of data to the given page and register
+ */
+static inline int bcm539x_write_16(struct bcm539x_data *bd, u8_t page,
+                                  u8_t reg, u16_t data)
+{
+       data = cpu_to_le16(data);
+       return bcm539x_write_bytes(bd, page, reg, &data, 2);
+}
+
+/*
+ * bcm539x_write_8
+ *     Writes 8 bits of data to the given page and register
+ */
+static inline int bcm539x_write_8(struct bcm539x_data *bd, u8_t page,
+                                 u8_t reg, u8_t data)
+{
+       return bcm539x_write_bytes(bd, page, reg, &data, 1);
+}
+
+/*
+ * bcm539x_read_bytes
+ *     Reads a number of bytes from a given page and register
+ */
+static int bcm539x_read_bytes(struct bcm539x_data *bd, u8_t page,
+                             u8_t reg, void *buf, u8_t len)
+{
+       u8_t txbuf[2];
+       int ret;
+
+       /*
+        * (1) Make sure the chip has finished processing our previous request
+        */
+       ret = bcm539x_wait_status(bd, BCM539X_GLOBAL_SPI_ST_SPIF, 0);
+       if (ret) {
+               return ret;
+       }
+
+       /*
+        * (2) Set the page
+        */
+       ret = bcm539x_set_page(bd, page);
+       if (ret) {
+               return ret;
+       }
+
+       /*
+        * (3) Kick off the register read
+        */
+       txbuf[0] = BCM539X_CMD_READ;
+       txbuf[1] = reg;
+       ret = spi_write_then_read(bd->spi, txbuf, 2, txbuf, 1);
+       if (ret) {
+               return ret;
+       }
+
+       /*
+        * (4) Wait for RACK
+        */
+       ret = bcm539x_wait_status(bd, BCM539X_GLOBAL_SPI_ST_RACK, 1);
+       if (ret) {
+               return ret;
+       }
+
+       /*
+        * (5) Read the data
+        */
+       txbuf[0] = BCM539X_CMD_READ;
+       txbuf[1] = BCM539X_GLOBAL_SPI_DATA0;
+
+       ret = spi_write_then_read(bd->spi, txbuf, 2, buf, len);
+
+#ifdef BCM539X_DEBUG
+       {
+               int i;
+               printk("read page %02x reg %02x len=%d rxbuf=",
+                      page, reg, len);
+               for (i = 0; i < len; i++) {
+                       printk("%02x ", ((u8_t *)buf)[i]);
+               }
+               printk("\n");
+       }
+#endif
+
+       return ret;
+}
+
+/*
+ * bcm539x_read_32
+ *     Reads an 32 bit number from a given page and register
+ */
+static int bcm539x_read_32(struct bcm539x_data *bd, u8_t page,
+                          u8_t reg, u32_t *buf)
+{
+       int ret = bcm539x_read_bytes(bd, page, reg, buf, 4);
+       *buf = le32_to_cpu(*buf);
+       return ret;
+}
+
+/*
+ * bcm539x_read_16
+ *     Reads an 16 bit number from a given page and register
+ */
+static int bcm539x_read_16(struct bcm539x_data *bd, u8_t page,
+                          u8_t reg, u16_t *buf)
+{
+       int ret = bcm539x_read_bytes(bd, page, reg, buf, 2);
+       *buf = le16_to_cpu(*buf);
+       return ret;
+}
+
+/*
+ * bcm539x_read_8
+ *     Reads an 8 bit number from a given page and register
+ */
+static int bcm539x_read_8(struct bcm539x_data *bd, u8_t page,
+                         u8_t reg, u8_t *buf)
+{
+       return bcm539x_read_bytes(bd, page, reg, buf, 1);
+}
+
+/*
+ * bcm539x_set_mode
+ */
+static int bcm539x_set_mode(struct bcm539x_data *bd, int state)
+{
+       u8_t buf;
+       int ret;
+
+       ret = bcm539x_read_8(bd, PAGE_PORT_TC, REG_CTRL_MODE, &buf);
+       if (ret) {
+               return ret;
+       }
+
+       buf &= ~(1 << 1);
+       buf |= state ? (1 << 1) : 0;
+
+       ret = bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_MODE, buf);
+       return ret;
+}
+
+/*
+ * bcm539x_handle_reset
+ */
+static int bcm539x_handle_reset(struct switch_device *dev, char *buf, int inst)
+{
+       struct bcm539x_data *bd =
+               (struct bcm539x_data *)switch_get_drvdata(dev);
+       int ret;
+
+       ret = bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_SRST,
+                             (1 << 7) | (1 << 4));
+       if (ret) {
+               return ret;
+       }
+
+       udelay(20);
+
+       ret = bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_SRST, 0);
+       return ret;
+}
+
+/*
+ * bcm539x_handle_vlan_ports_read
+ */
+static int bcm539x_handle_vlan_ports_read(struct switch_device *dev,
+                                         char *buf, int inst)
+{
+       struct bcm539x_data *bd =
+               (struct bcm539x_data *)switch_get_drvdata(dev);
+       int j;
+       int len = 0;
+       u8_t rxbuf8;
+       u32_t rxbuf32;
+       int ret;
+
+       ret = bcm539x_write_16(bd, PAGE_VTBL, REG_VTBL_INDX_5395, inst);
+       if (ret) {
+               return ret;
+       }
+
+       ret = bcm539x_write_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395,
+                             (1 << 7) | 1);
+       if (ret) {
+               return ret;
+       }
+
+       /*
+        * Wait for completion
+        */
+       for (j = 0; j < BCM539X_SPI_RETRIES; j++) {
+               ret = bcm539x_read_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395,
+                                    &rxbuf8);
+               if (ret) {
+                       return ret;
+               }
+               if (!(rxbuf8 & (1 << 7))) {
+                       break;
+               }
+       }
+
+       if (j == BCM539X_SPI_RETRIES) {
+               return -EIO;
+       }
+
+       /*
+        * Read the table entry
+        */
+       ret = bcm539x_read_32(bd, PAGE_VTBL, REG_VTBL_ENTRY_5395, &rxbuf32);
+       if (ret) {
+               return ret;
+       }
+
+       for (j = 0; j < 9; j++) {
+               if (rxbuf32 & (1 << j)) {
+                       u16_t rxbuf16;
+                       len += sprintf(buf + len, "%d", j);
+                       if (rxbuf32 & (1 << (j + 9))) {
+                               buf[len++] = 'u';
+                       } else {
+                               buf[len++] = 't';
+                       }
+                       ret = bcm539x_read_16(bd, PAGE_VLAN,
+                                             REG_VLAN_PTAG0 + (j << 1),
+                                             &rxbuf16);
+                       if (ret) {
+                               return ret;
+                       }
+                       if (rxbuf16 == inst) {
+                               buf[len++] = '*';
+                       }
+                       buf[len++] = '\t';
+               }
+       }
+
+       len += sprintf(buf + len, "\n");
+       buf[len] = '\0';
+
+       return len;
+}
+
+/*
+ * bcm539x_handle_vlan_ports_write
+ */
+static int bcm539x_handle_vlan_ports_write(struct switch_device *dev,
+                                          char *buf, int inst)
+{
+       struct bcm539x_data *bd =
+               (struct bcm539x_data *)switch_get_drvdata(dev);
+       int j;
+       u32_t untag;
+       u32_t ports;
+       u32_t def;
+
+       u8_t rxbuf8;
+       u16_t rxbuf16;
+       int ret;
+
+       switch_parse_vlan_ports(dev, buf, &untag, &ports, &def);
+
+#ifdef BCM539X_DEBUG
+       printk(KERN_DEBUG "'%s' inst=%d untag=%08x ports=%08x def=%08x\n",
+               buf, inst, untag, ports, def);
+#endif
+
+       if (!ports) {
+               return 0;
+       }
+
+       /*
+        * Change default vlan tag
+        */
+       for (j = 0; j < 9; j++) {
+               if ((untag | def) & (1 << j)) {
+                       ret = bcm539x_write_16(bd, PAGE_VLAN,
+                                              REG_VLAN_PTAG0 + (j << 1),
+                                              inst);
+                       if (ret) {
+                               return ret;
+                       }
+                       continue;
+               }
+
+               if (!(dev->port_mask[0] & (1 << j))) {
+                       continue;
+               }
+
+               /*
+                * Remove any ports which are not listed anymore as members of
+                * this vlan
+                */
+               ret = bcm539x_read_16(bd, PAGE_VLAN,
+                                     REG_VLAN_PTAG0 + (j << 1), &rxbuf16);
+               if (ret) {
+                       return ret;
+               }
+               if (rxbuf16 == inst) {
+                       ret = bcm539x_write_16(bd, PAGE_VLAN,
+                                              REG_VLAN_PTAG0 + (j << 1), 0);
+                       if (ret) {
+                               return ret;
+                       }
+               }
+       }
+
+       /*
+        * Write the VLAN table
+        */
+       ret = bcm539x_write_16(bd, PAGE_VTBL, REG_VTBL_INDX_5395, inst);
+       if (ret) {
+               return ret;
+       }
+
+       ret = bcm539x_write_32(bd, PAGE_VTBL, REG_VTBL_ENTRY_5395,
+                              (untag << 9) | ports);
+       if (ret) {
+               return ret;
+       }
+
+       ret = bcm539x_write_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395,
+                             (1 << 7) | 0);
+       if (ret) {
+               return ret;
+       }
+
+       /*
+        * Wait for completion
+        */
+       for (j = 0; j < BCM539X_SPI_RETRIES; j++) {
+               ret = bcm539x_read_bytes(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395,
+                                        &rxbuf8, 1);
+               if (ret) {
+                       return ret;
+               }
+               if (!(rxbuf8 & (1 << 7))) {
+                       break;
+               }
+       }
+
+       return (j < BCM539X_SPI_RETRIES) ? 0 : -EIO;
+}
+
+/*
+ * Handlers for <this_driver>/vlan/<vlan_id>
+ */
+static const struct switch_handler bcm539x_switch_handlers_vlan_dir[] = {
+       {
+               .name   = "ports",
+               .read   = bcm539x_handle_vlan_ports_read,
+               .write  = bcm539x_handle_vlan_ports_write,
+       },
+       {
+       },
+};
+
+/*
+ * bcm539x_handle_vlan_delete_write
+ */
+static int bcm539x_handle_vlan_delete_write(struct switch_device *dev,
+                                           char *buf, int inst)
+{
+       struct bcm539x_data *bd =
+               (struct bcm539x_data *)switch_get_drvdata(dev);
+       int vid;
+       u8_t rxbuf8;
+       u32_t txbuf;
+       int j;
+       int ret;
+
+       vid = simple_strtoul(buf, NULL, 0);
+       if (!vid) {
+               return -EINVAL;
+       }
+
+       /*
+        * Disable this VLAN
+        *
+        * Go through the port-based vlan registers and clear the appropriate
+        * ones out
+        */
+       for (j = 0; j < 9; j++) {
+               u16_t rxbuf16;
+               ret = bcm539x_read_16(bd, PAGE_VLAN, REG_VLAN_PTAG0 + (j << 1),
+                                     &rxbuf16);
+               if (ret) {
+                       return ret;
+               }
+               if (rxbuf16 == vid) {
+                       txbuf = 0;
+                       ret = bcm539x_write_16(bd, PAGE_VLAN,
+                                              REG_VLAN_PTAG0 + (j << 1),
+                                              txbuf);
+                       if (ret) {
+                               return ret;
+                       }
+               }
+       }
+
+       /*
+        * Write the VLAN table
+        */
+       txbuf = vid;
+       ret = bcm539x_write_16(bd, PAGE_VTBL, REG_VTBL_INDX_5395, txbuf);
+       if (ret) {
+               return ret;
+       }
+
+       txbuf = 0;
+       ret = bcm539x_write_32(bd, PAGE_VTBL, REG_VTBL_ENTRY_5395, txbuf);
+       if (ret) {
+               return ret;
+       }
+
+       txbuf = (1 << 7) | (0);
+       ret = bcm539x_write_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, txbuf);
+       if (ret) {
+               return ret;
+       }
+
+       /*
+        * Wait for completion
+        */
+       for (j = 0; j < BCM539X_SPI_RETRIES; j++) {
+               ret = bcm539x_read_bytes(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395,
+                                        &rxbuf8, 1);
+               if (ret) {
+                       return ret;
+               }
+               if (!(rxbuf8 & (1 << 7))) {
+                       break;
+               }
+       }
+
+       if (j == BCM539X_SPI_RETRIES) {
+               return -EIO;
+       }
+
+       return switch_remove_vlan_dir(dev, vid);
+}
+
+/*
+ * bcm539x_handle_vlan_create_write
+ */
+static int bcm539x_handle_vlan_create_write(struct switch_device *dev,
+                                           char *buf, int inst)
+{
+       int vid;
+
+       vid = simple_strtoul(buf, NULL, 0);
+       if (!vid) {
+               return -EINVAL;
+       }
+
+       return switch_create_vlan_dir(dev, vid,
+                                     bcm539x_switch_handlers_vlan_dir);
+}
+
+/*
+ * bcm539x_handle_enable_read
+ */
+static int bcm539x_handle_enable_read(struct switch_device *dev,
+                                     char *buf, int inst)
+{
+       struct bcm539x_data *bd =
+               (struct bcm539x_data *)switch_get_drvdata(dev);
+       u8_t rxbuf;
+       int ret;
+
+       ret = bcm539x_read_8(bd, PAGE_PORT_TC, REG_CTRL_MODE, &rxbuf);
+       if (ret) {
+               return ret;
+       }
+       rxbuf = (rxbuf & (1 << 1)) ? 1 : 0;
+
+       return sprintf(buf, "%d\n", rxbuf);
+}
+
+/*
+ * bcm539x_handle_enable_write
+ */
+static int bcm539x_handle_enable_write(struct switch_device *dev,
+                                      char *buf, int inst)
+{
+       struct bcm539x_data *bd =
+               (struct bcm539x_data *)switch_get_drvdata(dev);
+
+       return bcm539x_set_mode(bd, buf[0] == '1');
+}
+
+/*
+ * bcm539x_handle_enable_vlan_read
+ */
+static int bcm539x_handle_enable_vlan_read(struct switch_device *dev,
+                                          char *buf, int inst)
+{
+       struct bcm539x_data *bd =
+               (struct bcm539x_data *)switch_get_drvdata(dev);
+       u8_t rxbuf;
+       int ret;
+
+       ret = bcm539x_read_8(bd, PAGE_VLAN, REG_VLAN_CTRL0, &rxbuf);
+       if (ret) {
+               return ret;
+       }
+       rxbuf = (rxbuf & (1 << 7)) ? 1 : 0;
+
+       return sprintf(buf, "%d\n", rxbuf);
+}
+
+/*
+ * bcm539x_handle_enable_vlan_write
+ */
+static int bcm539x_handle_enable_vlan_write(struct switch_device *dev,
+                                           char *buf, int inst)
+{
+       struct bcm539x_data *bd =
+               (struct bcm539x_data *)switch_get_drvdata(dev);
+       int ret;
+
+       /*
+        * disable 802.1Q VLANs
+        */
+       if (buf[0] != '1') {
+               ret = bcm539x_write_8(bd, PAGE_VLAN, REG_VLAN_CTRL0, 0);
+               return ret;
+       }
+
+       /*
+        * enable 802.1Q VLANs
+        *
+        * Enable 802.1Q | IVL learning
+        */
+       ret = bcm539x_write_8(bd, PAGE_VLAN, REG_VLAN_CTRL0,
+                             (1 << 7) | (3 << 5));
+       if (ret) {
+               return ret;
+       }
+
+       /*
+        * RSV multicast fwd | RSV multicast chk
+        */
+       ret = bcm539x_write_8(bd, PAGE_VLAN, REG_VLAN_CTRL1,
+                             (1 << 2) | (1 << 3));
+       if (ret) {
+               return ret;
+       }
+#if 0
+       /*
+        * Drop invalid VID
+        */
+       ret = bcm539x_write_16(bd, PAGE_VLAN, REG_VLAN_CTRL3, 0x00FF);
+       if (ret) {
+               return ret;
+       }
+#endif
+       return 0;
+}
+
+/*
+ * bcm539x_handle_port_enable_read
+ */
+static int bcm539x_handle_port_enable_read(struct switch_device *dev,
+                                          char *buf, int inst)
+{
+       return sprintf(buf, "%d\n", 1);
+}
+
+/*
+ * bcm539x_handle_port_enable_write
+ */
+static int bcm539x_handle_port_enable_write(struct switch_device *dev,
+                                           char *buf, int inst)
+{
+       /*
+        * validate port
+        */
+       if (!(dev->port_mask[0] & (1 << inst))) {
+               return -EIO;
+       }
+
+       if (buf[0] != '1') {
+               printk(KERN_WARNING "switch port[%d] disabling is not supported\n", inst);
+       }
+       return 0;
+}
+
+/*
+ * bcm539x_handle_port_state_read
+ */
+static int bcm539x_handle_port_state_read(struct switch_device *dev,
+                                          char *buf, int inst)
+{
+       struct bcm539x_data *bd =
+               (struct bcm539x_data *)switch_get_drvdata(dev);
+       int ret;
+       u16_t link;
+
+       /*
+        * validate port
+        */
+       if (!(dev->port_mask[0] & (1 << inst))) {
+               return -EIO;
+       }
+
+       /*
+        * check PHY link state - CPU port (port 8) is always up
+        */
+       ret = bcm539x_read_16(bd, PAGE_STATUS, REG_LINK_STATUS, &link);
+       if (ret) {
+               return ret;
+       }
+       link |= (1 << 8);
+
+       return sprintf(buf, "%d\n", (link & (1 << inst)) ? 1 : 0);
+}
+
+/*
+ * bcm539x_handle_port_media_read
+ */
+static int bcm539x_handle_port_media_read(struct switch_device *dev,
+                                          char *buf, int inst)
+{
+       struct bcm539x_data *bd =
+               (struct bcm539x_data *)switch_get_drvdata(dev);
+       int ret;
+       u16_t link, duplex;
+       u32_t speed;
+
+       /*
+        * validate port
+        */
+       if (!(dev->port_mask[0] & (1 << inst))) {
+               return -EIO;
+       }
+
+       /*
+        * check PHY link state first - CPU port (port 8) is always up
+        */
+       ret = bcm539x_read_16(bd, PAGE_STATUS, REG_LINK_STATUS, &link);
+       if (ret) {
+               return ret;
+       }
+       link |= (1 << 8);
+
+       if (!(link & (1 << inst))) {
+               return sprintf(buf, "UNKNOWN\n");
+       }
+
+       /*
+        * get link speeda dn duplex - CPU port (port 8) is 1000/full
+        */
+       ret = bcm539x_read_32(bd, PAGE_STATUS, 4, &speed);
+       if (ret) {
+               return ret;
+       }
+       speed |= (2 << 16);
+       speed = (speed >> (2 * inst)) & 3;
+
+       ret = bcm539x_read_16(bd, PAGE_STATUS, 8, &duplex);
+       if (ret) {
+               return ret;
+       }
+       duplex |= (1 << 8);
+       duplex = (duplex >> inst) & 1;
+
+       return sprintf(buf, "%d%cD\n",
+               (speed == 0) ? 10 : ((speed == 1) ? 100 : 1000),
+               duplex ? 'F' : 'H');
+}
+
+/*
+ * bcm539x_handle_port_meida_write
+ */
+static int bcm539x_handle_port_meida_write(struct switch_device *dev,
+                                           char *buf, int inst)
+{
+       struct bcm539x_data *bd =
+               (struct bcm539x_data *)switch_get_drvdata(dev);
+       int ret;
+       u16_t ctrl_word, local_cap, local_giga_cap;
+
+       /*
+        * validate port (not for CPU port)
+        */
+       if (!(dev->port_mask[0] & (1 << inst) & ~(1 << 8))) {
+               return -EIO;
+       }
+
+       /*
+        * Get the maximum capability from status
+        *      SPI reg[0x00] = PHY[0x0] --- MII control
+        *      SPI reg[0x08] = PHY[0x4] --- MII local capability
+        *      SPI reg[0x12] = PHY[0x9] --- GMII control
+        */
+       ret = bcm539x_read_16(bd, REG_MII_PAGE + inst, (MII_ADVERTISE << 1), &local_cap);
+       if (ret) {
+               return ret;
+       }
+       ret = bcm539x_read_16(bd, REG_MII_PAGE + inst, (MII_CTRL1000 << 1), &local_giga_cap);
+       if (ret) {
+               return ret;
+       }
+
+       /* Configure to the requested speed */
+       if (strncmp(buf, "1000FD", 6) == 0) {
+               /* speed */
+               local_cap &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL);
+               local_cap &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL);
+               local_giga_cap |= (ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+               /* duplex */
+       } else if (strncmp(buf, "100FD", 5) == 0) {
+               /* speed */
+               local_cap &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL);
+               local_cap |= (ADVERTISE_100HALF | ADVERTISE_100FULL);
+               local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+               /* duplex */
+               local_cap &= ~(ADVERTISE_100HALF);
+       } else if (strncmp(buf, "100HD", 5) == 0) {
+               /* speed */
+               local_cap &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL);
+               local_cap |= (ADVERTISE_100HALF | ADVERTISE_100FULL);
+               local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+               /* duplex */
+               local_cap &= ~(ADVERTISE_100FULL);
+       } else if (strncmp(buf, "10FD", 4) == 0) {
+               /* speed */
+               local_cap |= (ADVERTISE_10HALF | ADVERTISE_10FULL);
+               local_cap &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL);
+               local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+               /* duplex */
+               local_cap &= ~(ADVERTISE_10HALF);
+       } else if (strncmp(buf, "10HD", 4) == 0) {
+               /* speed */
+               local_cap |= (ADVERTISE_10HALF | ADVERTISE_10FULL);
+               local_cap &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL);
+               local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+               /* duplex */
+               local_cap &= ~(ADVERTISE_10FULL);
+       } else if (strncmp(buf, "AUTO", 4) == 0) {
+               /* speed */
+               local_cap |= (ADVERTISE_10HALF | ADVERTISE_10FULL);
+               local_cap |= (ADVERTISE_100HALF | ADVERTISE_100FULL);
+               local_giga_cap |= (ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+       } else {
+               return -EINVAL;
+       }
+
+       /* Active PHY with the requested speed for auto-negotiation */
+       ret = bcm539x_write_16(bd, REG_MII_PAGE + inst, (MII_ADVERTISE << 1), local_cap);
+       if (ret) {
+               return ret;
+       }
+       ret = bcm539x_write_16(bd, REG_MII_PAGE + inst, (MII_CTRL1000 << 1), local_giga_cap);
+       if (ret) {
+               return ret;
+       }
+
+       ret = bcm539x_read_16(bd, REG_MII_PAGE + inst, (MII_BMCR << 1), &ctrl_word);
+       if (ret) {
+               return ret;
+       }
+       ctrl_word |= (BMCR_ANENABLE | BMCR_ANRESTART);
+       ret = bcm539x_write_16(bd, REG_MII_PAGE + inst, (MII_BMCR << 1), ctrl_word);
+       if (ret) {
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * proc_fs entries for this switch
+ */
+static const struct switch_handler bcm539x_switch_handlers[] = {
+       {
+               .name   = "enable",
+               .read   = bcm539x_handle_enable_read,
+               .write  = bcm539x_handle_enable_write,
+       },
+       {
+               .name   = "enable_vlan",
+               .read   = bcm539x_handle_enable_vlan_read,
+               .write  = bcm539x_handle_enable_vlan_write,
+       },
+       {
+               .name   = "reset",
+               .write  = bcm539x_handle_reset,
+       },
+       {
+       },
+};
+
+/*
+ * Handlers for <this_driver>/vlan
+ */
+static const struct switch_handler bcm539x_switch_handlers_vlan[] = {
+       {
+               .name   = "delete",
+               .write  = bcm539x_handle_vlan_delete_write,
+       },
+       {
+               .name   = "create",
+               .write  = bcm539x_handle_vlan_create_write,
+       },
+       {
+       },
+};
+
+/*
+ * Handlers for <this_driver>/port/<port number>
+ */
+static const struct switch_handler bcm539x_switch_handlers_port[] = {
+       {
+               .name   = "enable",
+               .read   = bcm539x_handle_port_enable_read,
+               .write  = bcm539x_handle_port_enable_write,
+       },
+       {
+               .name   = "state",
+               .read   = bcm539x_handle_port_state_read,
+       },
+       {
+               .name   = "media",
+               .read   = bcm539x_handle_port_media_read,
+               .write  = bcm539x_handle_port_meida_write,
+       },
+       {
+       },
+};
+
+/*
+ * bcm539x_probe
+ */
+static int __devinit bcm539x_probe(struct spi_device *spi)
+{
+       struct bcm539x_data *bd;
+       struct switch_core_platform_data *pdata;
+       struct switch_device *switch_dev = NULL;
+       int i, ret;
+       u8_t txbuf[2];
+
+       pdata = spi->dev.platform_data;
+       if (!pdata) {
+               return -EINVAL;
+       }
+
+       ret = spi_setup(spi);
+       if (ret < 0) {
+               return ret;
+       }
+
+       /*
+        * Reset the chip if requested
+        */
+       if (pdata->flags & SWITCH_DEV_FLAG_HW_RESET) {
+               ret = gpio_request(pdata->pin_reset, "switch-bcm539x-reset");
+               if (ret) {
+                       printk(KERN_WARNING "Could not request reset\n");
+                       return -EINVAL;
+               }
+
+               gpio_direction_output(pdata->pin_reset, 0);
+               udelay(10);
+               gpio_set_value(pdata->pin_reset, 1);
+               udelay(20);
+       }
+
+       /*
+        * Allocate our private data structure
+        */
+       bd = kzalloc(sizeof(struct bcm539x_data), GFP_KERNEL);
+       if (!bd) {
+               return -ENOMEM;
+       }
+
+       dev_set_drvdata(&spi->dev, bd);
+       bd->pdata = pdata;
+       bd->spi = spi;
+       bd->last_page = 0xFF;
+
+       /*
+        * First perform SW reset if needed
+        */
+       if (pdata->flags & SWITCH_DEV_FLAG_SW_RESET) {
+               txbuf[0] = (1 << 7) | (1 << 4);
+               ret = bcm539x_write_bytes(bd, PAGE_PORT_TC,
+                                         REG_CTRL_SRST, txbuf, 1);
+               if (ret) {
+                       goto fail;
+               }
+
+               udelay(20);
+
+               txbuf[0] = 0;
+               ret = bcm539x_write_bytes(bd, PAGE_PORT_TC,
+                                         REG_CTRL_SRST, txbuf, 1);
+               if (ret) {
+                       goto fail;
+               }
+       }
+
+       /*
+        * See if we can see the chip
+        */
+       for (i = 0; i < 10; i++) {
+               ret = bcm539x_read_bytes(bd, PAGE_MMR, REG_DEVICE_ID,
+                                        &bd->device_id, 1);
+               if (!ret) {
+                       break;
+               }
+       }
+       if (ret) {
+               goto fail;
+       }
+
+       /*
+        * We only support 5395, 5397, 5398
+        */
+       if ((bd->device_id != 0x95) && (bd->device_id != 0x97) &&
+           (bd->device_id != 0x98)) {
+               ret = -ENODEV;
+               goto fail;
+       }
+
+       /*
+        *  Override CPU port config: fixed link @1000 with flow control
+        */
+       ret = bcm539x_read_8(bd, PAGE_PORT_TC, REG_CTRL_MIIPO, txbuf);
+       bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_MIIPO, 0xbb);        // Override IMP port config
+       printk("Broadcom SW CPU port setting: 0x%x -> 0xbb\n", txbuf[0]);
+
+       /*
+        * Setup the switch driver structure
+        */
+       switch_dev = switch_alloc();
+       if (!switch_dev) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+       switch_dev->name = pdata->name;
+
+       switch_dev->ports = (bd->device_id == 0x98) ? 9 : 6;
+       switch_dev->port_mask[0] = (bd->device_id == 0x98) ? 0x1FF : 0x11F;
+       switch_dev->driver_handlers = bcm539x_switch_handlers;
+       switch_dev->reg_handlers = NULL;
+       switch_dev->vlan_handlers = bcm539x_switch_handlers_vlan;
+       switch_dev->port_handlers = bcm539x_switch_handlers_port;
+
+       bd->switch_dev = switch_dev;
+       switch_set_drvdata(switch_dev, (void *)bd);
+
+       ret = switch_register(bd->switch_dev);
+       if (ret < 0) {
+               goto fail;
+       }
+
+       printk(KERN_INFO "bcm53%02x switch chip initialized\n", bd->device_id);
+
+       return ret;
+
+fail:
+       if (switch_dev) {
+               switch_release(switch_dev);
+       }
+       dev_set_drvdata(&spi->dev, NULL);
+       kfree(bd);
+       return ret;
+}
+
+static int __attribute__((unused)) bcm539x_remove(struct spi_device *spi)
+{
+       struct bcm539x_data *bd;
+
+       bd = dev_get_drvdata(&spi->dev);
+
+       if (bd->pdata->flags & SWITCH_DEV_FLAG_HW_RESET) {
+               gpio_free(bd->pdata->pin_reset);
+       }
+
+       if (bd->switch_dev) {
+               switch_unregister(bd->switch_dev);
+               switch_release(bd->switch_dev);
+       }
+
+       dev_set_drvdata(&spi->dev, NULL);
+
+       kfree(bd);
+
+       return 0;
+}
+
+static struct spi_driver bcm539x_driver = {
+       .driver = {
+               .name           = DRIVER_NAME,
+               .owner          = THIS_MODULE,
+       },
+       .probe          = bcm539x_probe,
+       .remove         = __devexit_p(bcm539x_remove),
+};
+
+static int __init bcm539x_init(void)
+{
+       return spi_register_driver(&bcm539x_driver);
+}
+
+module_init(bcm539x_init);
+
+static void __exit bcm539x_exit(void)
+{
+       spi_unregister_driver(&bcm539x_driver);
+}
+module_exit(bcm539x_exit);
+
+MODULE_AUTHOR("Pat Tjin");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("bcm539x SPI switch chip driver");
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-core.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-core.c
new file mode 100644 (file)
index 0000000..855aa06
--- /dev/null
@@ -0,0 +1,737 @@
+/*
+ * arch/ubicom32/mach-common/switch-core.c
+ *   Ubicom32 architecture switch and /proc/switch/... implementation.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 2005 Felix Fietkau <openwrt@nbd.name>
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *
+ * Basic doc of driver's /proc interface:
+ * /proc/switch/<interface>/
+ *   registers:              read-only
+ *   counters:               read-only
+ *   reset:                  write causes hardware reset
+ *   enable:                 "0", "1"
+ *   enable_vlan:            "0", "1"
+ *   port/<port-number>/
+ *     enabled:              "0", "1"
+ *     link state:           read-only
+ *     media:                "AUTO", "1000FD", "100FD", "100HD", "10FD", "10HD"
+ *   vlan/<port-number>/
+ *     ports: same syntax as for nvram's vlan*ports (eg. "1 2 3 4 5*")
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/ctype.h>
+#include <linux/proc_fs.h>
+#include <linux/list.h>
+#include <linux/rwsem.h>
+#include <linux/device.h>
+
+#include "switch-core.h"
+
+/*
+ * Pointer to the root of our filesystem
+ */
+static struct proc_dir_entry *switch_root;
+
+/*
+ * Lock used to manage access to the switch list
+ */
+DECLARE_RWSEM(switch_list_lock);
+EXPORT_SYMBOL_GPL(switch_list_lock);
+
+/*
+ * List of switches we are managing
+ */
+LIST_HEAD(switch_list);
+EXPORT_SYMBOL_GPL(switch_list);
+
+/*
+ * List of handlers we have
+ */
+LIST_HEAD(switch_handler_list);
+EXPORT_SYMBOL_GPL(switch_handler_list);
+
+/*
+ * Keep track of all the handlers we added
+ */
+struct switch_handler_entry {
+       struct list_head                node;
+       struct proc_dir_entry           *parent;
+       struct switch_device            *dev;
+       const struct switch_handler     *handler;
+       int                             inst;
+};
+
+/*
+ * Keep track of all VLAN dirs we created
+ */
+struct switch_vlan_entry {
+       struct list_head                node;
+       struct proc_dir_entry           *pde;
+       int                             vlan_id;
+       const struct switch_handler     *handlers;
+};
+
+/*
+ * switch_parse_vlan_ports
+ *     Parse the vlan properties written to <driver>/vlan/<vlan_id>/ports
+ */
+void switch_parse_vlan_ports(struct switch_device *switch_dev,
+                            char *buf, u32_t *untag,
+                            u32_t *ports, u32_t *def)
+{
+       u32_t tag = 0;
+       *untag = 0;
+       *ports = 0;
+       *def = 0;
+
+
+       /*
+        * Skip any leading spaces
+        */
+       while (isspace(*buf)) {
+               buf++;
+       }
+
+       /*
+        * Parse out the string
+        */
+       while (*buf) {
+               u32_t port = simple_strtoul(buf, &buf, 10);
+               u32_t mask = (1 << port);
+
+               /*
+                * Parse out any flags
+                */
+               while (*buf && !isspace(*buf)) {
+                       switch (*buf++) {
+                       case 't':
+                               tag |= mask;
+                               break;
+                       case '*':
+                               *def |= mask;
+                               break;
+                       }
+               }
+               *ports |= mask;
+
+               /*
+                * Skip any spaces
+                */
+               while (isspace(*buf)) {
+                       buf++;
+               }
+       }
+
+       *untag = ~tag & *ports;
+}
+
+/*
+ * switch_proc_read
+ *     Handle reads from the procfs, dispatches the driver specific handler
+ */
+static ssize_t switch_proc_read(struct file *file, char *buf, size_t count,
+                               loff_t *ppos)
+{
+       struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+       char *page;
+       int len = 0;
+
+       page = kmalloc(SWITCH_MAX_BUFSZ, GFP_KERNEL);
+       if (!page) {
+               return -ENOBUFS;
+       }
+
+       if (pde->data != NULL) {
+               struct switch_handler_entry *she =
+                       (struct switch_handler_entry *)pde->data;
+               if (she->handler->read) {
+                       len += she->handler->read(she->dev, page + len,
+                                                 she->inst);
+               }
+       }
+       len += 1;
+
+       if (*ppos < len) {
+               len = min_t(int, len - *ppos, count);
+               if (copy_to_user(buf, (page + *ppos), len)) {
+                       kfree(page);
+                       return -EFAULT;
+               }
+               *ppos += len;
+       } else {
+               len = 0;
+       }
+
+       kfree(page);
+
+       return len;
+}
+
+/*
+ * switch_proc_write
+ *     Handle writes from the procfs, dispatches the driver specific handler
+ */
+static ssize_t switch_proc_write(struct file *file, const char *buf,
+                                size_t count, loff_t *data)
+{
+       struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
+       char *page;
+       int ret = -EINVAL;
+
+       page = kmalloc(count + 1, GFP_KERNEL);
+       if (page == NULL)
+               return -ENOBUFS;
+
+       if (copy_from_user(page, buf, count)) {
+               kfree(page);
+               return -EINVAL;
+       }
+       page[count] = 0;
+
+       if (pde->data != NULL) {
+               struct switch_handler_entry *she =
+                       (struct switch_handler_entry *)pde->data;
+               if (she->handler->write) {
+                       ret = she->handler->write(she->dev, page, she->inst);
+                       if (ret >= 0) {
+                               ret = count;
+                       }
+               }
+       }
+
+       kfree(page);
+       return ret;
+}
+
+/*
+ * File operations for the proc_fs, we must cast here since proc_fs' definitions
+ * differ from file_operations definitions.
+ */
+static struct file_operations switch_proc_fops = {
+       .read = (ssize_t (*) (struct file *, char __user *,
+                             size_t, loff_t *))switch_proc_read,
+       .write = (ssize_t (*) (struct file *, const char __user *,
+                              size_t, loff_t *))switch_proc_write,
+};
+
+/*
+ * switch_add_handler
+ */
+static int switch_add_handler(struct switch_device *switch_dev,
+                             struct proc_dir_entry *parent,
+                             const struct switch_handler *handler,
+                             int inst)
+{
+       struct switch_handler_entry *she;
+       struct proc_dir_entry *pde;
+       int mode;
+
+       she = (struct switch_handler_entry *)
+               kzalloc(sizeof(struct switch_handler_entry), GFP_KERNEL);
+       if (!she) {
+               return -ENOMEM;
+       }
+
+       INIT_LIST_HEAD(&she->node);
+       she->parent = parent;
+       she->dev = switch_dev;
+       she->inst = inst;
+       she->handler = handler;
+       list_add(&she->node, &switch_dev->handlers);
+
+       mode = 0;
+       if (handler->read != NULL) {
+               mode |= S_IRUSR;
+       }
+       if (handler->write != NULL) {
+               mode |= S_IWUSR;
+       }
+
+       pde = create_proc_entry(handler->name, mode, parent);
+       if (!pde) {
+               kfree(she);
+               printk("Failed to create node '%s' in parent %p\n",
+                      handler->name, parent);
+               return -ENOMEM;
+       }
+       pde->data = (void *)she;
+       pde->proc_fops = &switch_proc_fops;
+
+       return 0;
+}
+
+/*
+ * switch_add_handlers
+ */
+static int switch_add_handlers(struct switch_device *switch_dev,
+                              struct proc_dir_entry *parent,
+                              const struct switch_handler *handlers,
+                              int inst)
+{
+       while (handlers->name) {
+               int ret = switch_add_handler(switch_dev,
+                                            parent, handlers, inst);
+               if (ret) {
+                       return ret;
+               }
+               handlers++;
+       }
+
+       return 0;
+}
+
+/*
+ * switch_remove_vlan_dirs
+ *     Removes all vlan directories
+ *
+ * Assumes all vlan directories are empty, should be called after
+ * switch_remove_handlers
+ */
+static void switch_remove_vlan_dirs(struct switch_device *switch_dev)
+{
+       struct list_head *pos;
+       struct list_head *tmp;
+       struct switch_vlan_entry *sve;
+
+       list_for_each_safe(pos, tmp, &switch_dev->vlan_dirs) {
+               sve = list_entry(pos, struct switch_vlan_entry, node);
+               list_del(pos);
+               remove_proc_entry(sve->pde->name, switch_dev->vlan_dir);
+               kfree(sve);
+       }
+}
+
+/*
+ * switch_remove_handlers
+ *     Removes all handlers registered to the given switch_device
+ */
+static void switch_remove_handlers(struct switch_device *switch_dev)
+{
+       struct list_head *pos;
+       struct list_head *tmp;
+       struct switch_handler_entry *she;
+
+       list_for_each_safe(pos, tmp, &switch_dev->handlers) {
+               she = list_entry(pos, struct switch_handler_entry, node);
+               list_del(pos);
+               remove_proc_entry(she->handler->name, she->parent);
+               kfree(she);
+       }
+}
+
+/*
+ * switch_unregister_proc_nodes
+ *     Unregisters all proc nodes related to switch_dev
+ */
+void switch_unregister_proc_nodes(struct switch_device *switch_dev)
+{
+       switch_remove_handlers(switch_dev);
+
+       if (switch_dev->port_dirs) {
+               int i;
+
+               for (i = 0; i < switch_dev->ports; i++) {
+                       if (switch_dev->port_dirs[i]) {
+                               remove_proc_entry(
+                                       switch_dev->port_dirs[i]->name,
+                                       switch_dev->port_dir);
+                       }
+               }
+       }
+
+       if (switch_dev->port_dir) {
+               remove_proc_entry("port", switch_dev->driver_dir);
+               switch_dev->port_dir = NULL;
+       }
+
+       if (switch_dev->reg_dir) {
+               remove_proc_entry("reg", switch_dev->reg_dir);
+               switch_dev->reg_dir = NULL;
+       }
+
+       if (switch_dev->vlan_dir) {
+               switch_remove_vlan_dirs(switch_dev);
+               remove_proc_entry("vlan", switch_dev->driver_dir);
+               switch_dev->vlan_dir = NULL;
+       }
+
+       if (switch_dev->driver_dir) {
+               remove_proc_entry(switch_dev->name, switch_root);
+               switch_dev->driver_dir = NULL;
+       }
+}
+
+/*
+ * switch_remove_vlan_dir
+ *     Removes vlan dir in switch/<switch_driver>/vlan/<vlan_id>
+ */
+int switch_remove_vlan_dir(struct switch_device *switch_dev, int vlan_id)
+{
+       struct list_head *pos;
+       struct switch_vlan_entry *sve = NULL;
+
+       list_for_each(pos, &switch_dev->vlan_dirs) {
+               struct switch_vlan_entry *tmp =
+                       list_entry(pos, struct switch_vlan_entry, node);
+               if (tmp->vlan_id == vlan_id) {
+                       sve = tmp;
+                       break;
+               }
+       }
+
+       if (!sve) {
+               return -ENOENT;
+       }
+
+       /*
+        * Remove it from the list
+        */
+       list_del(pos);
+
+       /*
+        * Remove the handlers
+        */
+       while (sve->handlers->name) {
+               remove_proc_entry(sve->handlers->name, sve->pde);
+               sve->handlers++;
+       }
+
+       /*
+        * Remove the proc entry for the <vlan_id> dir
+        */
+       remove_proc_entry(sve->pde->name, switch_dev->vlan_dir);
+
+       kfree(sve);
+
+       return 0;
+}
+
+/*
+ * switch_create_vlan_dir
+ *     Creates vlan dir in switch/<switch_driver>/vlan/<vlan_id>
+ */
+int switch_create_vlan_dir(struct switch_device *switch_dev,
+                          int vlan_id, const struct switch_handler *handlers)
+{
+       char s[14];
+       struct proc_dir_entry *pde = NULL;
+       struct switch_vlan_entry *sve = NULL;
+       int ret;
+       struct list_head *pos;
+
+       /*
+        * Check to see if it exists already
+        */
+       list_for_each(pos, &switch_dev->vlan_dirs) {
+               sve = list_entry(pos, struct switch_vlan_entry, node);
+               if (sve->vlan_id == vlan_id) {
+                       return -EEXIST;
+               }
+       }
+       sve = NULL;
+
+       /*
+        * Create the vlan directory if we didn't have it before
+        */
+       if (!switch_dev->vlan_dir) {
+               switch_dev->vlan_dir = proc_mkdir("vlan",
+                                                 switch_dev->driver_dir);
+               if (!switch_dev->vlan_dir) {
+                       goto fail;
+               }
+               if (switch_dev->vlan_handlers) {
+                       ret = switch_add_handlers(switch_dev,
+                                                 switch_dev->vlan_dir,
+                                                 switch_dev->vlan_handlers, 0);
+                       if (ret) {
+                               goto fail;
+                       }
+               }
+       }
+
+       /*
+        * Create the vlan_id directory
+        */
+       snprintf(s, 14, "%d", vlan_id);
+       pde = proc_mkdir(s, switch_dev->vlan_dir);
+       if (!pde) {
+               goto fail;
+       }
+
+       /*
+        * Create the handlers for this vlan
+        */
+       if (handlers) {
+               ret = switch_add_handlers(switch_dev, pde, handlers, vlan_id);
+               if (ret) {
+                       goto fail;
+               }
+       }
+
+       /*
+        * Keep track of all the switch vlan entries created
+        */
+       sve = (struct switch_vlan_entry *)
+               kzalloc(sizeof(struct switch_vlan_entry), GFP_KERNEL);
+       if (!sve) {
+               goto fail;
+       }
+       INIT_LIST_HEAD(&sve->node);
+       sve->handlers = handlers;
+       sve->vlan_id = vlan_id;
+       sve->pde = pde;
+       list_add(&sve->node, &switch_dev->vlan_dirs);
+
+       return 0;
+
+fail:
+       if (sve) {
+               kfree(sve);
+       }
+
+       if (pde) {
+               /*
+                * Remove any proc entries we might have created
+                */
+               while (handlers->name) {
+                       remove_proc_entry(handlers->name, pde);
+                       handlers++;
+               }
+
+               remove_proc_entry(s, switch_dev->driver_dir);
+       }
+
+       return -ENOMEM;
+}
+
+/*
+ * switch_register_proc_nodes
+ */
+int switch_register_proc_nodes(struct switch_device *switch_dev)
+{
+       int i;
+       int n;
+
+       switch_dev->port_dirs = kzalloc(switch_dev->ports *
+                                       sizeof(struct proc_dir_entry *),
+                                       GFP_KERNEL);
+       if (!switch_dev->port_dirs) {
+               return -ENOMEM;
+       }
+
+       /*
+        * Create a new proc entry for this switch
+        */
+       switch_dev->driver_dir = proc_mkdir(switch_dev->name, switch_root);
+       if (!switch_dev->driver_dir) {
+               goto fail;
+       }
+       if (switch_dev->driver_handlers) {
+               switch_add_handlers(switch_dev,
+                                   switch_dev->driver_dir,
+                                   switch_dev->driver_handlers,
+                                   0);
+       }
+
+       /*
+        * Create the ports
+        */
+       switch_dev->port_dir = proc_mkdir("port", switch_dev->driver_dir);
+       if (!switch_dev->port_dir) {
+               goto fail;
+       }
+       for (n = 0, i = 0; i < (SWITCH_PORT_MASK_SIZE * 32); i++) {
+               if (switch_dev->port_mask[i / 32] & (1 << i % 32)) {
+                       char s[14];
+
+                       snprintf(s, 14, "%d", i);
+                       switch_dev->port_dirs[n] =
+                               proc_mkdir(s, switch_dev->port_dir);
+                       if (!switch_dev->port_dirs[n]) {
+                               goto fail;
+                       }
+                       if (switch_dev->port_handlers) {
+                               switch_add_handlers(switch_dev,
+                                                   switch_dev->port_dirs[n],
+                                                   switch_dev->port_handlers,
+                                                   i);
+                       }
+                       n++;
+               }
+       }
+
+       /*
+        * Create the register directory for switch register access.
+        */
+       if (switch_dev->reg_handlers) {
+               switch_dev->reg_dir = proc_mkdir("reg", switch_dev->driver_dir);
+               if (!switch_dev->reg_dir) {
+                       goto fail;
+               }
+
+               switch_add_handlers(switch_dev,
+                                   switch_dev->reg_dir,
+                                   switch_dev->reg_handlers,
+                                   0);
+       }
+
+       /*
+        * Create the vlan directory
+        */
+       if (switch_dev->vlan_handlers) {
+               switch_dev->vlan_dir = proc_mkdir("vlan",
+                                                 switch_dev->driver_dir);
+               if (!switch_dev->vlan_dir) {
+                       goto fail;
+               }
+               if (switch_dev->vlan_handlers) {
+                       switch_add_handlers(switch_dev,
+                                           switch_dev->vlan_dir,
+                                           switch_dev->vlan_handlers,
+                                           0);
+               }
+       }
+
+       return 0;
+
+fail:
+       switch_unregister_proc_nodes(switch_dev);
+       return -ENOMEM;
+}
+
+/*
+ * switch_release
+ */
+void switch_release(struct switch_device *switch_dev)
+{
+       kfree(switch_dev);
+}
+
+/*
+ * switch_alloc
+ */
+struct switch_device *switch_alloc(void)
+{
+       struct switch_device *switch_dev =
+               kzalloc(sizeof(struct switch_device),
+                                               GFP_KERNEL);
+       INIT_LIST_HEAD(&switch_dev->node);
+       INIT_LIST_HEAD(&switch_dev->vlan_dirs);
+       INIT_LIST_HEAD(&switch_dev->handlers);
+       return switch_dev;
+}
+
+/*
+ * switch_register
+ */
+int switch_register(struct switch_device *switch_dev)
+{
+       int ret;
+       int i;
+
+       /*
+        * Make sure that the number of ports and the port mask make sense
+        */
+       for (ret = 0, i = 0; i < (SWITCH_PORT_MASK_SIZE * 32); i++) {
+               if (switch_dev->port_mask[i / 32] & (1 << i % 32)) {
+                       ret++;
+               }
+       }
+       if (ret > switch_dev->ports) {
+               return -EINVAL;
+       }
+
+       /*
+        * Create the /proc entries
+        */
+       ret = switch_register_proc_nodes(switch_dev);
+       if (ret) {
+               return ret;
+       }
+
+       /*
+        * Add it to the list of switches
+        */
+       down_write(&switch_list_lock);
+       list_add_tail(&switch_dev->node, &switch_list);
+       up_write(&switch_list_lock);
+
+       printk(KERN_INFO "Registered switch device: %s\n", switch_dev->name);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(switch_register);
+
+/*
+ * switch_unregister
+ *     Unregisters a previously registered switch_device object
+ */
+void switch_unregister(struct switch_device *switch_dev)
+{
+       /*
+        * remove the proc entries
+        */
+       switch_unregister_proc_nodes(switch_dev);
+
+       /*
+        * Remove it from the list of switches
+        */
+       down_write(&switch_list_lock);
+       list_del(&switch_dev->node);
+       up_write(&switch_list_lock);
+
+       printk(KERN_INFO "Unregistered switch device: %s\n", switch_dev->name);
+}
+EXPORT_SYMBOL_GPL(switch_unregister);
+
+/*
+ * switch_init
+ */
+static int __init switch_init(void)
+{
+       switch_root = proc_mkdir("switch", NULL);
+       if (!switch_root) {
+               printk(KERN_WARNING "Failed to make root switch node\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+module_init(switch_init);
+
+/*
+ * switch_exit
+ */
+static void __exit switch_exit(void)
+{
+       remove_proc_entry("switch", NULL);
+}
+module_exit(switch_exit);
+
+MODULE_AUTHOR("Patrick Tjin");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Ethernet Switch Class Interface");
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-core.h b/target/linux/ubicom32/files/arch/ubicom32/mach-common/switch-core.h
new file mode 100644 (file)
index 0000000..1e18b1c
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * arch/ubicom32/mach-common/switch-core.h
+ *   Private data for the switch module
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _SWITCH_CORE_H_
+#define _SWITCH_CORE_H_
+
+struct switch_handler_entry;
+struct switch_vlan_entry;
+
+#define SWITCH_PORT_MASK_SIZE  2
+
+struct switch_device {
+       struct list_head                node;
+
+       const char                      *name;
+       void                            *drvdata;
+
+       u8_t                            ports;
+
+       struct proc_dir_entry           *driver_dir;
+       const struct switch_handler     *driver_handlers;
+
+       struct proc_dir_entry           *port_dir;
+       struct proc_dir_entry           **port_dirs;
+       const struct switch_handler     *port_handlers;
+
+       struct proc_dir_entry           *reg_dir;
+       const struct switch_handler     *reg_handlers;
+
+       struct proc_dir_entry           *vlan_dir;
+       const struct switch_handler     *vlan_handlers;
+       struct list_head                vlan_dirs;
+
+       struct list_head                handlers;
+
+       u32_t                           port_mask[SWITCH_PORT_MASK_SIZE];
+};
+
+typedef int (*switch_handler_fn)(struct switch_device *, char *buf, int nr);
+struct switch_handler {
+       const char              *name;
+
+       switch_handler_fn       read;
+       switch_handler_fn       write;
+};
+
+#define SWITCH_MAX_BUFSZ       4096
+
+static inline void switch_set_drvdata(struct switch_device *switch_dev, void *drvdata)
+{
+       switch_dev->drvdata = drvdata;
+}
+
+static inline void *switch_get_drvdata(struct switch_device *switch_dev)
+{
+       return switch_dev->drvdata;
+}
+
+extern int switch_create_vlan_dir(struct switch_device *switch_dev, int vlan_id, const struct switch_handler *handlers);
+extern int switch_remove_vlan_dir(struct switch_device *switch_dev, int vlan_id);
+extern void switch_parse_vlan_ports(struct switch_device *switch_dev, char *buf, u32_t *untag, u32_t *ports, u32_t *def);
+
+extern void switch_release(struct switch_device *switch_dev);
+extern struct switch_device *switch_alloc(void);
+extern int switch_register(struct switch_device *switch_dev);
+extern void switch_unregister(struct switch_device *switch_dev);
+
+#endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubi32-gpio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubi32-gpio.c
new file mode 100644 (file)
index 0000000..5fa22f5
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * arch/ubicom32/mach-common/ubi32-gpio.c
+ *   Ubicom gpio driver
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/version.h>
+
+#if defined(CONFIG_PROC_FS)
+#include <linux/proc_fs.h>
+#endif
+
+#include <linux/io.h>
+#include <asm/ip5000.h>
+#include <linux/gpio.h>
+
+#define UBI_GPIO_CHECK_RANGE     0  /* !0 enables range checking */
+
+
+/*
+ * Each I/O port can be configured to operate in one of several
+ * functional modes. One of these modes is GPIO, which causes the
+ * entire port to function as a GPIO port.  Since the various port
+ * registers serve the system with other important functions, such as
+ * ethernet, serial, USB, etc., it isn't advantageous to set any of
+ * the ports to be entirely dedicated for GPIO use.  The processor
+ * alternatively allows individual bits of a port to be assigned to be
+ * used as GPIO independently from the overall port function.  This
+ * bit-by-bit assignment is selected by setting the corresponding bit
+ * in the port's gpio_mask register.  When set, the selected bit is
+ * then enabled as a GPIO.  If the corresponding bit is set in the
+ * gpio_ctl register of the port, the bit is configured as a GPIO
+ * output.  Otherwise, it is an input.
+ *
+ * NOTE: This driver uses the bit-by-bit GPIO function assignment
+ * exclusively and *never* sets the port function registers to the
+ * GPIO function.
+ *
+ * GPIO is not the main function of any of the I/O ports.  The port
+ * bit widths are variable from one port to the next, determined by
+ * the more common I/O functions of the ports.  For simplicity, this
+ * driver assumes all the ports are 32 bits wide regardless of the
+ * real bit width of the port.  GPIO bits are numbered from zero to
+ * MAX_UBICOM_GPIOS.  Within a port, the least significant bit is
+ * numbered bit zero, the most significant is bit 31.  Since the ports
+ * are considered logically contiguous, GPIO #32 is the zeroth bit in
+ * port #1, and so on.  Due to the hardware definition, there are
+ * large gaps in the GPIO numbers representing real pins.
+ *
+ * NOTE: It is up to the programmer to refer to the processor data
+ * sheet to determine which bits in which ports can be accessed and
+ * used for GPIO.
+ *
+ */
+
+
+/* There are 9 ports, A through I. Not all 32 bits in each
+ * port can be a GPIO, but we pretend they are.  Its up to the
+ * programmer to refer to the processor data sheet.
+ */
+#define MAX_UBICOM_GPIOS   (9 * 32) /* ARCH_NR_GPIOS */
+#define NUM_GPIO_PORTS     (gpio_bank(MAX_UBICOM_GPIOS))
+
+
+/* GPIO reservation bit map array */
+static int reserved_gpio_map[NUM_GPIO_PORTS];
+
+
+/* Array of hardware io_port addresses */
+static struct ubicom32_io_port *gpio_bank_addr[NUM_GPIO_PORTS] =
+{
+       UBICOM32_IO_PORT(RA),
+       UBICOM32_IO_PORT(RB),
+       UBICOM32_IO_PORT(RC),
+       UBICOM32_IO_PORT(RD),
+       UBICOM32_IO_PORT(RE),
+       UBICOM32_IO_PORT(RF),
+       UBICOM32_IO_PORT(RG),
+       UBICOM32_IO_PORT(RH),
+       UBICOM32_IO_PORT(RI)
+};
+
+
+struct ubi_gpio_chip {
+       /*
+        * Right now, nothing else lives here.
+        */
+       struct gpio_chip gpio_chip;
+};
+
+
+#if UBI_GPIO_CHECK_RANGE
+inline int check_gpio(unsigned gpio)
+{
+       if (gpio >= MAX_UBICOM_GPIOS)
+               return -EINVAL;
+       return 0;
+}
+#else
+#define check_gpio(n)   (0)
+#endif
+
+/*
+ * ubi_gpio_get_port
+ *     Get the IO port associated with a certain gpio
+ */
+struct ubicom32_io_port *ubi_gpio_get_port(unsigned gpio)
+{
+       if (gpio_bank(gpio) > NUM_GPIO_PORTS) {
+               return NULL;
+       }
+       return gpio_bank_addr[gpio_bank(gpio)];
+}
+
+/*
+ * ubi_gpio_error()
+ */
+static void ubi_gpio_error(unsigned gpio)
+{
+       printk(KERN_ERR "ubicom-gpio: GPIO %d wasn't requested!\n", gpio);
+}
+
+/*
+ * ubi_port_setup()
+ */
+static void ubi_port_setup(unsigned gpio, unsigned short usage)
+{
+       if (!check_gpio(gpio)) {
+               if (usage) {
+                       UBICOM32_GPIO_ENABLE(gpio);
+               } else {
+                       UBICOM32_GPIO_DISABLE(gpio);
+               }
+       }
+}
+
+/*
+ * ubi_gpio_request()
+ */
+static int ubi_gpio_request(struct gpio_chip *chip, unsigned gpio)
+{
+       unsigned long flags;
+
+       if (check_gpio(gpio) < 0)
+               return -EINVAL;
+
+       local_irq_save(flags);
+
+       if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+               printk(KERN_ERR "ubi-gpio: GPIO %d is already reserved!\n",
+                      gpio);
+               local_irq_restore(flags);
+               return -EBUSY;
+       }
+
+       reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+
+       ubi_port_setup(gpio, 1);
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+/*
+ * ubi_gpio_free()
+ */
+static void ubi_gpio_free(struct gpio_chip *chip, unsigned gpio)
+{
+       unsigned long flags;
+
+       if (check_gpio(gpio) < 0)
+               return;
+
+       local_irq_save(flags);
+
+       if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
+               ubi_gpio_error(gpio);
+               local_irq_restore(flags);
+               return;
+       }
+
+       /* Assert the pin is no longer claimed */
+       reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+
+       /* Revert port bit to use specified by port->function */
+       ubi_port_setup(gpio, 0);
+
+       local_irq_restore(flags);
+}
+
+/*
+ * ubi_gpio_direction_input()
+ */
+static int ubi_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+       unsigned long flags;
+
+       if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+               ubi_gpio_error(gpio);
+               return -EINVAL;
+       }
+
+       local_irq_save(flags);
+
+       /* Configure pin as gpio */
+       ubi_port_setup(gpio, 1);
+
+       /* Assert pin is an input */
+       UBICOM32_GPIO_SET_PIN_INPUT(gpio);
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+
+/*
+ * ubi_gpio_direction_output()
+ */
+static int ubi_gpio_direction_output(struct gpio_chip *chip,
+                                    unsigned gpio, int value)
+{
+       unsigned long flags;
+
+       if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+               ubi_gpio_error(gpio);
+               return -EINVAL;
+       }
+
+       local_irq_save(flags);
+
+       /* Configure pin as gpio and set initial value in gpio_out register
+        * so that when we enable it as an output, it will have the correct
+        * initial value.
+        */
+       ubi_port_setup(gpio, 1);
+       if (value) {
+               UBICOM32_GPIO_SET_PIN_HIGH(gpio);
+       } else {
+               UBICOM32_GPIO_SET_PIN_LOW(gpio);
+       }
+
+       /* Enable the pin as an output */
+       UBICOM32_GPIO_SET_PIN_OUTPUT(gpio);
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+
+/*
+ * ubi_gpio_get_value()
+ */
+static int ubi_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+       return 0 != (gpio_bank_addr[gpio_bank(gpio)]->gpio_in & gpio_bit(gpio));
+}
+
+
+/*
+ * ubi_gpio_set_value()
+ */
+static void ubi_gpio_set_value(struct gpio_chip *chip, unsigned gpio,
+                              int arg)
+{
+       unsigned long flags;
+       local_irq_save(flags);
+
+       if (arg) {
+               UBICOM32_GPIO_SET_PIN_HIGH(gpio);
+       } else {
+               UBICOM32_GPIO_SET_PIN_LOW(gpio);
+       }
+
+       local_irq_restore(flags);
+}
+
+
+/*
+ * ubi_gpio_to_irq()
+ */
+static int ubi_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+       return gpio_to_irq(gpio);
+}
+
+
+/*
+ * ubi_gpio_init()
+ */
+int __init ubi_gpio_init(void)
+{
+       int k;
+       int status;
+       struct ubi_gpio_chip *chip;
+       struct gpio_chip *gc;
+
+       printk(KERN_INFO "Ubicom GPIO Controller\n");
+
+       chip = kzalloc(sizeof(struct ubi_gpio_chip), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+
+       gc = &chip->gpio_chip;
+       gc->request          = ubi_gpio_request;
+       gc->free             = ubi_gpio_free;
+       gc->to_irq           = ubi_gpio_to_irq;
+       gc->direction_input  = ubi_gpio_direction_input;
+       gc->direction_output = ubi_gpio_direction_output;
+       gc->get              = ubi_gpio_get_value;
+       gc->set              = ubi_gpio_set_value;
+       gc->can_sleep        = 0;
+       gc->base             = 0;
+       gc->ngpio            = MAX_UBICOM_GPIOS; /* ARCH_NR_GPIOS - 1 */
+       gc->label            = "ubi_gpio";
+
+       status = gpiochip_add(gc);
+       if (status != 0) {
+               kfree(chip);
+               return status;
+       }
+
+       /* Assert all pins are free */
+       for (k = 0; k < NUM_GPIO_PORTS; k++) {
+               reserved_gpio_map[k] = 0;
+       }
+
+       return 0;
+}
+
+#if defined(CONFIG_PROC_FS)
+/*
+ * ubi_get_gpio_dir()
+ */
+static int ubi_get_gpio_dir(unsigned gpio)
+{
+       if (gpio_bank_addr[gpio_bank(gpio)]->gpio_ctl & gpio_bit(gpio))
+               return 1;
+       else
+               return 0;
+}
+
+/*
+ * gpio_proc_read()
+ */
+static int ubi_gpio_proc_read(char *buf, char **start, off_t offset,
+                         int len, int *unused_i, void *unused_v)
+{
+       int c, outlen = 0;
+
+       for (c = 0; c < MAX_UBICOM_GPIOS; c++) {
+               if (!check_gpio(c) &&
+                   (reserved_gpio_map[gpio_bank(c)] & gpio_bit(c))) {
+                       len = sprintf(buf, "GPIO_%d:\t\tGPIO %s\n", c,
+                                     ubi_get_gpio_dir(c) ? "OUTPUT" : "INPUT");
+               } else {
+                       continue;
+               }
+
+               buf += len;
+               outlen += len;
+       }
+       return outlen;
+}
+
+/*
+ * ubi_gpio_register_proc()
+ */
+static __init int ubi_gpio_register_proc(void)
+{
+       struct proc_dir_entry *proc_gpio;
+
+       proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL);
+       if (proc_gpio)
+               proc_gpio->read_proc = ubi_gpio_proc_read;
+
+       return proc_gpio != NULL;
+}
+device_initcall(ubi_gpio_register_proc);
+#endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32hid.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32hid.c
new file mode 100644 (file)
index 0000000..3318eff
--- /dev/null
@@ -0,0 +1,557 @@
+/*
+ * arch/ubicom32/mach-common/ubicom32hid.c
+ *   I2C driver for HID coprocessor found on some DPF implementations.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+
+#include <asm/ubicom32hid.h>
+
+#define DRIVER_NAME "ubicom32hid"
+
+#ifdef DEBUG
+static int ubicom32hid_debug;
+#endif
+
+static const struct i2c_device_id ubicom32hid_id[] = {
+       { DRIVER_NAME, },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ubicom32hid_id);
+
+/*
+ * Define this to make IR checking strict, in general, it's not needed
+ */
+#undef UBICOM32HID_STRICT_IR_CHECK
+
+#define UBICOM32HID_CMD_SET_PWM                0x01
+#define UBICOM32HID_CMD_SET_BL_EN      0x02
+#define UBICOM32HID_BL_EN_LOW          0x00
+#define UBICOM32HID_BL_EN_HIZ          0x01
+#define UBICOM32HID_BL_EN_HI           0x02
+#define UBICOM32HID_CMD_FLUSH          0x99
+#define UBICOM32HID_CMD_RESET          0x99
+#define UBICOM32HID_CMD_GET_IR_SWITCH  0xC0
+#define UBICOM32HID_CMD_GET_REVISION   0xfd
+#define UBICOM32HID_CMD_GET_DEVICE_ID  0xfe
+#define UBICOM32HID_CMD_GET_VERSION    0xff
+#define UBICOM32HID_DEVICE_ID          0x49
+
+#define UBICOM32HID_MAX_BRIGHTNESS_PWM 255
+
+/*
+ * Data structure returned by the HID device
+ */
+struct ubicom32hid_input_data {
+       uint32_t        ircmd;
+       uint8_t         sw_state;
+       uint8_t         sw_changed;
+};
+
+/*
+ * Our private data
+ */
+struct ubicom32hid_data {
+       /*
+        * Pointer to the platform data structure, we need the settings.
+        */
+       const struct ubicom32hid_platform_data  *pdata;
+
+       /*
+        * Backlight device
+        */
+       struct backlight_device                 *bldev;
+
+       /*
+        * I2C client, for sending messages to the HID device
+        */
+       struct i2c_client                       *client;
+
+       /*
+        * Current intensity, used for get_intensity.
+        */
+       int                                     cur_intensity;
+
+       /*
+        * Input subsystem
+        *      We won't register an input subsystem if there are no mappings.
+        */
+       struct input_polled_dev                 *poll_dev;
+};
+
+
+/*
+ * ubicom32hid_set_intensity
+ */
+static int ubicom32hid_set_intensity(struct backlight_device *bd)
+{
+       struct ubicom32hid_data *ud =
+               (struct ubicom32hid_data *)bl_get_data(bd);
+       int intensity = bd->props.brightness;
+       int reg;
+       u8_t val;
+       int ret;
+
+       /*
+        * If we're blanked the the intensity doesn't matter.
+        */
+       if ((bd->props.power != FB_BLANK_UNBLANK) ||
+           (bd->props.fb_blank != FB_BLANK_UNBLANK)) {
+               intensity = 0;
+       }
+
+       /*
+        * Set the brightness based on the type of backlight
+        */
+       if (ud->pdata->type == UBICOM32HID_BL_TYPE_BINARY) {
+               reg = UBICOM32HID_CMD_SET_BL_EN;
+               if (intensity) {
+                       val = ud->pdata->invert
+                               ? UBICOM32HID_BL_EN_LOW : UBICOM32HID_BL_EN_HI;
+               } else {
+                       val = ud->pdata->invert
+                               ? UBICOM32HID_BL_EN_HI : UBICOM32HID_BL_EN_LOW;
+               }
+       } else {
+               reg = UBICOM32HID_CMD_SET_PWM;
+               val = ud->pdata->invert
+                       ? (UBICOM32HID_MAX_BRIGHTNESS_PWM - intensity) :
+                       intensity;
+       }
+
+       /*
+        * Send the command
+        */
+       ret = i2c_smbus_write_byte_data(ud->client, reg, val);
+       if (ret < 0) {
+               dev_warn(&ud->client->dev, "Unable to write backlight err=%d\n",
+                        ret);
+               return ret;
+       }
+
+       ud->cur_intensity = intensity;
+
+       return 0;
+}
+
+/*
+ * ubicom32hid_get_intensity
+ *     Return the current intensity of the backlight.
+ */
+static int ubicom32hid_get_intensity(struct backlight_device *bd)
+{
+       struct ubicom32hid_data *ud =
+               (struct ubicom32hid_data *)bl_get_data(bd);
+
+       return ud->cur_intensity;
+}
+
+/*
+ * ubicom32hid_verify_data
+ *     Verify the data to see if there is any action to be taken
+ *
+ * Returns 0 if no action is to be taken, non-zero otherwise
+ */
+static int ubicom32hid_verify_data(struct ubicom32hid_data *ud,
+                                  struct ubicom32hid_input_data *data)
+{
+       uint8_t *ircmd = (uint8_t *)&(data->ircmd);
+
+       /*
+        * ircmd == DEADBEEF means ir queue is empty.  Since this is a
+        * meaningful code, that means the rest of the message is most likely
+        * correct, so only process the data if the switch state has changed.
+        */
+       if (data->ircmd == 0xDEADBEEF) {
+               return data->sw_changed != 0;
+       }
+
+       /*
+        * We have an ircmd which is not empty:
+        *      Data[1] should be the complement of Data[0]
+        */
+       if (ircmd[0] != (u8_t)~ircmd[1]) {
+               return 0;
+       }
+
+#ifdef UBICOM32HID_STRICT_IR_CHECK
+       /*
+        * It seems that some remote controls don't follow the NEC protocol
+        * properly, so only do this check if the remote does indeed follow the
+        * spec.  Data[3] should be the complement of Data[2]
+        */
+       if (ircmd[2] == (u8_t)~ircmd[3]) {
+               return 1;
+       }
+
+       /*
+        * For non-compliant remotes, check the system code according to what
+        * they send.
+        */
+       if ((ircmd[2] != UBICOM32HID_IR_SYSTEM_CODE_CHECK) ||
+           (ircmd[3] != UBICOM32HID_IR_SYSTEM_CODE)) {
+               return 0;
+       }
+#endif
+
+       /*
+        * Data checks out, process
+        */
+       return 1;
+}
+
+/*
+ * ubicom32hid_poll_input
+ *     Poll the input from the HID device.
+ */
+static void ubicom32hid_poll_input(struct input_polled_dev *dev)
+{
+       struct ubicom32hid_data *ud = (struct ubicom32hid_data *)dev->private;
+       const struct ubicom32hid_platform_data *pdata = ud->pdata;
+       struct ubicom32hid_input_data data;
+       struct input_dev *id = dev->input;
+       int i;
+       int sync_needed = 0;
+       uint8_t cmd;
+       int ret;
+
+       /*
+        * Flush the queue
+        */
+       cmd = UBICOM32HID_CMD_FLUSH;
+       ret = i2c_master_send(ud->client, &cmd, 1);
+       if (ret < 0) {
+               return;
+       }
+
+       ret = i2c_smbus_read_i2c_block_data(
+               ud->client, UBICOM32HID_CMD_GET_IR_SWITCH, 6, (void *)&data);
+       if (ret < 0) {
+               return;
+       }
+
+       /*
+        * Verify the data to see if there is any action to be taken
+        */
+       if (!ubicom32hid_verify_data(ud, &data)) {
+               return;
+       }
+
+#ifdef DEBUG
+       if (ubicom32hid_debug) {
+               printk("Polled ircmd=%8x swstate=%2x swchanged=%2x\n",
+                      data.ircmd, data.sw_state, data.sw_changed);
+       }
+#endif
+
+       /*
+        * Process changed switches
+        */
+       if (data.sw_changed) {
+               const struct ubicom32hid_button *ub = pdata->buttons;
+               for (i = 0; i < pdata->nbuttons; i++, ub++) {
+                       uint8_t mask = (1 << ub->bit);
+                       if (!(data.sw_changed & mask)) {
+                               continue;
+                       }
+
+                       sync_needed = 1;
+                       input_event(id, ub->type, ub->code,
+                                   (data.sw_state & mask) ? 1 : 0);
+               }
+       }
+       if (sync_needed) {
+               input_sync(id);
+       }
+
+       /*
+        * Process ir codes
+        */
+       if (data.ircmd != 0xDEADBEEF) {
+               const struct ubicom32hid_ir *ui = pdata->ircodes;
+               for (i = 0; i < pdata->nircodes; i++, ui++) {
+                       if (ui->ir_code == data.ircmd) {
+                               /*
+                                * Simulate a up/down event
+                                */
+                               input_event(id, ui->type, ui->code, 1);
+                               input_sync(id);
+                               input_event(id, ui->type, ui->code, 0);
+                               input_sync(id);
+                       }
+               }
+       }
+}
+
+
+/*
+ * Backlight ops
+ */
+static struct backlight_ops ubicom32hid_blops = {
+       .get_brightness = ubicom32hid_get_intensity,
+       .update_status  = ubicom32hid_set_intensity,
+};
+
+/*
+ * ubicom32hid_probe
+ */
+static int ubicom32hid_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       struct ubicom32hid_platform_data *pdata;
+       struct ubicom32hid_data *ud;
+       int ret;
+       int i;
+       u8 version[2];
+       char buf[1];
+
+       pdata = client->dev.platform_data;
+       if (pdata == NULL) {
+               return -ENODEV;
+       }
+
+       /*
+        * See if we even have a device available before allocating memory.
+        *
+        * Hard reset the device
+        */
+       ret = gpio_request(pdata->gpio_reset, "ubicom32hid-reset");
+       if (ret < 0) {
+               return ret;
+       }
+       gpio_direction_output(pdata->gpio_reset, pdata->gpio_reset_polarity);
+       udelay(100);
+       gpio_set_value(pdata->gpio_reset, !pdata->gpio_reset_polarity);
+       udelay(100);
+
+       /*
+        * soft reset the device.  It sometimes takes a while to do this.
+        */
+       for (i = 0; i < 50; i++) {
+               buf[0] = UBICOM32HID_CMD_RESET;
+               ret = i2c_master_send(client, buf, 1);
+               if (ret > 0) {
+                       break;
+               }
+               udelay(10000);
+       }
+       if (i == 50) {
+               dev_warn(&client->dev, "Unable to reset device\n");
+               goto fail;
+       }
+
+       ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_DEVICE_ID);
+       if (ret != UBICOM32HID_DEVICE_ID) {
+               dev_warn(&client->dev, "Incorrect device id %02x\n", buf[0]);
+               ret = -ENODEV;
+               goto fail;
+       }
+
+       ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_VERSION);
+       if (ret < 0) {
+               dev_warn(&client->dev, "Unable to get version\n");
+               goto fail;
+       }
+       version[0] = ret;
+
+       ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_REVISION);
+       if (ret < 0) {
+               dev_warn(&client->dev, "Unable to get revision\n");
+               goto fail;
+       }
+       version[1] = ret;
+
+       /*
+        * Allocate our private data
+        */
+       ud = kzalloc(sizeof(struct ubicom32hid_data), GFP_KERNEL);
+       if (!ud) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+       ud->pdata = pdata;
+       ud->client = client;
+
+       /*
+        * Register our backlight device
+        */
+       ud->bldev = backlight_device_register(DRIVER_NAME, &client->dev,
+                                             ud, &ubicom32hid_blops);
+       if (IS_ERR(ud->bldev)) {
+               ret = PTR_ERR(ud->bldev);
+               goto fail2;
+       }
+       platform_set_drvdata(client, ud);
+
+       /*
+        * Start up the backlight with the requested intensity
+        */
+       ud->bldev->props.power = FB_BLANK_UNBLANK;
+       ud->bldev->props.max_brightness =
+               (pdata->type == UBICOM32HID_BL_TYPE_PWM) ?
+               UBICOM32HID_MAX_BRIGHTNESS_PWM : 1;
+       if (pdata->default_intensity < ud->bldev->props.max_brightness) {
+               ud->bldev->props.brightness = pdata->default_intensity;
+       } else {
+               dev_warn(&client->dev, "Default brightness out of range, "
+                        "setting to max\n");
+               ud->bldev->props.brightness = ud->bldev->props.max_brightness;
+       }
+
+       ubicom32hid_set_intensity(ud->bldev);
+
+       /*
+        * Check to see if we have any inputs
+        */
+       if (!pdata->nbuttons && !pdata->nircodes) {
+               goto done;
+       }
+
+       /*
+        * We have buttons or codes, we must register an input device
+        */
+       ud->poll_dev = input_allocate_polled_device();
+       if (!ud->poll_dev) {
+               ret = -ENOMEM;
+               goto fail3;
+       }
+
+       /*
+        * Setup the polling to default to 100ms
+        */
+       ud->poll_dev->poll = ubicom32hid_poll_input;
+       ud->poll_dev->poll_interval =
+               pdata->poll_interval ? pdata->poll_interval : 100;
+       ud->poll_dev->private = ud;
+
+       ud->poll_dev->input->name =
+               pdata->input_name ? pdata->input_name : "Ubicom32HID";
+       ud->poll_dev->input->phys = "ubicom32hid/input0";
+       ud->poll_dev->input->dev.parent = &client->dev;
+       ud->poll_dev->input->id.bustype = BUS_I2C;
+
+       /*
+        * Set the capabilities by running through the buttons and ir codes
+        */
+       for (i = 0; i < pdata->nbuttons; i++) {
+               const struct ubicom32hid_button *ub = &pdata->buttons[i];
+
+               input_set_capability(ud->poll_dev->input,
+                                    ub->type ? ub->type : EV_KEY, ub->code);
+       }
+
+       for (i = 0; i < pdata->nircodes; i++) {
+               const struct ubicom32hid_ir *ui = &pdata->ircodes[i];
+
+               input_set_capability(ud->poll_dev->input,
+                                    ui->type ? ui->type : EV_KEY, ui->code);
+       }
+
+       ret = input_register_polled_device(ud->poll_dev);
+       if (ret) {
+               goto fail3;
+       }
+
+done:
+       printk(KERN_INFO DRIVER_NAME ": enabled, version=%02x.%02x\n",
+              version[0], version[1]);
+
+       return 0;
+
+fail3:
+       gpio_free(ud->pdata->gpio_reset);
+       backlight_device_unregister(ud->bldev);
+fail2:
+       kfree(ud);
+fail:
+       gpio_free(pdata->gpio_reset);
+       return ret;
+}
+
+/*
+ * ubicom32hid_remove
+ */
+static int ubicom32hid_remove(struct i2c_client *client)
+{
+       struct ubicom32hid_data *ud =
+               (struct ubicom32hid_data *)platform_get_drvdata(client);
+
+       gpio_free(ud->pdata->gpio_reset);
+
+       backlight_device_unregister(ud->bldev);
+
+       if (ud->poll_dev) {
+               input_unregister_polled_device(ud->poll_dev);
+               input_free_polled_device(ud->poll_dev);
+       }
+
+       platform_set_drvdata(client, NULL);
+
+       kfree(ud);
+
+       return 0;
+}
+
+static struct i2c_driver ubicom32hid_driver = {
+       .driver = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ubicom32hid_probe,
+       .remove         = __exit_p(ubicom32hid_remove),
+       .id_table       = ubicom32hid_id,
+};
+
+/*
+ * ubicom32hid_init
+ */
+static int __init ubicom32hid_init(void)
+{
+       return i2c_add_driver(&ubicom32hid_driver);
+}
+module_init(ubicom32hid_init);
+
+/*
+ * ubicom32hid_exit
+ */
+static void __exit ubicom32hid_exit(void)
+{
+       i2c_del_driver(&ubicom32hid_driver);
+}
+module_exit(ubicom32hid_exit);
+
+MODULE_AUTHOR("Pat Tjin <@ubicom.com>")
+MODULE_DESCRIPTION("Ubicom HID driver");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input.c
new file mode 100644 (file)
index 0000000..e2e0c24
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * arch/ubicom32/mach-common/ubicom32input.c
+ *   Ubicom32 Input driver
+ *
+ *   based on gpio-keys
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ *
+ *
+ * TODO: add groups for inputs which can be sampled together (i.e. I2C)
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <asm/ubicom32input.h>
+
+struct ubicom32input_data {
+       struct ubicom32input_platform_data      *pdata;
+
+       struct input_polled_dev                 *poll_dev;
+
+       /*
+        * collection of previous states for buttons
+        */
+       u8                                      prev_state[0];
+};
+
+/*
+ * ubicom32input_poll
+ */
+static void ubicom32input_poll(struct input_polled_dev *dev)
+{
+       struct ubicom32input_data *ud =
+               (struct ubicom32input_data *)dev->private;
+       struct ubicom32input_platform_data *pdata = ud->pdata;
+       struct input_dev *id = dev->input;
+       int i;
+       int sync_needed = 0;
+
+       for (i = 0; i < pdata->nbuttons; i++) {
+               const struct ubicom32input_button *ub = &pdata->buttons[i];
+               int state = 0;
+
+               int val = gpio_get_value(ub->gpio);
+
+               /*
+                * Check to see if the state changed from the last time we
+                * looked
+                */
+               if (val == ud->prev_state[i]) {
+                       continue;
+               }
+
+               /*
+                * The state has changed, determine if we are "up" or "down"
+                */
+               ud->prev_state[i] = val;
+
+               if ((!val && ub->active_low) || (val && !ub->active_low)) {
+                       state = 1;
+               }
+
+               input_event(id, ub->type, ub->code, state);
+               sync_needed = 1;
+       }
+
+       if (sync_needed) {
+               input_sync(id);
+       }
+}
+
+/*
+ * ubicom32input_probe
+ */
+static int __devinit ubicom32input_probe(struct platform_device *pdev)
+{
+       int i;
+       struct ubicom32input_data *ud;
+       struct input_polled_dev *poll_dev;
+       struct input_dev *input_dev;
+       struct ubicom32input_platform_data *pdata;
+       int ret;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               return -EINVAL;
+       }
+
+       ud = kzalloc(sizeof(struct ubicom32input_data) +
+                    pdata->nbuttons, GFP_KERNEL);
+       if (!ud) {
+               return -ENOMEM;
+       }
+       ud->pdata = pdata;
+
+       poll_dev = input_allocate_polled_device();
+       if (!poll_dev) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       platform_set_drvdata(pdev, ud);
+
+       ud->poll_dev = poll_dev;
+       poll_dev->private = ud;
+       poll_dev->poll = ubicom32input_poll;
+
+       /*
+        * Set the poll interval requested, default to 50 msec
+        */
+       if (pdata->poll_interval) {
+               poll_dev->poll_interval = pdata->poll_interval;
+       } else {
+               poll_dev->poll_interval = 50;
+       }
+
+       /*
+        * Setup the input device
+        */
+       input_dev = poll_dev->input;
+       input_dev->name = pdata->name ? pdata->name : "Ubicom32 Input";
+       input_dev->phys = "ubicom32input/input0";
+       input_dev->dev.parent = &pdev->dev;
+       input_dev->id.bustype = BUS_HOST;
+
+       /*
+        * Reserve the GPIOs
+        */
+       for (i = 0; i < pdata->nbuttons; i++) {
+               const struct ubicom32input_button *ub = &pdata->buttons[i];
+
+               ret = gpio_request(ub->gpio,
+                                  ub->desc ? ub->desc : "ubicom32input");
+               if (ret < 0) {
+                       pr_err("ubicom32input: failed to request "
+                              "GPIO %d ret=%d\n", ub->gpio, ret);
+                       goto fail2;
+               }
+
+               ret = gpio_direction_input(ub->gpio);
+               if (ret < 0) {
+                       pr_err("ubicom32input: failed to set "
+                              "GPIO %d to input ret=%d\n", ub->gpio, ret);
+                       goto fail2;
+               }
+
+               /*
+                * Set the previous state to the non-active stae
+                */
+               ud->prev_state[i] = ub->active_low;
+
+               input_set_capability(input_dev,
+                                    ub->type ? ub->type : EV_KEY, ub->code);
+       }
+
+       /*
+        * Register
+        */
+       ret = input_register_polled_device(ud->poll_dev);
+       if (ret) {
+               goto fail2;
+       }
+
+       return 0;
+
+fail2:
+       /*
+        * release the GPIOs we have already requested.
+        */
+       while (--i >= 0) {
+               gpio_free(pdata->buttons[i].gpio);
+       }
+
+fail:
+       printk(KERN_ERR "Ubicom32Input: Failed to register driver %d", ret);
+       platform_set_drvdata(pdev, NULL);
+       input_free_polled_device(poll_dev);
+       kfree(ud);
+       return ret;
+}
+
+/*
+ * ubicom32input_remove
+ */
+static int __devexit ubicom32input_remove(struct platform_device *dev)
+{
+       struct ubicom32input_data *ud =
+               (struct ubicom32input_data *)platform_get_drvdata(dev);
+       int i;
+
+       /*
+        * Free the GPIOs
+        */
+       for (i = 0; i < ud->pdata->nbuttons; i++) {
+               gpio_free(ud->pdata->buttons[i].gpio);
+       }
+
+       platform_set_drvdata(dev, NULL);
+       input_unregister_polled_device(ud->poll_dev);
+       input_free_polled_device(ud->poll_dev);
+
+       kfree(ud);
+
+       return 0;
+}
+
+static struct platform_driver ubicom32input_driver = {
+       .driver         = {
+               .name   = "ubicom32input",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ubicom32input_probe,
+       .remove         = __devexit_p(ubicom32input_remove),
+};
+
+/*
+ * ubicom32input_init
+ */
+static int __devinit ubicom32input_init(void)
+{
+       return platform_driver_register(&ubicom32input_driver);
+}
+
+/*
+ * ubicom32input_exit
+ */
+static void __exit ubicom32input_exit(void)
+{
+       platform_driver_unregister(&ubicom32input_driver);
+}
+
+module_init(ubicom32input_init);
+module_exit(ubicom32input_exit);
+
+MODULE_AUTHOR("Pat Tjin <pattjin@ubicom.com>");
+MODULE_DESCRIPTION("Ubicom32 Input Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ubicom32-input");
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input_i2c.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/ubicom32input_i2c.c
new file mode 100644 (file)
index 0000000..b81f191
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * arch/ubicom32/mach-common/ubicom32input_i2c.c
+ *   Ubicom32 Input driver for I2C
+ *       Supports PCA953x and family
+ *
+ *   We hog the I2C device, turning it all to input.
+ *
+ *   Based on gpio-keys, pca953x
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/i2c.h>
+
+#include <asm/ubicom32input_i2c.h>
+
+#define UBICOM32INPUT_I2C_REG_INPUT    0
+#define UBICOM32INPUT_I2C_REG_OUTPUT   1
+#define UBICOM32INPUT_I2C_REG_INVERT   2
+#define UBICOM32INPUT_I2C_REG_DIRECTION        3
+
+static const struct i2c_device_id ubicom32input_i2c_id[] = {
+       { "ubicom32in_pca9534", 8, },
+       { "ubicom32in_pca9535", 16, },
+       { "ubicom32in_pca9536", 4, },
+       { "ubicom32in_pca9537", 4, },
+       { "ubicom32in_pca9538", 8, },
+       { "ubicom32in_pca9539", 16, },
+       { "ubicom32in_pca9554", 8, },
+       { "ubicom32in_pca9555", 16, },
+       { "ubicom32in_pca9557", 8, },
+       { "ubicom32in_max7310", 8, },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ubicom32input_i2c_id);
+
+struct ubicom32input_i2c_data {
+       struct ubicom32input_i2c_platform_data  *pdata;
+
+       struct i2c_client                       *client;
+
+       struct input_polled_dev                 *poll_dev;
+
+       /*
+        * collection of previous states for buttons
+        */
+       uint16_t                                prev_state;
+
+       uint8_t                                 ngpios;
+};
+
+/*
+ * ubicom32input_i2c_write_reg
+ *     writes a register to the I2C device.
+ */
+static int ubicom32input_i2c_write_reg(struct ubicom32input_i2c_data *ud,
+                                      int reg, uint16_t val)
+{
+       int ret;
+
+       if (ud->ngpios <= 8) {
+               ret = i2c_smbus_write_byte_data(ud->client, reg, val);
+       } else {
+               ret = i2c_smbus_write_word_data(ud->client, reg << 1, val);
+       }
+
+       if (ret < 0) {
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * ubicom32input_i2c_read_reg
+ *     reads a register from the I2C device.
+ */
+static int ubicom32input_i2c_read_reg(struct ubicom32input_i2c_data *ud,
+                                     int reg, uint16_t *val)
+{
+       int ret;
+
+       if (ud->ngpios <= 8) {
+               ret = i2c_smbus_read_byte_data(ud->client, reg);
+       } else {
+               ret = i2c_smbus_read_word_data(ud->client, reg);
+       }
+
+       if (ret < 0) {
+               return ret;
+       }
+
+       *val = (uint16_t)ret;
+
+       return 0;
+}
+
+/*
+ * ubicom32input_i2c_poll
+ */
+static void ubicom32input_i2c_poll(struct input_polled_dev *dev)
+{
+       struct ubicom32input_i2c_data *ud =
+               (struct ubicom32input_i2c_data *)dev->private;
+       struct ubicom32input_i2c_platform_data *pdata = ud->pdata;
+       struct input_dev *id = dev->input;
+       int i;
+       int sync_needed = 0;
+       uint16_t val;
+       uint16_t change_mask;
+
+       /*
+        * Try to get the input status, if we fail, bail out, maybe we can do it
+        * next time.
+        */
+       if (ubicom32input_i2c_read_reg(ud, UBICOM32INPUT_I2C_REG_INPUT, &val)) {
+               return;
+       }
+
+       /*
+        * see if anything changed by using XOR
+        */
+       change_mask = ud->prev_state ^ val;
+       ud->prev_state = val;
+
+       for (i = 0; i < pdata->nbuttons; i++) {
+               const struct ubicom32input_i2c_button *ub = &pdata->buttons[i];
+               uint16_t mask = 1 << ub->bit;
+               int state = val & mask;
+
+               /*
+                * Check to see if the state changed from the last time we
+                * looked
+                */
+               if (!(change_mask & mask)) {
+                       continue;
+               }
+               input_event(id, ub->type, ub->code, state);
+               sync_needed = 1;
+       }
+
+       if (sync_needed) {
+               input_sync(id);
+       }
+}
+
+/*
+ * ubicom32input_i2c_probe
+ */
+static int __devinit ubicom32input_i2c_probe(struct i2c_client *client,
+                                            const struct i2c_device_id *id)
+{
+       int i;
+       struct ubicom32input_i2c_data *ud;
+       struct input_polled_dev *poll_dev;
+       struct input_dev *input_dev;
+       struct ubicom32input_i2c_platform_data *pdata;
+       int ret;
+       uint16_t invert_mask = 0;
+
+       pdata = client->dev.platform_data;
+       if (!pdata) {
+               return -EINVAL;
+       }
+
+       ud = kzalloc(sizeof(struct ubicom32input_i2c_data), GFP_KERNEL);
+       if (!ud) {
+               return -ENOMEM;
+       }
+       ud->pdata = pdata;
+       ud->client = client;
+       ud->ngpios = id->driver_data;
+
+       poll_dev = input_allocate_polled_device();
+       if (!poll_dev) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       ud->poll_dev = poll_dev;
+       poll_dev->private = ud;
+       poll_dev->poll = ubicom32input_i2c_poll;
+
+       /*
+        * Set the poll interval requested, default to 100 msec
+        */
+       if (pdata->poll_interval) {
+               poll_dev->poll_interval = pdata->poll_interval;
+       } else {
+               poll_dev->poll_interval = 100;
+       }
+
+       /*
+        * Setup the input device
+        */
+       input_dev = poll_dev->input;
+       input_dev->name = pdata->name ? pdata->name : "Ubicom32 Input I2C";
+       input_dev->phys = "ubicom32input_i2c/input0";
+       input_dev->dev.parent = &client->dev;
+       input_dev->id.bustype = BUS_I2C;
+
+       /*
+        * Set the capabilities
+        */
+       for (i = 0; i < pdata->nbuttons; i++) {
+               const struct ubicom32input_i2c_button *ub = &pdata->buttons[i];
+
+               if (ub->active_low) {
+                       invert_mask |= (1 << ub->bit);
+               }
+
+               input_set_capability(input_dev,
+                                    ub->type ? ub->type : EV_KEY, ub->code);
+       }
+
+       /*
+        * Setup the device (all inputs)
+        */
+       ret = ubicom32input_i2c_write_reg(ud, UBICOM32INPUT_I2C_REG_DIRECTION,
+                                         0xFFFF);
+       if (ret < 0) {
+               goto fail;
+       }
+
+       ret = ubicom32input_i2c_write_reg(ud, UBICOM32INPUT_I2C_REG_INVERT,
+                                         invert_mask);
+       if (ret < 0) {
+               goto fail;
+       }
+
+       /*
+        * Register
+        */
+       ret = input_register_polled_device(ud->poll_dev);
+       if (ret) {
+               goto fail;
+       }
+
+       i2c_set_clientdata(client, ud);
+
+       return 0;
+
+fail:
+       printk(KERN_ERR "ubicom32input_i2c: Failed to register driver %d\n",
+              ret);
+       input_free_polled_device(poll_dev);
+       kfree(ud);
+       return ret;
+}
+
+/*
+ * ubicom32input_i2c_remove
+ */
+static int __devexit ubicom32input_i2c_remove(struct i2c_client *client)
+{
+       struct ubicom32input_i2c_data *ud =
+               (struct ubicom32input_i2c_data *)i2c_get_clientdata(client);
+
+       i2c_set_clientdata(client, NULL);
+       input_unregister_polled_device(ud->poll_dev);
+       input_free_polled_device(ud->poll_dev);
+
+       kfree(ud);
+
+       return 0;
+}
+
+static struct i2c_driver ubicom32input_i2c_driver = {
+       .driver         = {
+               .name   = "ubicom32input_i2c",
+               .owner  = THIS_MODULE,
+       },
+       .remove         = __devexit_p(ubicom32input_i2c_remove),
+       .id_table       = ubicom32input_i2c_id,
+       .probe          = ubicom32input_i2c_probe,
+};
+
+/*
+ * ubicom32input_i2c_init
+ */
+static int __devinit ubicom32input_i2c_init(void)
+{
+       return i2c_add_driver(&ubicom32input_i2c_driver);
+}
+
+/*
+ * ubicom32input_i2c_exit
+ */
+static void __exit ubicom32input_i2c_exit(void)
+{
+       i2c_del_driver(&ubicom32input_i2c_driver);
+}
+
+module_init(ubicom32input_i2c_init);
+module_exit(ubicom32input_i2c_exit);
+
+MODULE_AUTHOR("Pat Tjin <pattjin@ubicom.com>");
+MODULE_DESCRIPTION("Ubicom32 Input Driver I2C");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ubicom32-input");
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb.c
new file mode 100644 (file)
index 0000000..e13f640
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * arch/ubicom32/mach-common/ip5k_usb.c
+ *   Ubicom32 architecture usb support.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
+ * Author: Kevin Hilman
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb/musb.h>
+#include <asm/devtree.h>
+#include <asm/ip5000.h>
+#include "usb_tio.h"
+
+struct usbtionode *unode = NULL;
+
+static struct resource usb_resources[] = {
+       [0] = {
+               .start  = RJ + 0x800,
+               .end    = RJ + 0x1000,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = { /* general IRQ */
+               .start  = 1, /* this is a dummy value, the real irq number is passed from kernel_setup_param */
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+
+static struct musb_hdrc_eps_bits musb_eps[] = {
+       { "ep1_tx", 4, },
+       { "ep1_rx", 4, },
+       { "ep2_tx", 10, },
+       { "ep2_rx", 10, },
+       { "ep3_tx", 9, },
+       { "ep3_rx", 9, },
+       { "ep4_tx", 9, },
+       { "ep4_rx", 9, },
+       { "ep5_tx", 6, },
+       { "ep5_rx", 6, },
+};
+
+static struct musb_hdrc_config musb_config = {
+       .multipoint     = true,
+       .dyn_fifo       = false,
+       .soft_con       = true,
+       .dma            = false,
+
+       .num_eps        = 6,
+       .dma_channels   = 0,
+       .ram_bits       = 0,
+       .eps_bits       = musb_eps,
+};
+
+static struct musb_hdrc_platform_data usb_data = {
+#ifdef CONFIG_USB_MUSB_OTG
+       .mode           = MUSB_OTG,
+#else
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+       .mode           = MUSB_HOST,
+#else
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       .mode           = MUSB_PERIPHERAL,
+#endif
+#endif
+#endif
+       .clock          = NULL,
+       .set_clock      = NULL,
+       .config         = &musb_config,
+};
+
+static struct platform_device musb_device = {
+       .name           = "musb_hdrc",
+       .id             = 0,
+       .dev = {
+               .platform_data          = &usb_data,
+               .dma_mask               = NULL,
+               .coherent_dma_mask      = 0,
+       },
+       .resource       = usb_resources,
+       .num_resources  = ARRAY_SIZE(usb_resources),
+};
+
+struct usbtio_node *usb_node = NULL;
+void ubi32_usb_init(void)
+{
+       /*
+        * See if the usbtio is in the device tree.
+        */
+       usb_node = (struct usbtio_node *)devtree_find_node("usbtio");
+       if (!usb_node) {
+               printk(KERN_WARNING "usb init failed\n");
+               return;
+       }
+
+       usb_resources[1].start = usb_node->dn.recvirq;
+       if (platform_device_register(&musb_device) < 0) {
+               printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
+               return;
+       }
+}
+
+void ubi32_usb_int_clr(void)
+{
+        UBICOM32_IO_PORT(RJ)->int_clr = (1 << 3);
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb_tio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb_tio.c
new file mode 100644 (file)
index 0000000..95ace6d
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * arch/ubicom32/mach-common/usb_tio.c
+ *  Linux side Ubicom USB TIO driver
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <asm/devtree.h>
+#include "usb_tio.h"
+
+#ifdef CONFIG_SMP
+static DEFINE_SPINLOCK(tio_lock);
+#define USB_TIO_LOCK(lock, flag) spin_lock_irqsave(lock, flag)
+#define USB_TIO_UNLOCK(lock, flag) spin_unlock_irqrestore(lock, flag)
+#define USB_TIO_LOCK_ISLOCKED(lock) spin_try_lock(lock)
+#else
+#define USB_TIO_LOCK(lock, flag) local_irq_save(flag)
+#define USB_TIO_UNLOCK(lock, flag) local_irq_restore(flag)
+#endif
+
+spinlock_t usb_tio_lock;
+
+/*
+ * usb_tio_set_hrt_interrupt()
+ */
+static inline void usb_tio_set_hrt_interrupt(void)
+{
+       ubicom32_set_interrupt(usb_node->dn.sendirq);
+}
+
+static inline void usb_tio_wait_hrt(void)
+{
+       while (unlikely(usb_node->pdesc));
+}
+
+#if defined(USB_TIO_DEBUG)
+static void usb_tio_request_verify_magic(volatile struct usb_tio_request *req)
+{
+       BUG_ON(req->magic != USB_TIO_REQUEST_MAGIC2);
+}
+
+static void usb_tio_request_clear_magic(volatile struct usb_tio_request *req)
+{
+       req->magic = 0;
+}
+#endif
+
+static void usb_tio_request_set_magic(volatile struct usb_tio_request *req)
+{
+       req->magic = USB_TIO_REQUEST_MAGIC1;
+}
+
+/*
+ * usb_tio_commit_request()
+ */
+static inline void usb_tio_commit_request(volatile struct usb_tio_request *request)
+{
+       wmb();
+       usb_node->pdesc = request;
+
+       /*
+        * next thing to do is alway checking if (usb_node->pdesc == NULL)
+        * to see if the request is done, so add a mb() here
+        */
+       mb();
+       usb_tio_set_hrt_interrupt();
+}
+
+/*
+ * usb_tio_read_u16()
+ *     Synchronously read 16 bits.
+ */
+u8_t usb_tio_read_u16(u32_t address, u16_t *data)
+{
+       volatile struct usb_tio_request *tio_req = &usb_node->request;
+       unsigned long flag;
+
+       /*
+        * Wait for any previous request to complete and then make this request.
+        */
+       USB_TIO_LOCK(&tio_lock, flag);
+       usb_tio_wait_hrt();
+
+       /*
+        * Fill in the request.
+        */
+       tio_req->address = address;
+       tio_req->cmd = USB_TIO_READ16_SYNC;
+       USB_TIO_REQUEST_SET_MAGIC(tio_req);
+       usb_tio_commit_request(tio_req);
+
+       /*
+        * Wait for the result to show up.
+        */
+       usb_tio_wait_hrt();
+       USB_TIO_REQUEST_VERIFY_MAGIC(tio_req);
+       *data = (u16_t)tio_req->data;
+       USB_TIO_REQUEST_CLEAR_MAGIC(tio_req);
+       USB_TIO_UNLOCK(&tio_lock, flag);
+       return USB_TIO_OK;
+}
+
+/*
+ * usb_tio_read_u8()
+ *     Synchronously read 16 bits.
+ */
+u8_t usb_tio_read_u8(u32_t address, u8_t *data)
+{
+       volatile struct usb_tio_request *tio_req = &usb_node->request;
+       unsigned long flag;
+
+       /*
+        * Wait for any previous request to complete and then make this request.
+        */
+       USB_TIO_LOCK(&tio_lock, flag);
+       usb_tio_wait_hrt();
+
+       /*
+        * Fill in the request.
+        */
+       tio_req->address = address;
+       tio_req->cmd = USB_TIO_READ8_SYNC;
+       USB_TIO_REQUEST_SET_MAGIC(tio_req);
+
+       /*
+        * commit the request
+        */
+       usb_tio_commit_request(tio_req);
+
+       /*
+        * Wait for the result to show up.
+        */
+       usb_tio_wait_hrt();
+       USB_TIO_REQUEST_VERIFY_MAGIC(tio_req);
+       *data = (u8_t)tio_req->data;
+       USB_TIO_REQUEST_CLEAR_MAGIC(tio_req);
+       USB_TIO_UNLOCK(&tio_lock, flag);
+       return USB_TIO_OK;
+}
+
+/*
+ * usb_tio_write_u16()
+ *     Asynchronously  write 16 bits.
+ */
+u8_t usb_tio_write_u16(u32_t address, u16_t data)
+{
+       volatile struct usb_tio_request *tio_req = &usb_node->request;
+       unsigned long flag;
+
+       /*
+        * Wait for any previous write or pending read to complete.
+        */
+       USB_TIO_LOCK(&tio_lock, flag);
+       usb_tio_wait_hrt();
+
+       tio_req->address = address;
+       tio_req->data = data;
+       tio_req->cmd = USB_TIO_WRITE16_ASYNC;
+       USB_TIO_REQUEST_SET_MAGIC(tio_req);
+
+       /*
+        * commit the request
+        */
+       usb_tio_commit_request(tio_req);
+       USB_TIO_UNLOCK(&tio_lock, flag);
+       return USB_TIO_OK;
+}
+
+/*
+ * usb_tio_write_u8()
+ *     Asynchronously  write 8 bits.
+ */
+u8_t usb_tio_write_u8(u32_t address, u8_t data)
+{
+       volatile struct usb_tio_request *tio_req = &usb_node->request;
+       unsigned long flag;
+
+       /*
+        * Wait for any previous write or pending read to complete.
+        */
+       USB_TIO_LOCK(&tio_lock, flag);
+       usb_tio_wait_hrt();
+
+       tio_req->address = address;
+       tio_req->data = data;
+       tio_req->cmd = USB_TIO_WRITE8_ASYNC;
+       USB_TIO_REQUEST_SET_MAGIC(tio_req);
+
+       /*
+        * commit the request
+        */
+       usb_tio_commit_request(tio_req);
+       USB_TIO_UNLOCK(&tio_lock, flag);
+       return USB_TIO_OK;
+}
+
+/*
+ * usb_tio_read_fifo()
+ *     Synchronously read FIFO.
+ */
+u8_t usb_tio_read_fifo(u32_t address, u32_t buffer, u32_t bytes)
+{
+       volatile struct usb_tio_request *tio_req = &usb_node->request;
+       unsigned long flag;
+
+       /*
+        * Wait for any previous request to complete and then make this request.
+        */
+       USB_TIO_LOCK(&tio_lock, flag);
+       usb_tio_wait_hrt();
+
+       /*
+        * Fill in the request.
+        */
+       tio_req->address = address;
+       tio_req->cmd = USB_TIO_READ_FIFO_SYNC;
+       tio_req->buffer = buffer;
+       tio_req->transfer_length = bytes;
+       USB_TIO_REQUEST_SET_MAGIC(tio_req);
+
+       /*
+        * commit the request
+        */
+       usb_tio_commit_request(tio_req);
+
+        /*
+        * Wait for the result to show up.
+        */
+       usb_tio_wait_hrt();
+       USB_TIO_REQUEST_VERIFY_MAGIC(tio_req);
+       USB_TIO_REQUEST_CLEAR_MAGIC(tio_req);
+       USB_TIO_UNLOCK(&tio_lock, flag);
+       return USB_TIO_OK;
+}
+
+/*
+ * usb_tio_write_fifo()
+ *     Synchronously  write 32 bits.
+ */
+u8_t usb_tio_write_fifo(u32_t address, u32_t buffer, u32_t bytes)
+{
+       volatile struct usb_tio_request *tio_req = &usb_node->request;
+       unsigned long flag;
+
+       USB_TIO_LOCK(&tio_lock, flag);
+       usb_tio_wait_hrt();
+
+       tio_req->address = address;
+       tio_req->buffer = buffer;
+       tio_req->cmd = USB_TIO_WRITE_FIFO_SYNC;
+       tio_req->transfer_length = bytes;
+       USB_TIO_REQUEST_SET_MAGIC(tio_req);
+       /*
+        * commit the request
+        */
+       usb_tio_commit_request(tio_req);
+
+       /*
+        * Wait for the result to show up.
+        */
+       usb_tio_wait_hrt();
+       USB_TIO_REQUEST_VERIFY_MAGIC(tio_req);
+       USB_TIO_REQUEST_CLEAR_MAGIC(tio_req);
+       USB_TIO_UNLOCK(&tio_lock, flag);
+       return USB_TIO_OK;
+}
+
+/*
+ * usb_tio_write_fifo_async()
+ *     Asynchronously write 32 bits.
+ */
+u8_t usb_tio_write_fifo_async(u32_t address, u32_t buffer, u32_t bytes)
+{
+       volatile struct usb_tio_request *tio_req = &usb_node->request;
+       unsigned long flag;
+
+       USB_TIO_LOCK(&tio_lock, flag);
+       usb_tio_wait_hrt();
+
+       tio_req->address = address;
+
+       /*
+        * Is it necessary to make a local copy of the buffer? Any chance the URB is aborted before TIO finished the FIFO write?
+        */
+       tio_req->buffer = buffer;
+       tio_req->cmd = USB_TIO_WRITE_FIFO_SYNC;
+       tio_req->transfer_length = bytes;
+       USB_TIO_REQUEST_SET_MAGIC(tio_req);
+       /*
+        * commit the request
+        */
+       usb_tio_commit_request(tio_req);
+       USB_TIO_UNLOCK(&tio_lock, flag);
+       return USB_TIO_OK;
+}
+
+/*
+ * usb_tio_read_int_status()
+ *     read and clear the interrupt status registers
+ */
+void usb_tio_read_int_status(u8_t *int_usb, u16_t *int_tx, u16_t *int_rx)
+{
+
+       /*
+        * clear the interrupt must be syncronized with the TIO thread to prevent the racing condiiton
+        * that TIO thread try to set it at same time
+        */
+       asm volatile (
+       "1:     bset (%0), (%0), #0     \n\t" \
+       "       jmpne.f 1b              \n\t" \
+               :
+               : "a" (&usb_node->usb_vp_control)
+               : "memory", "cc"
+       );
+
+       *int_usb = usb_node->usb_vp_hw_int_usb;
+       *int_tx  = cpu_to_le16(usb_node->usb_vp_hw_int_tx);
+       *int_rx  = cpu_to_le16(usb_node->usb_vp_hw_int_rx);
+
+       //printk(KERN_INFO "int read %x, %x, %x\n", *int_usb, *int_tx, *int_rx);
+
+       /*
+        * The interrupt status register is read-clean, so clear it now
+        */
+       usb_node->usb_vp_hw_int_usb = 0;
+       usb_node->usb_vp_hw_int_tx = 0;
+       usb_node->usb_vp_hw_int_rx = 0;
+
+       /*
+        * release the lock bit
+        */
+       usb_node->usb_vp_control &= 0xfffe;
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb_tio.h b/target/linux/ubicom32/files/arch/ubicom32/mach-common/usb_tio.h
new file mode 100644 (file)
index 0000000..a88ea18
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * arch/ubicom32/mach-common/usb_tio.h
+ *   Definitions for usb_tio.c
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <asm/devtree.h>
+#include <asm/ip5000.h>
+
+#ifndef _USB_TIO_H
+#define _USB_TIO_H
+
+#undef  USB_TIO_DEBUG
+
+#define USB_TIO_REQUEST_MAGIC1 0x2307
+#define USB_TIO_REQUEST_MAGIC2 0x0789
+#if defined(USB_TIO_DEBUG)
+#define USB_TIO_REQUEST_VERIFY_MAGIC(req)      usb_tio_request_verify_magic(req)
+#define USB_TIO_REQUEST_SET_MAGIC(req)          usb_tio_request_set_magic(req)
+#define USB_TIO_REQUEST_CLEAR_MAGIC(req)       usb_tio_request_clear_magic(req)
+#else
+#define USB_TIO_REQUEST_VERIFY_MAGIC(req)
+#define USB_TIO_REQUEST_SET_MAGIC(req)          usb_tio_request_set_magic(req)
+#define USB_TIO_REQUEST_CLEAR_MAGIC(req)
+#endif
+
+enum USB_TIO_status {
+       USB_TIO_OK,
+       USB_TIO_ERROR,
+       USB_TIO_ERROR_COMMIT,
+};
+
+enum USB_TIO_cmds {
+       USB_TIO_READ16_SYNC,
+       USB_TIO_READ8_SYNC,
+       USB_TIO_READ_FIFO_SYNC,
+
+       USB_TIO_WRITE16_ASYNC,
+       USB_TIO_WRITE8_ASYNC,
+       USB_TIO_WRITE_FIFO_ASYNC,
+
+       USB_TIO_WRITE16_SYNC,
+       USB_TIO_WRITE8_SYNC,
+       USB_TIO_WRITE_FIFO_SYNC,
+
+};
+
+enum USB_TIO_state {
+       USB_TIO_NORMAL,
+       USB_TIO_DMA_SETUP,
+};
+
+struct usb_tio_request {
+       volatile u32_t address;
+       union {
+               volatile u32_t data;
+               volatile u32_t buffer;
+       };
+       volatile u16_t cmd;
+       const volatile u16_t status;
+       volatile u32_t transfer_length;
+       volatile u32_t thread_mask;
+       volatile u16_t magic;
+};
+
+struct usbtio_node {
+       struct devtree_node dn;
+       volatile struct usb_tio_request * volatile pdesc;
+       struct usb_tio_request  request;
+       volatile u32_t usb_vp_config;
+       volatile u32_t usb_vp_control;
+       const volatile u32_t usb_vp_status;
+       volatile u16_t usb_vp_hw_int_tx;
+       volatile u16_t usb_vp_hw_int_rx;
+       volatile u8_t  usb_vp_hw_int_usb;
+       volatile u8_t usb_vp_hw_int_mask_usb;
+        volatile u16_t usb_vp_hw_int_mask_tx;
+        volatile u16_t usb_vp_hw_int_mask_rx;
+
+};
+
+extern struct usbtio_node *usb_node;
+extern void ubi32_usb_init(void);
+#endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-common/vdc_tio.c b/target/linux/ubicom32/files/arch/ubicom32/mach-common/vdc_tio.c
new file mode 100644 (file)
index 0000000..cde0cb2
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * arch/ubicom32/mach-common/vdc_tio.c
+ *   Generic initialization for VDC
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#include <asm/devtree.h>
+#include <asm/vdc_tio.h>
+
+/*
+ * Resources that this driver uses
+ */
+static struct resource vdc_tio_resources[] = {
+       /*
+        * Send IRQ
+        */
+       [0] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Receive IRQ (optional)
+        */
+       [1] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Memory Mapped Registers
+        */
+       [2] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+/*
+ * The platform_device structure which is passed to the driver
+ */
+static struct platform_device vdc_tio_platform_device = {
+       .name           = "ubicom32fb",
+       .id             = -1,
+       .resource       = vdc_tio_resources,
+       .num_resources  = ARRAY_SIZE(vdc_tio_resources),
+};
+
+/*
+ * vdc_tio_init
+ *     Checks the device tree and instantiates the driver if found
+ */
+void __init vdc_tio_init(void)
+{
+       /*
+        * Check the device tree for the vdc_tio
+        */
+       struct vdc_tio_node *vdc_node =
+               (struct vdc_tio_node *)devtree_find_node("vdctio");
+       if (!vdc_node) {
+               printk(KERN_WARNING "No vdc_tio found\n");
+               return;
+       }
+
+       /*
+        * Fill in the resources and platform data from devtree information
+        */
+       vdc_tio_resources[0].start = vdc_node->dn.sendirq;
+       vdc_tio_resources[1].start = vdc_node->dn.recvirq;
+       vdc_tio_resources[2].start = (u32_t)vdc_node->regs;
+       vdc_tio_resources[2].end = (u32_t)vdc_node->regs +
+               sizeof(struct vdc_tio_vp_regs);
+
+       /*
+        * Try to get the device registered
+        */
+       if (platform_device_register(&vdc_tio_platform_device) < 0) {
+               printk(KERN_WARNING "VDC failed to register\n");
+       }
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/Kconfig b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/Kconfig
new file mode 100644 (file)
index 0000000..b53d239
--- /dev/null
@@ -0,0 +1,28 @@
+
+config IP5170DPF
+       bool "IP5170DPF"
+       select UBICOM32_V3
+       select I2C
+       select I2C_GPIO
+       select FB
+       select FB_UBICOM32
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       select UBICOM_HID
+       select NEW_LEDS
+       select LEDS_CLASS
+       select LEDS_GPIO
+       help
+               IP5170 Digital Picture Frame board, 8005-1113, IP5K-BEV-0011-13 v1.3
+
+config IP5160DEV
+       bool "IP5160Dev_Ver1Dot1"
+       select UBICOM32_V3
+       help
+               Ubicom StreamEngine 5000 Development Board, IP5K-BDV-0004-11 v1.1
+
+config IP5160EVAL
+       bool "IP5160RGWEval_Ver2Rev2"
+       select UBICOM32_V3
+       help
+               Ubicom StreamEngine 5000 RGW Evaluation Board, IP5K-RGW-0004-11 v2.2
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/Makefile b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/Makefile
new file mode 100644 (file)
index 0000000..d02f339
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# arch/ubicom32/mach-ip5k/Makefile
+#      Makefile for boards which have an ip5k on them.
+#
+# (C) Copyright 2009, Ubicom, Inc.
+#
+# This file is part of the Ubicom32 Linux Kernel Port.
+#
+# The Ubicom32 Linux Kernel Port 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.
+#
+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+# see <http://www.gnu.org/licenses/>.
+#
+# Ubicom32 implementation derived from (with many thanks):
+#   arch/m68knommu
+#   arch/blackfin
+#   arch/parisc
+#
+
+obj-$(CONFIG_IP5170DPF)                += board-ip5170dpf.o
+obj-$(CONFIG_IP5160DEV)                += board-ip5160dev.o
+obj-$(CONFIG_IP5160EVAL)       += board-ip5160rgw.o
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5160dev.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5160dev.c
new file mode 100644 (file)
index 0000000..4fb130d
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * arch/ubicom32/mach-ip5k/board-ip5160dev.c
+ *   Platform initialization for ip5160dev board.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <asm/board.h>
+#include <asm/machdep.h>
+#ifdef CONFIG_SERIAL_UBI32_SERDES
+#include <asm/ubicom32suart.h>
+#endif
+
+/*
+ * Factory Default Button on the board at PXn
+ * TODO: This is just a placeholder and it needs to include proper header files
+ */
+struct ubicom32fdb_platform_data {
+       int             fdb_gpio;
+       bool            fdb_polarity;
+};
+
+static struct ubicom32fdb_platform_data ip5160dev_fdb_data = {
+       .fdb_gpio               = 0,
+       .fdb_polarity           = true,
+};
+
+static struct platform_device ip5160dev_fdb_device = {
+       .name   = "ubicom32fdb",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &ip5160dev_fdb_data,
+       },
+};
+
+#ifdef CONFIG_SERIAL_UBI32_SERDES
+static struct resource ip5160dev_ubicom32_suart_resources[] = {
+        {
+               .start  = RD,
+               .end    = RD,
+               .flags  = IORESOURCE_MEM,
+        },
+        {
+               .start  = PORT_OTHER_INT(RD),
+               .end    = PORT_OTHER_INT(RD),
+               .flags  = IORESOURCE_IRQ,
+        },
+        {
+               .start  = 240000000,
+               .end    = 240000000,
+               .flags  = UBICOM32_SUART_IORESOURCE_CLOCK,
+        },
+};
+
+static struct platform_device ip5160dev_ubicom32_suart_device = {
+       .name           = "ubicom32suart",
+       .id             = -1,
+        .num_resources  = ARRAY_SIZE(ip5160dev_ubicom32_suart_resources),
+        .resource       = ip5160dev_ubicom32_suart_resources,
+};
+#endif
+
+/*
+ * List of all devices in our system
+ */
+static struct platform_device *ip5160dev_devices[] __initdata = {
+#ifdef CONFIG_SERIAL_UBI32_SERDES
+       &ip5160dev_ubicom32_suart_device,
+#endif
+       &ip5160dev_fdb_device,
+};
+
+/*
+ * ip5160dev_init
+ *     Called to add the devices which we have on this board
+ */
+static int __init ip5160dev_init(void)
+{
+       ubi_gpio_init();
+       printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
+       platform_add_devices(ip5160dev_devices, ARRAY_SIZE(ip5160dev_devices));
+       return 0;
+}
+
+arch_initcall(ip5160dev_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5160rgw.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5160rgw.c
new file mode 100644 (file)
index 0000000..fb928f7
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * arch/ubicom32/mach-ip5k/board-ip5160rgw.c
+ *   Platform initialization for ip5160rgw board.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <asm/board.h>
+#include <asm/machdep.h>
+
+/*
+ * Factory Default Button on the board at PXn
+ * TODO: This is just a placeholder and it needs to include proper header files
+ */
+struct ubicom32fdb_platform_data {
+       int             fdb_gpio;
+       bool            fdb_polarity;
+};
+
+static struct ubicom32fdb_platform_data ip5160rgw_fdb_data = {
+       .fdb_gpio               = 0,
+       .fdb_polarity           = true,
+};
+
+static struct platform_device ip5160rgw_fdb_device = {
+       .name   = "ubicom32fdb",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &ip5160rgw_fdb_data,
+       },
+};
+
+/*
+ * List of all devices in our system
+ */
+static struct platform_device *ip5160rgw_devices[] __initdata = {
+       &ip5160rgw_fdb_device,
+};
+
+/*
+ * ip5160rgw_init
+ *     Called to add the devices which we have on this board
+ */
+static int __init ip5160rgw_init(void)
+{
+       ubi_gpio_init();
+       printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
+       platform_add_devices(ip5160rgw_devices, ARRAY_SIZE(ip5160rgw_devices));
+       return 0;
+}
+
+arch_initcall(ip5160rgw_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5170dpf.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip5k/board-ip5170dpf.c
new file mode 100644 (file)
index 0000000..ef04dca
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * arch/ubicom32/mach-ip5k/board-ip5170dpf.c
+ *   Platform initialization for ip5160dpf board.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+
+#include <linux/input.h>
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/ubicom32hid.h>
+#include <asm/vdc_tio.h>
+
+/*
+ * LEDs
+ *
+ * WLAN                        PD9     (Note this is shared with MISO, but we don't use it)
+ * WPS                 PD8
+ *
+ * TODO: check triggers, are they generic?
+ */
+static struct gpio_led ip5170dpf_gpio_leds[] = {
+       {
+               .name                   = "d31:green:WLAN1",
+               .default_trigger        = "WLAN1",
+               .gpio                   = GPIO_RD_9,
+               .active_low             = 1,
+       },
+       {
+               .name                   = "d30:green:WPS",
+               .default_trigger        = "WPS",
+               .gpio                   = GPIO_RD_8,
+               .active_low             = 1,
+       },
+};
+
+static struct gpio_led_platform_data ip5170dpf_gpio_led_platform_data = {
+       .num_leds       = 2,
+       .leds           = ip5170dpf_gpio_leds,
+};
+
+static struct platform_device ip5170dpf_gpio_leds_device = {
+       .name           = "leds-gpio",
+       .id             = -1,
+       .dev = {
+               .platform_data = &ip5170dpf_gpio_led_platform_data,
+       },
+};
+
+/*
+ * Backlight on the board PD0, hardware PWM
+ */
+static const struct ubicom32hid_button ip5170dpf_ubicom32hid_buttons[] = {
+       {
+               .type   = EV_KEY,
+               .code   = KEY_UP,
+               .bit    = 0,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_LEFT,
+               .bit    = 1,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_RIGHT,
+               .bit    = 2,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_DOWN,
+               .bit    = 3,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_ENTER,
+               .bit    = 4,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_MENU,
+               .bit    = 5,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_ESC,
+               .bit    = 7,
+       },
+};
+
+static const struct ubicom32hid_ir ip5170dpf_ubicom32hid_ircodes[] = {
+       {
+               .type           = EV_KEY,
+               .code           = KEY_UP,
+               .ir_code        = 0xF807916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_DOWN,
+               .ir_code        = 0xF20D916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_LEFT,
+               .ir_code        = 0xF609916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_RIGHT,
+               .ir_code        = 0xF40B916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_ENTER,
+               .ir_code        = 0xF50A916E
+       },
+       {       /* rotate */
+               .type           = EV_KEY,
+               .code           = KEY_FN_F1,
+               .ir_code        = 0xF906916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_MENU,
+               .ir_code        = 0xF708916E
+       },
+       {       /* font size */
+               .type           = EV_KEY,
+               .code           = KEY_FN_F2,
+               .ir_code        = 0xF30C916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_ESC,
+               .ir_code        = 0xF10E916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_VOLUMEUP,
+               .ir_code        = 0xF00F916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_VOLUMEDOWN,
+               .ir_code        = 0xED12916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_MUTE,
+               .ir_code        = 0xEA15916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_INFO,
+               .ir_code        = 0xEF10916E
+       },
+       {       /* Like */
+               .type           = EV_KEY,
+               .code           = KEY_FN_F3,
+               .ir_code        = 0xEE11916E
+       },
+       {       /* Dislike */
+               .type           = EV_KEY,
+               .code           = KEY_FN_F4,
+               .ir_code        = 0xEB14916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_POWER,
+               .ir_code        = 0xFD02916E
+       },
+};
+
+static struct ubicom32hid_platform_data ip5170dpf_ubicom32hid_platform_data = {
+       .gpio_reset             = GPIO_RA_4,
+       .gpio_reset_polarity    = 0,
+       .type                   = UBICOM32HID_BL_TYPE_BINARY,
+       .invert                 = 0,
+       .default_intensity      = 1,
+       .buttons                = ip5170dpf_ubicom32hid_buttons,
+       .nbuttons               = ARRAY_SIZE(ip5170dpf_ubicom32hid_buttons),
+       .ircodes                = ip5170dpf_ubicom32hid_ircodes,
+       .nircodes               = ARRAY_SIZE(ip5170dpf_ubicom32hid_ircodes),
+};
+
+/*
+ * Devices on the I2C bus
+ */
+static struct i2c_board_info __initdata ip5170dpf_i2c_board_info[] = {
+       /*
+        * U24, ubicom32hid
+        */
+       {
+               .type           = "ubicom32hid",
+               .addr           = 0x08,
+               .platform_data  = &ip5170dpf_ubicom32hid_platform_data,
+       },
+
+       /*
+        * U14, CS4350 DAC, address 0x4B
+        */
+};
+
+/*
+ * I2C bus on the board, SDA PF13, SCL PF14
+ */
+static struct i2c_gpio_platform_data ip5170dpf_i2c_data = {
+       .sda_pin                = GPIO_RF_13,
+       .scl_pin                = GPIO_RF_14,
+       .sda_is_open_drain      = 0,
+       .scl_is_open_drain      = 0,
+       .scl_is_output_only     = 1,
+       .udelay                 = 5,
+};
+
+static struct platform_device ip5170dpf_i2c_device = {
+       .name   = "i2c-gpio",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &ip5170dpf_i2c_data,
+       },
+};
+
+/*
+ * List of all devices in our system
+ */
+static struct platform_device *ip5170dpf_devices[] __initdata = {
+       &ip5170dpf_i2c_device,
+       &ip5170dpf_gpio_leds_device,
+};
+
+/*
+ * ip5170dpf_init
+ *     Called to add the devices which we have on this board
+ */
+static int __init ip5170dpf_init(void)
+{
+       ubi_gpio_init();
+
+       vdc_tio_init();
+
+       printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
+       platform_add_devices(ip5170dpf_devices, ARRAY_SIZE(ip5170dpf_devices));
+
+       printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
+       i2c_register_board_info(0, ip5170dpf_i2c_board_info, ARRAY_SIZE(ip5170dpf_i2c_board_info));
+
+       return 0;
+}
+
+arch_initcall(ip5170dpf_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/Kconfig b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/Kconfig
new file mode 100644 (file)
index 0000000..8a7f2f1
--- /dev/null
@@ -0,0 +1,205 @@
+config IP7145DPF
+       bool "IP7145DPF"
+       select UBICOM32_V4
+       select UBICOM_INPUT
+       select UBICOM_INPUT_I2C
+       select RTC_CLASS
+       select RTC_DRV_S35390A
+       select I2C
+       select I2C_GPIO
+       select GPIO_PCA953X
+       select FB
+       select FB_UBICOM32
+       select LCD_CLASS_DEVICE
+       select LCD_UBICOM32POWER
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       select BACKLIGHT_UBICOM32
+       select SND_UBI32
+       select MMC_UBICOM32
+       select MMC
+       select MMC_BLOCK
+       help
+               IP7145 Digital Picture Frame reference design, supports:
+                       8007-0410 v1.0
+
+config IP7160RGW
+       bool "IP7160RGW"
+       select UBICOM32_V4
+       select UBICOM_INPUT
+       select NEW_LEDS
+       select LEDS_CLASS
+       select LEDS_GPIO
+       select SPI
+       select SPI_UBICOM32_GPIO
+       select VLAN_8021Q
+       select UBICOM_SWITCH
+       select UBICOM_SWITCH_BCM539X
+       help
+               Ubicom IP7160 RGW Eval, supports:
+                       8007-0110 v1.0
+                       8007-0111 v1.1
+                       8007-0112 v1.2
+
+config IP7160RGWLCD
+       bool "IP7160RGWLCD"
+       select UBICOM32_V4
+       select UBICOM_INPUT
+       select NEW_LEDS
+       select LEDS_CLASS
+       select LEDS_GPIO
+       select SPI
+       select SPI_UBICOM32_GPIO
+       select VLAN_8021Q
+       select UBICOM_SWITCH
+       select UBICOM_SWITCH_BCM539X
+       select INPUT_TOUCHSCREEN
+       select TOUCHSCREEN_TSC2007
+       select FB
+       select FB_UBICOM32_VIRTUAL
+       select I2C
+       select I2C_GPIO
+       help
+               Ubicom IP7160 RGW Eval, supports:
+                       8007-0112 v1.2 + 8007-1410 v1.0
+
+               With Ubicom LCD Adapter
+                       8007-0920 v2.0
+                       8007-0921 v2.1
+
+
+config IP7160BRINGUP
+       bool "IP7160BRINGUP"
+       select UBICOM32_V4
+       select NEW_LEDS
+       select LEDS_CLASS
+       select LEDS_GPIO
+       help
+               Ubicom IP7160 Bringup, supports:
+                       8007-0010 v1.0
+
+config IP7160DPF
+       bool "IP7160DPF"
+       select UBICOM32_V4
+       select I2C
+       select I2C_GPIO
+       select FB
+       select FB_UBICOM32
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       select SND_UBI32
+       select SND_UBI32_AUDIO_CS4350
+       select UBICOM_HID
+       help
+               IP7160 Digital Picture Frame board, supports:
+                       8007-0211 Rev 1.1
+
+config IP7500MODULE
+       bool "IP7500MODULE"
+       select UBICOM32_V4
+       help
+               Ubicom IP7500 CPU Module board, supports:
+                       8007-0510  v1.0
+                       8007-0510A v1.0
+
+               Please see ip7500module.c for more details.
+
+config IP7500AV
+       bool "IP7500AV"
+       select UBICOM32_V4
+       select I2C
+       select I2C_GPIO
+       select SND_UBI32
+       select SND_UBI32_AUDIO_CS4384
+       select FB
+       select FB_UBICOM32
+       help
+               Ubicom IP7500 Audio Video board, supports:
+                       8007-0810  v1.0
+
+               With Ubicom IP7500 CPU Module board:
+                       8007-0510  v1.0 -or-
+                       8007-0510A v1.0
+
+               Please see ip7500av.c for more details.
+
+config IP7500MEDIA
+       bool "IP7500MEDIA"
+       select UBICOM32_V4
+       select UBICOM_INPUT_I2C
+       select RTC_CLASS
+       select RTC_DRV_S35390A
+       select I2C
+       select I2C_GPIO
+       select GPIO_PCA953X
+       select FB
+       select FB_UBICOM32
+       select FB_UBICOM32_VIRTUAL
+       select FB_UBICOM32_VIRTUAL_NOAUTO
+       select LCD_CLASS_DEVICE
+       select LCD_UBICOM32POWER
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       select BACKLIGHT_UBICOM32
+       select INPUT_TOUCHSCREEN
+       select TOUCHSCREEN_TSC2007
+       select SOUND
+       select SND
+       select SND_UBI32
+       select SND_UBI32_AUDIO_CS4350
+       select MMC_UBICOM32
+       select MMC
+       select MMC_BLOCK
+       help
+               IP7500 Media Board w/ IP7500 CPU Module board, supports:
+                       8007-0610 v1.0 w/ 8007-0510 v1.0
+                       8007-0610 v1.0 w/ 8007-0510 v1.0 NOPHY
+                       8007-0610 v1.0 w/ 8007-0511 v1.1 NOPHY
+
+               Also supports optional LCD Adapter board:
+                       8006-0920 v2.0
+                       8006-0921 v2.1
+
+               Please see ip7500media.c for more details.
+
+config IP7500WSPKR
+       bool "IP7500WSPKR"
+       select UBICOM32_V4
+       select I2C
+       select I2C_GPIO
+       select SOUND
+       select SND
+       select SND_UBI32
+       select SND_UBI32_AUDIO_CS4350
+       help
+               IP7500 Wireless Speaker Board, supports:
+                       8007-1210 v1.0
+
+               Please see ip7500wspkr.c for more details.
+
+config IP7500IAP
+       bool "IP7500IAP"
+       select UBICOM32_V4
+       select I2C
+       select I2C_GPIO
+       select FB
+       select FB_UBICOM32_VIRTUAL
+       select SOUND
+       select SND
+       select SND_UBI32
+       select SND_UBI32_AUDIO_CS4350
+       select RTC_CLASS
+       select RTC_DRV_S35390A
+       select INPUT_TOUCHSCREEN
+       select TOUCHSCREEN_TSC2007
+       select BACKLIGHT_LCD_SUPPORT
+       select BACKLIGHT_CLASS_DEVICE
+       select BACKLIGHT_UBICOM32
+       help
+               IP7500 Internet Audio Player, supports:
+                       8007-1110 v1.0
+
+               Please see ip7500iap.c for more details.
+
+
+               Please see ip7500media.c for more details.
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/Makefile b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/Makefile
new file mode 100644 (file)
index 0000000..f9df397
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# arch/ubicom32/mach-ip7k/Makefile
+#      Makefile for ip7k based boards.
+#
+# (C) Copyright 2009, Ubicom, Inc.
+#
+# This file is part of the Ubicom32 Linux Kernel Port.
+#
+# The Ubicom32 Linux Kernel Port 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.
+#
+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+# see <http://www.gnu.org/licenses/>.
+#
+# Ubicom32 implementation derived from (with many thanks):
+#   arch/m68knommu
+#   arch/blackfin
+#   arch/parisc
+#
+
+obj-$(CONFIG_IP7145DPF)                += board-ip7145dpf.o
+obj-$(CONFIG_IP7160RGW)                += board-ip7160rgw.o
+obj-$(CONFIG_IP7160RGWLCD)     += board-ip7160rgw.o
+obj-$(CONFIG_IP7160BRINGUP)    += board-ip7160bringup.o
+obj-$(CONFIG_IP7160DPF)                += board-ip7160dpf.o
+obj-$(CONFIG_IP7500MODULE)     += board-ip7500module.o
+obj-$(CONFIG_IP7500MEDIA)      += board-ip7500media.o
+obj-$(CONFIG_IP7500AV)         += board-ip7500av.o
+obj-$(CONFIG_IP7500WSPKR)      += board-ip7500wspkr.o
+obj-$(CONFIG_IP7500IAP)                += board-ip7500iap.o
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7145dpf.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7145dpf.c
new file mode 100644 (file)
index 0000000..d3348d3
--- /dev/null
@@ -0,0 +1,715 @@
+/*
+ * arch/ubicom32/mach-ip7k/board-ip7145dpf.c
+ *   Board file for IP7145DPF, rev 1.0, P/N 8007-0410
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <linux/input.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/i2c/pca953x.h>
+
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/ubicom32input.h>
+#include <asm/ubicom32input_i2c.h>
+#include <asm/ubicom32bl.h>
+#include <asm/ubicom32lcdpower.h>
+#include <asm/vdc_tio.h>
+
+#include <asm/ubicom32sd.h>
+#include <asm/sd_tio.h>
+#include <asm/devtree.h>
+#include <asm/audio.h>
+
+#include <asm/ring_tio.h>
+
+/******************************************************************************
+ * SD/IO Port F (Slot 1) platform data
+ */
+static struct resource ip7145dpf_portf_sd_resources[] = {
+       /*
+        * Send IRQ
+        */
+       [0] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Receive IRQ
+        */
+       [1] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Memory Mapped Registers
+        */
+       [2] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct ubicom32sd_card ip7145dpf_portf_sd_cards[] = {
+       [0] = {
+               .pin_wp         = IP7145DPF_IOB0,
+               .wp_polarity    = 1,
+               .pin_pwr        = IP7145DPF_IOB4,
+               .pin_cd         = GPIO_RA_4,
+       },
+       [1] = {
+               .pin_wp         = IP7145DPF_IOB1,
+               .wp_polarity    = 1,
+               .pin_pwr        = IP7145DPF_IOB5,
+               .pin_cd         = GPIO_RA_6,
+       },
+};
+
+static struct ubicom32sd_platform_data ip7145dpf_portf_sd_platform_data = {
+       .ncards         = 2,
+       .cards          = ip7145dpf_portf_sd_cards,
+};
+
+static struct platform_device ip7145dpf_portf_sd_device = {
+       .name           = "ubicom32sd",
+       .id             = 0,
+       .resource       = ip7145dpf_portf_sd_resources,
+       .num_resources  = ARRAY_SIZE(ip7145dpf_portf_sd_resources),
+       .dev            = {
+                       .platform_data = &ip7145dpf_portf_sd_platform_data,
+       },
+
+};
+
+/*
+ * ip7145dpf_portf_sd_init
+ */
+static void ip7145dpf_portf_sd_init(void)
+{
+       /*
+        * Check the device tree for the sd_tio
+        */
+       struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portf_sd");
+       if (!sd_node) {
+               printk(KERN_INFO "PortF SDTIO not found\n");
+               return;
+       }
+
+       /*
+        * Fill in the resources and platform data from devtree information
+        */
+       ip7145dpf_portf_sd_resources[0].start = sd_node->dn.sendirq;
+       ip7145dpf_portf_sd_resources[1].start = sd_node->dn.recvirq;
+       ip7145dpf_portf_sd_resources[2].start = (u32_t)&(sd_node->regs);
+       ip7145dpf_portf_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs);
+
+       platform_device_register(&ip7145dpf_portf_sd_device);
+}
+
+/******************************************************************************
+ * SD/IO Port B (Slot 2) platform data
+ */
+static struct resource ip7145dpf_portb_sd_resources[] = {
+       /*
+        * Send IRQ
+        */
+       [0] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Receive IRQ
+        */
+       [1] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Memory Mapped Registers
+        */
+       [2] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct ubicom32sd_card ip7145dpf_portb_sd_cards[] = {
+       [0] = {
+               .pin_wp         = IP7145DPF_IOB2,
+               .wp_polarity    = 1,
+               .pin_pwr        = IP7145DPF_IOB6,
+               .pin_cd         = IP7145DPF_IOB3,
+       },
+};
+
+static struct ubicom32sd_platform_data ip7145dpf_portb_sd_platform_data = {
+       .ncards         = 1,
+       .cards          = ip7145dpf_portb_sd_cards,
+};
+
+static struct platform_device ip7145dpf_portb_sd_device = {
+       .name           = "ubicom32sd",
+       .id             = 1,
+       .resource       = ip7145dpf_portb_sd_resources,
+       .num_resources  = ARRAY_SIZE(ip7145dpf_portb_sd_resources),
+       .dev            = {
+                       .platform_data = &ip7145dpf_portb_sd_platform_data,
+       },
+
+};
+
+/*
+ * ip7145dpf_portb_sd_init
+ */
+static void ip7145dpf_portb_sd_init(void)
+{
+       /*
+        * Check the device tree for the sd_tio
+        */
+       struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portb_sd");
+       if (!sd_node) {
+               printk(KERN_INFO "PortB SDTIO not found\n");
+               return;
+       }
+
+       /*
+        * Fill in the resources and platform data from devtree information
+        */
+       ip7145dpf_portb_sd_resources[0].start = sd_node->dn.sendirq;
+       ip7145dpf_portb_sd_resources[1].start = sd_node->dn.recvirq;
+       ip7145dpf_portb_sd_resources[2].start = (u32_t)&(sd_node->regs);
+       ip7145dpf_portb_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs);
+
+       platform_device_register(&ip7145dpf_portb_sd_device);
+}
+
+
+#ifdef IP7145DPF_USE_MMC_SPI
+/******************************************************************************
+ * SPI over GPIO (MMC_SPI)
+ */
+#include <linux/spi/spi.h>
+#include <linux/spi/mmc_spi.h>
+#include <linux/mmc/host.h>
+#include <asm/ubicom32-spi-gpio.h>
+
+#define MMC_CS GPIO_RF_5       // PF5 D3
+#define MMC_CD GPIO_RA_4       // PA4 CD
+#define MMC_WP IP7145DPF_IOB0  // IOB0 WP
+#define MMC_PWR        IP7145DPF_IOB4  // IOB4 PWR
+
+/*
+ * SPI bus over GPIO (for SD card)
+ */
+static struct ubicom32_spi_gpio_platform_data ip7145dpf_spi_gpio_data = {
+       .pin_mosi       = GPIO_RF_0,    // PF0 CMD
+       .pin_miso       = GPIO_RF_2,    // PF2 D0
+       .pin_clk        = GPIO_RF_1,    // PF1 CLK
+       .bus_num        = 0,            // We'll call this SPI bus 0
+       .num_chipselect = 1,            // only one device on this SPI bus
+};
+
+static struct platform_device ip7145dpf_spi_gpio_device = {
+       .name   = "ubicom32-spi-gpio",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &ip7145dpf_spi_gpio_data,
+       },
+};
+
+/*
+ * ip7145dpf_mmc_spi_setpower_slot_a
+ *     Set the power state for slot A
+ */
+static void ip7145dpf_mmc_spi_setpower_slot_a(struct device *dev, unsigned int vdd)
+{
+       struct mmc_spi_platform_data *pd = dev->platform_data;
+
+       /*
+        * Power is inverted, we could tell the IOB to do it, but it's cleaner this way.
+        */
+       if ((1 << vdd) & pd->ocr_mask) {
+               gpio_set_value(MMC_PWR, 0);
+               return;
+       }
+       gpio_set_value(MMC_PWR, 1);
+}
+
+/*
+ * ip7145dpf_mmc_spi_get_cd_slot_a
+ *     Get the CD bit for slot A
+ */
+static int ip7145dpf_mmc_spi_get_cd_slot_a(struct device *dev)
+{
+       /*
+        * Note that the sense of the GPIO is inverted
+        */
+       return !gpio_get_value(MMC_CD);
+}
+
+/*
+ * ip7145dpf_mmc_spi_get_ro_slot_a
+ *     Get the WP bit for slot A
+ */
+static int ip7145dpf_mmc_spi_get_ro_slot_a(struct device *dev)
+{
+       /*
+        * Note that the sense of the GPIO is inverted, we could tell the IOB to do it, but
+        * it's clearer this way.
+        */
+       return !gpio_get_value(MMC_WP);
+}
+
+/*
+ * ip7145dpf_mmc_spi_exit_slot_a
+ *     Free the appropriate GPIOs for slot A SD slot.
+ */
+static void ip7145dpf_mmc_spi_exit_slot_a(struct device *dev, void *appdata)
+{
+       gpio_free(MMC_CD);
+       gpio_free(MMC_CS);
+       gpio_free(MMC_WP);
+       gpio_free(MMC_PWR);
+       platform_device_unregister(&ip7145dpf_spi_gpio_device);
+}
+
+/*
+ * ip7145dpf_mmc_spi_init_slot_a
+ *     Allocate the appropriate GPIOs for slot A SD slot.
+ *     WP is on IOB0, CD is PA4, CS is on PF5
+ *     TODO: make CD an interrupt
+ */
+static int ip7145dpf_mmc_spi_init_slot_a(void)
+{
+       int ret = gpio_request(MMC_CD, "mmc-a-cd");
+       if (ret) {
+               printk(KERN_ERR "%s: could not request mmc-a-cd pin\n", __FUNCTION__);
+               return -ENOSYS;
+       }
+       gpio_direction_input(MMC_CD);
+
+       ret = gpio_request(MMC_CS, "mmc-a-cs");
+       if (ret) {
+               printk(KERN_ERR "%s: could not request mmc-a-cs pin\n", __FUNCTION__);
+               goto no_cs;
+       }
+       gpio_direction_output(MMC_CS, 0);
+
+       ret = gpio_request(MMC_WP, "mmc-a-wp");
+       if (ret) {
+               printk(KERN_ERR "%s: could not request mmc-a-wp pin\n", __FUNCTION__);
+               goto no_wp;
+       }
+       gpio_direction_input(MMC_WP);
+
+       /*
+        * Start off with power off
+        */
+       ret = gpio_request(MMC_PWR, "mmc-a-pwr");
+       if (ret) {
+               printk(KERN_ERR "%s: could not request mmc-a-pwr pin\n", __FUNCTION__);
+               goto no_pwr;
+       }
+       ret = gpio_direction_output(MMC_PWR, 1);
+
+       return 0;
+
+no_pwr:
+       gpio_free(MMC_WP);
+
+no_wp:
+       gpio_free(MMC_CS);
+
+no_cs:
+       gpio_free(MMC_CD);
+       return -ENOSYS;
+}
+
+/*
+ * MMC_SPI driver (currently bitbang)
+ */
+static struct mmc_spi_platform_data ip7145dpf_mmc_platform_data = {
+       .ocr_mask       = MMC_VDD_33_34,
+       .exit           = ip7145dpf_mmc_spi_exit_slot_a,
+       .get_ro         = ip7145dpf_mmc_spi_get_ro_slot_a,
+       .get_cd         = ip7145dpf_mmc_spi_get_cd_slot_a,
+
+       .setpower       = ip7145dpf_mmc_spi_setpower_slot_a,
+       .powerup_msecs  = 500,
+
+       .detect_delay   = 100,
+
+       .caps           = MMC_CAP_NEEDS_POLL,
+};
+
+static struct ubicom32_spi_gpio_controller_data ip7145dpf_mmc_controller_data = {
+       .pin_cs =  MMC_CS,
+};
+
+static struct spi_board_info ip7145dpf_spi_board_info[] = {
+       {
+               .modalias = "mmc_spi",
+               .bus_num = 0,
+               .chip_select = 0,
+               .max_speed_hz = 2000000,
+               .platform_data = &ip7145dpf_mmc_platform_data,
+               .controller_data = &ip7145dpf_mmc_controller_data,
+       }
+};
+#endif /* IP7145DPF_USE_MMC_SPI */
+
+/*
+ * ip7145dpf_u72_setup
+ *     Called by I2C to tell us that u72 is setup.
+ *
+ * This function is called by I2C to tell us that u72 has been setup.  All
+ * devices which rely on this chip being initialized (or even present) need to
+ * be initialized in this function otherwise they may get initialized too early.
+ *
+ * Currently the only device depending on u72 is the SPI
+ */
+static int __init ip7145dpf_u72_setup(struct i2c_client *client, unsigned gpio, unsigned ngpio, void *context)
+{
+#ifdef IP7145DPF_USE_MMC_SPI
+       if (ip7145dpf_mmc_spi_init_slot_a()) {
+               printk(KERN_ERR "%s: could not request mmc resources\n", __FUNCTION__);
+       } else {
+               printk(KERN_INFO "%s: registering SPI resources\n", __FUNCTION__);
+               spi_register_board_info(ip7145dpf_spi_board_info, ARRAY_SIZE(ip7145dpf_spi_board_info));
+               platform_device_register(&ip7145dpf_spi_gpio_device);
+       }
+#else
+       /*
+        * Initialize the Port F/Port B SD slots
+        */
+       ip7145dpf_portf_sd_init();
+       ip7145dpf_portb_sd_init();
+#endif
+       return 0;
+}
+
+/******************************************************************************
+ * LCD VGH on the board at PE6
+ */
+static struct ubicom32lcdpower_platform_data ip7145dpf_lcdpower_data = {
+       .vgh_gpio               = GPIO_RE_6,
+       .vgh_polarity           = true,
+};
+
+static struct platform_device ip7145dpf_lcdpower_device = {
+       .name   = "ubicom32lcdpower",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &ip7145dpf_lcdpower_data,
+       },
+};
+
+/******************************************************************************
+ * Backlight on the board PD0, hardware PWM
+ */
+static struct ubicom32bl_platform_data ip7145dpf_backlight_data = {
+       .type                   = UBICOM32BL_TYPE_PWM,
+       .pwm_channel            = 2,
+       .pwm_prescale           = 15,
+       .pwm_period             = 60,
+       .default_intensity      = 0x80,
+};
+
+static struct platform_device ip7145dpf_backlight_device = {
+       .name   = "ubicom32bl",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &ip7145dpf_backlight_data,
+       },
+};
+
+/******************************************************************************
+ * Ubicom32Input on I2C, U48 MAX7310, address 0x18, 8 bits
+ */
+static struct ubicom32input_i2c_button ip7145dpf_ubicom32input_i2c_u48_buttons[] = {
+       {
+               .type           = EV_KEY,
+               .code           = KEY_UP,
+               .bit            = 0,
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_LEFT,
+               .bit            = 1,
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_RIGHT,
+               .bit            = 2,
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_DOWN,
+               .bit            = 3,
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_ENTER,
+               .bit            = 4,
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_MENU,
+               .bit            = 5,
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_ESC,
+               .bit            = 6,
+               .active_low     = 1,
+       },
+};
+
+static struct ubicom32input_i2c_platform_data ip7145dpf_ubicom32input_i2c_u48_platform_data = {
+       .buttons        = ip7145dpf_ubicom32input_i2c_u48_buttons,
+       .nbuttons       = ARRAY_SIZE(ip7145dpf_ubicom32input_i2c_u48_buttons),
+       .name           = "Ubicom32 Input I2C U48",
+};
+
+/******************************************************************************
+ * Additional GPIO chips
+ */
+static struct pca953x_platform_data ip7145dpf_gpio_u72_platform_data = {
+       .gpio_base = IP7145DPF_U72_BASE,
+       .setup = ip7145dpf_u72_setup,
+};
+
+/******************************************************************************
+ * Devices on the I2C bus
+ */
+static struct i2c_board_info __initdata ip7145dpf_i2c_board_info[] = {
+       /*
+        * U51, S35390A RTC, address 0x30
+        */
+       {
+               .type           = "s35390a",
+               .addr           = 0x30,
+       },
+
+       /*
+        * U48, MAX7310 IO expander, 8 bits, address 0x18
+        */
+       {
+               .type           = "ubicom32in_max7310",
+               .addr           = 0x18,
+               .platform_data  = &ip7145dpf_ubicom32input_i2c_u48_platform_data,
+       },
+
+       /*
+        * U72, MAX7310 IOB expander, 8 bits, address 0x19
+        */
+       {
+               .type           = "max7310",
+               .addr           = 0x19,
+               .platform_data  = &ip7145dpf_gpio_u72_platform_data,
+       },
+};
+
+/*
+ * I2C bus on the board, SDA PE1, SCL PE2
+ */
+static struct i2c_gpio_platform_data ip7145dpf_i2c_data = {
+       .sda_pin                = GPIO_RE_1,
+       .scl_pin                = GPIO_RE_2,
+       .sda_is_open_drain      = 0,
+       .scl_is_open_drain      = 0,
+};
+
+static struct platform_device ip7145dpf_i2c_device = {
+       .name   = "i2c-gpio",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &ip7145dpf_i2c_data,
+       },
+};
+
+/******************************************************************************
+ * Use ubicom32input driver to monitor the various pushbuttons on this board.
+ *
+ * WPS                 PF12
+ * FACT_DEFAULT                PF13
+ * POWER               PE4
+ *
+ * Not sutable for the keypad buttons since those run on I2C GPIO.  The polling
+ * of ubicom32input would seem to be excessive for this.
+ *
+ * TODO: pick some ubicom understood EV_xxx define for WPS and Fact Default
+ */
+static struct ubicom32input_button ip7145dpf_ubicom32input_buttons[] = {
+       {
+               .type           = EV_KEY,
+               .code           = KEY_FN_F1,
+               .gpio           = GPIO_RF_12,
+               .desc           = "WPS",
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_FN_F2,
+               .gpio           = GPIO_RF_13,
+               .desc           = "Factory Default",
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_POWER,
+               .gpio           = GPIO_RE_4,
+               .desc           = "Power",
+               .active_low     = 1,
+       },
+};
+
+static struct ubicom32input_platform_data ip7145dpf_ubicom32input_data = {
+       .buttons        = ip7145dpf_ubicom32input_buttons,
+       .nbuttons       = ARRAY_SIZE(ip7145dpf_ubicom32input_buttons),
+};
+
+static struct platform_device ip7145dpf_ubicom32input_device = {
+       .name   = "ubicom32input",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &ip7145dpf_ubicom32input_data,
+       },
+};
+
+/*
+ * List of all devices in our system
+ */
+static struct platform_device *ip7145dpf_devices[] __initdata = {
+       &ip7145dpf_i2c_device,
+       &ip7145dpf_lcdpower_device,
+       &ip7145dpf_backlight_device,
+       &ip7145dpf_ubicom32input_device,
+};
+
+/*
+ * ip7145dpf_power_off
+ *     Called to turn the power off for this board
+ */
+static void ip7145dpf_power_off(void)
+{
+       gpio_set_value(GPIO_RE_5, 0);
+}
+
+/*
+ * ip7145dpf_init
+ *     Called to add the devices which we have on this board
+ */
+static int __init ip7145dpf_init(void)
+{
+       int ret;
+       struct platform_device *audio_dev;
+
+       ubi_gpio_init();
+
+#ifdef CONFIG_UIO_UBICOM32RING
+       ring_tio_init("decoder_ring");
+#endif
+
+       /*
+        * Start up the video driver first
+        */
+       vdc_tio_init();
+
+       /*
+        * Take over holding of the power from the system
+        */
+       ret = gpio_request(GPIO_RE_5, "power_hold");
+       if (ret) {
+               printk(KERN_ERR "%s: could not request power hold GPIO\n", __FUNCTION__);
+       }
+       gpio_direction_output(GPIO_RE_5, 1);
+       mach_power_off = ip7145dpf_power_off;
+
+       /*
+        * USB SEL_HOST_USB line
+        */
+       ret = gpio_request(GPIO_RF_11, "SEL_HOST_USB");
+       if (ret) {
+               printk(KERN_ERR "%s: could not request SEL_HOST_USB GPIO\n", __FUNCTION__);
+       }
+       gpio_direction_output(GPIO_RF_11, 0);
+
+       /*
+        * Setup audio
+        */
+       audio_dev = audio_device_alloc("snd-ubi32-generic", "audio", "audio-i2sout", 0);
+       if (audio_dev) {
+               platform_device_register(audio_dev);
+       }
+
+       /*
+        * Register all of the devices we have on this board
+        */
+       printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
+       platform_add_devices(ip7145dpf_devices, ARRAY_SIZE(ip7145dpf_devices));
+
+       /*
+        * Register all of the devices which sit on the I2C bus
+        */
+       printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
+       i2c_register_board_info(0, ip7145dpf_i2c_board_info, ARRAY_SIZE(ip7145dpf_i2c_board_info));
+
+       /*
+        * We have to initialize the SPI after the I2C IOB gets setup. SPI is initialized in
+        * ip7145dpf_u72_setup
+        */
+
+       return 0;
+}
+
+arch_initcall(ip7145dpf_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160bringup.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160bringup.c
new file mode 100644 (file)
index 0000000..2527d8d
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * arch/ubicom32/mach-ip7k/board-ip7160bringup.c
+ *   Support for the IP7160 bringup board.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/ubicom32input.h>
+
+#ifdef CONFIG_SERIAL_UBI32_SERDES
+#include <asm/ubicom32suart.h>
+#endif
+
+/*
+ * Use ubicom32input driver to monitor the various pushbuttons on this board.
+ *
+ * WPS                 PD5
+ * FACT_DEFAULT                PD6
+ *
+ * TODO: pick some ubicom understood EV_xxx define for WPS and Fact Default
+ */
+static struct ubicom32input_button ip7160bringup_ubicom32input_buttons[] = {
+       {
+               .type           = EV_KEY,
+               .code           = KEY_FN_F1,
+               .gpio           = GPIO_RD_5,
+               .desc           = "WPS",
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_FN_F2,
+               .gpio           = GPIO_RD_6,
+               .desc           = "Factory Default",
+               .active_low     = 1,
+       },
+};
+
+static struct ubicom32input_platform_data ip7160bringup_ubicom32input_data = {
+       .buttons        = ip7160bringup_ubicom32input_buttons,
+       .nbuttons       = ARRAY_SIZE(ip7160bringup_ubicom32input_buttons),
+};
+
+static struct platform_device ip7160bringup_ubicom32input_device = {
+       .name   = "ubicom32input",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &ip7160bringup_ubicom32input_data,
+       },
+};
+
+#ifdef CONFIG_SERIAL_UBI32_SERDES
+static struct resource ip7160bringup_ubicom32_suart_resources[] = {
+       {
+               .start  = RE,
+               .end    = RE,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = PORT_OTHER_INT(RE),
+               .end    = PORT_OTHER_INT(RE),
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = 250000000,
+               .end    = 250000000,
+               .flags  = UBICOM32_SUART_IORESOURCE_CLOCK,
+       },
+};
+
+static struct platform_device ip7160bringup_ubicom32_suart_device = {
+       .name           = "ubicom32suart",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(ip7160bringup_ubicom32_suart_resources),
+       .resource       = ip7160bringup_ubicom32_suart_resources,
+};
+#endif
+
+/*
+ * List of all devices in our system
+ */
+static struct platform_device *ip7160bringup_devices[] __initdata = {
+#ifdef CONFIG_SERIAL_UBI32_SERDES
+       &ip7160bringup_ubicom32_suart_device,
+#endif
+       &ip7160bringup_ubicom32input_device,
+};
+
+/*
+ * ip7160bringup_init
+ *     Called to add the devices which we have on this board
+ */
+static int __init ip7160bringup_init(void)
+{
+       board_init();
+
+       ubi_gpio_init();
+
+       printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
+       platform_add_devices(ip7160bringup_devices, ARRAY_SIZE(ip7160bringup_devices));
+
+       return 0;
+}
+
+arch_initcall(ip7160bringup_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160dpf.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160dpf.c
new file mode 100644 (file)
index 0000000..7f4e4f3
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * arch/ubicom32/mach-ip7k/board-ip7160dpf.c
+ *   Platform initialization for ip7160dpf board.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+
+#include <linux/input.h>
+
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/ubicom32hid.h>
+#include <asm/vdc_tio.h>
+#include <asm/audio.h>
+
+/*
+ * Backlight on the board PD0, hardware PWM
+ */
+static const struct ubicom32hid_button ip7160dpf_ubicom32hid_buttons[] = {
+       {
+               .type   = EV_KEY,
+               .code   = KEY_UP,
+               .bit    = 0,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_LEFT,
+               .bit    = 1,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_RIGHT,
+               .bit    = 2,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_DOWN,
+               .bit    = 3,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_ENTER,
+               .bit    = 4,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_MENU,
+               .bit    = 5,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_ESC,
+               .bit    = 7,
+       },
+};
+
+static const struct ubicom32hid_ir ip7160dpf_ubicom32hid_ircodes[] = {
+       {
+               .type           = EV_KEY,
+               .code           = KEY_UP,
+               .ir_code        = 0xF807916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_DOWN,
+               .ir_code        = 0xF20D916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_LEFT,
+               .ir_code        = 0xF609916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_RIGHT,
+               .ir_code        = 0xF40B916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_ENTER,
+               .ir_code        = 0xF50A916E
+       },
+       {       /* rotate */
+               .type           = EV_KEY,
+               .code           = KEY_FN_F1,
+               .ir_code        = 0xF906916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_MENU,
+               .ir_code        = 0xF708916E
+       },
+       {       /* font size */
+               .type           = EV_KEY,
+               .code           = KEY_FN_F2,
+               .ir_code        = 0xF30C916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_ESC,
+               .ir_code        = 0xF10E916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_VOLUMEUP,
+               .ir_code        = 0xF00F916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_VOLUMEDOWN,
+               .ir_code        = 0xED12916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_MUTE,
+               .ir_code        = 0xEA15916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_INFO,
+               .ir_code        = 0xEF10916E
+       },
+       {       /* Like */
+               .type           = EV_KEY,
+               .code           = KEY_FN_F3,
+               .ir_code        = 0xEE11916E
+       },
+       {       /* Dislike */
+               .type           = EV_KEY,
+               .code           = KEY_FN_F4,
+               .ir_code        = 0xEB14916E
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_POWER,
+               .ir_code        = 0xFD02916E
+       },
+};
+
+static struct ubicom32hid_platform_data ip7160dpf_ubicom32hid_platform_data = {
+       .gpio_reset             = GPIO_RI_5,
+       .gpio_reset_polarity    = 0,
+       .type                   = UBICOM32HID_BL_TYPE_PWM,
+       .invert                 = 0,
+       .default_intensity      = 128,
+       .buttons                = ip7160dpf_ubicom32hid_buttons,
+       .nbuttons               = ARRAY_SIZE(ip7160dpf_ubicom32hid_buttons),
+       .ircodes                = ip7160dpf_ubicom32hid_ircodes,
+       .nircodes               = ARRAY_SIZE(ip7160dpf_ubicom32hid_ircodes),
+};
+
+/*
+ * Devices on the I2C bus
+ *     This board has a "bus 2" which is isolated from the main bus by U47
+ *     and pin RI0.  It should be safe to always enable bus 2 by setting
+ *     RI0 to low, however, it should be noted that on all existing configurations
+ *     of this board, U49 and U51 are not populated.
+ */
+static struct i2c_board_info __initdata ip7160dpf_i2c_board_info[] = {
+       /*
+        * U37, CS4350 DAC, address 0x4B, bus 2
+        *      THIS ENTRY MUST BE FIRST
+        */
+       {
+               .type           = "cs4350",
+               .addr           = 0x4B,
+       }
+
+       /*
+        * U24, ubicom32hid
+        */
+       {
+               .type           = "ubicom32hid",
+               .addr           = 0x08,
+               .platform_data  = &ip7160dpf_ubicom32hid_platform_data,
+       },
+
+       /*
+        * U49, ISL29001 Ambient Light Sensor, address 0x44, bus 2 (may not be stuffed)
+        */
+
+       /*
+        * U51, S35390A RTC, address 0x30, bus 2 (may not be stuffed)
+        */
+#ifdef CONFIG_RTC_DRV_S35390A
+       {
+               .type           = "s35390a",
+               .addr           = 0x30,
+       },
+#endif
+};
+
+/*
+ * I2C bus on the board, SDA PI1, SCL PI2
+ */
+static struct i2c_gpio_platform_data ip7160dpf_i2c_data = {
+       .sda_pin                = GPIO_RI_1,
+       .scl_pin                = GPIO_RI_2,
+       .sda_is_open_drain      = 0,
+       .scl_is_open_drain      = 0,
+       .scl_is_output_only     = 1,
+       .udelay                 = 6,
+};
+
+static struct platform_device ip7160dpf_i2c_device = {
+       .name   = "i2c-gpio",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &ip7160dpf_i2c_data,
+       },
+};
+
+/*
+ * List of all devices in our system
+ */
+static struct platform_device *ip7160dpf_devices[] __initdata = {
+       &ip7160dpf_i2c_device,
+};
+
+/*
+ * ip7160dpf_power_off
+ *     Called to turn the power off for this board
+ */
+static void ip7160dpf_power_off(void)
+{
+       gpio_set_value(GPIO_RF_14, 0);
+}
+
+/*
+ * ip7160dpf_init
+ *     Called to add the devices which we have on this board
+ */
+static int __init ip7160dpf_init(void)
+{
+       int ret;
+       struct platform_device *audio_dev;
+
+       ubi_gpio_init();
+
+       /*
+        * Hold the POWER_HOLD line
+        */
+       ret = gpio_request(GPIO_RF_14, "POWER_HOLD");
+       if (ret) {
+               printk(KERN_ERR "%s: could not request POWER_HOLD GPIO\n", __FUNCTION__);
+       }
+       gpio_direction_output(GPIO_RF_14, 1);
+       mach_power_off = ip7160dpf_power_off;
+
+       /*
+        * USB SEL_HOST_USB line
+        */
+       ret = gpio_request(GPIO_RI_13, "SEL_HOST_USB");
+       if (ret) {
+               printk(KERN_ERR "%s: could not request SEL_HOST_USB GPIO\n", __FUNCTION__);
+       }
+       gpio_direction_output(GPIO_RI_13, 0);
+
+       /*
+        * USB/DAC nRESET line
+        */
+       ret = gpio_request(GPIO_RI_3, "USB_DAC_nRESET");
+       if (ret) {
+               printk(KERN_ERR "%s: could not request USB_DAC_nRESET GPIO\n", __FUNCTION__);
+       }
+       gpio_direction_output(GPIO_RI_3, 0);
+       udelay(1);
+       gpio_direction_output(GPIO_RI_3, 1);
+
+       /*
+        * I2C BUS2 Disable line
+        */
+       ret = gpio_request(GPIO_RI_0, "DISABLE_BUS2");
+       if (ret) {
+               printk(KERN_ERR "%s: could not request DISABLE_BUS2 GPIO\n", __FUNCTION__);
+       }
+       gpio_direction_output(GPIO_RI_0, 0);
+
+       vdc_tio_init();
+
+       printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
+       platform_add_devices(ip7160dpf_devices, ARRAY_SIZE(ip7160dpf_devices));
+
+       /*
+        * Allocate the audio driver if we can
+        */
+       audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio-i2sout", 0);
+       if (audio_dev) {
+               ip7160dpf_i2c_board_info[0].platform_data = audio_dev;
+       }
+
+       printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
+       i2c_register_board_info(0, ip7160dpf_i2c_board_info, ARRAY_SIZE(ip7160dpf_i2c_board_info));
+
+       return 0;
+}
+
+arch_initcall(ip7160dpf_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160rgw.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7160rgw.c
new file mode 100644 (file)
index 0000000..4d50375
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+ * arch/ubicom32/mach-ip7k/board-ip7160rgw.c
+ *   Platform initialization for ip7160rgw board.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/spi/spi.h>
+
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/ubicom32input.h>
+
+#ifdef CONFIG_SERIAL_UBI32_SERDES
+#include <asm/ubicom32suart.h>
+#endif
+
+#include <asm/ubicom32-spi-gpio.h>
+#include <asm/switch-dev.h>
+
+#ifdef CONFIG_IP7160RGWLCD
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+/*
+ * LCD Adapter board 8007-092x support
+ *
+ * Touch controller
+ *
+ * Connected via I2C bus, interrupt on PA6
+ */
+#include <linux/i2c/tsc2007.h>
+
+/*
+ * ip7160rgwlcd_tsc2007_exit_platform_hw
+ */
+static void ip7160rgwlcd_tsc2007_exit_platform_hw(void)
+{
+       UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 17);
+       gpio_free(GPIO_RA_5);
+}
+
+/*
+ * ip7160rgwlcd_tsc2007_init_platform_hw
+ */
+static int ip7160rgwlcd_tsc2007_init_platform_hw(void)
+{
+       int res = gpio_request(GPIO_RA_5, "TSC2007_IRQ");
+       if (res) {
+               return res;
+       }
+
+       UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 17);
+       UBICOM32_IO_PORT(RA)->ctl0 |= (0x02 << 17);
+       return 0;
+}
+
+/*
+ * ip7160rgwlcd_tsc2007_get_pendown_state
+ */
+static int ip7160rgwlcd_tsc2007_get_pendown_state(void)
+{
+       return !gpio_get_value(GPIO_RA_5);
+}
+
+static struct tsc2007_platform_data ip7160rgwlcd_tsc2007_data = {
+       .model                  = 2007,
+       .x_plate_ohms           = 350,
+       .get_pendown_state      = ip7160rgwlcd_tsc2007_get_pendown_state,
+       .init_platform_hw       = ip7160rgwlcd_tsc2007_init_platform_hw,
+       .exit_platform_hw       = ip7160rgwlcd_tsc2007_exit_platform_hw,
+};
+
+/******************************************************************************
+ * I2C bus on the board, SDA PI14, SCL PI13
+ */
+static struct i2c_gpio_platform_data ip7160rgwlcd_i2c_data = {
+       .sda_pin                = GPIO_RI_14,
+       .scl_pin                = GPIO_RI_13,
+       .sda_is_open_drain      = 0,
+       .scl_is_open_drain      = 0,
+       .udelay                 = 50,
+};
+
+static struct platform_device ip7160rgwlcd_i2c_device = {
+       .name   = "i2c-gpio",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &ip7160rgwlcd_i2c_data,
+       },
+};
+
+static struct i2c_board_info __initdata ip7160rgwlcd_i2c_board_info[] = {
+       {
+               .type = "tsc2007",
+               .addr = 0x48,
+               .irq = 45, // RA5
+               .platform_data = &ip7160rgwlcd_tsc2007_data,
+       },
+};
+
+#endif
+
+/*
+ * SPI bus over GPIO for Gigabit Ethernet Switch
+ *     U58:
+ *             MOSI    PE0
+ *             MISO    PE1
+ *             CLK     PE3
+ *             CS      PE2
+ */
+static struct ubicom32_spi_gpio_platform_data ip7160rgw_spi_gpio_data = {
+       .pin_mosi       = GPIO_RE_0,
+       .pin_miso       = GPIO_RE_1,
+       .pin_clk        = GPIO_RE_3,
+       .bus_num        = 0,            // We'll call this SPI bus 0
+       .num_chipselect = 1,            // only one device on this SPI bus
+       .clk_default    = 1,
+};
+
+static struct platform_device ip7160rgw_spi_gpio_device = {
+       .name   = "ubicom32-spi-gpio",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &ip7160rgw_spi_gpio_data,
+       },
+};
+
+static struct ubicom32_spi_gpio_controller_data ip7160rgw_bcm539x_controller_data = {
+       .pin_cs = GPIO_RE_2,
+};
+
+static struct switch_core_platform_data ip7160rgw_bcm539x_platform_data = {
+       .flags          = SWITCH_DEV_FLAG_HW_RESET,
+       .pin_reset      = GPIO_RE_4,
+       .name           = "bcm539x",
+};
+
+static struct spi_board_info ip7160rgw_spi_board_info[] = {
+       {
+               .modalias               = "bcm539x-spi",
+               .bus_num                = 0,
+               .chip_select            = 0,
+               .max_speed_hz           = 2000000,
+               .platform_data          = &ip7160rgw_bcm539x_platform_data,
+               .controller_data        = &ip7160rgw_bcm539x_controller_data,
+               .mode                   = SPI_MODE_3,
+       }
+};
+
+/*
+ * LEDs
+ *
+ * WLAN1               PD0     (PWM capable)
+ * WLAN2               PD1
+ * USB2.0              PD2
+ * Status              PD3
+ * WPS                 PD4
+ *
+ * TODO: check triggers, are they generic?
+ */
+static struct gpio_led ip7160rgw_gpio_leds[] = {
+       {
+               .name                   = "d53:green:WLAN1",
+               .default_trigger        = "WLAN1",
+               .gpio                   = GPIO_RD_0,
+               .active_low             = 1,
+       },
+       {
+               .name                   = "d54:green:WLAN2",
+               .default_trigger        = "WLAN2",
+               .gpio                   = GPIO_RD_1,
+               .active_low             = 1,
+       },
+       {
+               .name                   = "d55:green:USB",
+               .default_trigger        = "USB",
+               .gpio                   = GPIO_RD_2,
+               .active_low             = 1,
+       },
+       {
+               .name                   = "d56:green:Status",
+               .default_trigger        = "Status",
+               .gpio                   = GPIO_RD_3,
+               .active_low             = 1,
+       },
+       {
+               .name                   = "d57:green:WPS",
+               .default_trigger        = "WPS",
+               .gpio                   = GPIO_RD_4,
+               .active_low             = 1,
+       },
+};
+
+static struct gpio_led_platform_data ip7160rgw_gpio_led_platform_data = {
+       .num_leds       = 5,
+       .leds           = ip7160rgw_gpio_leds,
+};
+
+static struct platform_device ip7160rgw_gpio_leds_device = {
+       .name           = "leds-gpio",
+       .id             = -1,
+       .dev = {
+               .platform_data = &ip7160rgw_gpio_led_platform_data,
+       },
+};
+
+/*
+ * Use ubicom32input driver to monitor the various pushbuttons on this board.
+ *
+ * WPS                 PD5
+ * FACT_DEFAULT                PD6
+ *
+ * TODO: pick some ubicom understood EV_xxx define for WPS and Fact Default
+ */
+static struct ubicom32input_button ip7160rgw_ubicom32input_buttons[] = {
+       {
+               .type           = EV_KEY,
+               .code           = KEY_FN_F1,
+               .gpio           = GPIO_RD_5,
+               .desc           = "WPS",
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_FN_F2,
+               .gpio           = GPIO_RD_6,
+               .desc           = "Factory Default",
+               .active_low     = 1,
+       },
+};
+
+static struct ubicom32input_platform_data ip7160rgw_ubicom32input_data = {
+       .buttons        = ip7160rgw_ubicom32input_buttons,
+       .nbuttons       = ARRAY_SIZE(ip7160rgw_ubicom32input_buttons),
+};
+
+static struct platform_device ip7160rgw_ubicom32input_device = {
+       .name   = "ubicom32input",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &ip7160rgw_ubicom32input_data,
+       },
+};
+
+#ifdef CONFIG_SERIAL_UBI32_SERDES
+static struct resource ip7160rgw_ubicom32_suart_resources[] = {
+       {
+               .start  = RE,
+               .end    = RE,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .start  = PORT_OTHER_INT(RE),
+               .end    = PORT_OTHER_INT(RE),
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .start  = 250000000,
+               .end    = 250000000,
+               .flags  = UBICOM32_SUART_IORESOURCE_CLOCK,
+       },
+};
+
+static struct platform_device ip7160rgw_ubicom32_suart_device = {
+       .name           = "ubicom32suart",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(ip7160rgw_ubicom32_suart_resources),
+       .resource       = ip7160rgw_ubicom32_suart_resources,
+};
+#endif
+
+/*
+ * List of all devices in our system
+ */
+static struct platform_device *ip7160rgw_devices[] __initdata = {
+#ifdef CONFIG_SERIAL_UBI32_SERDES
+       &ip7160rgw_ubicom32_suart_device,
+#endif
+       &ip7160rgw_ubicom32input_device,
+       &ip7160rgw_gpio_leds_device,
+       &ip7160rgw_spi_gpio_device,
+#ifdef CONFIG_IP7160RGWLCD
+       &ip7160rgwlcd_i2c_device,
+#endif
+};
+
+/*
+ * ip7160rgw_init
+ *     Called to add the devices which we have on this board
+ */
+static int __init ip7160rgw_init(void)
+{
+       board_init();
+
+       /*
+        * Rev 1.2 boards have spi in a different place than 1.1/1.0
+        */
+       if (strcmp(board_get_revision(), "1.2") == 0) {
+               ip7160rgw_spi_gpio_data.pin_mosi = GPIO_RD_7;
+       }
+
+       ubi_gpio_init();
+
+       /*
+        * Reserve switch SPI CS on behalf on switch driver
+        */
+       if (gpio_request(ip7160rgw_bcm539x_controller_data.pin_cs, "switch-bcm539x-cs")) {
+               printk(KERN_WARNING "Could not request cs of switch SPI I/F\n");
+               return -EIO;
+       }
+       gpio_direction_output(ip7160rgw_bcm539x_controller_data.pin_cs, 1);
+
+       printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
+       platform_add_devices(ip7160rgw_devices, ARRAY_SIZE(ip7160rgw_devices));
+
+       printk(KERN_INFO "%s: registering SPI resources\n", __FUNCTION__);
+       spi_register_board_info(ip7160rgw_spi_board_info, ARRAY_SIZE(ip7160rgw_spi_board_info));
+
+#ifdef CONFIG_IP7160RGWLCD
+       printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
+       i2c_register_board_info(0, ip7160rgwlcd_i2c_board_info, ARRAY_SIZE(ip7160rgwlcd_i2c_board_info));
+       printk(KERN_INFO "IP7160 RGW + LCD\n");
+#else
+       printk(KERN_INFO "IP7160 RGW\n");
+#endif
+       return 0;
+}
+
+arch_initcall(ip7160rgw_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500av.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500av.c
new file mode 100644 (file)
index 0000000..7cd25fc
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * arch/ubicom32/mach-ip7k/board-ip7500av.c
+ *   Support for IP7500 Audio Video Board + CPU module board.
+ *
+ * This file supports the IP7500 Audio Video Board:
+ *     8007-0810  Rev 1.0
+ * with one of the following CPU module boards:
+ *     8007-0510  Rev 1.0
+ *     8007-0510A Rev 1.0 (with ethernet)
+ *
+ * DIP Switch SW2 configuration: (*) default
+ *     POS 1: on(*) = PCI enabled, off = PCI disabled
+ *     POS 2: on(*) = TTYX => PA6, off = TTYX => PF12
+ *     POS 3: on(*) = TTYY => PA7, off = TTYY => PF15
+ *     POS 4: unused
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/delay.h>
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/ring_tio.h>
+#include <asm/vdc_tio.h>
+#include <asm/audio.h>
+#include <asm/ubi32-pcm.h>
+#include <asm/ubi32-cs4384.h>
+
+/******************************************************************************
+ * Devices on the I2C bus
+ *
+ * BEWARE of changing the order of things in this array as we depend on
+ * certain things to be in certain places.
+ */
+static struct i2c_board_info __initdata ip7500av_i2c_board_info[] = {
+       /*
+        * U6, CS4384 DAC, address 0x19
+        */
+       {
+               .type           = "cs4384",
+               .addr           = 0x19,
+       },
+};
+
+/*
+ * I2C bus on the board, SDA PD1, SCL PD2
+ */
+static struct i2c_gpio_platform_data ip7500av_i2c_data = {
+       .sda_pin                = GPIO_RD_6,
+       .scl_pin                = GPIO_RD_3,
+       .sda_is_open_drain      = 0,
+       .scl_is_open_drain      = 0,
+       .udelay                 = 50,
+};
+
+static struct platform_device ip7500av_i2c_device = {
+       .name   = "i2c-gpio",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &ip7500av_i2c_data,
+       },
+};
+
+/*
+ * List of possible mclks we can generate.  This depends on the CPU frequency.
+ */
+static struct ubi32_cs4384_mclk_entry ip7500av_cs4384_mclk_entries[] = {
+       {
+               .rate   =       12288000,
+               .div    =       44,
+       },
+       {
+               .rate   =       11289600,
+               .div    =       48,
+       },
+};
+
+/*
+ * List of all devices in our system
+ */
+static struct platform_device *ip7500av_devices[] __initdata = {
+       &ip7500av_i2c_device,
+};
+
+/*
+ * ip7500av_vdac_write
+ */
+static int __init ip7500av_vdac_write(int reg, int val)
+{
+       struct i2c_adapter *adap;
+       struct i2c_msg msg[1];
+       unsigned char data[2];
+       int err;
+
+       adap = i2c_get_adapter(0);
+       if (!adap) {
+               printk(KERN_WARNING "%s: failed to get i2c adapter\n", __FUNCTION__);
+               return -ENODEV;
+       }
+       msg->addr = 0x2B;
+       msg->flags = 0;
+       msg->len = 2;
+       msg->buf = data;
+       data[0] = reg;
+       data[1] = val;
+       err = i2c_transfer(adap, msg, 1);
+       i2c_put_adapter(adap);
+       if (err >= 0) {
+               return 0;
+       }
+       return err;
+}
+
+/*
+ * ip7500av_vdac_init
+ *     Initializes the video DAC via I2C
+ *
+ * Equivalent mode line: 720x480p = 27 Mhz, 720 736 800 858 480 484 492 525
+ */
+static int __init ip7500av_vdac_init(void)
+{
+       int err;
+
+       printk(KERN_INFO "Initializing ADV7393 DAC\n");
+
+       /*
+        * Reset the VDAC
+        */
+       if (gpio_request(GPIO_RF_6, "VDAC Reset")) {
+               printk(KERN_WARNING "%s: failed to allocate VDAC Reset\n", __FUNCTION__);
+               return -EBUSY;
+       }
+       gpio_direction_output(GPIO_RF_6, 0);
+       udelay(1);
+       gpio_set_value(GPIO_RF_6, 1);
+
+       /*
+        * See table 100 of ADV7393 data sheet: 16-bit 525p YCrCb In, YPbPr Out
+        */
+       err = ip7500av_vdac_write(0x17, 0x02);
+       if (err) {
+               printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__);
+               return err;
+       }
+       err = ip7500av_vdac_write(0x00, 0x1c);
+       if (err) {
+               printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__);
+               return err;
+       }
+       err = ip7500av_vdac_write(0x01, 0x10);
+       if (err) {
+               printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__);
+               return err;
+       }
+       err = ip7500av_vdac_write(0x31, 0x01);
+       if (err) {
+               printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__);
+               return err;
+       }
+#ifdef IP7500AV_VDAC_SWAP_PBPR
+       err = ip7500av_vdac_write(0x35, 0x08);
+       if (err) {
+               printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__);
+               return err;
+       }
+#endif
+#ifdef IP7500AV_VDAC_FULL_RANGE
+       err = ip7500av_vdac_write(0x30, 0x02);
+       if (err) {
+               printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__);
+               return err;
+       }
+#endif
+       return 0;
+}
+late_initcall(ip7500av_vdac_init);
+
+/*
+ * ip7500av_init
+ *     Called to add the devices which we have on this board
+ */
+static int __init ip7500av_init(void)
+{
+       struct platform_device *audio_dev;
+       struct platform_device *audio_dev2;
+       struct ubi32_cs4384_platform_data *cs4384_pd;
+
+       board_init();
+
+       ubi_gpio_init();
+
+       vdc_tio_init();
+
+       printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
+       platform_add_devices(ip7500av_devices, ARRAY_SIZE(ip7500av_devices));
+
+       /*
+        * CS4384 DAC
+        */
+       audio_dev = audio_device_alloc("snd-ubi32-cs4384", "audio", "audio-i2sout",
+                       sizeof(struct ubi32_cs4384_platform_data));
+       if (audio_dev) {
+               /*
+                * Attempt to figure out a good divisor.  This will only work
+                * assuming the core frequency is compatible.
+                */
+               int i;
+               unsigned int freq = processor_frequency();
+               for (i = 0; i < ARRAY_SIZE(ip7500av_cs4384_mclk_entries); i++) {
+                       unsigned int div;
+                       unsigned int rate = ip7500av_cs4384_mclk_entries[i].rate / 1000;
+                       div = ((freq / rate) + 500) / 1000;
+                       ip7500av_cs4384_mclk_entries[i].div = div;
+                       printk("CS4384 mclk %d rate %u000Hz div %u act %u\n", i, rate, div, freq / div);
+               }
+
+               cs4384_pd = audio_device_priv(audio_dev);
+               cs4384_pd->mclk_src = UBI32_CS4384_MCLK_PWM_0;
+               cs4384_pd->n_mclk = ARRAY_SIZE(ip7500av_cs4384_mclk_entries);
+               cs4384_pd->mclk_entries = ip7500av_cs4384_mclk_entries;
+               ip7500av_i2c_board_info[0].platform_data = audio_dev;
+
+               /*
+                * Reset the DAC
+                */
+               if (gpio_request(GPIO_RF_4, "DAC Reset") == 0) {
+                       gpio_direction_output(GPIO_RF_4, 0);
+                       udelay(1);
+                       gpio_direction_output(GPIO_RF_4, 1);
+               } else {
+                       printk("Unable to request DAC reset GPIO\n");
+               }
+       }
+
+       /*
+        * SPDIF port
+        */
+       audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0);
+       if (audio_dev2) {
+               platform_device_register(audio_dev2);
+       }
+
+       /*
+        * Register all of the devices which sit on the I2C bus
+        */
+       printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
+       i2c_register_board_info(0, ip7500av_i2c_board_info, ARRAY_SIZE(ip7500av_i2c_board_info));
+
+       printk(KERN_INFO "IP7500 Audio/Video Board\n");
+       return 0;
+}
+arch_initcall(ip7500av_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500iap.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500iap.c
new file mode 100644 (file)
index 0000000..f565cdd
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * arch/ubicom32/mach-ip7k/board-ip7500iap.c
+ *   Support for IP7500 Internet Audio Player
+ *
+ * This file supports the IP7500 Internet Audio Player:
+ *     8007-1110  Rev 1.0
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <asm/board.h>
+
+#include <linux/delay.h>
+
+#include <linux/platform_device.h>
+#include <asm/audio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+
+#include <asm/ubicom32sd.h>
+#include <asm/sd_tio.h>
+
+#include <asm/ubicom32bl.h>
+
+#include <asm/machdep.h>
+
+/******************************************************************************
+ * SD/IO Port F (Slot 1) platform data
+ */
+static struct resource ip7500iap_portf_sd_resources[] = {
+       /*
+        * Send IRQ
+        */
+       [0] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Receive IRQ
+        */
+       [1] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Memory Mapped Registers
+        */
+       [2] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct ubicom32sd_card ip7500iap_portf_sd_cards[] = {
+       [0] = {
+               .pin_wp         = GPIO_RF_7,
+               .wp_polarity    = 1,
+               .pin_pwr        = GPIO_RF_8,
+               .pin_cd         = GPIO_RF_6,
+       },
+};
+
+static struct ubicom32sd_platform_data ip7500iap_portf_sd_platform_data = {
+       .ncards         = 1,
+       .cards          = ip7500iap_portf_sd_cards,
+};
+
+static struct platform_device ip7500iap_portf_sd_device = {
+       .name           = "ubicom32sd",
+       .id             = 0,
+       .resource       = ip7500iap_portf_sd_resources,
+       .num_resources  = ARRAY_SIZE(ip7500iap_portf_sd_resources),
+       .dev            = {
+                       .platform_data = &ip7500iap_portf_sd_platform_data,
+       },
+
+};
+
+/*
+ * ip7500iap_portf_sd_init
+ */
+static void ip7500iap_portf_sd_init(void)
+{
+       /*
+        * Check the device tree for the sd_tio
+        */
+       struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portf_sd");
+       if (!sd_node) {
+               printk(KERN_INFO "PortF SDTIO not found\n");
+               return;
+       }
+
+       /*
+        * Fill in the resources and platform data from devtree information
+        */
+       ip7500iap_portf_sd_resources[0].start = sd_node->dn.sendirq;
+       ip7500iap_portf_sd_resources[1].start = sd_node->dn.recvirq;
+       ip7500iap_portf_sd_resources[2].start = (u32_t)&(sd_node->regs);
+       ip7500iap_portf_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs);
+
+       platform_device_register(&ip7500iap_portf_sd_device);
+}
+
+/******************************************************************************
+ * SD/IO Port B (Slot 2) platform data
+ */
+static struct resource ip7500iap_portb_sd_resources[] = {
+       /*
+        * Send IRQ
+        */
+       [0] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Receive IRQ
+        */
+       [1] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Memory Mapped Registers
+        */
+       [2] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct ubicom32sd_card ip7500iap_portb_sd_cards[] = {
+       [0] = {
+               .pin_wp         = GPIO_RB_13,
+               .wp_polarity    = 1,
+               .pin_pwr        = GPIO_RB_11,
+               .pin_cd         = GPIO_RB_12,
+       },
+};
+
+static struct ubicom32sd_platform_data ip7500iap_portb_sd_platform_data = {
+       .ncards         = 1,
+       .cards          = ip7500iap_portb_sd_cards,
+};
+
+static struct platform_device ip7500iap_portb_sd_device = {
+       .name           = "ubicom32sd",
+       .id             = 1,
+       .resource       = ip7500iap_portb_sd_resources,
+       .num_resources  = ARRAY_SIZE(ip7500iap_portb_sd_resources),
+       .dev            = {
+                       .platform_data = &ip7500iap_portb_sd_platform_data,
+       },
+
+};
+
+/*
+ * ip7500iap_portb_sd_init
+ */
+static void ip7500iap_portb_sd_init(void)
+{
+       /*
+        * Check the device tree for the sd_tio
+        */
+       struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portb_sd");
+       if (!sd_node) {
+               printk(KERN_INFO "PortB SDTIO not found\n");
+               return;
+       }
+
+       /*
+        * Fill in the resources and platform data from devtree information
+        */
+       ip7500iap_portb_sd_resources[0].start = sd_node->dn.sendirq;
+       ip7500iap_portb_sd_resources[1].start = sd_node->dn.recvirq;
+       ip7500iap_portb_sd_resources[2].start = (u32_t)&(sd_node->regs);
+       ip7500iap_portb_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs);
+
+       platform_device_register(&ip7500iap_portb_sd_device);
+}
+
+/******************************************************************************
+ * Touch controller
+ *
+ * Connected via I2C bus, interrupt on PA6
+ */
+#include <linux/i2c/tsc2007.h>
+
+/*
+ * ip7500iap_tsc2007_exit_platform_hw
+ */
+static void ip7500iap_tsc2007_exit_platform_hw(void)
+{
+       UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 19);
+       gpio_free(GPIO_RA_6);
+}
+
+/*
+ * ip7500iap_tsc2007_init_platform_hw
+ */
+static int ip7500iap_tsc2007_init_platform_hw(void)
+{
+       int res = gpio_request(GPIO_RA_6, "TSC2007_IRQ");
+       if (res) {
+               return res;
+       }
+
+       UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 19);
+       UBICOM32_IO_PORT(RA)->ctl0 |= (0x02 << 19);
+       return 0;
+}
+
+/*
+ * ip7500iap_tsc2007_get_pendown_state
+ */
+static int ip7500iap_tsc2007_get_pendown_state(void)
+{
+       return !gpio_get_value(GPIO_RA_6);
+}
+
+static struct tsc2007_platform_data ip7500iap_tsc2007_data = {
+       .model                  = 2007,
+       .x_plate_ohms           = 350,
+       .get_pendown_state      = ip7500iap_tsc2007_get_pendown_state,
+       .init_platform_hw       = ip7500iap_tsc2007_init_platform_hw,
+       .exit_platform_hw       = ip7500iap_tsc2007_exit_platform_hw,
+};
+
+/******************************************************************************
+ * i2c devices
+ *
+ * DO NOT CHANGE THE ORDER HERE unless you know how this works.  There
+ * are hardcoded indicies which refer to the order of drivers listed here.
+ */
+static struct i2c_board_info __initdata ip7500iap_i2c_board_info[] = {
+       /*
+        * U6, CS4350 DAC, address 0x4B
+        */
+       {
+               .type           = "cs4350",
+               .addr           = 0x4B,
+       },
+
+       /*
+        * U20, S35390A RTC, address 0x30
+        */
+       {
+               .type           = "s35390a",
+               .addr           = 0x30,
+       },
+
+       /*
+        * U9, TSC2007 Touch screen controller, address 0x49, irq RA6
+        */
+       {
+               .type           = "tsc2007",
+               .addr           = 0x49,
+               .irq            = 46,
+               .platform_data  = &ip7500iap_tsc2007_data,
+       },
+};
+
+/*
+ * I2C bus on the board, SDA PE4, SCL PE5
+ */
+static struct i2c_gpio_platform_data ip7500iap_i2c_data = {
+       .sda_pin                = GPIO_RF_14,
+       .scl_pin                = GPIO_RF_13,
+       .sda_is_open_drain      = 0,
+       .scl_is_open_drain      = 0,
+       .udelay                 = 50,
+};
+
+static struct platform_device ip7500iap_i2c_device = {
+       .name   = "i2c-gpio",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &ip7500iap_i2c_data,
+       },
+};
+
+/******************************************************************************
+ * Backlight on the board PD0, hardware PWM
+ */
+static struct ubicom32bl_platform_data ip7500iap_backlight_data = {
+       .type                   = UBICOM32BL_TYPE_PWM,
+       .pwm_channel            = 2,
+       .pwm_prescale           = 15,
+       .pwm_period             = 60,
+       .default_intensity      = 0x80,
+};
+
+static struct platform_device ip7500iap_backlight_device = {
+       .name   = "ubicom32bl",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &ip7500iap_backlight_data,
+       },
+};
+
+/******************************************************************************
+ * Devices on this board
+ */
+static struct platform_device *ip7500iap_devices[] __initdata = {
+       &ip7500iap_i2c_device,
+       &ip7500iap_backlight_device,
+};
+
+/*
+ * ip7500iap_power_off
+ *     Called to turn the power off for this board
+ */
+static void ip7500iap_power_off(void)
+{
+       gpio_set_value(GPIO_RF_11, 0);
+}
+
+/*
+ * ip7500iap_init
+ *     Called to add the devices which we have on this board
+ */
+static int __init ip7500iap_init(void)
+{
+       struct platform_device *audio_dev;
+       struct platform_device *audio_dev2;
+       int ret;
+
+       board_init();
+
+       ubi_gpio_init();
+
+       /*
+        * Hold the POWER_HOLD line
+        */
+       ret = gpio_request(GPIO_RF_11, "POWER_HOLD");
+       if (ret) {
+               printk(KERN_ERR "%s: could not request POWER_HOLD GPIO\n", __FUNCTION__);
+       }
+       gpio_direction_output(GPIO_RF_11, 1);
+       mach_power_off = ip7500iap_power_off;
+
+       /*
+        * DAC nRESET line
+        */
+       ret = gpio_request(GPIO_RE_7, "DAC_nRESET");
+       if (ret) {
+               printk(KERN_ERR "%s: could not request DAC_nRESET GPIO\n", __FUNCTION__);
+       }
+       gpio_direction_output(GPIO_RE_7, 0);
+       udelay(1);
+       gpio_set_value(GPIO_RE_7, 1);
+
+       /*
+        * Bring up any SDIO slots
+        */
+       ip7500iap_portb_sd_init();
+       ip7500iap_portf_sd_init();
+
+       /*
+        * Bring up audio devices
+        */
+       platform_add_devices(ip7500iap_devices, ARRAY_SIZE(ip7500iap_devices));
+
+       audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio", "audio-i2sout", 0);
+       if (audio_dev) {
+               ip7500iap_i2c_board_info[0].platform_data = audio_dev;
+       }
+
+       audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0);
+       if (audio_dev2) {
+               platform_device_register(audio_dev2);
+       }
+
+       printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
+       i2c_register_board_info(0, ip7500iap_i2c_board_info, ARRAY_SIZE(ip7500iap_i2c_board_info));
+
+       printk(KERN_INFO "IP7500 Internet Audio Player\n");
+
+       return 0;
+}
+
+arch_initcall(ip7500iap_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500media.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500media.c
new file mode 100644 (file)
index 0000000..3a51aec
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * arch/ubicom32/mach-ip7k/board-ip7500media.c
+ *   Board file for IP7500 media board.
+ *
+ * Supports the following configuration
+ *     CPU Module:
+ *             P/N 8007-0510 rev 1.0 NOPHY
+ *             P/N 8007-0511 rev 1.1 NOPHY
+ *                     DIP Switch SW2 configuration:
+ *                             POS 1: on  = PCI enabled
+ *                             POS 2: off = TTYX => PF12
+ *                             POS 3: off = TTYY => PF15
+ *                             POS 4: unused
+ *     Media Board:
+ *             P/N 8007-0610 rev 1.0
+ *
+ *     LCD Adapter Board: (optional)
+ *             P/N 8007-0920 rev 2.0
+ *             P/N 8007-0921 rev 2.1
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <linux/input.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/i2c/pca953x.h>
+
+#include <asm/board.h>
+#include <asm/machdep.h>
+#include <asm/ubicom32input_i2c.h>
+#include <asm/ubicom32bl.h>
+#include <asm/ubicom32lcdpower.h>
+#include <asm/vdc_tio.h>
+
+#include <asm/ubicom32sd.h>
+#include <asm/sd_tio.h>
+#include <asm/devtree.h>
+#include <asm/audio.h>
+
+#include <asm/ring_tio.h>
+
+/******************************************************************************
+ * SD/IO Port F (Slot 1) platform data
+ */
+static struct resource ip7500media_portf_sd_resources[] = {
+       /*
+        * Send IRQ
+        */
+       [0] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Receive IRQ
+        */
+       [1] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Memory Mapped Registers
+        */
+       [2] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct ubicom32sd_card ip7500media_portf_sd_cards[] = {
+       [0] = {
+               .pin_wp         = IP7500MEDIA_IO16,
+               .wp_polarity    = 1,
+               .pin_pwr        = IP7500MEDIA_IO20,
+               .pin_cd         = IP7500MEDIA_IO23,
+       },
+       [1] = {
+               .pin_wp         = IP7500MEDIA_IO17,
+               .wp_polarity    = 1,
+               .pin_pwr        = IP7500MEDIA_IO21,
+               .pin_cd         = IP7500MEDIA_IO24,
+       },
+};
+
+static struct ubicom32sd_platform_data ip7500media_portf_sd_platform_data = {
+       .ncards         = 2,
+       .cards          = ip7500media_portf_sd_cards,
+};
+
+static struct platform_device ip7500media_portf_sd_device = {
+       .name           = "ubicom32sd",
+       .id             = 0,
+       .resource       = ip7500media_portf_sd_resources,
+       .num_resources  = ARRAY_SIZE(ip7500media_portf_sd_resources),
+       .dev            = {
+                       .platform_data = &ip7500media_portf_sd_platform_data,
+       },
+
+};
+
+/*
+ * ip7500media_portf_sd_init
+ */
+static void ip7500media_portf_sd_init(void)
+{
+       /*
+        * Check the device tree for the sd_tio
+        */
+       struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portf_sd");
+       if (!sd_node) {
+               printk(KERN_INFO "PortF SDTIO not found\n");
+               return;
+       }
+
+       /*
+        * Fill in the resources and platform data from devtree information
+        */
+       ip7500media_portf_sd_resources[0].start = sd_node->dn.sendirq;
+       ip7500media_portf_sd_resources[1].start = sd_node->dn.recvirq;
+       ip7500media_portf_sd_resources[2].start = (u32_t)&(sd_node->regs);
+       ip7500media_portf_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs);
+
+       platform_device_register(&ip7500media_portf_sd_device);
+}
+
+/******************************************************************************
+ * SD/IO Port B (Slot 2) platform data
+ */
+static struct resource ip7500media_portb_sd_resources[] = {
+       /*
+        * Send IRQ
+        */
+       [0] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Receive IRQ
+        */
+       [1] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_IRQ,
+       },
+
+       /*
+        * Memory Mapped Registers
+        */
+       [2] = {
+               /*
+                * The init routine will query the devtree and fill this in
+                */
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct ubicom32sd_card ip7500media_portb_sd_cards[] = {
+       [0] = {
+               .pin_wp         = IP7500MEDIA_IO19,
+               .wp_polarity    = 1,
+               .pin_pwr        = IP7500MEDIA_IO22,
+               .pin_cd         = IP7500MEDIA_IO18,
+       },
+};
+
+static struct ubicom32sd_platform_data ip7500media_portb_sd_platform_data = {
+       .ncards         = 1,
+       .cards          = ip7500media_portb_sd_cards,
+};
+
+static struct platform_device ip7500media_portb_sd_device = {
+       .name           = "ubicom32sd",
+       .id             = 1,
+       .resource       = ip7500media_portb_sd_resources,
+       .num_resources  = ARRAY_SIZE(ip7500media_portb_sd_resources),
+       .dev            = {
+                       .platform_data = &ip7500media_portb_sd_platform_data,
+       },
+
+};
+
+/*
+ * ip7500media_portb_sd_init
+ */
+static void ip7500media_portb_sd_init(void)
+{
+       /*
+        * Check the device tree for the sd_tio
+        */
+       struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portb_sd");
+       if (!sd_node) {
+               printk(KERN_INFO "PortB SDTIO not found\n");
+               return;
+       }
+
+       /*
+        * Fill in the resources and platform data from devtree information
+        */
+       ip7500media_portb_sd_resources[0].start = sd_node->dn.sendirq;
+       ip7500media_portb_sd_resources[1].start = sd_node->dn.recvirq;
+       ip7500media_portb_sd_resources[2].start = (u32_t)&(sd_node->regs);
+       ip7500media_portb_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs);
+
+       platform_device_register(&ip7500media_portb_sd_device);
+}
+
+/*
+ * ip7500media_u17_setup
+ *     Called by I2C to tell us that u17 is setup.
+ *
+ * This function is called by I2C to tell us that u17 has been setup.  All
+ * devices which rely on this chip being initialized (or even present) need to
+ * be initialized in this function otherwise they may get initialized too early.
+ *
+ * Currently the only device depending on u17 is the SDIO
+ */
+static int __init ip7500media_u17_setup(struct i2c_client *client, unsigned gpio, unsigned ngpio, void *context)
+{
+       /*
+        * Initialize the Port F/Port B SD slots (only the enabled ports will init)
+        */
+       ip7500media_portf_sd_init();
+       ip7500media_portb_sd_init();
+
+       return 0;
+}
+
+/******************************************************************************
+ * LCD VGH on the board at PE6
+ */
+static struct ubicom32lcdpower_platform_data ip7500media_lcdpower_data = {
+       .vgh_gpio               = GPIO_RE_7,
+       .vgh_polarity           = true,
+};
+
+static struct platform_device ip7500media_lcdpower_device = {
+       .name   = "ubicom32lcdpower",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &ip7500media_lcdpower_data,
+       },
+};
+
+/******************************************************************************
+ * Backlight on the board PD0, hardware PWM
+ */
+static struct ubicom32bl_platform_data ip7500media_backlight_data = {
+       .type                   = UBICOM32BL_TYPE_PWM,
+       .pwm_channel            = 2,
+       .pwm_prescale           = 15,
+       .pwm_period             = 60,
+       .default_intensity      = 0x80,
+};
+
+static struct platform_device ip7500media_backlight_device = {
+       .name   = "ubicom32bl",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &ip7500media_backlight_data,
+       },
+};
+
+/******************************************************************************
+ * Ubicom32Input on I2C, U15 MAX7310, address 0x18, 8 bits
+ */
+static struct ubicom32input_i2c_button ip7500media_ubicom32input_i2c_u15_buttons[] = {
+       {
+               .type           = EV_KEY,
+               .code           = KEY_LEFT,
+               .bit            = 0,
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_RIGHT,
+               .bit            = 1,
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_UP,
+               .bit            = 2,
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_DOWN,
+               .bit            = 3,
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_ENTER,
+               .bit            = 4,
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_MENU,
+               .bit            = 5,
+               .active_low     = 1,
+       },
+       {
+               .type           = EV_KEY,
+               .code           = KEY_ESC,
+               .bit            = 6,
+               .active_low     = 1,
+       },
+};
+
+static struct ubicom32input_i2c_platform_data ip7500media_ubicom32input_i2c_u15_platform_data = {
+       .buttons        = ip7500media_ubicom32input_i2c_u15_buttons,
+       .nbuttons       = ARRAY_SIZE(ip7500media_ubicom32input_i2c_u15_buttons),
+       .name           = "Ubicom32 Input I2C U15",
+};
+
+/******************************************************************************
+ * Additional GPIO chips
+ */
+static struct pca953x_platform_data ip7500media_gpio_u16_platform_data = {
+       .gpio_base = IP7500MEDIA_U16_BASE,
+};
+
+static struct pca953x_platform_data ip7500media_gpio_u17_platform_data = {
+       .gpio_base = IP7500MEDIA_U17_BASE,
+       .setup = ip7500media_u17_setup,
+};
+
+static struct pca953x_platform_data ip7500media_gpio_u18_platform_data = {
+       .gpio_base = IP7500MEDIA_U18_BASE,
+};
+
+
+/******************************************************************************
+ * Touch controller present on LCD Adapter board
+ *
+ * Connected via I2C bus, interrupt on PD1
+ */
+#include <linux/i2c/tsc2007.h>
+
+/*
+ * ip7500media_tsc2007_exit_platform_hw
+ */
+static void ip7500media_tsc2007_exit_platform_hw(void)
+{
+       UBICOM32_IO_PORT(RD)->int_mask &= ~(1 << 11);
+       UBICOM32_IO_PORT(RD)->ctl2 &= ~(0x03 << 16);
+       gpio_free(GPIO_RD_1);
+}
+
+/*
+ * ip7500media_tsc2007_init_platform_hw
+ */
+static int ip7500media_tsc2007_init_platform_hw(void)
+{
+       int res = gpio_request(GPIO_RD_1, "TSC2007_IRQ");
+       if (res) {
+               return res;
+       }
+       UBICOM32_IO_PORT(RD)->function = 0;
+       UBICOM32_IO_PORT(RD)->int_mask = (1 << 11);
+       UBICOM32_IO_PORT(RD)->ctl2 &= ~(0x03 << 16);
+       UBICOM32_IO_PORT(RD)->ctl2 |= (0x02 << 16);
+
+       return 0;
+}
+
+/*
+ * ip7500media_tsc2007_clear_penirq
+ */
+static void ip7500media_tsc2007_clear_penirq(void)
+{
+       UBICOM32_IO_PORT(RD)->int_clr = (1 << 11);
+}
+
+/*
+ * ip7500media_tsc2007_get_pendown_state
+ */
+static int ip7500media_tsc2007_get_pendown_state(void)
+{
+       return !gpio_get_value(GPIO_RD_1);
+}
+
+static struct tsc2007_platform_data ip7500media_tsc2007_data = {
+       .model                  = 2007,
+       .x_plate_ohms           = 350,
+       .get_pendown_state      = ip7500media_tsc2007_get_pendown_state,
+       .init_platform_hw       = ip7500media_tsc2007_init_platform_hw,
+       .exit_platform_hw       = ip7500media_tsc2007_exit_platform_hw,
+       .clear_penirq           = ip7500media_tsc2007_clear_penirq,
+};
+
+/******************************************************************************
+ * Devices on the I2C bus
+ *
+ * BEWARE of changing the order of things in this array as we depend on
+ * certain things to be in certain places.
+ */
+static struct i2c_board_info __initdata ip7500media_i2c_board_info[] = {
+       /*
+        * U6, CS4350 DAC, address 0x4B
+        */
+       {
+               .type           = "cs4350",
+               .addr           = 0x4B,
+       },
+
+       /*
+        * U14, S35390A RTC, address 0x30
+        */
+       {
+               .type           = "s35390a",
+               .addr           = 0x30,
+       },
+
+       /*
+        * U15, MAX7310 IO expander, 8 bits, address 0x18
+        *      IO0: User I/O (J16-1) (Left)    IO4: User I/O (J16-5) (Enter)
+        *      IO1: User I/O (J16-2) (Right)   IO5: User I/O (J16-6) (Menu)
+        *      IO2: User I/O (J16-3) (Up)      IO6: User I/O (J16-7) (Back)
+        *      IO3: User I/O (J16-4) (Down)    IO7: User I/O (J16-8)
+        */
+       {
+               .type           = "ubicom32in_max7310",
+               .addr           = 0x18,
+               .platform_data  = &ip7500media_ubicom32input_i2c_u15_platform_data,
+       },
+
+       /*
+        * U16, MAX7310 IO expander, 8 bits, address 0x1C
+        *      IO8 : User I/O (J16-9)          IO12: User I/O (J16-17)
+        *      IO9 : User I/O (J16-10)         IO13: User I/O (J16-18)
+        *      IO10: User I/O (J16-15)         IO14: User I/O (J16-19)
+        *      IO11: User I/O (J16-16)         IO15: User I/O (J16-20)
+        */
+       {
+               .type           = "max7310",
+               .addr           = 0x1C,
+               .platform_data  = &ip7500media_gpio_u16_platform_data,
+       },
+
+       /*
+        * U17, MAX7310 IO expander, 8 bits, address 0x1A
+        *      IO16: SDIO1A_WP                 IO20: SD1A_PWREN
+        *      IO17: SDIO1B_WP                 IO21: SD1B_PWREN
+        *      IO18: SDIO2_CD                  IO22: SD2_PWREN
+        *      IO19: SDIO2_WP                  IO23: SDIO1A_CD
+        *
+        */
+       {
+               .type           = "max7310",
+               .addr           = 0x1A,
+               .platform_data  = &ip7500media_gpio_u17_platform_data,
+       },
+
+       /*
+        * U18, MAX7310 IOB expander, 8 bits, address 0x1E
+        *      IO24: SDIO1B_CD                 IO28: User I/O TP6
+        *      IO25: User I/O TP9              IO29: User I/O TP5
+        *      IO26: User I/O TP8              IO30: User I/O TP4
+        *      IO27: User I/O TP7              IO31: User I/O TP3
+        */
+       {
+               .type           = "max7310",
+               .addr           = 0x1E,
+               .platform_data  = &ip7500media_gpio_u18_platform_data,
+       },
+};
+
+/*
+ * Additional I2C devices to add when a LCD adapter board is present
+ */
+static struct i2c_board_info __initdata ip7500media_lcd_adapter_i2c_board_info[] = {
+       {
+               I2C_BOARD_INFO("tsc2007", 0x48),
+               .irq = PORT_OTHER_INT(RD),
+               .platform_data = &ip7500media_tsc2007_data,
+       },
+};
+
+/*
+ * I2C bus on the board, SDA PE4, SCL PE5
+ */
+static struct i2c_gpio_platform_data ip7500media_i2c_data = {
+       .sda_pin                = GPIO_RE_4,
+       .scl_pin                = GPIO_RE_5,
+       .sda_is_open_drain      = 0,
+       .scl_is_open_drain      = 0,
+       .udelay                 = 50,
+};
+
+static struct platform_device ip7500media_i2c_device = {
+       .name   = "i2c-gpio",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &ip7500media_i2c_data,
+       },
+};
+
+/*
+ * Virtual Frame Buffer device for use with LCD Adapter
+ */
+static struct platform_device ip7500media_vfb_device = {
+       .name   = "ubicom32vfb",
+       .id     = -1,
+};
+
+/*
+ * vdc_override:
+ *     0: no override (auto-detect)
+ *     1: force vdc usage
+ *     2: force lcd adapter usage
+ */
+static int __initdata vdc_override = 0;
+
+/*
+ * ip7500media_set_forcevdc
+ *     Called when forcevdc is present on the kernel boot line
+ */
+static int __init ip7500media_set_forcevdc(char *str)
+{
+       if (str[0] == '1') {
+               vdc_override = 1;
+       } else {
+               vdc_override = 2;
+       }
+       return 1;
+}
+
+/*
+ * ip7500media_video_init
+ *     Called late to determine what kind of video we have on this board
+ */
+static int __init ip7500media_video_init(void)
+{
+       struct i2c_adapter *adap;
+       struct i2c_msg msg[1];
+       unsigned char *data;
+       unsigned char checksum;
+       int err;
+       int i;
+
+       if (vdc_override == 1) {
+               printk(KERN_INFO "Force VDCTIO mode\n");
+               goto no_adapter;
+       }
+       if (vdc_override == 2) {
+               printk(KERN_INFO "Force LCD Adapter Board mode\n");
+               return 0;
+       }
+
+       /*
+        * Check to see if there is an EEPROM out there.  If we see an
+        * EEPROM then we will assume a LCD Adapter Board (8007-092x)
+        * exists.
+        */
+       data = kmalloc(256, GFP_KERNEL);
+       if (!data) {
+               printk(KERN_WARNING "%s: Failed to allocate memory\n", __FUNCTION__);
+               return -ENOMEM;
+       }
+
+       adap = i2c_get_adapter(0);
+       if (!adap) {
+               printk(KERN_WARNING "%s: Failed to get i2c adapter\n", __FUNCTION__);
+               kfree(data);
+               return -ENODEV;
+       }
+       data[0] = 0;
+       msg->addr = 0x50;
+       msg->flags = 0;
+       msg->len = 1;
+       msg->buf = data;
+       err = i2c_transfer(adap, msg, 1);
+       if (err < 0) {
+               goto no_adapter;
+       }
+
+       msg->addr = 0x50;
+       msg->flags = I2C_M_RD;
+       msg->len = 256;
+       msg->buf = data;
+       err = i2c_transfer(adap, msg, 1);
+       if (err < 0) {
+               goto no_adapter;
+       }
+
+       i2c_put_adapter(adap);
+
+       /*
+        * Verify the checksum
+        */
+       checksum = 0xff;
+       for (i = 0; i < 255; i++) {
+               checksum ^= data[i];
+       }
+       if (checksum != data[255]) {
+               printk(KERN_WARNING "%s: Checksum mismatch\n", __FUNCTION__);
+       }
+
+       kfree(data);
+
+       /*
+        * Bring up VFB
+        */
+       platform_device_register(&ip7500media_vfb_device);
+
+       /*
+        * Add the i2c devices on the LCD Adapter board.  (We have to use i2c_new_device
+        * since it's late in the boot process.)
+        */
+       printk(KERN_INFO "%s: registering LCD Adapter board i2c resources\n", __FUNCTION__);
+       for (i = 0; i < ARRAY_SIZE(ip7500media_lcd_adapter_i2c_board_info); i++) {
+               i2c_new_device(adap, &ip7500media_lcd_adapter_i2c_board_info[i]);
+       }
+
+       i2c_put_adapter(adap);
+
+       return 0;
+
+       /*
+        * No LCD Adapter board, bring up VDC
+        */
+no_adapter:
+       vdc_tio_init();
+       return 0;
+}
+late_initcall(ip7500media_video_init);
+__setup("forcevdc=", ip7500media_set_forcevdc);
+
+/*
+ * ip7500media_init
+ *     Called to add the devices which we have on this board
+ */
+static int __init ip7500media_init(void)
+{
+       struct platform_device *audio_dev;
+       int have_ethernet = (devtree_find_node("eth_lan") != 0);
+
+       board_init();
+
+       ubi_gpio_init();
+
+#ifdef CONFIG_UIO_UBICOM32RING
+       ring_tio_init("decoder_ring");
+#endif
+
+       /*
+        * Register all of the devices we have on this board
+        */
+       printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
+       platform_device_register(&ip7500media_i2c_device);
+       platform_device_register(&ip7500media_backlight_device);
+
+       /*
+        * If ethernet doesn't exist then we can init the lcdpower
+        */
+       if (!have_ethernet) {
+               platform_device_register(&ip7500media_lcdpower_device);
+       }
+
+       /*
+        * Allocate the audio drivers.  SPDIF not supported on boards with ethernet.
+        */
+       audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio", "audio-i2sout", 0);
+       if (audio_dev) {
+               ip7500media_i2c_board_info[0].platform_data = audio_dev;
+       }
+
+       if (!have_ethernet) {
+               struct platform_device *audio_dev2;
+
+               audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0);
+               if (audio_dev2) {
+                       platform_device_register(audio_dev2);
+               }
+       }
+
+       /*
+        * Register all of the devices which sit on the I2C bus
+        */
+       printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
+       i2c_register_board_info(0, ip7500media_i2c_board_info, ARRAY_SIZE(ip7500media_i2c_board_info));
+
+       /*
+        * We have to initialize the SDIO after the I2C IOB gets setup.  SDIO is initialized in
+        * ip7500media_u17_setup
+        */
+
+       printk("IP7500 Media Board\n");
+
+       return 0;
+}
+
+arch_initcall(ip7500media_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500module.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500module.c
new file mode 100644 (file)
index 0000000..c8c223a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * arch/ubicom32/mach-ip7k/board-ip7500module.c
+ *   Support for IP7500 CPU module board.
+ *
+ * This file supports the IP7500 CPU module board:
+ *     8007-0510  Rev 1.0
+ *     8007-0510A Rev 1.0 (with ethernet)
+ *
+ * DIP Switch SW2 configuration: (*) default
+ *     POS 1: on(*) = PCI enabled, off = PCI disabled
+ *     POS 2: on(*) = TTYX => PA6, off = TTYX => PF12
+ *     POS 3: on(*) = TTYY => PA7, off = TTYY => PF15
+ *     POS 4: unused
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <asm/board.h>
+
+/*
+ * ip7500module_init
+ *     Called to add the devices which we have on this board
+ */
+static int __init ip7500module_init(void)
+{
+       board_init();
+
+       ubi_gpio_init();
+
+       return 0;
+}
+
+arch_initcall(ip7500module_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500wspkr.c b/target/linux/ubicom32/files/arch/ubicom32/mach-ip7k/board-ip7500wspkr.c
new file mode 100644 (file)
index 0000000..7f27933
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * arch/ubicom32/mach-ip7k/board-ip7500wspkr.c
+ *   Support for IP7500 Wireless Speaker board.
+ *
+ * This file supports the IP7500 Wireless Speaker board:
+ *     8007-1210  Rev 1.0
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <asm/board.h>
+
+#include <linux/platform_device.h>
+#include <asm/audio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+
+static struct i2c_board_info __initdata ip7500wspkr_i2c_board_info[] = {
+       /*
+        * U6, CS4350 DAC, address 0x4B
+        */
+       {
+               .type           = "cs4350",
+               .addr           = 0x4B,
+       },
+};
+
+/*
+ * I2C bus on the board, SDA PE4, SCL PE5
+ */
+static struct i2c_gpio_platform_data ip7500wspkr_i2c_data = {
+       .sda_pin                = GPIO_RD_5,
+       .scl_pin                = GPIO_RD_6,
+       .sda_is_open_drain      = 0,
+       .scl_is_open_drain      = 0,
+       .udelay                 = 50,
+};
+
+static struct platform_device ip7500wspkr_i2c_device = {
+       .name   = "i2c-gpio",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &ip7500wspkr_i2c_data,
+       },
+};
+
+static struct platform_device *ip7500wspkr_devices[] __initdata = {
+       &ip7500wspkr_i2c_device,
+};
+
+/*
+ * ip7500wspkr_init
+ *     Called to add the devices which we have on this board
+ */
+static int __init ip7500wspkr_init(void)
+{
+       struct platform_device *audio_dev;
+       struct platform_device *audio_dev2;
+
+       board_init();
+
+       ubi_gpio_init();
+
+       platform_add_devices(ip7500wspkr_devices, ARRAY_SIZE(ip7500wspkr_devices));
+
+       audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio", "audio-i2sout", 0);
+       if (audio_dev) {
+               ip7500wspkr_i2c_board_info[0].platform_data = audio_dev;
+       }
+
+       audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0);
+       if (audio_dev2) {
+               platform_device_register(audio_dev2);
+       }
+
+       printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
+       i2c_register_board_info(0, ip7500wspkr_i2c_board_info, ARRAY_SIZE(ip7500wspkr_i2c_board_info));
+
+       printk(KERN_INFO "IP7500 Wireless Speaker Board\n");
+
+       return 0;
+}
+
+arch_initcall(ip7500wspkr_init);
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mm/Makefile b/target/linux/ubicom32/files/arch/ubicom32/mm/Makefile
new file mode 100644 (file)
index 0000000..222128d
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# arch/ubicom32/mm/Makefile
+#      <TODO: Replace with short file description>
+#
+# (C) Copyright 2009, Ubicom, Inc.
+#
+# This file is part of the Ubicom32 Linux Kernel Port.
+#
+# The Ubicom32 Linux Kernel Port 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.
+#
+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+# see <http://www.gnu.org/licenses/>.
+#
+# Ubicom32 implementation derived from (with many thanks):
+#   arch/m68knommu
+#   arch/blackfin
+#   arch/parisc
+#
+#
+# Makefile for the linux m68knommu specific parts of the memory manager.
+#
+
+obj-y += init.o fault.o memory.o kmap.o ocm-alloc.o
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mm/fault.c b/target/linux/ubicom32/files/arch/ubicom32/mm/fault.c
new file mode 100644 (file)
index 0000000..ce6b1c7
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * arch/ubicom32/mm/fault.c
+ *   Ubicom32 architecture page fault implementation.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
+ *  Copyright (C) 2000  Lineo, Inc.  (www.lineo.com)
+ *
+ *  Based on:
+ *
+ *  linux/arch/m68k/mm/fault.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/module.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+
+extern void die_if_kernel(char *, struct pt_regs *, long);
+
+/*
+ * This routine handles page faults.  It determines the problem, and
+ * then passes it off to one of the appropriate routines.
+ *
+ * error_code:
+ *     bit 0 == 0 means no page found, 1 means protection fault
+ *     bit 1 == 0 means read, 1 means write
+ *
+ * If this routine detects a bad access, it returns 1, otherwise it
+ * returns 0.
+ */
+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
+                             unsigned long error_code)
+{
+#ifdef DEBUG
+       printk (KERN_DEBUG "regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld\n",
+               regs->sr, regs->pc, address, error_code);
+#endif
+
+       /*
+        * Oops. The kernel tried to access some bad page. We'll have to
+        * terminate things with extreme prejudice.
+        */
+       if ((unsigned long) address < PAGE_SIZE) {
+               printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+       } else
+               printk(KERN_ALERT "Unable to handle kernel access");
+       printk(KERN_ALERT " at virtual address %08lx\n",address);
+       die_if_kernel("Oops", regs, error_code);
+       do_exit(SIGKILL);
+
+       return 1;
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mm/init.c b/target/linux/ubicom32/files/arch/ubicom32/mm/init.c
new file mode 100644 (file)
index 0000000..c486835
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * arch/ubicom32/mm/init.c
+ *   Ubicom32 architecture virtual memory initialization.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
+ *                      Kenneth Albanowski <kjahds@kjahds.com>,
+ *  Copyright (C) 2000  Lineo, Inc.  (www.lineo.com)
+ *
+ *  Based on:
+ *
+ *  linux/arch/m68k/mm/init.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ *
+ *  JAN/1999 -- hacked to support ColdFire (gerg@snapgear.com)
+ *  DEC/2000 -- linux 2.4 support <davidm@snapgear.com>
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/bootmem.h>
+#include <linux/slab.h>
+
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/ocm-alloc.h>
+#include <asm/processor.h>
+
+#undef DEBUG
+
+extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void free_initmem(void);
+
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+static unsigned long empty_bad_page_table;
+
+static unsigned long empty_bad_page;
+
+unsigned long empty_zero_page;
+
+void show_mem(void)
+{
+    unsigned long i;
+    int free = 0, total = 0, reserved = 0, shared = 0;
+    int cached = 0;
+
+    printk(KERN_INFO "\nMem-info:\n");
+    show_free_areas();
+    i = max_mapnr;
+    while (i-- > 0) {
+       total++;
+       if (PageReserved(mem_map+i))
+           reserved++;
+       else if (PageSwapCache(mem_map+i))
+           cached++;
+       else if (!page_count(mem_map+i))
+           free++;
+       else
+           shared += page_count(mem_map+i) - 1;
+    }
+    printk(KERN_INFO "%d pages of RAM\n",total);
+    printk(KERN_INFO "%d free pages\n",free);
+    printk(KERN_INFO "%d reserved pages\n",reserved);
+    printk(KERN_INFO "%d pages shared\n",shared);
+    printk(KERN_INFO "%d pages swap cached\n",cached);
+}
+
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+extern char __ocm_free_begin;
+extern char __ocm_free_end;
+
+/*
+ * paging_init() continues the virtual memory environment setup which
+ * was begun by the code in arch/head.S.
+ * The parameters are pointers to where to stick the starting and ending
+ * addresses of available kernel virtual memory.
+ */
+void __init paging_init(void)
+{
+       /*
+        * Make sure start_mem is page aligned, otherwise bootmem and
+        * page_alloc get different views of the world.
+        */
+#ifdef DEBUG
+       unsigned long start_mem = PAGE_ALIGN(memory_start);
+#endif
+       unsigned long end_mem   = memory_end & PAGE_MASK;
+
+#ifdef DEBUG
+       printk (KERN_DEBUG "start_mem is %#lx\nvirtual_end is %#lx\n",
+               start_mem, end_mem);
+#endif
+
+       /*
+        * Initialize the bad page table and bad page to point
+        * to a couple of allocated pages.
+        */
+       empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+       empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+       empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+       memset((void *)empty_zero_page, 0, PAGE_SIZE);
+
+       /*
+        * TODO: enable setting up for user memory management interface.
+        */
+
+#ifdef DEBUG
+       printk (KERN_DEBUG "before free_area_init\n");
+
+       printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n",
+               start_mem, end_mem);
+#endif
+
+       {
+               unsigned long zones_size[MAX_NR_ZONES] = {0, };
+#ifdef CONFIG_ZONE_DMA
+               zones_size[ZONE_DMA] = OCMSIZE >> PAGE_SHIFT;
+#endif
+               zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+#ifdef CONFIG_HIGHMEM
+               zones_size[ZONE_HIGHMEM] = 0;
+#endif
+               free_area_init(zones_size);
+       }
+}
+
+void __init mem_init(void)
+{
+       int codek = 0, datak = 0, initk = 0;
+       unsigned long tmp, ram_start, ram_end, len;
+       extern char _etext, _stext, _sdata, _ebss, __init_begin, __init_end;
+
+       unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */
+       unsigned long end_mem   = memory_end; /* DAVIDM - this must not include kernel stack at top */
+       processor_dram(&ram_start, &ram_end);
+       len = (ram_end - ram_start) + OCMSIZE;
+#ifdef DEBUG
+       printk(KERN_DEBUG "Mem_init: start=%lx, end=%lx\n", start_mem, end_mem);
+#endif
+
+       end_mem &= PAGE_MASK;
+       high_memory = (void *) end_mem;
+
+       start_mem = PAGE_ALIGN(start_mem);
+       max_mapnr = num_physpages = (((unsigned long) high_memory) - PAGE_OFFSET) >> PAGE_SHIFT;
+
+       /* this will put all memory onto the freelists */
+#ifdef CONFIG_ZONE_DMA
+       {
+               unsigned long ocm_free_begin = (unsigned long)&__ocm_free_begin;
+               unsigned long ocm_free_end = (unsigned long)&__ocm_free_end;
+               unsigned long zone_dma_begin = (ocm_free_begin + PAGE_SIZE - 1) & PAGE_MASK;
+               unsigned long zone_dma_end = ocm_free_end & PAGE_MASK;
+               if (zone_dma_end > zone_dma_begin)
+                       free_bootmem(zone_dma_begin, zone_dma_end-zone_dma_begin);
+       }
+#endif
+       totalram_pages = free_all_bootmem();
+
+       codek = (&_etext - &_stext) >> 10;
+       datak = (&_ebss - &_sdata) >> 10;
+       initk = (&__init_begin - &__init_end) >> 10;
+
+       tmp = nr_free_pages() << PAGE_SHIFT;
+       printk(KERN_INFO "Memory available: %luk/%luk RAM, (%dk kernel code, %dk data)\n",
+              tmp >> 10,
+              len >> 10,
+              codek,
+              datak
+              );
+
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+       int pages = 0;
+       for (; start < end; start += PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(start));
+               init_page_count(virt_to_page(start));
+               free_page(start);
+               totalram_pages++;
+               pages++;
+       }
+       printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages);
+}
+#endif
+
+void
+free_initmem()
+{
+#ifdef CONFIG_RAMKERNEL
+       unsigned long addr;
+       extern char __init_begin, __init_end;
+       /*
+        * The following code should be cool even if these sections
+        * are not page aligned.
+        */
+       addr = PAGE_ALIGN((unsigned long)(&__init_begin));
+       /* next to check that the page we free is not a partial page */
+       for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) {
+               ClearPageReserved(virt_to_page(addr));
+               init_page_count(virt_to_page(addr));
+               free_page(addr);
+               totalram_pages++;
+       }
+       printk(KERN_NOTICE "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n",
+                       (addr - PAGE_ALIGN((long) &__init_begin)) >> 10,
+                       (int)(PAGE_ALIGN((unsigned long)(&__init_begin))),
+                       (int)(addr - PAGE_SIZE));
+#endif
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mm/kmap.c b/target/linux/ubicom32/files/arch/ubicom32/mm/kmap.c
new file mode 100644 (file)
index 0000000..48b489f
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * arch/ubicom32/mm/kmap.c
+ *   Ubicom32 architecture non-mmu ioremap and friends implementation.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 2000 Lineo, <davidm@snapgear.com>
+ * Copyright (C) 2000-2002 David McCullough <davidm@snapgear.com>
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#undef DEBUG
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
+{
+       return (void *)physaddr;
+}
+
+/*
+ * Unmap a ioremap()ed region again.
+ */
+void iounmap(void *addr)
+{
+}
+
+/*
+ * __iounmap unmaps nearly everything, so be careful
+ * it doesn't free currently pointer/page tables anymore but it
+ * wans't used anyway and might be added later.
+ */
+void __iounmap(void *addr, unsigned long size)
+{
+}
+
+/*
+ * Set new cache mode for some kernel address space.
+ * The caller must push data for that range itself, if such data may already
+ * be in the cache.
+ */
+void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
+{
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mm/memory.c b/target/linux/ubicom32/files/arch/ubicom32/mm/memory.c
new file mode 100644 (file)
index 0000000..17075ff
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * arch/ubicom32/mm/memory.c
+ *   Ubicom32 architecture kernel_map() implementation.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *  Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
+ *  Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ *
+ *  Based on:
+ *
+ *  linux/arch/m68k/mm/memory.c
+ *
+ *  Copyright (C) 1995  Hamish Macdonald
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+/*
+ * Map some physical address range into the kernel address space.
+ * The code is copied and adapted from map_chunk().
+ */
+
+unsigned long kernel_map(unsigned long paddr, unsigned long size,
+                        int nocacheflag, unsigned long *memavailp )
+{
+       return paddr;
+}
diff --git a/target/linux/ubicom32/files/arch/ubicom32/mm/ocm-alloc.c b/target/linux/ubicom32/files/arch/ubicom32/mm/ocm-alloc.c
new file mode 100644 (file)
index 0000000..5a10c29
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * arch/ubicom32/mm/ocm-alloc.c
+ *     OCM allocator for Uibcom32 On-Chip memory
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *  Copyright 2004-2008 Analog Devices Inc.
+ *
+ *  Based on:
+ *
+ *  arch/blackfin/mm/sram-alloc.c
+ *
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/mutex.h>
+#include <linux/rtc.h>
+#include <asm/ocm-alloc.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt, a...)
+#endif
+/*
+ * the data structure for OCM heap pieces
+ */
+struct ocm_piece {
+       void *paddr;
+       int size;
+       pid_t pid;
+       struct ocm_piece *next;
+};
+
+/*
+ * struct ocm_heap
+ */
+struct ocm_heap {
+       struct ocm_piece free_head;
+       struct ocm_piece used_head;
+       struct mutex lock;
+};
+
+static struct ocm_heap ocm_inst_heap;
+int ubi32_ocm_skbuf_max = 21, ubi32_ocm_skbuf, ubi32_ddr_skbuf;
+
+/*
+ * OCM area for storing code
+ */
+extern asmlinkage void *__ocm_free_begin;
+extern asmlinkage void *__ocm_free_end;
+extern asmlinkage void *__ocm_inst_heap_begin;
+extern asmlinkage void *__ocm_inst_heap_end;
+#define OCM_INST_HEAP_BEGIN ((unsigned int)&__ocm_inst_heap_begin)
+#define OCM_INST_HEAP_END ((unsigned int)&__ocm_inst_heap_end)
+#define OCM_INST_HEAP_LENGTH (OCM_INST_HEAP_END - OCM_INST_HEAP_BEGIN)
+
+static struct kmem_cache *ocm_piece_cache;
+
+/*
+ * _ocm_heap_init()
+ */
+static int __init _ocm_heap_init(struct ocm_heap *ocmh,
+                                 unsigned int start,
+                                 unsigned int size)
+{
+       ocmh->free_head.next = kmem_cache_alloc(ocm_piece_cache, GFP_KERNEL);
+
+       if (!ocmh->free_head.next)
+               return -1;
+
+       ocmh->free_head.next->paddr = (void *)start;
+       ocmh->free_head.next->size = size;
+       ocmh->free_head.next->pid = 0;
+       ocmh->free_head.next->next = 0;
+
+       ocmh->used_head.next = NULL;
+
+       /* mutex initialize */
+       mutex_init(&ocmh->lock);
+
+       return 0;
+}
+
+/*
+ * _ocm_alloc_init()
+ *
+ * starts the ocm heap(s)
+ */
+static int __init _ocm_alloc_init(void)
+{
+       if (OCM_INST_HEAP_LENGTH) {
+               ocm_piece_cache = kmem_cache_create("ocm_piece_cache",
+                                                   sizeof(struct ocm_piece),
+                                                   0, SLAB_PANIC, NULL);
+
+               if (_ocm_heap_init(&ocm_inst_heap,
+                                  OCM_INST_HEAP_BEGIN,
+                                  OCM_INST_HEAP_LENGTH) == 0)
+                       printk(KERN_INFO "OCM Instruction Heap %d KB\n",
+                              OCM_INST_HEAP_LENGTH >> 10);
+               else
+                       printk(KERN_INFO "Failed to initialize OCM "
+                              "Instruction Heap\n");
+
+       } else
+               printk(KERN_INFO "No space available for OCM "
+                      "Instruction Heap\n");
+
+       return 0;
+}
+pure_initcall(_ocm_alloc_init);
+
+/*
+ * _ocm_alloc()
+ *     generic alloc a block in the ocm heap, if successful
+ *     returns the pointer.
+ */
+static void *_ocm_alloc(size_t size, pid_t pid, struct ocm_heap *ocmheap)
+{
+       struct ocm_piece *pslot, *plast, *pavail;
+       struct ocm_piece *pfree_head = &ocmheap->free_head;
+       struct ocm_piece *pused_head = &ocmheap->used_head;
+
+       if (size <= 0 || !pfree_head || !pused_head)
+               return NULL;
+
+       /* Align the size */
+       size = (size + 3) & ~3;
+
+       pslot = pfree_head->next;
+       plast = pfree_head;
+
+       /*
+        * search an available piece slot
+        */
+       while (pslot != NULL && size > pslot->size) {
+               plast = pslot;
+               pslot = pslot->next;
+       }
+
+       if (!pslot)
+               return NULL;
+
+       if (pslot->size == size) {
+               /*
+                * Unlink this block from the list
+                */
+               plast->next = pslot->next;
+               pavail = pslot;
+       } else {
+               /*
+                * Split this block in two.
+                */
+               pavail = kmem_cache_alloc(ocm_piece_cache, GFP_KERNEL);
+
+               if (!pavail)
+                       return NULL;
+
+               pavail->paddr = pslot->paddr;
+               pavail->size = size;
+               pslot->paddr += size;
+               pslot->size -= size;
+       }
+
+       pavail->pid = pid;
+
+       pslot = pused_head->next;
+       plast = pused_head;
+
+       /*
+        * insert new piece into used piece list !!!
+        */
+       while (pslot != NULL && pavail->paddr < pslot->paddr) {
+               plast = pslot;
+               pslot = pslot->next;
+       }
+
+       pavail->next = pslot;
+       plast->next = pavail;
+
+       DEBUGP("_ocm_alloc %d bytes at %p from in %p",
+              size, pavail->paddr, ocmheap);
+
+       return pavail->paddr;
+}
+
+#if 0
+/* Allocate the largest available block.  */
+static void *_ocm_alloc_max(struct ocm_heap *ocmheap,
+                            unsigned long *psize)
+{
+       struct ocm_piece *pfree_head = &ocmheap->free_head;
+       struct ocm_piece *pslot, *pmax;
+
+       pmax = pslot = pfree_head->next;
+
+       /* search an available piece slot */
+       while (pslot != NULL) {
+               if (pslot->size > pmax->size)
+                       pmax = pslot;
+               pslot = pslot->next;
+       }
+
+       if (!pmax)
+               return NULL;
+
+       *psize = pmax->size;
+
+       return _ocm_alloc(*psize, ocmheap);
+}
+#endif
+
+/*
+ * _ocm_free()
+ *     generic free a block in the ocm heap, if successful
+ */
+static int _ocm_free(const void *addr,
+                    struct ocm_heap *ocmheap)
+{
+       struct ocm_piece *pslot, *plast, *pavail;
+       struct ocm_piece *pfree_head = &ocmheap->free_head;
+       struct ocm_piece *pused_head = &ocmheap->used_head;
+
+       /* search the relevant memory slot */
+       pslot = pused_head->next;
+       plast = pused_head;
+
+       /* search an available piece slot */
+       while (pslot != NULL && pslot->paddr != addr) {
+               plast = pslot;
+               pslot = pslot->next;
+       }
+
+       if (!pslot) {
+               DEBUGP("_ocm_free %p  not found in %p", addr, ocmheap);
+               return -1;
+       }
+       DEBUGP("_ocm_free %p from in %p", addr, ocmheap);
+
+       plast->next = pslot->next;
+       pavail = pslot;
+       pavail->pid = 0;
+
+       /* insert free pieces back to the free list */
+       pslot = pfree_head->next;
+       plast = pfree_head;
+
+       while (pslot != NULL && addr > pslot->paddr) {
+               plast = pslot;
+               pslot = pslot->next;
+       }
+
+       if (plast != pfree_head &&
+           plast->paddr + plast->size == pavail->paddr) {
+               plast->size += pavail->size;
+               kmem_cache_free(ocm_piece_cache, pavail);
+       } else {
+               pavail->next = plast->next;
+               plast->next = pavail;
+               plast = pavail;
+       }
+
+       if (pslot && plast->paddr + plast->size == pslot->paddr) {
+               plast->size += pslot->size;
+               plast->next = pslot->next;
+               kmem_cache_free(ocm_piece_cache, pslot);
+       }
+
+       return 0;
+}
+
+/*
+ * ocm_inst_alloc()
+ *
+ *     allocates a block of size in the ocm instrction heap, if
+ *     successful returns address allocated.
+ */
+void *ocm_inst_alloc(size_t size, pid_t pid)
+{
+       void *addr;
+
+       if (!OCM_INST_HEAP_LENGTH)
+               return NULL;
+
+
+       mutex_lock(&ocm_inst_heap.lock);
+
+       addr = _ocm_alloc(size, pid, &ocm_inst_heap);
+
+       mutex_unlock(&ocm_inst_heap.lock);
+
+       return addr;
+}
+EXPORT_SYMBOL(ocm_inst_alloc);
+
+/*
+ * ocm_inst_free()
+ *     free a block in the ocm instrction heap, returns 0 if successful.
+ */
+int ocm_inst_free(const void *addr)
+{
+       int ret;
+
+       if (!OCM_INST_HEAP_LENGTH)
+               return -1;
+
+       mutex_lock(&ocm_inst_heap.lock);
+
+       ret = _ocm_free(addr, &ocm_inst_heap);
+
+       mutex_unlock(&ocm_inst_heap.lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(ocm_inst_free);
+
+/*
+ * ocm_free()
+ *     free a block in one of the ocm heaps, returns 0 if successful.
+ */
+int ocm_free(const void *addr)
+{
+       if (addr >= (void *)OCM_INST_HEAP_BEGIN
+                && addr < (void *)(OCM_INST_HEAP_END))
+               return ocm_inst_free(addr);
+       else
+               return -1;
+}
+EXPORT_SYMBOL(ocm_free);
+
+
+#ifdef CONFIG_PROC_FS
+/* Need to keep line of output the same.  Currently, that is 46 bytes
+ * (including newline).
+ */
+static int _ocm_proc_read(char *buf, int *len, int count, const char *desc,
+                          struct ocm_heap *ocmheap)
+{
+       struct ocm_piece *pslot;
+       struct ocm_piece *pfree_head = &ocmheap->free_head;
+       struct ocm_piece *pused_head = &ocmheap->used_head;
+
+       /* The format is the following
+        * --- OCM 123456789012345 Size   PID State     \n
+        * 12345678-12345678 1234567890 12345 1234567890\n
+        */
+       int l;
+       l = sprintf(&buf[*len], "--- OCM %-15s Size   PID State     \n",
+                   desc);
+
+       *len += l;
+       count -= l;
+
+       mutex_lock(&ocm_inst_heap.lock);
+
+       /*
+        * search the relevant memory slot
+        */
+       pslot = pused_head->next;
+
+       while (pslot != NULL && count > 46) {
+               l = sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
+                            pslot->paddr, pslot->paddr + pslot->size,
+                            pslot->size, pslot->pid, "ALLOCATED");
+
+               *len += l;
+               count -= l;
+               pslot = pslot->next;
+       }
+
+       pslot = pfree_head->next;
+
+       while (pslot != NULL && count > 46) {
+               l = sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
+                           pslot->paddr, pslot->paddr + pslot->size,
+                           pslot->size, pslot->pid, "FREE");
+
+               *len += l;
+               count -= l;
+               pslot = pslot->next;
+       }
+
+       mutex_unlock(&ocm_inst_heap.lock);
+
+       return 0;
+}
+
+static int ocm_proc_read(char *buf, char **start, off_t offset, int count,
+               int *eof, void *data)
+{
+       int len = 0;
+
+       len = sprintf(&buf[len], "--- OCM SKB usage (max RX buf %d)\n"
+                       "(SKB in OCM) %d - (SKB in DDR) %d\n",
+                       ubi32_ocm_skbuf_max,
+                       ubi32_ocm_skbuf,
+                       ubi32_ddr_skbuf);
+
+       len += sprintf(&buf[len], "--- OCM Data Heap       Size\n"
+                       "%p-%p %10i\n",
+                       ((void *)&__ocm_free_begin),
+                       ((void *)&__ocm_free_end),
+                       ((unsigned int)&__ocm_free_end) -
+                       ((unsigned int)&__ocm_free_begin));
+
+       if (_ocm_proc_read(buf, &len, count - len, "Inst Heap",
+                           &ocm_inst_heap))
+               goto not_done;
+       *eof = 1;
+ not_done:
+       return len;
+}
+
+static int ocm_proc_write(struct file *file, const char __user *buffer,
+                           unsigned long count, void *data)
+{
+       int n, v;
+       char in[8];
+
+       if (count > sizeof(in))
+               return -EINVAL;
+
+       if (copy_from_user(in, buffer, count))
+               return -EFAULT;
+       in[count-1] = 0;
+
+       printk(KERN_INFO "OCM skb alloc max = %s\n", in);
+
+       n = 0;
+       v = 0;
+       while ((in[n] >= '0') && (in[n] <= '9')) {
+               v = v * 10 + (int)(in[n] - '0');
+               n++;
+       }
+
+       if (v == 0)
+               return -EINVAL;
+
+       ubi32_ocm_skbuf_max = v;
+       ubi32_ocm_skbuf = ubi32_ddr_skbuf = 0;
+
+       return count;
+}
+
+static int __init sram_proc_init(void)
+{
+       struct proc_dir_entry *ptr;
+       ptr = create_proc_entry("ocm", S_IFREG | S_IRUGO, NULL);
+       if (!ptr) {
+               printk(KERN_WARNING "unable to create /proc/ocm\n");
+               return -1;
+       }
+       ptr->read_proc = ocm_proc_read;
+       ptr->write_proc = ocm_proc_write;
+       return 0;
+}
+late_initcall(sram_proc_init);
+#endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/oprofile/Makefile b/target/linux/ubicom32/files/arch/ubicom32/oprofile/Makefile
new file mode 100644 (file)
index 0000000..969d2f7
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# arch/ubicom32/Makefile
+#       Makefile for Oprofile support on Ubicom32
+#
+# (C) Copyright 2009, Ubicom, Inc.
+#
+# This file is part of the Ubicom32 Linux Kernel Port.
+#
+# The Ubicom32 Linux Kernel Port 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.
+#
+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+# see <http://www.gnu.org/licenses/>.
+#
+# Ubicom32 implementation derived from (with many thanks):
+#   arch/m68knommu
+#   arch/blackfin
+#   arch/parisc
+#
+
+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) profile.o
diff --git a/target/linux/ubicom32/files/arch/ubicom32/oprofile/ipProf.h b/target/linux/ubicom32/files/arch/ubicom32/oprofile/ipProf.h
new file mode 100644 (file)
index 0000000..2a785f0
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __IP_PROF_H__
+#define __IP_PROF_H__
+
+/* This number MUST match what is used in the ultra configuration! */
+#define IPPROFILETIO_MAX_SAMPLES       600
+
+/* Move to .h file used in both; avoid special types  */
+struct profile_sample {
+       unsigned int    pc;             /* PC value */
+       unsigned int    parent;         /* a5 contents, to find the caller */
+       unsigned char   cond_codes;     /* for branch prediction */
+       unsigned char   thread;         /* I-blocked, D-blocked,
+                                          4-bit thread number */
+       unsigned short  active;         /* which threads are active -
+                                          for accurate counting */
+       unsigned short  blocked;        /* which threads are blocked due to
+                                          I or D cache misses */
+       unsigned int    latency;        /* CPU clocks since the last message
+                                          dispatch in this thread
+                                          (thread 0 only for now) */
+};
+
+
+struct profilenode {
+       struct devtree_node dn;
+       volatile unsigned char enabled; /* Is the tio enabled to
+                                          take samples? */
+       volatile unsigned char busy;    /* set when the samples
+                                          are being read */
+       volatile unsigned int mask;     /* Threads that change the MT_EN flag */
+       volatile unsigned short rate;   /* What is the sampling rate? */
+       volatile unsigned short head;   /* sample taker puts samples here */
+       volatile unsigned short tail;   /* packet filler takes samples here */
+       volatile unsigned short count;  /* number of valid samples */
+       volatile unsigned short total;  /* Total samples */
+       struct profile_sample samples[IPPROFILETIO_MAX_SAMPLES];
+};
+
+#endif
diff --git a/target/linux/ubicom32/files/arch/ubicom32/oprofile/profile.c b/target/linux/ubicom32/files/arch/ubicom32/oprofile/profile.c
new file mode 100644 (file)
index 0000000..aeac3c6
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * arch/ubicom32/oprofile/profile.c
+ *     Oprofile support for arch Ubicom32
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+/**
+ * @file profile.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Hunyue Yau <hy@hy-research.com>
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <asm/devtree.h>
+#include <asm/thread.h>
+
+/* For identifying userland vs kernel address */
+#include <asm/stacktrace.h>
+#include "ipProf.h"
+
+/* For communications with the backend */
+static struct profilenode *profile_node;
+
+/* Bitmask containing all Linux threads - as seen by the ROSR reg */
+static unsigned long th_all_mask;
+
+/* Lookup table to translate a hardware thread into a CPU identifier
+ * Table is indexed by the ROSR value which is assumed to be
+ * relatively small (0...15).
+ */
+unsigned int cpu_map[THREAD_ARCHITECTURAL_MAX];
+
+static struct pt_regs regs;
+
+/*
+ * For each sample returned, checked to see if they are relevant to
+ * us. This is necessary as the ubicom32 architecture has other software
+ * running outside of Linux. Only then, put the sample into the relevant
+ * cpu bins.
+ *
+ * To minimize overhead, a global mask with all possible threads of in
+ * interest to us is used as a first check. Then a second mask identifying
+ * the thread is used to obtain an identifier for that "CPU".
+ */
+
+/*
+ * ubicom32_build_cpu_th_mask()
+ *
+ * Build a lookup table for translation between hardware thread
+ * "ROSR" values and Linux CPU ids
+ *
+ * *** This gets executed on all CPUs at once! ***
+ */
+static void ubicom32_build_cpu_th_mask(void *mask)
+{
+       thread_t self = thread_get_self();
+       unsigned long *th_m = mask;
+
+       BUG_ON(self <= 0 || self >= THREAD_ARCHITECTURAL_MAX);
+       cpu_map[self] = smp_processor_id();
+
+       set_bit(self, th_m);
+}
+
+/*
+ * profile_interrupt()
+ *
+ * Process samples returned from the profiler backend. The backend
+ * may return samples that are irrelevant to us or may even return
+ * multiple samples for the same CPU. Note that the sames may be
+ * for ANY cpu. At this time, this is unique and to support this requires
+ * Oprofile to expose an interface to accept the CPU that the same came
+ * frome.
+ */
+static irqreturn_t profile_interrupt(int irq, void *arg)
+{
+       int i, buf_entry;
+       int is_kernel;
+       unsigned int bit_th;
+       unsigned int th;
+
+       if (!(profile_node->enabled) || profile_node->count < 0) {
+               printk(KERN_WARNING
+                       "Unexpected interrupt, no samples or not enabled!\n");
+               return IRQ_HANDLED;
+       }
+
+       profile_node->busy = 1;         /* Keep backend out */
+
+       for (i = 0; i < profile_node->count; i++) {
+               buf_entry = profile_node->tail;
+               profile_node->tail++;
+               profile_node->tail %= IPPROFILETIO_MAX_SAMPLES;
+
+               /* Note - the "thread" ID is only the lower 4 bits */
+               th = (0x0f & profile_node->samples[buf_entry].thread);
+               bit_th = (1 << th);
+
+               if ((bit_th & th_all_mask) == 0)
+                       continue;
+
+               regs.pc = profile_node->samples[buf_entry].pc;
+
+               is_kernel = ubicom32_is_kernel(regs.pc);
+
+               oprofile_add_ext_sample_cpu(regs.pc, &regs, 0, is_kernel,
+                                           cpu_map[th]);
+       }
+       profile_node->count = 0;
+       profile_node->busy = 0;
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * profile_start()
+ *
+ * Notification from oprofile to start the profiler
+ */
+static int profile_start(void)
+{
+       if (!profile_node)
+               return -1;
+
+       profile_node->enabled = 1;
+
+       return 0;
+}
+
+/*
+ * profile_stop()
+ *
+ * Notification from oprofile to stop the profiler
+ */
+static void profile_stop(void)
+{
+       if (profile_node)
+               profile_node->enabled = 0;
+}
+
+/*
+ * oprofile_arch_init()
+ *
+ * Attach to Oprofile after qualify the availability of the backend
+ * profiler support.
+ */
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+       int r = -ENODEV;
+
+       profile_node = (struct profilenode *)devtree_find_node("profiler");
+
+       if (profile_node == NULL) {
+               printk(KERN_WARNING "Cannot find profiler node\n");
+               return r;
+       }
+
+       r = request_irq(profile_node->dn.recvirq, profile_interrupt,
+                       IRQF_DISABLED, "profiler", NULL);
+
+       if (r < 0) {
+               profile_node = NULL;
+               printk(KERN_WARNING "Cannot get profiler IRQ\n");
+               return r;
+       }
+
+       ops->start = profile_start;
+       ops->stop = profile_stop;
+       ops->cpu_type = "timer";
+
+       memset(cpu_map, 0, sizeof(cpu_map));
+
+       on_each_cpu(ubicom32_build_cpu_th_mask, &th_all_mask, 1);
+
+       memset(&regs, 0, sizeof(regs));
+
+       return r;
+}
+
+/*
+ * oprofile_arch_exit()
+ *
+ * External call to take outselves out.
+ * Make sure backend is not running.
+ */
+void oprofile_arch_exit(void)
+{
+       BUG_ON(profile_node->enabled);
+}
diff --git a/target/linux/ubicom32/files/drivers/char/hw_random/ubicom32-rng.c b/target/linux/ubicom32/files/drivers/char/hw_random/ubicom32-rng.c
new file mode 100644 (file)
index 0000000..e429589
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * drivers/net/ubi32-eth.c
+ *   Ubicom32 hardware random number generator driver.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/hw_random.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/ip5000.h>
+
+#define MODULE_NAME "ubicom32_rng"
+
+static int ubicom32_rng_data_present(struct hwrng *rng, int wait)
+{
+       int data, i;
+
+       for (i = 0; i < 20; i++) {
+               data = *(int *)(TIMER_BASE + TIMER_TRN);
+               if (data || !wait)
+                       break;
+               udelay(10);
+       }
+       return data;
+}
+
+static int ubicom32_rng_data_read(struct hwrng *rng, u32 *data)
+{
+       *data = *(int *)(TIMER_BASE + TIMER_TRN);
+       return 4;
+}
+
+static int ubicom32_rng_init(struct hwrng *rng)
+{
+       printk(KERN_INFO "ubicom32 rng init\n");
+       *(int *)(TIMER_BASE + TIMER_TRN_CFG) = TIMER_TRN_CFG_ENABLE_OSC;
+       return 0;
+}
+
+static void ubicom32_rng_cleanup(struct hwrng *rng)
+{
+       printk(KERN_INFO "ubicom32 rng cleanup\n");
+       *(int *)(TIMER_BASE + TIMER_TRN_CFG) = 0;
+}
+
+static struct hwrng ubicom32_rng = {
+       .name           = MODULE_NAME,
+       .init           = ubicom32_rng_init,
+       .cleanup        = ubicom32_rng_cleanup,
+       .data_present   = ubicom32_rng_data_present,
+       .data_read      = ubicom32_rng_data_read,
+       .priv           = 0,
+};
+
+static int __init mod_init(void)
+{
+       int err;
+
+       printk(KERN_INFO "ubicom32 rng started\n");
+       err = hwrng_register(&ubicom32_rng);
+       if (err) {
+               printk(KERN_ERR "ubicom32 rng register failed (%d)\n",
+                       err);
+       }
+
+       return err;
+}
+
+static void __exit mod_exit(void)
+{
+       printk(KERN_INFO "ubicom32 rng stopped\n");
+       hwrng_unregister(&ubicom32_rng);
+}
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ubicom, Inc.");
+MODULE_DESCRIPTION("H/W rng driver for ubicom32 processor");
+MODULE_VERSION("1:1.0.a");
diff --git a/target/linux/ubicom32/files/drivers/mmc/host/ubicom32sd.c b/target/linux/ubicom32/files/drivers/mmc/host/ubicom32sd.c
new file mode 100644 (file)
index 0000000..107c92a
--- /dev/null
@@ -0,0 +1,773 @@
+/*
+ * drivers/mmc/host/ubicom32sd.c
+ *     Ubicom32 Secure Digital Host Controller Interface driver
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/scatterlist.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/mmc/host.h>
+
+#include <asm/ubicom32sd.h>
+
+#define DRIVER_NAME "ubicom32sd"
+
+#define sd_printk(...)
+//#define sd_printk printk
+
+#define SDTIO_VP_VERSION       3
+
+#define SDTIO_MAX_SG_BLOCKS    16
+
+enum sdtio_commands {
+       SDTIO_COMMAND_NOP,
+       SDTIO_COMMAND_SETUP,
+       SDTIO_COMMAND_SETUP_SDIO,
+       SDTIO_COMMAND_EXECUTE,
+       SDTIO_COMMAND_RESET,
+};
+
+#define SDTIO_COMMAND_SHIFT                    24
+#define SDTIO_COMMAND_FLAG_STOP_RSP_CRC                (1 << 10)
+#define SDTIO_COMMAND_FLAG_STOP_RSP_136                (1 << 9)
+#define SDTIO_COMMAND_FLAG_STOP_RSP            (1 << 8)
+#define SDTIO_COMMAND_FLAG_STOP_CMD            (1 << 7)
+#define SDTIO_COMMAND_FLAG_DATA_STREAM         (1 << 6)
+#define SDTIO_COMMAND_FLAG_DATA_RD             (1 << 5)
+#define SDTIO_COMMAND_FLAG_DATA_WR             (1 << 4)
+#define SDTIO_COMMAND_FLAG_CMD_RSP_CRC         (1 << 3)
+#define SDTIO_COMMAND_FLAG_CMD_RSP_136         (1 << 2)
+#define SDTIO_COMMAND_FLAG_CMD_RSP             (1 << 1)
+#define SDTIO_COMMAND_FLAG_CMD                 (1 << 0)
+
+/*
+ * SDTIO_COMMAND_SETUP_SDIO
+ */
+#define SDTIO_COMMAND_FLAG_SDIO_INT_EN         (1 << 0)
+
+/*
+ * SDTIO_COMMAND_SETUP
+ *      clock speed in arg
+ */
+#define SDTIO_COMMAND_FLAG_4BIT                 (1 << 3)
+#define SDTIO_COMMAND_FLAG_1BIT                 (1 << 2)
+#define SDTIO_COMMAND_FLAG_SET_CLOCK            (1 << 1)
+#define SDTIO_COMMAND_FLAG_SET_WIDTH            (1 << 0)
+
+#define SDTIO_COMMAND_FLAG_CMD_RSP_MASK                (SDTIO_COMMAND_FLAG_CMD_RSP | SDTIO_COMMAND_FLAG_CMD_RSP_136)
+#define SDTIO_COMMAND_FLAG_STOP_RSP_MASK       (SDTIO_COMMAND_FLAG_STOP_RSP | SDTIO_COMMAND_FLAG_STOP_RSP_136)
+#define SDTIO_COMMAND_FLAG_RSP_MASK            (SDTIO_COMMAND_FLAG_CMD_RSP_MASK | SDTIO_COMMAND_FLAG_STOP_RSP_MASK)
+
+struct sdtio_vp_sg {
+       volatile void           *addr;
+       volatile u32_t          len;
+};
+
+#define SDTIO_VP_INT_STATUS_DONE               (1 << 31)
+#define SDTIO_VP_INT_STATUS_SDIO_INT           (1 << 10)
+#define SDTIO_VP_INT_STATUS_DATA_CRC_ERR       (1 << 9)
+#define SDTIO_VP_INT_STATUS_DATA_PROG_ERR      (1 << 8)
+#define SDTIO_VP_INT_STATUS_DATA_TIMEOUT       (1 << 7)
+#define SDTIO_VP_INT_STATUS_STOP_RSP_CRC       (1 << 6)
+#define SDTIO_VP_INT_STATUS_STOP_RSP_TIMEOUT   (1 << 5)
+#define SDTIO_VP_INT_STATUS_CMD_RSP_CRC                (1 << 4)
+#define SDTIO_VP_INT_STATUS_CMD_RSP_TIMEOUT    (1 << 3)
+#define SDTIO_VP_INT_STATUS_CMD_TIMEOUT                (1 << 2)
+#define SDTIO_VP_INT_STATUS_CARD1_INSERT       (1 << 1)
+#define SDTIO_VP_INT_STATUS_CARD0_INSERT       (1 << 0)
+
+struct sdtio_vp_regs {
+       u32_t                           version;
+       u32_t                           f_max;
+       u32_t                           f_min;
+
+       volatile u32_t                  int_status;
+
+       volatile u32_t                  command;
+       volatile u32_t                  arg;
+
+       volatile u32_t                  cmd_opcode;
+       volatile u32_t                  cmd_arg;
+       volatile u32_t                  cmd_rsp0;
+       volatile u32_t                  cmd_rsp1;
+       volatile u32_t                  cmd_rsp2;
+       volatile u32_t                  cmd_rsp3;
+
+       volatile u32_t                  stop_opcode;
+       volatile u32_t                  stop_arg;
+       volatile u32_t                  stop_rsp0;
+       volatile u32_t                  stop_rsp1;
+       volatile u32_t                  stop_rsp2;
+       volatile u32_t                  stop_rsp3;
+
+       volatile u32_t                  data_timeout_ns;
+       volatile u16_t                  data_blksz;
+       volatile u16_t                  data_blkct;
+       volatile u32_t                  data_bytes_transferred;
+       volatile u32_t                  sg_len;
+       struct sdtio_vp_sg              sg[SDTIO_MAX_SG_BLOCKS];
+};
+
+struct ubicom32sd_data {
+       const struct ubicom32sd_platform_data   *pdata;
+
+       struct mmc_host                         *mmc;
+
+       /*
+        * Lock used to protect the data structure
+       spinlock_t                              lock;
+        */
+       int     int_en;
+       int     int_pend;
+
+       /*
+        * Receive and transmit interrupts used for communicating
+        * with hardware
+        */
+       int                                     irq_tx;
+       int                                     irq_rx;
+
+       /*
+        * Current outstanding mmc request
+        */
+       struct mmc_request                      *mrq;
+
+       /*
+        * Hardware registers
+        */
+       struct sdtio_vp_regs                    *regs;
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Suspend/resume                                                            *
+ *                                                                           *
+\*****************************************************************************/
+
+#if 0//def CONFIG_PM
+
+int ubicom32sd_suspend_host(struct ubicom32sd_host *host, pm_message_t state)
+{
+       int ret;
+
+       ret = mmc_suspend_host(host->mmc, state);
+       if (ret)
+               return ret;
+
+       free_irq(host->irq, host);
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(ubicom32sd_suspend_host);
+
+int ubicom32sd_resume_host(struct ubicom32sd_host *host)
+{
+       int ret;
+
+       if (host->flags & UBICOM32SD_USE_DMA) {
+               if (host->ops->enable_dma)
+                       host->ops->enable_dma(host);
+       }
+
+       ret = request_irq(host->irq, ubicom32sd_irq, IRQF_SHARED,
+                         mmc_hostname(host->mmc), host);
+       if (ret)
+               return ret;
+
+       ubicom32sd_init(host);
+       mmiowb();
+
+       ret = mmc_resume_host(host->mmc);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(ubicom32sd_resume_host);
+
+#endif /* CONFIG_PM */
+
+/*
+ * ubicom32sd_send_command_sync
+ */
+static void ubicom32sd_send_command_sync(struct ubicom32sd_data *ud, u32_t command, u32_t arg)
+{
+       ud->regs->command = command;
+       ud->regs->arg = arg;
+       ubicom32_set_interrupt(ud->irq_tx);
+       while (ud->regs->command) {
+               ndelay(100);
+       }
+}
+
+/*
+ * ubicom32sd_send_command
+ */
+static void ubicom32sd_send_command(struct ubicom32sd_data *ud, u32_t command, u32_t arg)
+{
+       ud->regs->command = command;
+       ud->regs->arg = arg;
+       ubicom32_set_interrupt(ud->irq_tx);
+}
+
+/*
+ * ubicom32sd_reset
+ */
+static void ubicom32sd_reset(struct ubicom32sd_data *ud)
+{
+       ubicom32sd_send_command_sync(ud, SDTIO_COMMAND_RESET << SDTIO_COMMAND_SHIFT, 0);
+       ud->regs->int_status = 0;
+}
+
+/*
+ * ubicom32sd_mmc_request
+ */
+static void ubicom32sd_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc);
+       u32_t command = SDTIO_COMMAND_EXECUTE << SDTIO_COMMAND_SHIFT;
+       int ret = 0;
+
+       WARN(ud->mrq != NULL, "ud->mrq still set to %p\n", ud->mrq);
+       //pr_debug("send cmd %08x arg %08x flags %08x\n", cmd->opcode, cmd->arg, cmd->flags);
+
+       if (mrq->cmd) {
+               struct mmc_command *cmd = mrq->cmd;
+
+               sd_printk("%s:\t\t\tsetup cmd %02d arg %08x flags %08x\n", mmc_hostname(mmc), cmd->opcode, cmd->arg, cmd->flags);
+
+               ud->regs->cmd_opcode = cmd->opcode;
+               ud->regs->cmd_arg = cmd->arg;
+
+               command |= SDTIO_COMMAND_FLAG_CMD;
+
+               if (cmd->flags & MMC_RSP_PRESENT) {
+                       command |= SDTIO_COMMAND_FLAG_CMD_RSP;
+               }
+
+               if (cmd->flags & MMC_RSP_136) {
+                       command |= SDTIO_COMMAND_FLAG_CMD_RSP_136;
+               }
+
+               if (cmd->flags & MMC_RSP_CRC) {
+                       command |= SDTIO_COMMAND_FLAG_CMD_RSP_CRC;
+               }
+       }
+
+       if (mrq->data) {
+               struct mmc_data *data = mrq->data;
+               struct scatterlist *sg = data->sg;
+               int i;
+
+printk("%s:\t\t\tsetup data blksz %d num %d sglen=%d fl=%08x Tns=%u\n", mmc_hostname(mmc), data->blksz, data->blocks, data->sg_len, data->flags, data->timeout_ns);
+
+               sd_printk("%s:\t\t\tsetup data blksz %d num %d sglen=%d fl=%08x Tns=%u\n",
+                         mmc_hostname(mmc), data->blksz, data->blocks, data->sg_len,
+                         data->flags, data->timeout_ns);
+
+               if (data->sg_len > SDTIO_MAX_SG_BLOCKS) {
+                       ret = -EINVAL;
+                       data->error = -EINVAL;
+                       goto fail;
+               }
+
+               ud->regs->data_timeout_ns = data->timeout_ns;
+               ud->regs->data_blksz = data->blksz;
+               ud->regs->data_blkct = data->blocks;
+               ud->regs->sg_len = data->sg_len;
+
+               /*
+                * Load all of our sg list into the driver sg buffer
+                */
+               for (i = 0; i < data->sg_len; i++) {
+                       sd_printk("%s: sg %d = %p %d\n", mmc_hostname(mmc), i, sg_virt(sg), sg->length);
+                       ud->regs->sg[i].addr = sg_virt(sg);
+                       ud->regs->sg[i].len = sg->length;
+                       if (((u32_t)ud->regs->sg[i].addr & 0x03) || (sg->length & 0x03)) {
+                               sd_printk("%s: Need aligned buffers\n", mmc_hostname(mmc));
+                               ret = -EINVAL;
+                               data->error = -EINVAL;
+                               goto fail;
+                       }
+                       sg++;
+               }
+               if (data->flags & MMC_DATA_READ) {
+                       command |= SDTIO_COMMAND_FLAG_DATA_RD;
+               } else if (data->flags & MMC_DATA_WRITE) {
+                       command |= SDTIO_COMMAND_FLAG_DATA_WR;
+               } else if (data->flags & MMC_DATA_STREAM) {
+                       command |= SDTIO_COMMAND_FLAG_DATA_STREAM;
+               }
+       }
+
+       if (mrq->stop) {
+               struct mmc_command *stop = mrq->stop;
+               sd_printk("%s: \t\t\tsetup stop %02d arg %08x flags %08x\n", mmc_hostname(mmc), stop->opcode, stop->arg, stop->flags);
+
+               ud->regs->stop_opcode = stop->opcode;
+               ud->regs->stop_arg = stop->arg;
+
+               command |= SDTIO_COMMAND_FLAG_STOP_CMD;
+
+               if (stop->flags & MMC_RSP_PRESENT) {
+                       command |= SDTIO_COMMAND_FLAG_STOP_RSP;
+               }
+
+               if (stop->flags & MMC_RSP_136) {
+                       command |= SDTIO_COMMAND_FLAG_STOP_RSP_136;
+               }
+
+               if (stop->flags & MMC_RSP_CRC) {
+                       command |= SDTIO_COMMAND_FLAG_STOP_RSP_CRC;
+               }
+       }
+
+       ud->mrq = mrq;
+
+       sd_printk("%s: Sending command %08x\n", mmc_hostname(mmc), command);
+
+       ubicom32sd_send_command(ud, command, 0);
+
+       return;
+fail:
+       sd_printk("%s: mmcreq ret = %d\n", mmc_hostname(mmc), ret);
+       mrq->cmd->error = ret;
+       mmc_request_done(mmc, mrq);
+}
+
+/*
+ * ubicom32sd_mmc_set_ios
+ */
+static void ubicom32sd_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc);
+       u32_t command = SDTIO_COMMAND_SETUP << SDTIO_COMMAND_SHIFT;
+       u32_t arg = 0;
+       sd_printk("%s: ios call bw:%u pm:%u clk:%u\n", mmc_hostname(mmc), 1 << ios->bus_width, ios->power_mode, ios->clock);
+
+       switch (ios->bus_width) {
+       case MMC_BUS_WIDTH_1:
+               command |= SDTIO_COMMAND_FLAG_SET_WIDTH | SDTIO_COMMAND_FLAG_1BIT;
+               break;
+
+       case MMC_BUS_WIDTH_4:
+               command |= SDTIO_COMMAND_FLAG_SET_WIDTH | SDTIO_COMMAND_FLAG_4BIT;
+               break;
+       }
+
+       if (ios->clock) {
+               arg = ios->clock;
+               command |= SDTIO_COMMAND_FLAG_SET_CLOCK;
+       }
+
+       switch (ios->power_mode) {
+
+       /*
+        * Turn off the SD bus (power + clock)
+        */
+       case MMC_POWER_OFF:
+               gpio_set_value(ud->pdata->cards[0].pin_pwr, !ud->pdata->cards[0].pwr_polarity);
+               command |= SDTIO_COMMAND_FLAG_SET_CLOCK;
+               break;
+
+       /*
+        * Turn on the power to the SD bus
+        */
+       case MMC_POWER_ON:
+               gpio_set_value(ud->pdata->cards[0].pin_pwr, ud->pdata->cards[0].pwr_polarity);
+               break;
+
+       /*
+        * Turn on the clock to the SD bus
+        */
+       case MMC_POWER_UP:
+               /*
+                * Done above
+                */
+               break;
+       }
+
+       ubicom32sd_send_command_sync(ud, command, arg);
+
+       /*
+        * Let the power settle down
+        */
+       udelay(500);
+}
+
+/*
+ * ubicom32sd_mmc_get_cd
+ */
+static int ubicom32sd_mmc_get_cd(struct mmc_host *mmc)
+{
+       struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc);
+       sd_printk("%s: get cd %u %u\n", mmc_hostname(mmc), ud->pdata->cards[0].pin_cd, gpio_get_value(ud->pdata->cards[0].pin_cd));
+
+       return gpio_get_value(ud->pdata->cards[0].pin_cd) ?
+                               ud->pdata->cards[0].cd_polarity :
+                               !ud->pdata->cards[0].cd_polarity;
+}
+
+/*
+ * ubicom32sd_mmc_get_ro
+ */
+static int ubicom32sd_mmc_get_ro(struct mmc_host *mmc)
+{
+       struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc);
+       sd_printk("%s: get ro %u %u\n", mmc_hostname(mmc), ud->pdata->cards[0].pin_wp, gpio_get_value(ud->pdata->cards[0].pin_wp));
+
+       return gpio_get_value(ud->pdata->cards[0].pin_wp) ?
+                               ud->pdata->cards[0].wp_polarity :
+                               !ud->pdata->cards[0].wp_polarity;
+}
+
+/*
+ * ubicom32sd_mmc_enable_sdio_irq
+ */
+static void ubicom32sd_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+       struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc);
+
+       ud->int_en = enable;
+       if (enable && ud->int_pend) {
+               ud->int_pend = 0;
+               mmc_signal_sdio_irq(mmc);
+       }
+}
+
+/*
+ * ubicom32sd_interrupt
+ */
+static irqreturn_t ubicom32sd_interrupt(int irq, void *dev)
+{
+       struct mmc_host *mmc = (struct mmc_host *)dev;
+       struct mmc_request *mrq;
+       struct ubicom32sd_data *ud;
+       u32_t int_status;
+
+       if (!mmc) {
+               return IRQ_HANDLED;
+       }
+
+       ud = (struct ubicom32sd_data *)mmc_priv(mmc);
+       if (!ud) {
+               return IRQ_HANDLED;
+       }
+
+       int_status = ud->regs->int_status;
+       ud->regs->int_status &= ~int_status;
+
+       if (int_status & SDTIO_VP_INT_STATUS_SDIO_INT) {
+               if (ud->int_en) {
+                       ud->int_pend = 0;
+                       mmc_signal_sdio_irq(mmc);
+               } else {
+                       ud->int_pend++;
+               }
+       }
+
+       if (!(int_status & SDTIO_VP_INT_STATUS_DONE)) {
+               return IRQ_HANDLED;
+       }
+
+       mrq = ud->mrq;
+       if (!mrq) {
+               sd_printk("%s: Spurious interrupt", mmc_hostname(mmc));
+               return IRQ_HANDLED;
+       }
+       ud->mrq = NULL;
+
+       /*
+        * SDTIO_VP_INT_DONE
+        */
+       if (mrq->cmd->flags & MMC_RSP_PRESENT) {
+               struct mmc_command *cmd = mrq->cmd;
+               cmd->error = 0;
+
+               if ((cmd->flags & MMC_RSP_CRC) && (int_status & SDTIO_VP_INT_STATUS_CMD_RSP_CRC)) {
+                       cmd->error = -EILSEQ;
+               } else if (int_status & SDTIO_VP_INT_STATUS_CMD_RSP_TIMEOUT) {
+                       cmd->error = -ETIMEDOUT;
+                       goto done;
+               } else if (cmd->flags & MMC_RSP_136) {
+                       cmd->resp[0] = ud->regs->cmd_rsp0;
+                       cmd->resp[1] = ud->regs->cmd_rsp1;
+                       cmd->resp[2] = ud->regs->cmd_rsp2;
+                       cmd->resp[3] = ud->regs->cmd_rsp3;
+               } else {
+                       cmd->resp[0] = ud->regs->cmd_rsp0;
+               }
+               sd_printk("%s:\t\t\tResponse %08x %08x %08x %08x err=%d\n", mmc_hostname(mmc), cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error);
+       }
+
+       if (mrq->data) {
+               struct mmc_data *data = mrq->data;
+
+               if (int_status & SDTIO_VP_INT_STATUS_DATA_TIMEOUT) {
+                       data->error = -ETIMEDOUT;
+                       sd_printk("%s:\t\t\tData Timeout\n", mmc_hostname(mmc));
+                       goto done;
+               } else if (int_status & SDTIO_VP_INT_STATUS_DATA_CRC_ERR) {
+                       data->error = -EILSEQ;
+                       sd_printk("%s:\t\t\tData CRC\n", mmc_hostname(mmc));
+                       goto done;
+               } else if (int_status & SDTIO_VP_INT_STATUS_DATA_PROG_ERR) {
+                       data->error = -EILSEQ;
+                       sd_printk("%s:\t\t\tData Program Error\n", mmc_hostname(mmc));
+                       goto done;
+               } else {
+                       data->error = 0;
+                       data->bytes_xfered = ud->regs->data_bytes_transferred;
+               }
+       }
+
+       if (mrq->stop && (mrq->stop->flags & MMC_RSP_PRESENT)) {
+               struct mmc_command *stop = mrq->stop;
+               stop->error = 0;
+
+               if ((stop->flags & MMC_RSP_CRC) && (int_status & SDTIO_VP_INT_STATUS_STOP_RSP_CRC)) {
+                       stop->error = -EILSEQ;
+               } else if (int_status & SDTIO_VP_INT_STATUS_STOP_RSP_TIMEOUT) {
+                       stop->error = -ETIMEDOUT;
+                       goto done;
+               } else if (stop->flags & MMC_RSP_136) {
+                       stop->resp[0] = ud->regs->stop_rsp0;
+                       stop->resp[1] = ud->regs->stop_rsp1;
+                       stop->resp[2] = ud->regs->stop_rsp2;
+                       stop->resp[3] = ud->regs->stop_rsp3;
+               } else {
+                       stop->resp[0] = ud->regs->stop_rsp0;
+               }
+               sd_printk("%s:\t\t\tStop Response %08x %08x %08x %08x err=%d\n", mmc_hostname(mmc), stop->resp[0], stop->resp[1], stop->resp[2], stop->resp[3], stop->error);
+       }
+
+done:
+       mmc_request_done(mmc, mrq);
+
+       return IRQ_HANDLED;
+}
+
+static struct mmc_host_ops ubicom32sd_ops = {
+       .request                = ubicom32sd_mmc_request,
+       .set_ios                = ubicom32sd_mmc_set_ios,
+       .get_ro                 = ubicom32sd_mmc_get_ro,
+       .get_cd                 = ubicom32sd_mmc_get_cd,
+       .enable_sdio_irq        = ubicom32sd_mmc_enable_sdio_irq,
+};
+
+/*
+ * ubicom32sd_probe
+ */
+static int __devinit ubicom32sd_probe(struct platform_device *pdev)
+{
+       struct ubicom32sd_platform_data *pdata = (struct ubicom32sd_platform_data *)pdev->dev.platform_data;
+       struct mmc_host *mmc;
+       struct ubicom32sd_data *ud;
+       struct resource *res_regs;
+       struct resource *res_irq_tx;
+       struct resource *res_irq_rx;
+       int ret;
+
+       /*
+        * Get our resources, regs is the hardware driver base address
+        * and the tx and rx irqs are used to communicate with the
+        * hardware driver.
+        */
+       res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       res_irq_tx = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       res_irq_rx = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+       if (!res_regs || !res_irq_tx || !res_irq_rx) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       /*
+        * Reserve any gpios we need
+        */
+       ret = gpio_request(pdata->cards[0].pin_wp, "sd-wp");
+       if (ret) {
+               goto fail;
+       }
+       gpio_direction_input(pdata->cards[0].pin_wp);
+
+       ret = gpio_request(pdata->cards[0].pin_cd, "sd-cd");
+       if (ret) {
+               goto fail_cd;
+       }
+       gpio_direction_input(pdata->cards[0].pin_cd);
+
+       /*
+        * HACK: for the dual port controller on port F, we don't support the second port right now
+        */
+       if (pdata->ncards > 1) {
+               ret = gpio_request(pdata->cards[1].pin_pwr, "sd-pwr");
+               gpio_direction_output(pdata->cards[1].pin_pwr, !pdata->cards[1].pwr_polarity);
+               gpio_direction_output(pdata->cards[1].pin_pwr, pdata->cards[1].pwr_polarity);
+       }
+
+       ret = gpio_request(pdata->cards[0].pin_pwr, "sd-pwr");
+       if (ret) {
+               goto fail_pwr;
+       }
+       gpio_direction_output(pdata->cards[0].pin_pwr, !pdata->cards[0].pwr_polarity);
+
+       /*
+        * Allocate the MMC driver, it includes memory for our data.
+        */
+       mmc = mmc_alloc_host(sizeof(struct ubicom32sd_data), &pdev->dev);
+       if (!mmc) {
+               ret = -ENOMEM;
+               goto fail_mmc;
+       }
+       ud = (struct ubicom32sd_data *)mmc_priv(mmc);
+       ud->mmc = mmc;
+       ud->pdata = pdata;
+       ud->regs = (struct sdtio_vp_regs *)res_regs->start;
+       ud->irq_tx = res_irq_tx->start;
+       ud->irq_rx = res_irq_rx->start;
+       platform_set_drvdata(pdev, mmc);
+
+       ret = request_irq(ud->irq_rx, ubicom32sd_interrupt, IRQF_DISABLED, mmc_hostname(mmc), mmc);
+       if (ret) {
+               goto fail_mmc;
+       }
+
+       /*
+        * Fill in the mmc structure
+        */
+       mmc->ops = &ubicom32sd_ops;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NEEDS_POLL | MMC_CAP_SDIO_IRQ |
+                   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
+
+       mmc->f_min = ud->regs->f_min;
+       mmc->f_max = ud->regs->f_max;
+       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+       /*
+        * Setup some restrictions on transfers
+        *
+        * We allow up to SDTIO_MAX_SG_BLOCKS of data to DMA into, there are
+        * not really any "max_seg_size", "max_req_size", or "max_blk_count"
+        * restrictions (must be less than U32_MAX though), pick
+        * something large?!...
+        *
+        * The hardware can do up to 4095 bytes per block, since the spec
+        * only requires 2048, we'll set it to that and not worry about
+        * potential weird blk lengths.
+        */
+       mmc->max_hw_segs = SDTIO_MAX_SG_BLOCKS;
+       mmc->max_phys_segs = SDTIO_MAX_SG_BLOCKS;
+       mmc->max_seg_size = 1024 * 1024;
+       mmc->max_req_size = 1024 * 1024;
+       mmc->max_blk_count = 1024;
+
+       mmc->max_blk_size = 2048;
+
+       ubicom32sd_reset(ud);
+
+       /*
+        * enable interrupts
+        */
+       ud->int_en = 0;
+       ubicom32sd_send_command_sync(ud, SDTIO_COMMAND_SETUP_SDIO << SDTIO_COMMAND_SHIFT | SDTIO_COMMAND_FLAG_SDIO_INT_EN, 0);
+
+       mmc_add_host(mmc);
+
+       printk(KERN_INFO "%s at %p, irq %d/%d\n", mmc_hostname(mmc),
+                       ud->regs, ud->irq_tx, ud->irq_rx);
+       return 0;
+
+fail_mmc:
+       gpio_free(pdata->cards[0].pin_pwr);
+fail_pwr:
+       gpio_free(pdata->cards[0].pin_cd);
+fail_cd:
+       gpio_free(pdata->cards[0].pin_wp);
+fail:
+       return ret;
+}
+
+/*
+ * ubicom32sd_remove
+ */
+static int __devexit ubicom32sd_remove(struct platform_device *pdev)
+{
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (mmc) {
+               struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc);
+
+               gpio_free(ud->pdata->cards[0].pin_pwr);
+               gpio_free(ud->pdata->cards[0].pin_cd);
+               gpio_free(ud->pdata->cards[0].pin_wp);
+
+               mmc_remove_host(mmc);
+               mmc_free_host(mmc);
+       }
+
+       /*
+        * Note that our data is allocated as part of the mmc structure
+        * so we don't need to free it.
+        */
+       return 0;
+}
+
+static struct platform_driver ubicom32sd_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = ubicom32sd_probe,
+       .remove = __devexit_p(ubicom32sd_remove),
+#if 0
+       .suspend = ubicom32sd_suspend,
+       .resume = ubicom32sd_resume,
+#endif
+};
+
+/*
+ * ubicom32sd_init
+ */
+static int __init ubicom32sd_init(void)
+{
+       return platform_driver_register(&ubicom32sd_driver);
+}
+module_init(ubicom32sd_init);
+
+/*
+ * ubicom32sd_exit
+ */
+static void __exit ubicom32sd_exit(void)
+{
+    platform_driver_unregister(&ubicom32sd_driver);
+}
+module_exit(ubicom32sd_exit);
+
+MODULE_AUTHOR("Patrick Tjin");
+MODULE_DESCRIPTION("Ubicom32 Secure Digital Host Controller Interface driver");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/drivers/mtd/devices/nand-spi-er.c b/target/linux/ubicom32/files/drivers/mtd/devices/nand-spi-er.c
new file mode 100644 (file)
index 0000000..73938c8
--- /dev/null
@@ -0,0 +1,1017 @@
+/*
+ * Micron SPI-ER NAND Flash Memory
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#define NAND_SPI_ER_BLOCK_FROM_ROW(row)                (row >> 6)
+
+#define NAND_SPI_ER_STATUS_P_FAIL              (1 << 3)
+#define NAND_SPI_ER_STATUS_E_FAIL              (1 << 2)
+#define NAND_SPI_ER_STATUS_OIP                 (1 << 0)
+
+#define NAND_SPI_ER_LAST_ROW_INVALID           0xFFFFFFFF
+#define        NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET       0x08
+
+struct nand_spi_er_device {
+       const char              *name;
+
+       uint8_t                 id0;
+       uint8_t                 id1;
+
+       unsigned int            blocks;
+       unsigned int            pages_per_block;
+       unsigned int            page_size;
+       unsigned int            write_size;
+       unsigned int            erase_size;
+};
+
+struct nand_spi_er {
+       char                            name[24];
+
+       const struct nand_spi_er_device *device;
+
+       struct mutex                    lock;
+       struct spi_device               *spi;
+
+       struct mtd_info                 mtd;
+
+       unsigned int                    last_row;       /* the last row we fetched */
+
+       /*
+        * Bad block table (MUST be last in strcuture)
+        */
+       unsigned long                   nbb;
+       unsigned long                   bbt[0];
+};
+
+const struct nand_spi_er_device nand_spi_er_devices[] = {
+       {
+               name:                   "MT29F1G01ZDC",
+               id0:                    0x2C,
+               id1:                    0x12,
+               blocks:                 1024,
+               pages_per_block:        64,
+               page_size:              2048,
+               write_size:             512,
+               erase_size:             64 * 2048,
+       },
+       {
+               name:                   "MT29F1G01ZDC",
+               id0:                    0x2C,
+               id1:                    0x13,
+               blocks:                 1024,
+               pages_per_block:        64,
+               page_size:              2048,
+               write_size:             512,
+               erase_size:             64 * 2048,
+       },
+};
+
+static int read_only = 0;
+module_param(read_only, int, 0);
+MODULE_PARM_DESC(read_only, "Leave device locked");
+
+/*
+ * nand_spi_er_get_feature
+ *     Get Feature register
+ */
+static int nand_spi_er_get_feature(struct nand_spi_er *chip, int reg, uint8_t *data)
+{
+       uint8_t txbuf[2];
+       uint8_t rxbuf[1];
+       int res;
+
+       txbuf[0] = 0x0F;
+       txbuf[1] = reg;
+       res = spi_write_then_read(chip->spi, txbuf, 2, rxbuf, 1);
+       if (res) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: failed get feature res=%d\n", chip->name, res);
+               return res;
+       }
+       *data = rxbuf[0];
+       return 0;
+}
+
+/*
+ * nand_spi_er_busywait
+ *     Wait until the chip is not busy
+ */
+static int nand_spi_er_busywait(struct nand_spi_er *chip, uint8_t *data)
+{
+       int i;
+
+       for (i = 0; i < 100; i++) {
+               int res = nand_spi_er_get_feature(chip, 0xC0, data);
+               if (res) {
+                       return res;
+               }
+               if (!(*data & NAND_SPI_ER_STATUS_OIP)) {
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * nand_spi_er_erase
+ *     Erase a block, parameters must be block aligned
+ */
+static int nand_spi_er_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+       struct nand_spi_er *chip = mtd->priv;
+       struct spi_device *spi = chip->spi;
+       uint8_t txbuf[4];
+       int res;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "%s: erase addr:%x len:%x\n", chip->name, instr->addr, instr->len);
+
+       if ((instr->addr + instr->len) > mtd->size) {
+               return -EINVAL;
+       }
+
+       if (instr->addr & (chip->device->erase_size - 1)) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: erase address is not aligned %x\n", chip->name, instr->addr);
+               return -EINVAL;
+       }
+
+       if (instr->len & (chip->device->erase_size - 1)) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: erase len is not aligned %x\n", chip->name, instr->len);
+               return -EINVAL;
+       }
+
+       mutex_lock(&chip->lock);
+       chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID;
+
+       while (instr->len) {
+               uint32_t block = instr->addr >> 17;
+               uint32_t row = block << 6;
+               uint8_t stat;
+               DEBUG(MTD_DEBUG_LEVEL3, "%s: block erase row:%x block:%x addr:%x rem:%x\n", chip->name, row, block, instr->addr, instr->len);
+
+               /*
+                * Write enable
+                */
+               txbuf[0] = 0x06;
+               res = spi_write(spi, txbuf, 1);
+               if (res) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write enable res=%d\n", chip->name, res);
+                       mutex_unlock(&chip->lock);
+                       return res;
+               }
+
+               /*
+                * Test for bad block
+                */
+               if (test_bit(block, chip->bbt)) {
+                       instr->fail_addr = block << 17;
+                       instr->state = MTD_ERASE_FAILED;
+                       res = -EBADMSG;
+                       goto done;
+               }
+
+               /*
+                * Block erase
+                */
+               txbuf[0] = 0xD8;
+               txbuf[1] = 0x00;
+               txbuf[2] = row >> 8;
+               txbuf[3] = row & 0xFF;
+               res = spi_write(spi, txbuf, 4);
+               if (res) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: failed block erase res=%d\n", chip->name, res);
+                       instr->fail_addr = block << 17;
+                       instr->state = MTD_ERASE_FAILED;
+                       goto done;
+               }
+
+               /*
+                * Wait
+                */
+               res = nand_spi_er_busywait(chip, &stat);
+               if (res || (stat & NAND_SPI_ER_STATUS_OIP)) {
+                       instr->fail_addr = block << 17;
+                       instr->state = MTD_ERASE_FAILED;
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat);
+                       if (res) {
+                               goto done;
+                       }
+
+                       /*
+                        * Chip is stuck?
+                        */
+                       res = -EIO;
+                       goto done;
+               }
+
+               /*
+                * Check the status register
+                */
+               if (stat & NAND_SPI_ER_STATUS_E_FAIL) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: E_FAIL signalled (%02x)\n", chip->name, stat);
+                       instr->fail_addr = block << 17;
+                       instr->state = MTD_ERASE_FAILED;
+                       goto done;
+               }
+
+               /*
+                * Next
+                */
+               block++;
+               instr->len -= chip->device->erase_size;
+               instr->addr += chip->device->erase_size;
+       }
+
+       instr->state = MTD_ERASE_DONE;
+
+       mutex_unlock(&chip->lock);
+       return 0;
+
+done:
+       /*
+        * Write disable
+        */
+       txbuf[0] = 0x04;
+       res = spi_write(spi, txbuf, 1);
+       if (res) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write disable res=%d\n", chip->name, res);
+       }
+
+       mutex_unlock(&chip->lock);
+
+       mtd_erase_callback(instr);
+       return 0;
+}
+
+/*
+ * nand_spi_er_read
+ *
+ * return -EUCLEAN: ecc error recovered
+ * return -EBADMSG: ecc error not recovered
+*/
+static int nand_spi_er_read(struct mtd_info *mtd, loff_t from, size_t len,
+                              size_t *retlen, u_char *buf)
+{
+       struct nand_spi_er *chip = mtd->priv;
+       struct spi_device *spi = chip->spi;
+
+       uint32_t row;
+       uint32_t column;
+       int retval = 0;
+
+       *retlen = 0;
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: read block from %llx len %d into %p\n", chip->name, from, len, buf);
+
+       /*
+        * Zero length reads, nothing to do
+        */
+       if (len == 0) {
+               return 0;
+       }
+
+       /*
+        * Reject reads which go over the end of the flash
+        */
+       if ((from + len) > mtd->size) {
+               return -EINVAL;
+       }
+
+       /*
+        * Get the row and column address to start at
+        */
+       row = from >> 11;
+       column = from & 0x7FF;
+       DEBUG(MTD_DEBUG_LEVEL3, "%s: row=%x %d column=%x %d last_row=%x %d\n", chip->name, row, row, column, column, chip->last_row, chip->last_row);
+
+       /*
+        * Read the data from the chip
+        */
+       mutex_lock(&chip->lock);
+       while (len) {
+               uint8_t stat;
+               uint8_t txbuf[4];
+               struct spi_message message;
+               struct spi_transfer x[2];
+               int res;
+               size_t toread;
+
+               /*
+                * Figure out how much to read
+                *
+                * If we are reading from the middle of a page then the most we
+                * can read is to the end of the page
+                */
+               toread = len;
+               if (toread > (chip->device->page_size - column)) {
+                       toread = chip->device->page_size - column;
+               }
+
+               DEBUG(MTD_DEBUG_LEVEL3, "%s: buf=%p toread=%x row=%x column=%x last_row=%x\n", chip->name, buf, toread, row, column, chip->last_row);
+
+               if (chip->last_row != row) {
+                       /*
+                        * Check if the block is bad
+                        */
+                       if (test_bit(NAND_SPI_ER_BLOCK_FROM_ROW(row), chip->bbt)) {
+                               mutex_unlock(&chip->lock);
+                               return -EBADMSG;
+                       }
+
+                       /*
+                        * Load the appropriate page
+                        */
+                       txbuf[0] = 0x13;
+                       txbuf[1] = 0x00;
+                       txbuf[2] = row >> 8;
+                       txbuf[3] = row & 0xFF;
+                       res = spi_write(spi, txbuf, 4);
+                       if (res) {
+                               DEBUG(MTD_DEBUG_LEVEL1, "%s: failed page load res=%d\n", chip->name, res);
+                               mutex_unlock(&chip->lock);
+                               return res;
+                       }
+
+                       /*
+                        * Wait
+                        */
+                       res = nand_spi_er_busywait(chip, &stat);
+                       if (res || (stat & NAND_SPI_ER_STATUS_OIP)) {
+                               DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat);
+                               if (res) {
+                                       mutex_unlock(&chip->lock);
+                                       return res;
+                               }
+
+                               /*
+                                * Chip is stuck?
+                                */
+                               mutex_unlock(&chip->lock);
+                               return -EIO;
+                       }
+
+                       /*
+                        * Check the ECC bits
+                        */
+                       stat >>= 4;
+                       if (stat == 1) {
+                               DEBUG(MTD_DEBUG_LEVEL1, "%s: ECC recovered, row=%x\n", chip->name, row);
+                               retval = -EUCLEAN;
+                       }
+                       if (stat == 2) {
+                               DEBUG(MTD_DEBUG_LEVEL0, "%s: failed ECC, row=%x\n", chip->name, row);
+                               chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID;
+                               mutex_unlock(&chip->lock);
+                               return -EBADMSG;
+                       }
+
+               }
+
+               chip->last_row = row;
+
+               /*
+                * Read out the data
+                */
+               spi_message_init(&message);
+               memset(x, 0, sizeof(x));
+
+               txbuf[0] = 0x03;
+               txbuf[1] = column >> 8;
+               txbuf[2] = column & 0xFF;
+               txbuf[3] = 0;
+               x[0].tx_buf = txbuf;
+               x[0].len = 4;
+               spi_message_add_tail(&x[0], &message);
+
+               x[1].rx_buf = buf;
+               x[1].len = toread;
+               spi_message_add_tail(&x[1], &message);
+
+               res = spi_sync(spi, &message);
+               if (res) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: failed data read res=%d\n", chip->name, res);
+                       mutex_unlock(&chip->lock);
+                       return res;
+               }
+               buf += toread;
+               len -= toread;
+               *retlen += toread;
+
+               /*
+                * For the next page, increment the row and always start at column 0
+                */
+               column = 0;
+               row++;
+       }
+
+       mutex_unlock(&chip->lock);
+       return retval;
+}
+
+/*
+ * nand_spi_er_write
+ */
+#define NOT_ALIGNED(x) ((x & (device->write_size - 1)) != 0)
+static int nand_spi_er_write(struct mtd_info *mtd, loff_t to, size_t len,
+                               size_t *retlen, const u_char *buf)
+{
+       struct nand_spi_er *chip = mtd->priv;
+       struct spi_device *spi = chip->spi;
+       const struct nand_spi_er_device *device = chip->device;
+       uint32_t row;
+       uint32_t col;
+       uint8_t txbuf[4];
+       int res;
+       size_t towrite;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: write block to %llx len %d from %p\n", chip->name, to, len, buf);
+
+       *retlen = 0;
+
+       /*
+        * nothing to write
+        */
+       if (!len) {
+               return 0;
+       }
+
+       /*
+        * Reject writes which go over the end of the flash
+        */
+       if ((to + len) > mtd->size) {
+               return -EINVAL;
+       }
+
+       /*
+        * Check to see if everything is page aligned
+        */
+       if (NOT_ALIGNED(to) || NOT_ALIGNED(len)) {
+               printk(KERN_NOTICE "nand_spi_er_write: Attempt to write non page aligned data\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&chip->lock);
+       chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID;
+
+       /*
+        * If the first write is a partial write then write at most the number of
+        * bytes to get us page aligned and then the remainder will be
+        * page aligned.  The last bit may be a partial page as well.
+        */
+       col = to & (device->page_size - 1);
+       towrite = device->page_size - col;
+       if (towrite > len) {
+               towrite = len;
+       }
+
+       /*
+        * Write the data
+        */
+       row = to >> 11;
+       while (len) {
+               struct spi_message message;
+               struct spi_transfer x[2];
+               uint8_t stat;
+
+               DEBUG(MTD_DEBUG_LEVEL3, "%s: write %p to row:%x col:%x len:%x rem:%x\n", chip->name, buf, row, col, towrite, len);
+
+               /*
+                * Write enable
+                */
+               txbuf[0] = 0x06;
+               res = spi_write(spi, txbuf, 1);
+               if (res) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write enable res=%d\n", chip->name, res);
+                       mutex_unlock(&chip->lock);
+                       return res;
+               }
+
+               /*
+                * Write the data into the cache
+                */
+               spi_message_init(&message);
+               memset(x, 0, sizeof(x));
+               txbuf[0] = 0x02;
+               txbuf[1] = col >> 8;
+               txbuf[2] = col & 0xFF;
+               x[0].tx_buf = txbuf;
+               x[0].len = 3;
+               spi_message_add_tail(&x[0], &message);
+               x[1].tx_buf = buf;
+               x[1].len = towrite;
+               spi_message_add_tail(&x[1], &message);
+               res = spi_sync(spi, &message);
+               if (res) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: failed cache write res=%d\n", chip->name, res);
+                       goto done;
+               }
+
+               /*
+                * Program execute
+                */
+               txbuf[0] = 0x10;
+               txbuf[1] = 0x00;
+               txbuf[2] = row >> 8;
+               txbuf[3] = row & 0xFF;
+               res = spi_write(spi, txbuf, 4);
+               if (res) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: failed prog execute res=%d\n", chip->name, res);
+                       goto done;
+               }
+
+               /*
+                * Wait
+                */
+               res = nand_spi_er_busywait(chip, &stat);
+               if (res || (stat & NAND_SPI_ER_STATUS_OIP)) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat);
+                       if (res) {
+                               goto done;
+                       }
+
+                       /*
+                        * Chip is stuck?
+                        */
+                       res = -EIO;
+                       goto done;
+               }
+
+               if (stat & (1 << 3)) {
+                       res = -EBADMSG;
+                       goto done;
+               }
+
+               row++;
+               buf += towrite;
+               len -= towrite;
+               *retlen += towrite;
+
+               /*
+                * At this point, we are always page aligned so start at column 0.
+                * Note we may not have a full page to write at the end, hence the
+                * check if towrite > len.
+                */
+               col = 0;
+               towrite = device->page_size;
+               if (towrite > len) {
+                       towrite = len;
+               }
+       }
+
+       mutex_unlock(&chip->lock);
+       return res;
+
+done:
+       /*
+        * Write disable
+        */
+       txbuf[0] = 0x04;
+       res = spi_write(spi, txbuf, 1);
+       if (res) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write disable res=%d\n", chip->name, res);
+       }
+
+       mutex_unlock(&chip->lock);
+
+       return res;
+}
+
+/*
+ * nand_spi_er_isbad
+ */
+static int nand_spi_er_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+       struct nand_spi_er *chip = mtd->priv;
+       uint32_t block;
+
+       if (ofs & (chip->device->erase_size - 1)) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs);
+               return -EINVAL;
+       }
+
+       block = ofs >> 17;
+
+       return test_bit(block, chip->bbt);
+}
+
+/*
+ * nand_spi_er_markbad
+ */
+static int nand_spi_er_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+       struct nand_spi_er *chip = mtd->priv;
+       struct spi_device *spi = chip->spi;
+       uint32_t block;
+       uint32_t row;
+       uint8_t txbuf[7];
+       int res;
+       uint8_t stat;
+
+       if (ofs & (chip->device->erase_size - 1)) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs);
+               return -EINVAL;
+       }
+
+       block = ofs >> 17;
+
+       /*
+        * If it's already marked bad, no need to mark it
+        */
+       if (test_bit(block, chip->bbt)) {
+               return 0;
+       }
+
+       /*
+        * Mark it in our cache
+        */
+       __set_bit(block, chip->bbt);
+
+       /*
+        * Write the user bad block mark.  If it fails, then we really
+        * can't do anything about it.
+        */
+       mutex_lock(&chip->lock);
+       chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID;
+
+       /*
+        * Write enable
+        */
+       txbuf[0] = 0x06;
+       res = spi_write(spi, txbuf, 1);
+       if (res) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write enable res=%d\n", chip->name, res);
+               mutex_unlock(&chip->lock);
+               return res;
+       }
+
+       /*
+        * Write the mark
+        */
+       txbuf[0] = 0x84;
+       txbuf[1] = 0x08;
+       txbuf[2] = NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET;
+       txbuf[3] = 0xde;
+       txbuf[4] = 0xad;
+       txbuf[5] = 0xbe;
+       txbuf[6] = 0xef;
+       res = spi_write(spi, txbuf, 7);
+       if (res) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write mark res=%d\n", chip->name, res);
+               goto done;
+       }
+
+       /*
+        * Program execute
+        */
+       row = ofs >> 11;
+       txbuf[0] = 0x10;
+       txbuf[1] = 0x00;
+       txbuf[2] = row >> 8;
+       txbuf[3] = row & 0xFF;
+       res = spi_write(spi, txbuf, 4);
+       if (res) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: failed program execute res=%d\n", chip->name, res);
+               goto done;
+       }
+
+       /*
+        * Wait
+        */
+       res = nand_spi_er_busywait(chip, &stat);
+       if (res || (stat & NAND_SPI_ER_STATUS_OIP)) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat);
+               if (res) {
+                       goto done;
+               }
+
+               /*
+                * Chip is stuck?
+                */
+               res = -EIO;
+               goto done;
+       }
+
+       if (stat & (1 << 3)) {
+               res = -EBADMSG;
+       }
+
+done:
+       /*
+        * Write disable
+        */
+       txbuf[0] = 0x04;
+       res = spi_write(spi, txbuf, 1);
+       if (res) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write disable res=%d\n", chip->name, res);
+       }
+
+       mutex_unlock(&chip->lock);
+
+       return res;
+}
+
+/*
+ * nand_spi_er_read_bbt
+ */
+static int nand_spi_er_read_bbt(struct nand_spi_er *chip)
+{
+       int j;
+       for (j = 0; j < chip->device->blocks; j++) {
+               uint8_t txbuf[4];
+               uint8_t rxbuf[16];
+               uint32_t bbmark;
+               int res;
+               unsigned short row = j << 6;
+               uint8_t stat;
+
+               /*
+                * Read Page
+                */
+               txbuf[0] = 0x13;
+               txbuf[1] = 0x00;
+               txbuf[2] = row >> 8;
+               txbuf[3] = row & 0xFF;
+               res = spi_write(chip->spi, txbuf, 4);
+               if (res) {
+                       return res;
+               }
+
+               /*
+                * Wait
+                */
+               res = nand_spi_er_busywait(chip, &stat);
+               if (res || (stat & NAND_SPI_ER_STATUS_OIP)) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat);
+                       if (res) {
+                               return res;
+                       }
+
+                       /*
+                        * Chip is stuck?
+                        */
+                       return -EIO;
+               }
+
+               /*
+                * Check factory bad block mark
+                */
+               txbuf[0] = 0x03;
+               txbuf[1] = 0x08;
+               txbuf[2] = 0x00;
+               txbuf[3] = 0x00;
+               res = spi_write_then_read(chip->spi, txbuf, 4, rxbuf, 16);
+               if (res) {
+                       return res;
+               }
+               if (rxbuf[0] != 0xFF) {
+                       chip->nbb++;
+                       __set_bit(j, chip->bbt);
+                       continue;
+               }
+
+               memcpy(&bbmark, &rxbuf[8], 4);
+               if (bbmark == 0xdeadbeef) {
+                       chip->nbb++;
+                       __set_bit(j, chip->bbt);
+               }
+       }
+
+#if defined(CONFIG_MTD_DEBUG) && (MTD_DEBUG_LEVEL3 <= CONFIG_MTD_DEBUG_VERBOSE)
+       printk("%s: Bad Block Table:", chip->name);
+       for (j = 0; j < chip->device->blocks; j++) {
+               if ((j % 64) == 0) {
+                       printk("\n%s: block %03x: ", chip->name, j);
+               }
+               printk("%c", test_bit(j, chip->bbt) ? 'X' : '.');
+       }
+       printk("\n%s: Bad Block Numbers: ", chip->name);
+       for (j = 0; j < chip->device->blocks; j++) {
+               if (test_bit(j, chip->bbt)) {
+                       printk("%x ", j);
+               }
+       }
+       printk("\n");
+#endif
+
+       return 0;
+}
+
+#ifndef MODULE
+/*
+ * Called at boot time:
+ *
+ * nand_spi_er=read_only
+ *     if read_only specified then do not unlock device
+ */
+static int __init nand_spi_er_setup(char *str)
+{
+       if (str && (strncasecmp(str, "read_only", 9) == 0)) {
+               read_only = 1;
+       }
+       return 0;
+}
+
+__setup("nand_spi_er=", nand_spi_er_setup);
+#endif
+
+/*
+ * nand_spi_er_probe
+ *     Detect and initialize nand_spi_er device.
+ */
+static int __devinit nand_spi_er_probe(struct spi_device *spi)
+{
+       uint8_t txbuf[3];
+       uint8_t rxbuf[2];
+       int i;
+       int res;
+       size_t bbt_bytes;
+       struct nand_spi_er *chip;
+       const struct nand_spi_er_device *device;
+
+       res = spi_setup(spi);
+       if (res) {
+               return res;
+       }
+
+       /*
+        * Reset
+        */
+       for (i = 0; i < 2; i++) {
+               txbuf[0] = 0xFF;
+               res = spi_write(spi, txbuf, 1);
+               if (res) {
+                       return res;
+               }
+               udelay(250);
+       }
+       udelay(1000);
+
+       /*
+        * Read ID
+        */
+       txbuf[0] = 0x9F;
+       txbuf[1] = 0x00;
+       res = spi_write_then_read(spi, txbuf, 2, rxbuf, 2);
+       if (res) {
+               return res;
+       }
+
+       device = nand_spi_er_devices;
+       for (i = 0; i < ARRAY_SIZE(nand_spi_er_devices); i++) {
+               if ((device->id0 == rxbuf[0]) && (device->id1 == rxbuf[1])) {
+                       break;
+               }
+               device++;
+       }
+       if (i == ARRAY_SIZE(nand_spi_er_devices)) {
+               return -ENODEV;
+       }
+
+       /*
+        * Initialize our chip structure
+        */
+       bbt_bytes = DIV_ROUND_UP(device->blocks, BITS_PER_BYTE);
+       chip = kzalloc(sizeof(struct nand_spi_er) + bbt_bytes, GFP_KERNEL);
+       if (!chip) {
+               return -ENOMEM;
+       }
+       snprintf(chip->name, sizeof(chip->name), "%s.%d.%d", device->name, spi->master->bus_num, spi->chip_select);
+
+       chip->spi = spi;
+       chip->device = device;
+       chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID;
+
+       mutex_init(&chip->lock);
+
+       chip->mtd.type = MTD_NANDFLASH;
+       chip->mtd.flags = MTD_WRITEABLE;
+
+       /*
+        * #blocks * block size * n blocks
+        */
+       chip->mtd.size = device->blocks * device->pages_per_block * device->page_size;
+       chip->mtd.erasesize = device->erase_size;
+
+       /*
+        * 1 page, optionally we can support partial write (512)
+        */
+       chip->mtd.writesize = device->write_size;
+       chip->mtd.name = device->name;
+       chip->mtd.erase = nand_spi_er_erase;
+       chip->mtd.read = nand_spi_er_read;
+       chip->mtd.write = nand_spi_er_write;
+       chip->mtd.block_isbad = nand_spi_er_isbad;
+       chip->mtd.block_markbad = nand_spi_er_markbad;
+       chip->mtd.priv = chip;
+
+       /*
+        * Cache the bad block table
+        */
+       res = nand_spi_er_read_bbt(chip);
+       if (res) {
+               kfree(chip);
+               return res;
+       }
+
+       /*
+        * Un/lock the chip
+        */
+       txbuf[0] = 0x1F;
+       txbuf[1] = 0xA0;
+       if (read_only) {
+               txbuf[2] = 0x38;
+       } else {
+               txbuf[2] = 0x00;
+       }
+       res = spi_write(spi, txbuf, 3);
+       if (res) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: failed lock operation res=%d\n", chip->name, res);
+               mutex_unlock(&chip->lock);
+               return res;
+       }
+
+       spi_set_drvdata(spi, chip);
+
+       printk(KERN_INFO "%s: added device %s size: %u KBytes %u bad blocks %s\n", spi->dev.bus_id, chip->mtd.name, DIV_ROUND_UP(chip->mtd.size, 1024), chip->nbb, read_only ? "[read only]" : "");
+       return add_mtd_device(&chip->mtd);
+}
+
+/*
+ * nand_spi_er_remove
+ */
+static int __devexit nand_spi_er_remove(struct spi_device *spi)
+{
+       struct nand_spi_er *chip = spi_get_drvdata(spi);
+       int status = 0;
+
+       DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", spi->dev.bus_id);
+       status = del_mtd_device(&chip->mtd);
+       if (status == 0)
+               kfree(chip);
+       return status;
+}
+
+static struct spi_driver nand_spi_er_driver = {
+       .driver = {
+               .name           = "nand-spi-er",
+               .bus            = &spi_bus_type,
+               .owner          = THIS_MODULE,
+       },
+
+       .probe          = nand_spi_er_probe,
+       .remove         = __devexit_p(nand_spi_er_remove),
+
+       /* FIXME:  investigate suspend and resume... */
+};
+
+/*
+ * nand_spi_er_init
+ */
+static int __init nand_spi_er_init(void)
+{
+       return spi_register_driver(&nand_spi_er_driver);
+}
+module_init(nand_spi_er_init);
+
+/*
+ * nand_spi_er_exit
+ */
+static void __exit nand_spi_er_exit(void)
+{
+       spi_unregister_driver(&nand_spi_er_driver);
+}
+module_exit(nand_spi_er_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick Tjin");
+MODULE_DESCRIPTION("MTD nand_spi_er driver");
diff --git a/target/linux/ubicom32/files/drivers/mtd/devices/ubi32-m25p80.c b/target/linux/ubicom32/files/drivers/mtd/devices/ubi32-m25p80.c
new file mode 100644 (file)
index 0000000..405491c
--- /dev/null
@@ -0,0 +1,1066 @@
+/*
+ * drivers/mtd/devices/ubi32-m25p80.c
+ *   NOR flash driver, Ubicom processor internal SPI flash interface.
+ *
+ *   This code instantiates the serial flash that contains the
+ *   original bootcode.  The serial flash start at address 0x60000000
+ *   in both Ubicom32V3 and Ubicom32V4 ISAs.
+ *
+ *   This piece of flash is made to appear as a Memory Technology
+ *   Device (MTD) with this driver to allow Read/Write/Erase operations.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+
+#include <asm/ip5000.h>
+#include <asm/devtree.h>
+
+#define UBICOM32_FLASH_BASE    0x60000000
+#define UBICOM32_FLASH_MAX_SIZE 0x01000000
+#define UBICOM32_FLASH_START   0x00000000
+#define UBICOM32_KERNEL_OFFSET 0x00010000 /* The kernel starts after Ubicom
+                                           * .protect section. */
+
+static struct mtd_partition ubicom32_flash_partitions[] = {
+       {
+               .name   = "Bootloader",         /* Protected Section
+                                                * Partition */
+               .size   = 0x10000,
+               .offset = UBICOM32_FLASH_START,
+//             .mask_flags = MTD_WRITEABLE     /* Mark Read-only */
+       },
+       {
+               .name   = "Kernel",             /* Kernel Partition. */
+               .size   = 0,                    /* this will be set up during
+                                                * probe stage. At that time we
+                                                * will know end of linux image
+                                                * in flash. */
+               .offset = MTDPART_OFS_APPEND,   /* Starts right after Protected
+                                                * section. */
+//             .mask_flags = MTD_WRITEABLE     /* Mark Read-only */
+       },
+       {
+               .name   = "Rest",               /* Rest of the flash. */
+               .size   = 0x200000,             /* Use up what remains in the
+                                                * flash. */
+               .offset = MTDPART_OFS_NXTBLK,   /* Starts right after Protected
+                                                * section. */
+       }
+};
+
+static struct flash_platform_data ubicom32_flash_data = {
+       .name = "ubicom32_boot_flash",
+       .parts = ubicom32_flash_partitions,
+       .nr_parts = ARRAY_SIZE(ubicom32_flash_partitions),
+};
+
+static struct resource ubicom32_flash_resource[] = {
+       {
+               .start  = UBICOM32_FLASH_BASE,
+               .end    = UBICOM32_FLASH_BASE +
+               UBICOM32_FLASH_MAX_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device ubicom32_flash_device = {
+       .name = "ubicom32flashdriver",
+       .id = 0, /* Bus number */
+       .num_resources = ARRAY_SIZE(ubicom32_flash_resource),
+       .resource = ubicom32_flash_resource,
+       .dev = {
+               .platform_data = &ubicom32_flash_data,
+       },
+};
+
+static struct platform_device *ubicom32_flash_devices[] = {
+       &ubicom32_flash_device,
+};
+
+static int __init ubicom32_flash_init(void)
+{
+       printk(KERN_INFO "%s(): registering device resources\n",
+              __FUNCTION__);
+       platform_add_devices(ubicom32_flash_devices,
+                            ARRAY_SIZE(ubicom32_flash_devices));
+       return 0;
+}
+
+arch_initcall(ubicom32_flash_init);
+
+/*
+ * MTD SPI driver for ST M25Pxx (and similar) serial flash chips through
+ * Ubicom32 SPI controller.
+ *
+ * Author: Mike Lavender, mike@steroidmicros.com
+ *
+ * Copyright (c) 2005, Intec Automation Inc.
+ *
+ * Some parts are based on lart.c by Abraham Van Der Merwe
+ *
+ * Cleaned up and generalized based on mtd_dataflash.c
+ *
+ * This code is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#define FLASH_PAGESIZE         256
+
+/* Flash opcodes. */
+#define        OPCODE_WREN             0x06    /* Write enable */
+#define        OPCODE_RDSR             0x05    /* Read status register */
+#define        OPCODE_READ             0x03    /* Read data bytes (low frequency) */
+#define        OPCODE_FAST_READ        0x0b    /* Read data bytes (high frequency) */
+#define        OPCODE_PP               0x02    /* Page program (up to 256 bytes) */
+#define        OPCODE_BE_4K            0x20    /* Erase 4KiB block */
+#define        OPCODE_BE_32K           0x52    /* Erase 32KiB block */
+#define        OPCODE_SE               0xd8    /* Sector erase (usually 64KiB) */
+#define        OPCODE_RDID             0x9f    /* Read JEDEC ID */
+
+/* Status Register bits. */
+#define        SR_WIP                  1       /* Write in progress */
+#define        SR_WEL                  2       /* Write enable latch */
+/* meaning of other SR_* bits may differ between vendors */
+#define        SR_BP0                  4       /* Block protect 0 */
+#define        SR_BP1                  8       /* Block protect 1 */
+#define        SR_BP2                  0x10    /* Block protect 2 */
+#define        SR_SRWD                 0x80    /* SR write protect */
+
+/* Define max times to check status register before we give up. */
+#define        MAX_READY_WAIT_COUNT    100000
+
+
+#ifdef CONFIG_MTD_PARTITIONS
+#define        mtd_has_partitions()    (1)
+#else
+#define        mtd_has_partitions()    (0)
+#endif
+
+/*
+ * Ubicom32 FLASH Command Set
+ */
+#define FLASH_FC_INST_CMD      0x00    /* for SPI command only transaction */
+#define FLASH_FC_INST_WR       0x01    /* for SPI write transaction */
+#define FLASH_FC_INST_RD       0x02    /* for SPI read transaction */
+
+#define ALIGN_DOWN(v, a) ((v) & ~((a) - 1))
+#define ALIGN_UP(v, a) (((v) + ((a) - 1)) & ~((a) - 1))
+
+#define        FLASH_COMMAND_KICK_OFF(io)                                                      \
+       asm volatile(                                                                   \
+       "       bset    "D(IO_INT_CLR)"(%0), #0, #%%bit("D(IO_XFL_INT_DONE)")   \n\t"   \
+       "       jmpt.t  .+4                                                     \n\t"   \
+       "       bset    "D(IO_INT_SET)"(%0), #0, #%%bit("D(IO_XFL_INT_START)")  \n\t"   \
+               :                                                                       \
+               : "a" (io)                                                              \
+               : "memory", "cc"                                                        \
+       );
+
+#define        FLASH_COMMAND_WAIT_FOR_COMPLETION(io)                                           \
+       asm volatile(                                                                   \
+       "       btst    "D(IO_INT_STATUS)"(%0), #%%bit("D(IO_XFL_INT_DONE)")    \n\t"   \
+       "       jmpeq.f .-4                                                     \n\t"   \
+               :                                                                       \
+               : "a" (io)                                                              \
+               : "memory", "cc"                                                                        \
+       );
+
+#define        FLASH_COMMAND_EXEC(io)                                                          \
+       FLASH_COMMAND_KICK_OFF(io)                                                      \
+       FLASH_COMMAND_WAIT_FOR_COMPLETION(io)
+
+
+#define OSC1_FREQ 12000000
+#define TEN_MICRO_SECONDS (OSC1_FREQ * 10 / 1000000)
+
+/*
+ * We will have to eventually replace this null definition with the real thing.
+ */
+#define WATCHDOG_RESET()
+
+#define EXTFLASH_WRITE_FIFO_SIZE 32
+#define EXTFLASH_WRITE_BLOCK_SIZE EXTFLASH_WRITE_FIFO_SIZE /* limit the size to
+                                                           * FIFO capacity, so
+                                                           * the thread can be
+                                                           * suspended. */
+
+#define JFFS2_FILESYSTEM_SIZE 0x100000
+
+/****************************************************************************/
+
+struct m25p {
+       struct platform_device  *plt_dev;
+       struct mutex            lock;
+       struct mtd_info         mtd;
+       unsigned                partitioned:1;
+       u8                      erase_opcode;
+       u8                      command[4];
+};
+
+static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
+{
+       return container_of(mtd, struct m25p, mtd);
+}
+
+/****************************************************************************/
+
+/*
+ * Internal helper functions
+ */
+
+/*
+ * Read the status register, returning its value in the location
+ * Return the status register value.
+ * Returns negative if error occurred.
+ */
+static int read_sr(struct m25p *flash)
+{
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA;
+
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) |
+               IO_XFL_CTL1_FC_DATA(1);
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_RDSR);
+       FLASH_COMMAND_EXEC(io);
+
+       return io->status1 & 0xff;
+}
+
+/*
+ * mem_flash_io_read_u32()
+ */
+static u32 mem_flash_io_read_u32(u32 addr)
+{
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA;
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) |
+               IO_XFL_CTL1_FC_DATA(4) | IO_XFL_CTL1_FC_DUMMY(1) |
+               IO_XFL_CTL1_FC_ADDR;
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_FAST_READ) |
+               IO_XFL_CTL2_FC_ADDR(addr);
+       FLASH_COMMAND_EXEC(io);
+       return io->status1;
+}
+
+/*
+ * mem_flash_read_u8()
+ */
+static u8 mem_flash_read_u8(u32 addr)
+{
+       u32 tmp_addr = ALIGN_DOWN(addr, 4);
+       u32 tmp_data = mem_flash_io_read_u32(tmp_addr);
+       u8 *ptr = (u8 *)&tmp_data;
+       return ptr[addr & 0x3];
+}
+
+/*
+ * mem_flash_read()
+ *     No need to lock as read is implemented with ireads (same as normal flash
+ *     execution).
+ */
+static void mem_flash_read(u32 addr, void *dst, size_t length)
+{
+       /*
+        * Range check
+        */
+       /*
+        * Fix source alignment.
+        */
+       while (addr & 0x03) {
+               if (length == 0) {
+                       return;
+               }
+               *((u8 *)dst) = mem_flash_read_u8(addr++);
+               dst++;
+               length--;
+       }
+
+       while (length >= 4) {
+               u32 tmp_data = mem_flash_io_read_u32(addr);
+               addr += 4;
+               length -= 4;
+
+               /*
+                * Send the data to the destination.
+                */
+               memcpy((void *)dst, (void *)&tmp_data, 4);
+               dst += 4;
+       }
+
+       while (length--) {
+               *((u8 *)dst) = mem_flash_read_u8(addr++);
+               dst++;
+       }
+}
+
+/*
+ * mem_flash_wait_until_complete()
+ */
+static void mem_flash_wait_until_complete(void)
+{
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA;
+
+       do {
+               /*
+                * Put a delay here to deal with flash programming problem.
+                */
+               u32 mptval = UBICOM32_IO_TIMER->mptval + TEN_MICRO_SECONDS;
+               while (UBICOM32_IO_TIMER->mptval < mptval)
+                       ;
+
+               io->ctl1 &= ~IO_XFL_CTL1_MASK;
+               io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) |
+                       IO_XFL_CTL1_FC_DATA(1);
+               io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_RDSR);
+               FLASH_COMMAND_EXEC(io);
+       } while (io->status1 & SR_WIP);
+}
+
+/*
+ * mem_flash_write_next()
+ */
+static size_t mem_flash_write_next(u32 addr, u8 *buf, size_t length)
+{
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA;
+       u32 data_start = addr;
+       u32 data_end = addr + length;
+       size_t count;
+       u32 i, j;
+
+       /*
+        * Top limit address.
+        */
+       u32 block_start = ALIGN_DOWN(data_start, 4);
+       u32 block_end = block_start + EXTFLASH_WRITE_BLOCK_SIZE;
+
+       union {
+               u8 byte[EXTFLASH_WRITE_BLOCK_SIZE];
+               u32 word[EXTFLASH_WRITE_BLOCK_SIZE / 4];
+       } write_buf;
+
+       u32 *flash_addr = (u32 *)block_start;
+
+       /*
+        * The write block must be limited by FLASH internal buffer.
+        */
+       u32 block_end_align = ALIGN_DOWN(block_end, 256);
+       bool write_needed;
+
+       block_end = (block_end_align > block_start)
+               ? block_end_align : block_end;
+       data_end = (data_end <= block_end) ? data_end : block_end;
+       block_end = ALIGN_UP(data_end, 4);
+       count = data_end - data_start;
+
+       /*
+        * Transfer data to a buffer.
+        */
+       for (i = 0; i < (block_end - block_start) / 4; i++) {
+               /*
+                * The FLASH read can hold D-cache for a long time.
+                * Use I/O operation to read FLASH to avoid starving other
+                * threads, especially HRT.  (Do this for application only)
+                */
+               write_buf.word[i] = mem_flash_io_read_u32(
+                       (u32)(&flash_addr[i]));
+       }
+
+       write_needed = false;
+       for (i = 0, j = (data_start - block_start);
+            i < (data_end - data_start); i++, j++) {
+               write_needed = write_needed || (write_buf.byte[j] != buf[i]);
+               write_buf.byte[j] &= buf[i];
+       }
+
+
+       /*
+        * If the data in FLASH is identical to what to be written. Then skip
+        * it.
+        */
+       if (write_needed) {
+               /*
+                * Write to flash.
+                */
+               void *tmp __attribute__((unused));
+               s32 extra_words;
+
+               asm volatile(
+               "       move.4  %0, %2                                                                  \n\t"
+               "       bset    "D(IO_INT_SET)"(%1), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)")        \n\t"
+               "       pipe_flush 0                                                                    \n\t"
+               "       .rept   "D(EXTFLASH_WRITE_FIFO_SIZE / 4)"                                       \n\t"
+               "       move.4  "D(IO_TX_FIFO)"(%1), (%0)4++                                            \n\t"
+               "       .endr                                                                           \n\t"
+                       : "=&a" (tmp)
+                       : "a" (io), "r" (&write_buf.word[0])
+                       : "memory", "cc"
+               );
+
+               /* Lock FLASH for write access. */
+               io->ctl0 |= IO_XFL_CTL0_MCB_LOCK;
+
+               /* Command: WREN */
+               io->ctl1 &= ~IO_XFL_CTL1_MASK;
+               io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD);
+               io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_WREN);
+               FLASH_COMMAND_EXEC(io);
+
+               /* Command: BYTE PROGRAM */
+               io->ctl1 &= ~IO_XFL_CTL1_MASK;
+               io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) |
+                       IO_XFL_CTL1_FC_DATA(block_end - block_start) |
+                       IO_XFL_CTL1_FC_ADDR;
+               io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_PP) |
+                       IO_XFL_CTL2_FC_ADDR(block_start);
+               FLASH_COMMAND_KICK_OFF(io);
+
+               extra_words = (s32)(block_end - block_start -
+                                   EXTFLASH_WRITE_FIFO_SIZE) / 4;
+               if (extra_words > 0) {
+                       asm volatile(
+                       "       move.4          %0, %3                          \n\t"
+                       "1:     cmpi            "D(IO_FIFO_LEVEL)"(%1), #4      \n\t"
+                       "       jmpgt.s.t       1b                              \n\t"
+                       "       move.4          "D(IO_TX_FIFO)"(%1), (%0)4++    \n\t"
+                       "       add.4           %2, #-1, %2                     \n\t"
+                       "       jmpgt.t         1b                              \n\t"
+                               : "=&a" (tmp)
+                               : "a" (io), "d" (extra_words),
+                                 "r" (&write_buf.word[EXTFLASH_WRITE_FIFO_SIZE / 4])
+                               : "memory", "cc"
+                       );
+               }
+               FLASH_COMMAND_WAIT_FOR_COMPLETION(io);
+
+               mem_flash_wait_until_complete();
+
+
+               /* Unlock FLASH for cache access. */
+               io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK;
+       }
+
+       /*
+        * Complete.
+        */
+       return count;
+}
+
+/*
+ * mem_flash_write()
+ */
+static void mem_flash_write(u32 addr, const void *src, size_t length)
+{
+       /*
+        * Write data
+        */
+       u8_t *ptr = (u8_t *)src;
+       while (length) {
+               size_t count = mem_flash_write_next(addr, ptr, length);
+               addr += count;
+               ptr += count;
+               length -= count;
+       }
+}
+
+/*
+ * Service routine to read status register until ready, or timeout occurs.
+ * Returns non-zero if error.
+ */
+static int wait_till_ready(struct m25p *flash)
+{
+       int count;
+       int sr;
+
+       /* one chip guarantees max 5 msec wait here after page writes,
+        * but potentially three seconds (!) after page erase.
+        */
+       for (count = 0; count < MAX_READY_WAIT_COUNT; count++) {
+               u32 mptval;
+               sr = read_sr(flash);
+               if (sr < 0)
+                       break;
+               else if (!(sr & SR_WIP))
+                       return 0;
+
+               /*
+                * Put a 10us delay here to deal with flash programming problem.
+                */
+               mptval = UBICOM32_IO_TIMER->mptval + TEN_MICRO_SECONDS;
+               while ((s32)(mptval - UBICOM32_IO_TIMER->mptval) > 0) {
+                       WATCHDOG_RESET();
+               }
+               /* REVISIT sometimes sleeping would be best */
+       }
+
+       return 1;
+}
+
+/*
+ * mem_flash_erase_page()
+ */
+static void mem_flash_erase_page(u32 addr)
+{
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA;
+
+       /* Lock FLASH for write access. */
+       io->ctl0 |= IO_XFL_CTL0_MCB_LOCK;
+
+       /* Command: WREN */
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD);
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_WREN);
+       FLASH_COMMAND_EXEC(io);
+
+       /* Command: ERASE */
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD) |
+               IO_XFL_CTL1_FC_ADDR;
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_SE) |
+               IO_XFL_CTL2_FC_ADDR(addr);
+       FLASH_COMMAND_EXEC(io);
+
+       mem_flash_wait_until_complete();
+
+       /* Unlock FLASH for cache access. */
+       io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK;
+}
+
+/*
+ * mem_flash_erase()
+ */
+static u32 mem_flash_erase(u32 addr, u32 length)
+{
+       /*
+        * Calculate the endaddress to be the first address of the page
+        * just beyond this erase section of pages.
+        */
+       u32 endaddr = addr + length;
+
+       /*
+        * Erase.
+        */
+       while (addr < endaddr) {
+               u32 test_addr = addr;
+               mem_flash_erase_page(addr);
+
+               /*
+                * Test how much was erased as actual flash page at this address
+                * may be smaller than the expected page size.
+                */
+               while (test_addr < endaddr) {
+                       /*
+                        * The FLASH read can hold D-cache for a long time.  Use
+                        * I/O operation to read FLASH to avoid starving other
+                        * threads, especially HRT.  (Do this for application
+                        * only)
+                        */
+                       if (mem_flash_io_read_u32(test_addr) != 0xFFFFFFFF) {
+                               break;
+                       }
+                       test_addr += 4;
+               }
+               if (test_addr == addr) {
+                       printk("erase failed at address 0x%x, skipping",
+                              test_addr);
+                       test_addr += 4;
+                       return 1;
+               }
+               addr = test_addr;
+       }
+       return 0;
+}
+
+
+/****************************************************************************/
+
+/*
+ * MTD implementation
+ */
+
+/*
+ * Erase an address range on the flash chip.  The address range may extend
+ * one or more erase sectors.  Return an error is there is a problem erasing.
+ */
+static int ubicom32_flash_driver_erase(struct mtd_info *mtd,
+                                      struct erase_info *instr)
+{
+       struct m25p *flash = mtd_to_m25p(mtd);
+       u32 addr, len;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %lld\n",
+             dev_name(&flash->plt_dev->dev), __FUNCTION__, "at",
+             (u32)instr->addr, instr->len);
+
+       /* sanity checks */
+       if (instr->addr + instr->len > flash->mtd.size)
+               return -EINVAL;
+       if ((instr->addr % mtd->erasesize) != 0
+                       || (instr->len % mtd->erasesize) != 0) {
+               return -EINVAL;
+       }
+
+       addr = instr->addr + UBICOM32_FLASH_BASE;
+       len = instr->len;
+
+       mutex_lock(&flash->lock);
+
+       /* REVISIT in some cases we could speed up erasing large regions
+        * by using OPCODE_SE instead of OPCODE_BE_4K
+        */
+
+       /* now erase those sectors */
+       if (mem_flash_erase(addr, len)) {
+               instr->state = MTD_ERASE_FAILED;
+               mutex_unlock(&flash->lock);
+               return -EIO;
+       }
+
+       mutex_unlock(&flash->lock);
+       instr->state = MTD_ERASE_DONE;
+       mtd_erase_callback(instr);
+       return 0;
+}
+
+/*
+ * Read an address range from the flash chip.  The address range
+ * may be any size provided it is within the physical boundaries.
+ */
+static int ubicom32_flash_driver_read(struct mtd_info *mtd, loff_t from,
+                                     size_t len, size_t *retlen, u_char *buf)
+{
+       struct m25p *flash = mtd_to_m25p(mtd);
+       u32 base_addr = UBICOM32_FLASH_BASE + from;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n",
+             dev_name(&flash->plt_dev->dev), __FUNCTION__, "from",
+             (u32)from, len);
+
+       /* sanity checks */
+       if (!len)
+               return 0;
+
+       if (from + len > flash->mtd.size)
+               return -EINVAL;
+
+       /* Byte count starts at zero. */
+       if (retlen)
+               *retlen = 0;
+
+       mutex_lock(&flash->lock);
+
+       /* Wait till previous write/erase is done. */
+       if (wait_till_ready(flash)) {
+               /* REVISIT status return?? */
+               mutex_unlock(&flash->lock);
+               return 1;
+       }
+
+       mem_flash_read(base_addr, (void *)buf, len);
+
+       if (retlen)
+               *retlen = len;
+
+       mutex_unlock(&flash->lock);
+
+       return 0;
+}
+
+/*
+ * Write an address range to the flash chip.  Data must be written in
+ * FLASH_PAGESIZE chunks.  The address range may be any size provided
+ * it is within the physical boundaries.
+ */
+static int ubicom32_flash_driver_write(struct mtd_info *mtd, loff_t to,
+                                      size_t len, size_t *retlen,
+                                      const u_char *buf)
+{
+       struct m25p *flash = mtd_to_m25p(mtd);
+       u32 base_addr = UBICOM32_FLASH_BASE + to;
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n",
+             dev_name(&flash->plt_dev->dev), __FUNCTION__, "to",
+             (u32)to, len);
+
+       if (retlen)
+               *retlen = 0;
+
+       /* sanity checks */
+       if (!len)
+               return 0;
+
+       if (to + len > flash->mtd.size)
+               return -EINVAL;
+
+       mutex_lock(&flash->lock);
+
+       mem_flash_write(base_addr, (void *) buf, len);
+
+       /* Wait until finished previous write command. */
+       if (wait_till_ready(flash)) {
+               mutex_unlock(&flash->lock);
+               return 1;
+       }
+
+       if (retlen)
+               *retlen = len;
+
+       mutex_unlock(&flash->lock);
+       return 0;
+}
+
+
+/****************************************************************************/
+
+/*
+ * SPI device driver setup and teardown
+ */
+
+struct flash_info {
+       char            *name;
+
+       /* JEDEC id zero means "no ID" (most older chips); otherwise it has
+        * a high byte of zero plus three data bytes: the manufacturer id,
+        * then a two byte device id.
+        */
+       u32             jedec_id;
+
+       /* The size listed here is what works with OPCODE_SE, which isn't
+        * necessarily called a "sector" by the vendor.
+        */
+       unsigned        sector_size;
+       u16             n_sectors;
+
+       u16             flags;
+#define        SECT_4K         0x01            /* OPCODE_BE_4K works uniformly */
+};
+
+
+/* NOTE: double check command sets and memory organization when you add
+ * more flash chips.  This current list focusses on newer chips, which
+ * have been converging on command sets which including JEDEC ID.
+ */
+static struct flash_info __devinitdata m25p_data[] = {
+
+       /* Atmel -- some are (confusingly) marketed as "DataFlash" */
+       { "at25fs010",  0x1f6601, 32 * 1024, 4, SECT_4K, },
+       { "at25fs040",  0x1f6604, 64 * 1024, 8, SECT_4K, },
+
+       { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, },
+
+       { "at26f004",   0x1f0400, 64 * 1024, 8, SECT_4K, },
+       { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, },
+       { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, },
+       { "at26df321",  0x1f4701, 64 * 1024, 64, SECT_4K, },
+
+       /* Spansion -- single (large) sector size only, at least
+        * for the chips listed here (without boot sectors).
+        */
+       { "s25sl004a", 0x010212, 64 * 1024, 8, },
+       { "s25sl008a", 0x010213, 64 * 1024, 16, },
+       { "s25sl016a", 0x010214, 64 * 1024, 32, },
+       { "s25sl032a", 0x010215, 64 * 1024, 64, },
+       { "s25sl064a", 0x010216, 64 * 1024, 128, },
+
+       /* SST -- large erase sizes are "overlays", "sectors" are 4K */
+       { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, },
+       { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, },
+       { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, },
+       { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, },
+
+       /* ST Microelectronics -- newer production may have feature updates */
+       { "m25p05",  0x202010,  32 * 1024, 2, },
+       { "m25p10",  0x202011,  32 * 1024, 4, },
+       { "m25p20",  0x202012,  64 * 1024, 4, },
+       { "m25p40",  0x202013,  64 * 1024, 8, },
+       { "m25p80",         0,  64 * 1024, 16, },
+       { "m25p16",  0x202015,  64 * 1024, 32, },
+       { "m25p32",  0x202016,  64 * 1024, 64, },
+       { "m25p64",  0x202017,  64 * 1024, 128, },
+       { "m25p128", 0x202018, 256 * 1024, 64, },
+
+       { "m45pe80", 0x204014,  64 * 1024, 16, },
+       { "m45pe16", 0x204015,  64 * 1024, 32, },
+
+       { "m25pe80", 0x208014,  64 * 1024, 16, },
+       { "m25pe16", 0x208015,  64 * 1024, 32, SECT_4K, },
+
+       /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
+       { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, },
+       { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, },
+       { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, },
+       { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, },
+       { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, },
+       { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, },
+       { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, },
+
+       /* Macronix -- mx25lxxx */
+       { "mx25l32",  0xc22016, 64 * 1024,  64, },
+       { "mx25l64",  0xc22017, 64 * 1024, 128, },
+       { "mx25l128", 0xc22018, 64 * 1024, 256, },
+
+};
+
+struct flash_info *__devinit jedec_probe(struct platform_device *spi)
+{
+       int                     tmp;
+       u32                     jedec;
+       struct flash_info       *info;
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA;
+
+       /*
+        * Setup and run RDID command on the flash.
+        */
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) |
+               IO_XFL_CTL1_FC_DATA(3);
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_RDID);
+       FLASH_COMMAND_EXEC(io);
+
+       jedec = io->status1 & 0x00ffffff;
+
+       for (tmp = 0, info = m25p_data;
+                       tmp < ARRAY_SIZE(m25p_data);
+                       tmp++, info++) {
+               if (info->jedec_id == jedec)
+                       return info;
+       }
+       dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
+       return NULL;
+}
+
+
+/*
+ * board specific setup should have ensured the SPI clock used here
+ * matches what the READ command supports, at least until this driver
+ * understands FAST_READ (for clocks over 25 MHz).
+ */
+static int __devinit ubicom32_flash_probe(struct platform_device *spi)
+{
+       struct flash_platform_data      *data;
+       struct m25p                     *flash;
+       struct flash_info               *info;
+       unsigned                        i;
+
+       /* Platform data helps sort out which chip type we have, as
+        * well as how this board partitions it.  If we don't have
+        * a chip ID, try the JEDEC id commands; they'll work for most
+        * newer chips, even if we don't recognize the particular chip.
+        */
+       data = spi->dev.platform_data;
+       if (data && data->type) {
+               for (i = 0, info = m25p_data;
+                               i < ARRAY_SIZE(m25p_data);
+                               i++, info++) {
+                       if (strcmp(data->type, info->name) == 0)
+                               break;
+               }
+
+               /* unrecognized chip? */
+               if (i == ARRAY_SIZE(m25p_data)) {
+                       DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n",
+                             dev_name(&spi->dev), data->type);
+                       info = NULL;
+
+               /* recognized; is that chip really what's there? */
+               } else if (info->jedec_id) {
+                       struct flash_info       *chip = jedec_probe(spi);
+
+                       if (!chip || chip != info) {
+                               dev_warn(&spi->dev, "found %s, expected %s\n",
+                                               chip ? chip->name : "UNKNOWN",
+                                               info->name);
+                               info = NULL;
+                       }
+               }
+       } else
+               info = jedec_probe(spi);
+
+       if (!info)
+               return -ENODEV;
+
+       flash = kzalloc(sizeof *flash, GFP_KERNEL);
+       if (!flash)
+               return -ENOMEM;
+
+       flash->plt_dev = spi;
+       mutex_init(&flash->lock);
+       dev_set_drvdata(&spi->dev, flash);
+
+       if (data && data->name)
+               flash->mtd.name = data->name;
+       else
+               flash->mtd.name = dev_name(&spi->dev);
+
+       flash->mtd.type = MTD_NORFLASH;
+       flash->mtd.writesize = 1;
+       flash->mtd.flags = MTD_CAP_NORFLASH;
+       flash->mtd.size = info->sector_size * info->n_sectors;
+       flash->mtd.erase = ubicom32_flash_driver_erase;
+       flash->mtd.read = ubicom32_flash_driver_read;
+       flash->mtd.write = ubicom32_flash_driver_write;
+
+       /* prefer "small sector" erase if possible */
+       /*
+        * The Ubicom erase code does not use the opcode for smaller sectors,
+        * so disable that functionality and keep erasesize == sector_size
+        * so that the test in ubicom32_flash_driver_erase works properly.
+        *
+        * This was: `if (info->flags & SECT_4K) {' instead of `if (0) {'
+        */
+       if (0) {
+               flash->erase_opcode = OPCODE_BE_4K;
+               flash->mtd.erasesize = 4096;
+       } else {
+               flash->erase_opcode = OPCODE_SE;
+               flash->mtd.erasesize = info->sector_size;
+       }
+
+       dev_info(&spi->dev, "%s (%lld Kbytes)\n", info->name,
+                flash->mtd.size / 1024);
+
+       DEBUG(MTD_DEBUG_LEVEL2,
+               "mtd .name = %s, .size = 0x%.8llx (%lluMiB) "
+                       ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
+               flash->mtd.name,
+               flash->mtd.size, flash->mtd.size / (1024*1024),
+               flash->mtd.erasesize, flash->mtd.erasesize / 1024,
+               flash->mtd.numeraseregions);
+
+       if (flash->mtd.numeraseregions)
+               for (i = 0; i < flash->mtd.numeraseregions; i++)
+                       DEBUG(MTD_DEBUG_LEVEL2,
+                               "mtd.eraseregions[%d] = { .offset = 0x%.8llx, "
+                               ".erasesize = 0x%.8x (%uKiB), "
+                               ".numblocks = %d }\n",
+                               i, flash->mtd.eraseregions[i].offset,
+                               flash->mtd.eraseregions[i].erasesize,
+                               flash->mtd.eraseregions[i].erasesize / 1024,
+                               flash->mtd.eraseregions[i].numblocks);
+
+
+       /* partitions should match sector boundaries; and it may be good to
+        * use readonly partitions for writeprotected sectors (BP2..BP0).
+        */
+       if (mtd_has_partitions()) {
+               struct mtd_partition    *parts = NULL;
+               int                     nr_parts = 0;
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+               static const char *part_probes[] = { "cmdlinepart", NULL, };
+
+               nr_parts = parse_mtd_partitions(&flash->mtd,
+                               part_probes, &parts, 0);
+#endif
+
+               if (nr_parts <= 0 && data && data->parts) {
+                       parts = data->parts;
+                       nr_parts = data->nr_parts;
+                       if (nr_parts >= 2) {
+                               /*
+                                * Set last partition size to be 1M.
+                                */
+                               parts[1].size = flash->mtd.size -
+                                       parts[0].size - JFFS2_FILESYSTEM_SIZE;
+                               parts[2].size = JFFS2_FILESYSTEM_SIZE;
+                       }
+               }
+
+               if (nr_parts > 0) {
+                       for (i = 0; i < nr_parts; i++) {
+                               DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
+                                       "{.name = %s, .offset = 0x%.8llx, "
+                                               ".size = 0x%.8llx (%lluKiB) }\n",
+                                       i, parts[i].name,
+                                       parts[i].offset,
+                                       parts[i].size,
+                                       parts[i].size / 1024);
+                       }
+                       flash->partitioned = 1;
+                       return add_mtd_partitions(&flash->mtd, parts, nr_parts);
+               }
+       } else if (data->nr_parts)
+               dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
+                               data->nr_parts, data->name);
+
+       return add_mtd_device(&flash->mtd) == 1 ? -ENODEV : 0;
+}
+
+
+static int __devexit ubicom32_flash_remove(struct spi_device *spi)
+{
+       struct m25p     *flash = dev_get_drvdata(&spi->dev);
+       int             status;
+
+       /* Clean up MTD stuff. */
+       if (mtd_has_partitions() && flash->partitioned)
+               status = del_mtd_partitions(&flash->mtd);
+       else
+               status = del_mtd_device(&flash->mtd);
+       if (status == 0)
+               kfree(flash);
+       return 0;
+}
+
+static struct platform_driver ubicom32_flash_driver = {
+       .driver = {
+               .name   = "ubicom32flashdriver",
+               .bus    = &platform_bus_type,
+               .owner  = THIS_MODULE,
+       },
+       .probe  = ubicom32_flash_probe,
+       .remove = NULL,
+};
+
+static int ubicom32_flash_driver_init(void)
+{
+       return platform_driver_register(&ubicom32_flash_driver);
+}
+
+
+static void ubicom32_flash_driver_exit(void)
+{
+       platform_driver_unregister(&ubicom32_flash_driver);
+}
+
+
+module_init(ubicom32_flash_driver_init);
+module_exit(ubicom32_flash_driver_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Lavender");
+MODULE_DESCRIPTION("Ubicom32 MTD SPI driver for ST M25Pxx flash chips");
diff --git a/target/linux/ubicom32/files/drivers/mtd/devices/ubi32-nand-spi-er.c b/target/linux/ubicom32/files/drivers/mtd/devices/ubi32-nand-spi-er.c
new file mode 100644 (file)
index 0000000..897bed7
--- /dev/null
@@ -0,0 +1,1188 @@
+/*
+ * Micron SPI-ER NAND Flash Memory
+ *     This code uses the built in Ubicom flash controller
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#define DRIVER_NAME                            "ubi32-nand-spi-er"
+#define UBI32_NAND_SPI_ER_BLOCK_FROM_ROW(row)  (row >> 6)
+
+#define UBI32_NAND_SPI_ER_STATUS_P_FAIL                (1 << 3)
+#define UBI32_NAND_SPI_ER_STATUS_E_FAIL                (1 << 2)
+#define UBI32_NAND_SPI_ER_STATUS_OIP           (1 << 0)
+
+#define UBI32_NAND_SPI_ER_LAST_ROW_INVALID     0xFFFFFFFF
+#define        UBI32_NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET 0x08
+
+struct ubi32_nand_spi_er_device {
+       const char              *name;
+
+       uint16_t                id;
+
+       unsigned int            blocks;
+       unsigned int            pages_per_block;
+       unsigned int            page_size;
+       unsigned int            write_size;
+       unsigned int            erase_size;
+};
+
+struct ubi32_nand_spi_er {
+       char                            name[24];
+
+       const struct ubi32_nand_spi_er_device   *device;
+
+       struct mutex                    lock;
+       struct platform_device          *pdev;
+
+       struct mtd_info                 mtd;
+
+       unsigned int                    last_row;       /* the last row we fetched */
+
+       /*
+        * Bad block table (MUST be last in strcuture)
+        */
+       unsigned long                   nbb;
+       unsigned long                   bbt[0];
+};
+
+/*
+ * Chip supports a write_size of 512, but we cannot do partial
+ * page with command 0x84.
+ *
+ * We need to use command 0x84 because we cannot fill the FIFO fast
+ * enough to transfer the whole 512 bytes at a time. (maybe through
+ * OCM?)
+ */
+const struct ubi32_nand_spi_er_device ubi32_nand_spi_er_devices[] = {
+       {
+               name:                   "MT29F1G01ZDC",
+               id:                     0x2C12,
+               blocks:                 1024,
+               pages_per_block:        64,
+               page_size:              2048,
+               write_size:             2048,
+               erase_size:             64 * 2048,
+       },
+       {
+               name:                   "MT29F1G01ZDC",
+               id:                     0x2C13,
+               blocks:                 1024,
+               pages_per_block:        64,
+               page_size:              2048,
+               write_size:             2048,
+               erase_size:             64 * 2048,
+       },
+};
+
+static int read_only = 0;
+module_param(read_only, int, 0);
+MODULE_PARM_DESC(read_only, "Leave device locked");
+
+/*
+ * Ubicom32 FLASH Command Set
+ */
+#define FLASH_PORT             RA
+
+#define FLASH_FC_INST_CMD      0x00    /* for SPI command only transaction */
+#define FLASH_FC_INST_WR       0x01    /* for SPI write transaction */
+#define FLASH_FC_INST_RD       0x02    /* for SPI read transaction */
+
+#define FLASH_COMMAND_KICK_OFF(io)                                                             \
+       asm volatile(                                                                           \
+               "       bset    "D(IO_INT_CLR)"(%0), #0, #%%bit("D(IO_XFL_INT_DONE)")   \n\t"   \
+               "       jmpt.t  .+4                                                     \n\t"   \
+               "       bset    "D(IO_INT_SET)"(%0), #0, #%%bit("D(IO_XFL_INT_START)")  \n\t"   \
+               :                                                                               \
+               : "a" (io)                                                                      \
+               : "cc"                                                                          \
+               );
+
+#define FLASH_COMMAND_WAIT_FOR_COMPLETION(io)                                                  \
+       asm volatile(                                                                           \
+               "       btst    "D(IO_INT_STATUS)"(%0), #%%bit("D(IO_XFL_INT_DONE)")    \n\t"   \
+               "       jmpeq.f .-4                                                     \n\t"   \
+               :                                                                               \
+               : "a" (io)                                                                      \
+               : "cc"                                                                          \
+       );
+
+#define FLASH_COMMAND_EXEC(io)                         \
+               FLASH_COMMAND_KICK_OFF(io)              \
+               FLASH_COMMAND_WAIT_FOR_COMPLETION(io)
+
+/*
+ * ubi32_nand_spi_er_get_feature
+ *     Get Feature register
+ */
+static uint8_t ubi32_nand_spi_er_get_feature(uint32_t reg)
+{
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
+
+       /*
+        * Note that this will produce the sequence:
+        *      SI [0F][REG][00][00]
+        *      SO ---------[SR][SR][SR]
+        * Since the flash controller can only output 24 bits of address, this is
+        * ok for this command since the data will just repeat as long as the CS
+        * is asserted and the clock is running.
+        */
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | IO_XFL_CTL1_FC_DATA(1) |
+                   IO_XFL_CTL1_FC_ADDR;
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(0x0F) | IO_XFL_CTL2_FC_ADDR(reg << 16);
+       FLASH_COMMAND_EXEC(io);
+
+       return io->status1 & 0xFF;
+}
+
+/*
+ * ubi32_nand_spi_er_write_buf
+ *     writes a buffer to the bus
+ *
+ * Writes 511 + 1 bytes to the bus, we have to stuff one data byte into the address.
+ */
+static void ubi32_nand_spi_er_write_buf(const uint8_t *buf, uint32_t col)
+{
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
+       uint32_t tmp;
+
+       asm volatile (
+               "       bset            "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)")   \n\t"
+               "       pipe_flush      0                                                                       \n\t"
+               :
+               : [port] "a" (FLASH_PORT)
+               : "cc"
+       );
+
+       /*
+        * Write the data into the cache
+        */
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+#ifdef SUPPORT_512_FIFO
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(511) |
+#endif
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(31) |
+                   IO_XFL_CTL1_FC_ADDR;
+
+       /*
+        * Construct the address with the first byte of data
+        */
+       tmp = (col << 8) | *buf++;
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(0x84) | IO_XFL_CTL2_FC_ADDR(tmp);
+
+       asm volatile (
+
+               /*
+                * Move 32 bytes
+                *
+                * The first word needs to be [11][22][33][33] to work around a flash
+                * controller bug.
+                */
+               "       move.2          %[tmp], (%[data])2++                                                    \n\t"
+               "       shmrg.1         %[tmp], (%[data]), %[tmp]                                               \n\t"
+               "       shmrg.1         %[tmp], (%[data])1++, %[tmp]                                            \n\t"
+               "       move.4          "D(IO_TX_FIFO)"(%[port]), %[tmp]                                        \n\t"
+
+               /*
+                * We're aligned again!
+                */
+               "       .rept 7                                                                                 \n\t"
+               "       move.4          "D(IO_TX_FIFO)"(%[port]), (%[data])4++                                  \n\t"
+               "       .endr                                                                                   \n\t"
+
+               /*
+                * Kick off the flash command
+                */
+               "       bset    "D(IO_INT_CLR)"(%[port]), #0, #%%bit("D(IO_XFL_INT_DONE)")                      \n\t"
+               "       jmpt.t  .+4                                                                             \n\t"
+               "       bset    "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_XFL_INT_START)")                     \n\t"
+
+#ifdef SUPPORT_512_FIFO
+               /*
+                * Fill the remaining 120 words as space becomes available
+                */
+               "1:                                                                                             \n\t"
+               "       cmpi            "D(IO_FIFO_LEVEL)"(%[port]), #4                                         \n\t"
+               "       jmpgt.s.t       1b                                                                      \n\t"
+               "       move.4          "D(IO_TX_FIFO)"(%[port]), (%[data])4++                                  \n\t"
+               "       move.4          "D(IO_TX_FIFO)"(%[port]), (%[data])4++                                  \n\t"
+               "       move.4          "D(IO_TX_FIFO)"(%[port]), (%[data])4++                                  \n\t"
+               "       move.4          "D(IO_TX_FIFO)"(%[port]), (%[data])4++                                  \n\t"
+               "       add.4           %[cnt], #-4, %[cnt]                                                     \n\t"
+               "       jmpgt.t         1b                                                                      \n\t"
+#endif
+               /*
+                * Wait for the transaction to finish
+                */
+               "       btst    "D(IO_INT_STATUS)"(%[port]), #%%bit("D(IO_XFL_INT_DONE)")                       \n\t"
+               "       jmpeq.f .-4                                                                             \n\t"
+
+               : [tmp] "=&d" (tmp),
+                 [data] "+&a" (buf)
+               : [column] "d" (col),
+                 [port] "a" (FLASH_PORT),
+                 [cnt] "d" (120)               // see above comment
+               : "cc"
+       );
+}
+
+/*
+ * ubi32_nand_spi_er_send_rd_addr
+ *     perform FC_RD: CMD + address
+ */
+static void ubi32_nand_spi_er_send_rd_addr(uint8_t command, uint32_t address)
+{
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
+
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | IO_XFL_CTL1_FC_DATA(4) |
+                   IO_XFL_CTL1_FC_ADDR;
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(command) | IO_XFL_CTL2_FC_ADDR(address);
+       FLASH_COMMAND_EXEC(io);
+}
+
+/*
+ * ubi32_nand_spi_er_send_cmd_addr
+ *     perform FC_(xxx): CMD + address
+ */
+static void ubi32_nand_spi_er_send_cmd_addr(uint8_t command, uint32_t address)
+{
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
+
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD) | IO_XFL_CTL1_FC_ADDR;
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(command) | IO_XFL_CTL2_FC_ADDR(address);
+       FLASH_COMMAND_EXEC(io);
+}
+
+/*
+ * ubi32_nand_spi_er_write_disable
+ *     clear the write enable bit
+ */
+static void ubi32_nand_spi_er_write_disable(void)
+{
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
+
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD);
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(0x04);
+       FLASH_COMMAND_EXEC(io);
+}
+
+/*
+ * ubi32_nand_spi_er_write_enable
+ *     set the write enable bit
+ */
+static void ubi32_nand_spi_er_write_enable(void)
+{
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
+
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD);
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(0x06);
+       FLASH_COMMAND_EXEC(io);
+}
+
+/*
+ * ubi32_nand_spi_er_busywait
+ *     Wait until the chip is not busy
+ */
+static uint8_t ubi32_nand_spi_er_busywait(void)
+{
+       int i;
+       uint8_t data;
+
+       /*
+        * tRD is 100us, so don't delay too long, however, tERS is
+        * 10ms so you'd better loop enough.
+        */
+       for (i = 0; i < 200; i++) {
+               data = ubi32_nand_spi_er_get_feature(0xC0);
+               if (!(data & UBI32_NAND_SPI_ER_STATUS_OIP)) {
+                       break;
+               }
+
+               udelay(50);
+       }
+
+       return data;
+}
+
+/*
+ * ubi32_nand_spi_er_erase
+ *     Erase a block, parameters must be block aligned
+ */
+static int ubi32_nand_spi_er_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+       struct ubi32_nand_spi_er *chip = mtd->priv;
+       int res;
+
+       DEBUG(MTD_DEBUG_LEVEL3, "%s: erase addr:%x len:%x\n", chip->name, instr->addr, instr->len);
+
+       if ((instr->addr + instr->len) > mtd->size) {
+               return -EINVAL;
+       }
+
+       if (instr->addr & (chip->device->erase_size - 1)) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: erase address is not aligned %x\n", chip->name, instr->addr);
+               return -EINVAL;
+       }
+
+       if (instr->len & (chip->device->erase_size - 1)) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: erase len is not aligned %x\n", chip->name, instr->len);
+               return -EINVAL;
+       }
+
+       mutex_lock(&chip->lock);
+       chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID;
+
+       while (instr->len) {
+               uint32_t block = instr->addr >> 17;
+               uint32_t row = block << 6;
+               uint8_t stat;
+               DEBUG(MTD_DEBUG_LEVEL3, "%s: block erase row:%x block:%x addr:%x rem:%x\n", chip->name, row, block, instr->addr, instr->len);
+
+               /*
+                * Test for bad block
+                */
+               if (test_bit(block, chip->bbt)) {
+                       instr->fail_addr = block << 17;
+                       instr->state = MTD_ERASE_FAILED;
+                       res = -EBADMSG;
+                       goto done;
+               }
+
+               ubi32_nand_spi_er_write_enable();
+
+               /*
+                * Block erase
+                */
+               ubi32_nand_spi_er_send_cmd_addr(0xD8, row);
+
+               /*
+                * Wait
+                */
+               stat = ubi32_nand_spi_er_busywait();
+               if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) {
+                       instr->fail_addr = block << 17;
+                       instr->state = MTD_ERASE_FAILED;
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat);
+
+                       /*
+                        * Chip is stuck?
+                        */
+                       res = -EIO;
+                       goto done;
+               }
+
+               /*
+                * Check the status register
+                */
+               if (stat & UBI32_NAND_SPI_ER_STATUS_E_FAIL) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: E_FAIL signalled (%02x)\n", chip->name, stat);
+                       instr->fail_addr = block << 17;
+                       instr->state = MTD_ERASE_FAILED;
+                       goto done;
+               }
+
+               /*
+                * Next
+                */
+               block++;
+               instr->len -= chip->device->erase_size;
+               instr->addr += chip->device->erase_size;
+       }
+
+       instr->state = MTD_ERASE_DONE;
+
+       mutex_unlock(&chip->lock);
+       return 0;
+
+done:
+       ubi32_nand_spi_er_write_disable();
+
+       mutex_unlock(&chip->lock);
+
+       mtd_erase_callback(instr);
+       return 0;
+}
+
+/*
+ * ubi32_nand_spi_er_read
+ *
+ * return -EUCLEAN: ecc error recovered
+ * return -EBADMSG: ecc error not recovered
+*/
+static int ubi32_nand_spi_er_read(struct mtd_info *mtd, loff_t from, size_t len,
+                                 size_t *retlen, u_char *buf)
+{
+       struct ubi32_nand_spi_er *chip = mtd->priv;
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
+
+       uint32_t row;
+       uint32_t column;
+       int retval = 0;
+       uint32_t *pbuf = (uint32_t *)buf;
+
+       *retlen = 0;
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: read block from %llx len %d into %p\n", chip->name, from, len, buf);
+
+       /*
+        * buf should be aligned
+        */
+       if ((uint32_t)buf & 0x03) {
+               return -EINVAL;
+       }
+
+       /*
+        * Zero length reads, nothing to do
+        */
+       if (len == 0) {
+               return 0;
+       }
+
+       /*
+        * Reject reads which go over the end of the flash
+        */
+       if ((from + len) > mtd->size) {
+               return -EINVAL;
+       }
+
+       /*
+        * Get the row and column address to start at
+        */
+       row = from >> 11;
+       column = from & 0x7FF;
+       DEBUG(MTD_DEBUG_LEVEL3, "%s: row=%x %d column=%x %d last_row=%x %d\n", chip->name, row, row, column, column, chip->last_row, chip->last_row);
+
+       /*
+        * Read the data from the chip
+        */
+       mutex_lock(&chip->lock);
+       while (len) {
+               uint8_t stat;
+               size_t toread;
+               int i;
+               int tmp;
+
+               /*
+                * Figure out how much to read
+                *
+                * If we are reading from the middle of a page then the most we
+                * can read is to the end of the page
+                */
+               toread = len;
+               if (toread > (chip->device->page_size - column)) {
+                       toread = chip->device->page_size - column;
+               }
+
+               DEBUG(MTD_DEBUG_LEVEL3, "%s: buf=%p toread=%x row=%x column=%x last_row=%x\n", chip->name, pbuf, toread, row, column, chip->last_row);
+
+               if (chip->last_row != row) {
+                       /*
+                        * Check if the block is bad
+                        */
+                       if (test_bit(UBI32_NAND_SPI_ER_BLOCK_FROM_ROW(row), chip->bbt)) {
+                               mutex_unlock(&chip->lock);
+                               return -EBADMSG;
+                       }
+
+                       /*
+                        * Load the appropriate page
+                        */
+                       ubi32_nand_spi_er_send_cmd_addr(0x13, row);
+
+                       /*
+                        * Wait
+                        */
+                       stat = ubi32_nand_spi_er_busywait();
+                       if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) {
+                               DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat);
+
+                               /*
+                                * Chip is stuck?
+                                */
+                               mutex_unlock(&chip->lock);
+                               return -EIO;
+                       }
+
+                       /*
+                        * Check the ECC bits
+                        */
+                       stat >>= 4;
+                       if (stat == 1) {
+                               DEBUG(MTD_DEBUG_LEVEL1, "%s: ECC recovered, row=%x\n", chip->name, row);
+                               retval = -EUCLEAN;
+                       }
+                       if (stat == 2) {
+                               DEBUG(MTD_DEBUG_LEVEL0, "%s: failed ECC, row=%x\n", chip->name, row);
+                               chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID;
+                               mutex_unlock(&chip->lock);
+                               return -EBADMSG;
+                       }
+
+               }
+
+               chip->last_row = row;
+
+               /*
+                * Read out the data:
+                *      We can always read a little too much since there is the
+                *      OOB after byte addr 2047.  The most we'll overread is 3 bytes.
+                */
+               if (((uint32_t)pbuf & 0x03) == 0) {
+                       /*
+                        * Aligned read
+                        */
+                       tmp = toread & (~0x03);
+                       for (i = 0; i < tmp; i += 4) {
+                               ubi32_nand_spi_er_send_rd_addr(0x03, column << 8);
+                               *pbuf++ = io->status1;
+                               column += 4;
+                       }
+               } else {
+                       /*
+                        * Unaligned read
+                        */
+                       tmp = toread & (~0x03);
+                       for (i = 0; i < tmp; i += 4) {
+                               ubi32_nand_spi_er_send_rd_addr(0x03, column << 8);
+                               memcpy(pbuf, &io->status1, 4);
+                               column += 4;
+                       }
+               }
+
+               /*
+                * Fill in any single bytes
+                */
+               tmp = toread & 0x03;
+               if (tmp) {
+                       uint8_t *bbuf = pbuf;
+                       uint32_t val;
+                       ubi32_nand_spi_er_send_rd_addr(0x03, column << 8);
+                       val = io->status1;
+                       for (i = 0; i < tmp; i++) {
+                               *bbuf++ = val >> 24;
+                               val <<= 8;
+                       }
+               }
+
+               len -= toread;
+               *retlen += toread;
+
+               /*
+                * For the next page, increment the row and always start at column 0
+                */
+               column = 0;
+               row++;
+       }
+
+       mutex_unlock(&chip->lock);
+       return retval;
+}
+
+/*
+ * ubi32_nand_spi_er_write
+ */
+#define WRITE_NOT_ALIGNED(x) ((x & (device->write_size - 1)) != 0)
+static int ubi32_nand_spi_er_write(struct mtd_info *mtd, loff_t to, size_t len,
+                                  size_t *retlen, const u_char *buf)
+{
+       struct ubi32_nand_spi_er *chip = mtd->priv;
+       const struct ubi32_nand_spi_er_device *device = chip->device;
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
+       uint32_t row;
+       uint32_t col;
+       int res = 0;
+       size_t towrite;
+
+       DEBUG(MTD_DEBUG_LEVEL2, "%s: write block to %llx len %d from %p\n", chip->name, to, len, buf);
+
+       *retlen = 0;
+
+       /*
+        * nothing to write
+        */
+       if (!len) {
+               return 0;
+       }
+
+       /*
+        * Reject writes which go over the end of the flash
+        */
+       if ((to + len) > mtd->size) {
+               return -EINVAL;
+       }
+
+       /*
+        * buf should be aligned to 16 bits
+        */
+       if ((uint32_t)buf & 0x01) {
+               return -EINVAL;
+       }
+
+       /*
+        * Check to see if everything is page aligned
+        */
+       if (WRITE_NOT_ALIGNED(to) || WRITE_NOT_ALIGNED(len)) {
+               printk(KERN_NOTICE "ubi32_nand_spi_er_write: Attempt to write non page aligned data\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&chip->lock);
+
+       io->ctl0 |= IO_XFL_CTL0_MCB_LOCK;
+
+       chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID;
+
+       /*
+        * If the first write is a partial write then write at most the number of
+        * bytes to get us page aligned and then the remainder will be
+        * page aligned.  The last bit may be a partial page as well.
+        */
+       col = to & (device->page_size - 1);
+       towrite = device->page_size - col;
+       if (towrite > len) {
+               towrite = len;
+       }
+
+       /*
+        * Write the data
+        */
+       row = to >> 11;
+       while (len) {
+               uint8_t stat;
+               uint32_t my_towrite;
+
+               DEBUG(MTD_DEBUG_LEVEL3, "%s: write %p to row:%x col:%x len:%x rem:%x\n", chip->name, buf, row, col, towrite, len);
+
+               ubi32_nand_spi_er_write_enable();
+
+               /*
+                * Move the data into the cache
+                */
+               my_towrite = towrite;
+               while (my_towrite) {
+                       uint32_t len = my_towrite;
+                       if (len > 32) {
+                               len = 32;
+                       }
+
+                       ubi32_nand_spi_er_write_buf(buf, col);
+                       buf += len;
+                       col += len;
+                       my_towrite -= len;
+               }
+
+               /*
+                * Program execute
+                */
+               ubi32_nand_spi_er_send_cmd_addr(0x10, row);
+
+               /*
+                * Wait
+                */
+               stat = ubi32_nand_spi_er_busywait();
+               if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat);
+
+                       /*
+                        * Chip is stuck?
+                        */
+                       res = -EIO;
+                       goto done;
+               }
+
+               if (stat & (1 << 3)) {
+                       res = -EBADMSG;
+                       goto done;
+               }
+
+               row++;
+               len -= towrite;
+               *retlen += towrite;
+
+               /*
+                * At this point, we are always page aligned so start at column 0.
+                * Note we may not have a full page to write at the end, hence the
+                * check if towrite > len.
+                */
+               col = 0;
+               towrite = device->page_size;
+               if (towrite > len) {
+                       towrite = len;
+               }
+       }
+
+       io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK;
+
+       mutex_unlock(&chip->lock);
+       return res;
+
+done:
+       ubi32_nand_spi_er_write_disable();
+
+       io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK;
+
+       mutex_unlock(&chip->lock);
+
+       return res;
+}
+
+/*
+ * ubi32_nand_spi_er_isbad
+ */
+static int ubi32_nand_spi_er_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+       struct ubi32_nand_spi_er *chip = mtd->priv;
+       uint32_t block;
+
+       if (ofs & (chip->device->erase_size - 1)) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs);
+               return -EINVAL;
+       }
+
+       block = ofs >> 17;
+
+       return test_bit(block, chip->bbt);
+}
+
+/*
+ * ubi32_nand_spi_er_markbad
+ */
+static int ubi32_nand_spi_er_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+       struct ubi32_nand_spi_er *chip = mtd->priv;
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
+       uint32_t block;
+       uint32_t row;
+       int res = 0;
+       uint8_t stat;
+
+       if (ofs & (chip->device->erase_size - 1)) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs);
+               return -EINVAL;
+       }
+
+       block = ofs >> 17;
+
+       /*
+        * If it's already marked bad, no need to mark it
+        */
+       if (test_bit(block, chip->bbt)) {
+               return 0;
+       }
+
+       /*
+        * Mark it in our cache
+        */
+       __set_bit(block, chip->bbt);
+
+       /*
+        * Write the user bad block mark.  If it fails, then we really
+        * can't do anything about it.
+        */
+       mutex_lock(&chip->lock);
+       chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID;
+
+       ubi32_nand_spi_er_write_enable();
+
+       /*
+        * Write the mark
+        */
+       io->ctl0 |= IO_XFL_CTL0_MCB_LOCK;
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(6);
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(0x84);
+
+       asm volatile (
+               "       bset            "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)")   \n\t"
+               "       pipe_flush      0                                                                       \n\t"
+
+               /*
+                * Move the data into the FIFO
+                */
+               "       move.4          "D(IO_TX_FIFO)"(%[port]), %[word1]                                      \n\t"
+               "       move.4          "D(IO_TX_FIFO)"(%[port]), %[word2]                                      \n\t"
+
+               /*
+                * Kick off the flash command
+                */
+               "       bset    "D(IO_INT_CLR)"(%[port]), #0, #%%bit("D(IO_XFL_INT_DONE)")                      \n\t"
+               "       jmpt.t  .+4                                                                             \n\t"
+               "       bset    "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_XFL_INT_START)")                     \n\t"
+
+               /*
+                * Wait for the transaction to finish
+                */
+               "       btst    "D(IO_INT_STATUS)"(%[port]), #%%bit("D(IO_XFL_INT_DONE)")                       \n\t"
+               "       jmpeq.f .-4                                                                             \n\t"
+
+               :
+               : [word1] "d" (0x0800dead | (UBI32_NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET << 16)),
+                 [word2] "d" (0xbeef0000),
+                 [port] "a" (FLASH_PORT)
+               : "cc"
+       );
+
+       io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK;
+
+       /*
+        * Program execute
+        */
+       row = block << 6;
+       ubi32_nand_spi_er_send_cmd_addr(0x10, row);
+
+       /*
+        * Wait
+        */
+       stat = ubi32_nand_spi_er_busywait();
+       if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) {
+               DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat);
+
+               /*
+                * Chip is stuck?
+                */
+               res = -EIO;
+               goto done;
+       }
+
+       if (stat & (1 << 3)) {
+               res = -EBADMSG;
+       }
+
+done:
+       ubi32_nand_spi_er_write_disable();
+
+       mutex_unlock(&chip->lock);
+
+       return res;
+}
+
+/*
+ * ubi32_nand_spi_er_read_bbt
+ */
+static int ubi32_nand_spi_er_read_bbt(struct ubi32_nand_spi_er *chip)
+{
+       int j;
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
+
+       for (j = 0; j < chip->device->blocks; j++) {
+               unsigned short row = j << 6;
+               uint8_t stat;
+
+               /*
+                * Read Page
+                */
+               ubi32_nand_spi_er_send_cmd_addr(0x13, row);
+
+               /*
+                * Wait
+                */
+               stat = ubi32_nand_spi_er_busywait();
+               if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) {
+                       DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat);
+
+                       /*
+                        * Chip is stuck?
+                        */
+                       return -EIO;
+               }
+
+               /*
+                * Check factory bad block mark
+                */
+               ubi32_nand_spi_er_send_rd_addr(0x03, 0x080000);
+
+               if ((io->status1 >> 24) != 0xFF) {
+                       chip->nbb++;
+                       __set_bit(j, chip->bbt);
+                       continue;
+               }
+
+               ubi32_nand_spi_er_send_rd_addr(0x03, 0x080000 | (UBI32_NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET << 8));
+               if (io->status1 == 0xdeadbeef) {
+                       chip->nbb++;
+                       __set_bit(j, chip->bbt);
+               }
+       }
+
+#if defined(CONFIG_MTD_DEBUG) && (MTD_DEBUG_LEVEL3 <= CONFIG_MTD_DEBUG_VERBOSE)
+       printk("%s: Bad Block Table:", chip->name);
+       for (j = 0; j < chip->device->blocks; j++) {
+               if ((j % 64) == 0) {
+                       printk("\n%s: block %03x: ", chip->name, j);
+               }
+               printk("%c", test_bit(j, chip->bbt) ? 'X' : '.');
+       }
+       printk("\n%s: Bad Block Numbers: ", chip->name);
+       for (j = 0; j < chip->device->blocks; j++) {
+               if (test_bit(j, chip->bbt)) {
+                       printk("%x ", j);
+               }
+       }
+       printk("\n");
+#endif
+
+       return 0;
+}
+
+#ifndef MODULE
+/*
+ * Called at boot time:
+ *
+ * ubi32_nand_spi_er=read_only
+ *     if read_only specified then do not unlock device
+ */
+static int __init ubi32_nand_spi_er_setup(char *str)
+{
+       if (str && (strncasecmp(str, "read_only", 9) == 0)) {
+               read_only = 1;
+       }
+       return 0;
+}
+
+__setup("ubi32_nand_spi_er=", ubi32_nand_spi_er_setup);
+#endif
+
+/*
+ * ubi32_nand_spi_er_probe
+ *     Detect and initialize ubi32_nand_spi_er device.
+ */
+static int __devinit ubi32_nand_spi_er_probe(struct platform_device *pdev)
+{
+       uint32_t i;
+       uint32_t id;
+       int res;
+       size_t bbt_bytes;
+       struct ubi32_nand_spi_er *chip;
+       const struct ubi32_nand_spi_er_device *device;
+       struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
+
+       /*
+        * Reset
+        */
+       for (i = 0; i < 2; i++) {
+               io->ctl1 &= ~IO_XFL_CTL1_MASK;
+               io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD);
+               io->ctl2 = IO_XFL_CTL2_FC_CMD(0xFF);
+               FLASH_COMMAND_EXEC(io);
+               udelay(250);
+       }
+       udelay(1000);
+
+       /*
+        * Read out ID
+        */
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | IO_XFL_CTL1_FC_DATA(2) |
+                   IO_XFL_CTL1_FC_ADDR;
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(0x9F);
+       FLASH_COMMAND_EXEC(io);
+
+       id = io->status1 >> 16;
+       device = ubi32_nand_spi_er_devices;
+       for (i = 0; i < ARRAY_SIZE(ubi32_nand_spi_er_devices); i++) {
+               if (device->id == id) {
+                       break;
+               }
+               device++;
+       }
+       if (i == ARRAY_SIZE(ubi32_nand_spi_er_devices)) {
+               return -ENODEV;
+       }
+
+       /*
+        * Initialize our chip structure
+        */
+       bbt_bytes = DIV_ROUND_UP(device->blocks, BITS_PER_BYTE);
+       chip = kzalloc(sizeof(struct ubi32_nand_spi_er) + bbt_bytes, GFP_KERNEL);
+       if (!chip) {
+               return -ENOMEM;
+       }
+       snprintf(chip->name, sizeof(chip->name), "%s", device->name);
+
+       chip->device = device;
+       chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID;
+
+       mutex_init(&chip->lock);
+
+       chip->mtd.type = MTD_NANDFLASH;
+       chip->mtd.flags = MTD_WRITEABLE;
+
+       /*
+        * #blocks * block size * n blocks
+        */
+       chip->mtd.size = device->blocks * device->pages_per_block * device->page_size;
+       chip->mtd.erasesize = device->erase_size;
+
+       /*
+        * 1 page, optionally we can support partial write (512)
+        */
+       chip->mtd.writesize = device->write_size;
+       chip->mtd.name = device->name;
+       chip->mtd.erase = ubi32_nand_spi_er_erase;
+       chip->mtd.read = ubi32_nand_spi_er_read;
+       chip->mtd.write = ubi32_nand_spi_er_write;
+       chip->mtd.block_isbad = ubi32_nand_spi_er_isbad;
+       chip->mtd.block_markbad = ubi32_nand_spi_er_markbad;
+       chip->mtd.priv = chip;
+
+       /*
+        * Cache the bad block table
+        */
+       res = ubi32_nand_spi_er_read_bbt(chip);
+       if (res) {
+               kfree(chip);
+               return res;
+       }
+
+       /*
+        * Un/lock the chip
+        */
+       io->ctl0 |= IO_XFL_CTL0_MCB_LOCK;
+       io->ctl1 &= ~IO_XFL_CTL1_MASK;
+       io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(2);
+       io->ctl2 = IO_XFL_CTL2_FC_CMD(0x1F);
+
+       if (read_only) {
+               i = 0xa0380000;
+       } else {
+               i = 0xa0000000;
+       }
+       asm volatile (
+               "       bset            "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)")   \n\t"
+               "       pipe_flush      0                                                                       \n\t"
+
+               /*
+                * Move the data into the FIFO
+                */
+               "       move.4          "D(IO_TX_FIFO)"(%[port]), %[word1]                                      \n\t"
+
+               /*
+                * Kick off the flash command
+                */
+               "       bset    "D(IO_INT_CLR)"(%[port]), #0, #%%bit("D(IO_XFL_INT_DONE)")                      \n\t"
+               "       jmpt.t  .+4                                                                             \n\t"
+               "       bset    "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_XFL_INT_START)")                     \n\t"
+
+               /*
+                * Wait for the transaction to finish
+                */
+               "       btst    "D(IO_INT_STATUS)"(%[port]), #%%bit("D(IO_XFL_INT_DONE)")                       \n\t"
+               "       jmpeq.f .-4                                                                             \n\t"
+
+               :
+               : [word1] "d" (i),
+                 [port] "a" (FLASH_PORT)
+               : "cc"
+       );
+       io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK;
+
+       dev_set_drvdata(&pdev->dev, chip);
+
+       printk(KERN_INFO "%s: added device size: %u KBytes %lu bad blocks %s\n", chip->mtd.name, DIV_ROUND_UP(chip->mtd.size, 1024), chip->nbb, read_only ? "[read only]" : "");
+       return add_mtd_device(&chip->mtd);
+}
+
+/*
+ * ubi32_nand_spi_er_remove
+ */
+static int __devexit ubi32_nand_spi_er_remove(struct platform_device *pdev)
+{
+       struct ubi32_nand_spi_er *chip = dev_get_drvdata(&pdev->dev);
+       int status;
+
+       DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", chip->name);
+
+       status = del_mtd_device(&chip->mtd);
+       if (status == 0) {
+               kfree(chip);
+       }
+
+       dev_set_drvdata(&pdev->dev, NULL);
+       return status;
+}
+
+static struct platform_device *ubi32_nand_spi_er_device;
+
+static struct platform_driver ubi32_nand_spi_er_driver = {
+       .driver = {
+               .name           = DRIVER_NAME,
+               .owner          = THIS_MODULE,
+       },
+
+       .probe          = ubi32_nand_spi_er_probe,
+       .remove         = ubi32_nand_spi_er_remove,
+};
+
+/*
+ * ubi32_nand_spi_er_init
+ */
+static int __init ubi32_nand_spi_er_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&ubi32_nand_spi_er_driver);
+
+       if (ret) {
+               return ret;
+       }
+
+       ubi32_nand_spi_er_device = platform_device_alloc(DRIVER_NAME, 0);
+       if (!ubi32_nand_spi_er_device) {
+               return -ENOMEM;
+       }
+
+       ret = platform_device_add(ubi32_nand_spi_er_device);
+       if (ret) {
+               platform_device_put(ubi32_nand_spi_er_device);
+               platform_driver_unregister(&ubi32_nand_spi_er_driver);
+       }
+
+       return ret;
+}
+module_init(ubi32_nand_spi_er_init);
+
+/*
+ * ubi32_nand_spi_er_exit
+ */
+static void __exit ubi32_nand_spi_er_exit(void)
+{
+       platform_device_unregister(ubi32_nand_spi_er_device);
+       platform_driver_unregister(&ubi32_nand_spi_er_driver);
+}
+module_exit(ubi32_nand_spi_er_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick Tjin");
+MODULE_DESCRIPTION("MTD ubi32_nand_spi_er driver for ubicom32 SPI flash controller.");
diff --git a/target/linux/ubicom32/files/drivers/net/ubi32-eth.c b/target/linux/ubicom32/files/drivers/net/ubi32-eth.c
new file mode 100644 (file)
index 0000000..e6c7392
--- /dev/null
@@ -0,0 +1,760 @@
+/*
+ * drivers/net/ubi32-eth.c
+ *   Ubicom32 ethernet TIO interface driver.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+/*
+ * ubi32_eth.c
+ * Ethernet driver for Ip5k/Ip7K
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <asm/checksum.h>
+#include <asm/ip5000.h>
+#include <asm/devtree.h>
+#include <asm/system.h>
+
+#define UBICOM32_USE_NAPI      /* define this to use NAPI instead of tasklet */
+//#define UBICOM32_USE_POLLING /* define this to use polling instead of interrupt */
+#include "ubi32-eth.h"
+
+/*
+ * TODO:
+ * mac address from flash
+ * multicast filter
+ * ethtool support
+ * sysfs support
+ * skb->nrfrag support
+ * ioctl
+ * monitor phy status
+ */
+
+extern int ubi32_ocm_skbuf_max, ubi32_ocm_skbuf, ubi32_ddr_skbuf;
+static const char *eth_if_name[UBI32_ETH_NUM_OF_DEVICES] =
+       {"eth_lan", "eth_wan"};
+static struct net_device *ubi32_eth_devices[UBI32_ETH_NUM_OF_DEVICES] =
+       {NULL, NULL};
+static u8_t mac_addr[UBI32_ETH_NUM_OF_DEVICES][ETH_ALEN] = {
+       {0x00, 0x03, 0x64, 'l', 'a', 'n'},
+       {0x00, 0x03, 0x64, 'w', 'a', 'n'}};
+
+#if (defined(CONFIG_ZONE_DMA) && defined(CONFIG_UBICOM32_OCM_FOR_SKB))
+static inline struct sk_buff *ubi32_alloc_skb_ocm(struct net_device *dev, unsigned int length)
+{
+       return __dev_alloc_skb(length, GFP_ATOMIC | __GFP_NOWARN | __GFP_NORETRY | GFP_DMA);
+}
+#endif
+
+static inline struct sk_buff *ubi32_alloc_skb(struct net_device *dev, unsigned int length)
+{
+       return __dev_alloc_skb(length, GFP_ATOMIC | __GFP_NOWARN);
+}
+
+static void ubi32_eth_vp_rxtx_enable(struct net_device *dev)
+{
+       struct ubi32_eth_private *priv = netdev_priv(dev);
+       priv->regs->command = UBI32_ETH_VP_CMD_RX_ENABLE | UBI32_ETH_VP_CMD_TX_ENABLE;
+       priv->regs->int_mask = (UBI32_ETH_VP_INT_RX | UBI32_ETH_VP_INT_TX);
+       ubicom32_set_interrupt(priv->vp_int_bit);
+}
+
+static void ubi32_eth_vp_rxtx_stop(struct net_device *dev)
+{
+       struct ubi32_eth_private *priv = netdev_priv(dev);
+       priv->regs->command = 0;
+       priv->regs->int_mask = 0;
+       ubicom32_set_interrupt(priv->vp_int_bit);
+
+       /* Wait for graceful shutdown */
+       while (priv->regs->status & (UBI32_ETH_VP_STATUS_RX_STATE | UBI32_ETH_VP_STATUS_TX_STATE));
+}
+
+/*
+ * ubi32_eth_tx_done()
+ */
+static int ubi32_eth_tx_done(struct net_device *dev)
+{
+       struct ubi32_eth_private *priv;
+       struct sk_buff *skb;
+       volatile void *pdata;
+       struct ubi32_eth_dma_desc *desc;
+       u32_t   count = 0;
+
+       priv = netdev_priv(dev);
+
+       priv->regs->int_status &= ~UBI32_ETH_VP_INT_TX;
+       while (priv->tx_tail != priv->regs->tx_out) {
+               pdata = priv->regs->tx_dma_ring[priv->tx_tail];
+               BUG_ON(pdata == NULL);
+
+               skb = container_of((void *)pdata, struct sk_buff, cb);
+               desc = (struct ubi32_eth_dma_desc *)pdata;
+               if (unlikely(!(desc->status & UBI32_ETH_VP_TX_OK))) {
+                       dev->stats.tx_errors++;
+               } else {
+                       dev->stats.tx_packets++;
+                       dev->stats.tx_bytes += skb->len;
+               }
+               dev_kfree_skb_any(skb);
+               priv->regs->tx_dma_ring[priv->tx_tail] = NULL;
+               priv->tx_tail = (priv->tx_tail + 1) & TX_DMA_RING_MASK;
+               count++;
+       }
+
+       if (unlikely(priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL)) {
+               spin_lock(&priv->lock);
+               if (priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL) {
+                       priv->regs->status &= ~UBI32_ETH_VP_STATUS_TX_Q_FULL;
+                       netif_wake_queue(dev);
+               }
+               spin_unlock(&priv->lock);
+       }
+       return count;
+}
+
+/*
+ * ubi32_eth_receive()
+ *     To avoid locking overhead, this is called only
+ *     by tasklet when not using NAPI, or
+ *     by NAPI poll when using NAPI.
+ *     return number of frames processed
+ */
+static int ubi32_eth_receive(struct net_device *dev, int quota)
+{
+       struct ubi32_eth_private *priv = netdev_priv(dev);
+       unsigned short rx_in = priv->regs->rx_in;
+       struct sk_buff *skb;
+       struct ubi32_eth_dma_desc *desc = NULL;
+       volatile void *pdata;
+
+       int extra_reserve_adj;
+       int extra_alloc = UBI32_ETH_RESERVE_SPACE + UBI32_ETH_TRASHED_MEMORY;
+       int replenish_cnt, count = 0;
+       int replenish_max = RX_DMA_MAX_QUEUE_SIZE;
+#if (defined(CONFIG_ZONE_DMA) && defined(CONFIG_UBICOM32_OCM_FOR_SKB))
+       if (likely(dev == ubi32_eth_devices[0]))
+               replenish_max = min(ubi32_ocm_skbuf_max, RX_DMA_MAX_QUEUE_SIZE);;
+#endif
+
+       if (unlikely(rx_in == priv->regs->rx_out))
+               priv->vp_stats.rx_q_full_cnt++;
+
+       priv->regs->int_status &= ~UBI32_ETH_VP_INT_RX;
+       while (priv->rx_tail != priv->regs->rx_out) {
+               if (unlikely(count == quota)) {
+                       /* There is still frame pending to be processed */
+                       priv->vp_stats.rx_throttle++;
+                       break;
+               }
+
+               pdata = priv->regs->rx_dma_ring[priv->rx_tail];
+               BUG_ON(pdata == NULL);
+
+               desc = (struct ubi32_eth_dma_desc *)pdata;
+               skb = container_of((void *)pdata, struct sk_buff, cb);
+               count++;
+               priv->regs->rx_dma_ring[priv->rx_tail] = NULL;
+               priv->rx_tail = ((priv->rx_tail + 1) & RX_DMA_RING_MASK);
+
+               /*
+                * Check only RX_OK bit here.
+                * The rest of status word is used as timestamp
+                */
+               if (unlikely(!(desc->status & UBI32_ETH_VP_RX_OK))) {
+                       dev->stats.rx_errors++;
+                       dev_kfree_skb_any(skb);
+                       continue;
+               }
+
+               skb_put(skb, desc->data_len);
+               skb->dev = dev;
+               skb->protocol = eth_type_trans(skb, dev);
+               skb->ip_summed = CHECKSUM_NONE;
+               dev->stats.rx_bytes += skb->len;
+               dev->stats.rx_packets++;
+#ifndef UBICOM32_USE_NAPI
+               netif_rx(skb);
+#else
+               netif_receive_skb(skb);
+#endif
+       }
+
+       /* fill in more descripor for VP*/
+       replenish_cnt =  replenish_max -
+               ((RX_DMA_RING_SIZE + rx_in - priv->rx_tail) & RX_DMA_RING_MASK);
+       if (replenish_cnt > 0) {
+#if (defined(CONFIG_ZONE_DMA) && defined(CONFIG_UBICOM32_OCM_FOR_SKB))
+               /*
+                * black magic for perforamnce:
+                *   Try to allocate skb from OCM only for first Ethernet I/F.
+                *   Also limit number of RX buffers to 21 due to limited OCM.
+                */
+               if (likely(dev == ubi32_eth_devices[0])) {
+                       do {
+                               skb = ubi32_alloc_skb_ocm(dev, RX_BUF_SIZE + extra_alloc);
+                               if (!skb) {
+                                       break;
+                               }
+                               /* set up dma descriptor */
+                               ubi32_ocm_skbuf++;
+                               desc = (struct ubi32_eth_dma_desc *)skb->cb;
+                               extra_reserve_adj =
+                                       ((u32)skb->data + UBI32_ETH_RESERVE_SPACE + ETH_HLEN) &
+                                       (CACHE_LINE_SIZE - 1);
+                               skb_reserve(skb, UBI32_ETH_RESERVE_SPACE - extra_reserve_adj);
+                               desc->data_pointer = skb->data;
+                               desc->buffer_len = RX_BUF_SIZE + UBI32_ETH_TRASHED_MEMORY;
+                               desc->data_len = 0;
+                               desc->status = 0;
+                               priv->regs->rx_dma_ring[rx_in] = desc;
+                               rx_in = (rx_in + 1) & RX_DMA_RING_MASK;
+                       } while (--replenish_cnt > 0);
+               }
+#endif
+
+               while (replenish_cnt-- > 0) {
+                       skb = ubi32_alloc_skb(dev, RX_BUF_SIZE + extra_alloc);
+                       if (!skb) {
+                               priv->vp_stats.rx_alloc_err++;
+                               break;
+                       }
+                       /* set up dma descriptor */
+                       ubi32_ddr_skbuf++;
+                       desc = (struct ubi32_eth_dma_desc *)skb->cb;
+                       extra_reserve_adj =
+                               ((u32)skb->data + UBI32_ETH_RESERVE_SPACE + ETH_HLEN) &
+                               (CACHE_LINE_SIZE - 1);
+                       skb_reserve(skb, UBI32_ETH_RESERVE_SPACE - extra_reserve_adj);
+                       desc->data_pointer = skb->data;
+                       desc->buffer_len = RX_BUF_SIZE + UBI32_ETH_TRASHED_MEMORY;
+                       desc->data_len = 0;
+                       desc->status = 0;
+                       priv->regs->rx_dma_ring[rx_in] = desc;
+                       rx_in = (rx_in + 1) & RX_DMA_RING_MASK;
+               }
+
+               wmb();
+               priv->regs->rx_in = rx_in;
+               ubicom32_set_interrupt(priv->vp_int_bit);
+       }
+
+       if (likely(count > 0)) {
+               dev->last_rx = jiffies;
+       }
+       return count;
+}
+
+#ifdef UBICOM32_USE_NAPI
+static int ubi32_eth_napi_poll(struct napi_struct *napi, int budget)
+{
+       struct ubi32_eth_private *priv = container_of(napi, struct ubi32_eth_private, napi);
+       struct net_device *dev = priv->dev;
+       u32_t count;
+
+       if (priv->tx_tail != priv->regs->tx_out) {
+                ubi32_eth_tx_done(dev);
+        }
+
+       count = ubi32_eth_receive(dev, budget);
+
+       if (count < budget) {
+               napi_complete(napi);
+               priv->regs->int_mask |= (UBI32_ETH_VP_INT_RX | UBI32_ETH_VP_INT_TX);
+               if ((priv->rx_tail != priv->regs->rx_out) || (priv->tx_tail != priv->regs->tx_out)) {
+                       if (napi_reschedule(napi)) {
+                               priv->regs->int_mask = 0;
+                       }
+               }
+       }
+       return count;
+}
+
+#else
+static void ubi32_eth_do_tasklet(unsigned long arg)
+{
+       struct net_device *dev = (struct net_device *)arg;
+       struct ubi32_eth_private *priv = netdev_priv(dev);
+
+       if (priv->tx_tail != priv->regs->tx_out) {
+               ubi32_eth_tx_done(dev);
+       }
+
+       /* always call receive to process new RX frame as well as replenish RX buffers */
+       ubi32_eth_receive(dev, UBI32_RX_BOUND);
+
+       priv->regs->int_mask |= (UBI32_ETH_VP_INT_RX | UBI32_ETH_VP_INT_TX);
+       if ((priv->rx_tail != priv->regs->rx_out) || (priv->tx_tail != priv->regs->tx_out)) {
+               priv->regs->int_mask = 0;
+               tasklet_schedule(&priv->tsk);
+       }
+}
+#endif
+
+#if defined(UBICOM32_USE_POLLING)
+static struct timer_list eth_poll_timer;
+
+static void ubi32_eth_poll(unsigned long arg)
+{
+       struct net_device *dev;
+       struct ubi32_eth_private *priv;
+       int i;
+
+       for (i = 0; i < UBI32_ETH_NUM_OF_DEVICES; i++) {
+               dev = ubi32_eth_devices[i];
+               if (dev && (dev->flags & IFF_UP)) {
+                       priv = netdev_priv(dev);
+#ifdef UBICOM32_USE_NAPI
+                       napi_schedule(&priv->napi);
+#else
+                       tasklet_schedule(&priv->tsk);
+#endif
+               }
+       }
+
+       eth_poll_timer.expires = jiffies + 2;
+       add_timer(&eth_poll_timer);
+}
+
+#else
+static irqreturn_t ubi32_eth_interrupt(int irq, void *dev_id)
+{
+       struct ubi32_eth_private *priv;
+
+       struct net_device *dev = (struct net_device *)dev_id;
+       BUG_ON(irq != dev->irq);
+
+       priv = netdev_priv(dev);
+       if (unlikely(!(priv->regs->int_status & priv->regs->int_mask))) {
+               return IRQ_NONE;
+       }
+
+       /*
+        * Disable port interrupt
+        */
+#ifdef UBICOM32_USE_NAPI
+       if (napi_schedule_prep(&priv->napi)) {
+               priv->regs->int_mask = 0;
+               __napi_schedule(&priv->napi);
+       }
+#else
+       priv->regs->int_mask = 0;
+       tasklet_schedule(&priv->tsk);
+#endif
+       return IRQ_HANDLED;
+}
+#endif
+
+/*
+ * ubi32_eth_open
+ */
+static int ubi32_eth_open(struct net_device *dev)
+{
+       struct ubi32_eth_private *priv = netdev_priv(dev);
+       int err;
+
+       printk(KERN_INFO "eth open %s\n",dev->name);
+#ifndef UBICOM32_USE_POLLING
+       /* request_region() */
+       err = request_irq(dev->irq, ubi32_eth_interrupt, IRQF_DISABLED, dev->name, dev);
+       if (err) {
+               printk(KERN_WARNING "fail to request_irq %d\n",err);
+                return -ENODEV;
+       }
+#endif
+#ifdef  UBICOM32_USE_NAPI
+       napi_enable(&priv->napi);
+#else
+       tasklet_init(&priv->tsk, ubi32_eth_do_tasklet, (unsigned long)dev);
+#endif
+
+       /* call receive to supply RX buffers */
+       ubi32_eth_receive(dev, RX_DMA_MAX_QUEUE_SIZE);
+
+       /* check phy status and call netif_carrier_on */
+       ubi32_eth_vp_rxtx_enable(dev);
+       netif_start_queue(dev);
+       return 0;
+}
+
+static int ubi32_eth_close(struct net_device *dev)
+{
+       struct ubi32_eth_private *priv = netdev_priv(dev);
+       volatile void *pdata;
+       struct sk_buff *skb;
+
+#ifndef UBICOM32_USE_POLLING
+       free_irq(dev->irq, dev);
+#endif
+       netif_stop_queue(dev); /* can't transmit any more */
+#ifdef UBICOM32_USE_NAPI
+       napi_disable(&priv->napi);
+#else
+       tasklet_kill(&priv->tsk);
+#endif
+       ubi32_eth_vp_rxtx_stop(dev);
+
+       /*
+        * RX clean up
+        */
+       while (priv->rx_tail != priv->regs->rx_in) {
+               pdata = priv->regs->rx_dma_ring[priv->rx_tail];
+               skb = container_of((void *)pdata, struct sk_buff, cb);
+               priv->regs->rx_dma_ring[priv->rx_tail] = NULL;
+               dev_kfree_skb_any(skb);
+               priv->rx_tail = ((priv->rx_tail + 1) & RX_DMA_RING_MASK);
+       }
+       priv->regs->rx_in = 0;
+       priv->regs->rx_out = priv->regs->rx_in;
+       priv->rx_tail = priv->regs->rx_in;
+
+       /*
+        * TX clean up
+        */
+       BUG_ON(priv->regs->tx_out != priv->regs->tx_in);
+       ubi32_eth_tx_done(dev);
+       BUG_ON(priv->tx_tail != priv->regs->tx_in);
+       priv->regs->tx_in = 0;
+       priv->regs->tx_out = priv->regs->tx_in;
+       priv->tx_tail = priv->regs->tx_in;
+
+       return 0;
+}
+
+/*
+ * ubi32_eth_set_config
+ */
+static int ubi32_eth_set_config(struct net_device *dev, struct ifmap *map)
+{
+       /* if must to down to config it */
+       printk(KERN_INFO "set_config %x\n", dev->flags);
+       if (dev->flags & IFF_UP)
+               return -EBUSY;
+
+       /* I/O and IRQ can not be changed */
+       if (map->base_addr != dev->base_addr) {
+               printk(KERN_WARNING "%s: Can't change I/O address\n", dev->name);
+               return -EOPNOTSUPP;
+       }
+
+#ifndef UBICOM32_USE_POLLING
+       if (map->irq != dev->irq) {
+               printk(KERN_WARNING "%s: Can't change IRQ\n", dev->name);
+               return -EOPNOTSUPP;
+       }
+#endif
+
+       /* ignore other fields */
+       return 0;
+}
+
+static int ubi32_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ubi32_eth_private *priv = netdev_priv(dev);
+       struct ubi32_eth_dma_desc *desc = NULL;
+       unsigned short space, tx_in;
+
+       tx_in = priv->regs->tx_in;
+
+       dev->trans_start = jiffies; /* save the timestamp */
+       space = TX_DMA_RING_MASK - ((TX_DMA_RING_SIZE + tx_in - priv->tx_tail) & TX_DMA_RING_MASK);
+
+       if (unlikely(space == 0)) {
+               if (!(priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL)) {
+                       spin_lock(&priv->lock);
+                       if (!(priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL)) {
+                               priv->regs->status |= UBI32_ETH_VP_STATUS_TX_Q_FULL;
+                               priv->vp_stats.tx_q_full_cnt++;
+                               netif_stop_queue(dev);
+                       }
+                       spin_unlock(&priv->lock);
+               }
+
+               /* give both HW and this driver an extra trigger */
+               priv->regs->int_mask |= UBI32_ETH_VP_INT_TX;
+#ifndef UBICOM32_USE_POLLING
+               ubicom32_set_interrupt(dev->irq);
+#endif
+               ubicom32_set_interrupt(priv->vp_int_bit);
+
+               return NETDEV_TX_BUSY;
+       }
+
+       /*still have room */
+       desc = (struct ubi32_eth_dma_desc *)skb->cb;
+       desc->data_pointer = skb->data;
+       desc->data_len = skb->len;
+       priv->regs->tx_dma_ring[tx_in] = desc;
+       tx_in = ((tx_in + 1) & TX_DMA_RING_MASK);
+       wmb();
+       priv->regs->tx_in = tx_in;
+       /* kick the HRT */
+       ubicom32_set_interrupt(priv->vp_int_bit);
+
+       return NETDEV_TX_OK;
+}
+
+/*
+ * Deal with a transmit timeout.
+ */
+static void ubi32_eth_tx_timeout (struct net_device *dev)
+{
+       struct ubi32_eth_private *priv = netdev_priv(dev);
+       dev->stats.tx_errors++;
+       priv->regs->int_mask |= UBI32_ETH_VP_INT_TX;
+#ifndef UBICOM32_USE_POLLING
+       ubicom32_set_interrupt(dev->irq);
+#endif
+       ubicom32_set_interrupt(priv->vp_int_bit);
+}
+
+static int ubi32_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct ubi32_eth_private *priv = netdev_priv(dev);
+       struct mii_ioctl_data *data = if_mii(rq);
+
+       printk(KERN_INFO "ioctl %s, %d\n", dev->name, cmd);
+       switch (cmd) {
+       case SIOCGMIIPHY:
+               data->phy_id = 0;
+               break;
+
+       case SIOCGMIIREG:
+               if ((data->reg_num & 0x1F) == MII_BMCR) {
+                       /* Make up MII control register value from what we know */
+                       data->val_out = 0x0000
+                       | ((priv->regs->status & UBI32_ETH_VP_STATUS_DUPLEX)
+                                       ? BMCR_FULLDPLX : 0)
+                       | ((priv->regs->status & UBI32_ETH_VP_STATUS_SPEED100)
+                                       ? BMCR_SPEED100 : 0)
+                       | ((priv->regs->status & UBI32_ETH_VP_STATUS_SPEED1000)
+                                       ? BMCR_SPEED1000 : 0);
+               } else if ((data->reg_num & 0x1F) == MII_BMSR) {
+                       /* Make up MII status register value from what we know */
+                       data->val_out =
+                       (BMSR_100FULL|BMSR_100HALF|BMSR_10FULL|BMSR_10HALF)
+                       | ((priv->regs->status & UBI32_ETH_VP_STATUS_LINK)
+                                       ? BMSR_LSTATUS : 0);
+               } else {
+                       return -EIO;
+               }
+               break;
+
+       case SIOCSMIIREG:
+               return -EOPNOTSUPP;
+               break;
+
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+/*
+ * Return statistics to the caller
+ */
+static struct net_device_stats *ubi32_eth_get_stats(struct net_device *dev)
+{
+       return &dev->stats;
+}
+
+
+static int ubi32_eth_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct ubi32_eth_private *priv = netdev_priv(dev);
+       unsigned long flags;
+
+       if ((new_mtu < 68) || (new_mtu > 1500))
+               return -EINVAL;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       dev->mtu = new_mtu;
+       spin_unlock_irqrestore(&priv->lock, flags);
+       printk(KERN_INFO "set mtu to %d", new_mtu);
+       return 0;
+}
+
+/*
+ * ubi32_eth_cleanup: unload the module
+ */
+void ubi32_eth_cleanup(void)
+{
+       struct ubi32_eth_private *priv;
+       struct net_device *dev;
+       int i;
+
+       for (i = 0; i < UBI32_ETH_NUM_OF_DEVICES; i++) {
+               dev = ubi32_eth_devices[i];
+               if (dev) {
+                       priv = netdev_priv(dev);
+                       kfree(priv->regs->tx_dma_ring);
+                       unregister_netdev(dev);
+                       free_netdev(dev);
+                       ubi32_eth_devices[i] = NULL;
+               }
+       }
+}
+
+int ubi32_eth_init_module(void)
+{
+       struct ethtionode *eth_node;
+       struct net_device *dev;
+       struct ubi32_eth_private *priv;
+       int i, err;
+
+       /*
+        * Device allocation.
+        */
+       err = 0;
+       for (i = 0; i < UBI32_ETH_NUM_OF_DEVICES; i++) {
+               /*
+                * See if the eth_vp is in the device tree.
+                */
+               eth_node = (struct ethtionode *)devtree_find_node(eth_if_name[i]);
+               if (!eth_node) {
+                       printk(KERN_INFO "%s does not exist\n", eth_if_name[i]);
+                       continue;
+               }
+
+               eth_node->tx_dma_ring = (struct ubi32_eth_dma_desc **)kmalloc(
+                               sizeof(struct ubi32_eth_dma_desc *) *
+                               (TX_DMA_RING_SIZE + RX_DMA_RING_SIZE),
+                               GFP_ATOMIC | __GFP_NOWARN | __GFP_NORETRY | GFP_DMA);
+
+               if (eth_node->tx_dma_ring == NULL) {
+                       eth_node->tx_dma_ring = (struct ubi32_eth_dma_desc **)kmalloc(
+                               sizeof(struct ubi32_eth_dma_desc *) *
+                               (TX_DMA_RING_SIZE + RX_DMA_RING_SIZE), GFP_KERNEL);
+                       printk(KERN_INFO "fail to allocate from OCM\n");
+               }
+
+               if (!eth_node->tx_dma_ring) {
+                       err = -ENOMEM;
+                       break;
+               }
+               eth_node->rx_dma_ring = eth_node->tx_dma_ring + TX_DMA_RING_SIZE;
+               eth_node->tx_sz = TX_DMA_RING_SIZE - 1;
+               eth_node->rx_sz = RX_DMA_RING_SIZE - 1;
+
+               dev = alloc_etherdev(sizeof(struct ubi32_eth_private));
+               if (!dev) {
+                       kfree(eth_node->tx_dma_ring);
+                       err = -ENOMEM;
+                       break;
+               }
+               priv = netdev_priv(dev);
+               priv->dev = dev;
+
+               /*
+                * This just fill in some default Ubicom MAC address
+                */
+               memcpy(dev->dev_addr, mac_addr[i], ETH_ALEN);
+               memset(dev->broadcast, 0xff, ETH_ALEN);
+
+               priv->regs = eth_node;
+               priv->regs->command = 0;
+               priv->regs->int_mask = 0;
+               priv->regs->int_status = 0;
+               priv->regs->tx_out = 0;
+               priv->regs->rx_out = 0;
+               priv->regs->tx_in = 0;
+               priv->regs->rx_in = 0;
+               priv->rx_tail = 0;
+               priv->tx_tail = 0;
+
+               priv->vp_int_bit = eth_node->dn.sendirq;
+               dev->irq = eth_node->dn.recvirq;
+
+               spin_lock_init(&priv->lock);
+
+               dev->open               = ubi32_eth_open;
+               dev->stop               = ubi32_eth_close;
+               dev->hard_start_xmit    = ubi32_eth_start_xmit;
+               dev->tx_timeout         = ubi32_eth_tx_timeout;
+               dev->watchdog_timeo     = UBI32_ETH_VP_TX_TIMEOUT;
+
+               dev->set_config         = ubi32_eth_set_config;
+               dev->do_ioctl           = ubi32_eth_ioctl;
+               dev->get_stats          = ubi32_eth_get_stats;
+               dev->change_mtu         = ubi32_eth_change_mtu;
+#ifdef UBICOM32_USE_NAPI
+               netif_napi_add(dev, &priv->napi, ubi32_eth_napi_poll, UBI32_ETH_NAPI_WEIGHT);
+#endif
+               err = register_netdev(dev);
+               if (err) {
+                       printk(KERN_WARNING "Failed to register netdev %s\n", eth_if_name[i]);
+                       //release_region();
+                       free_netdev(dev);
+                       kfree(eth_node->tx_dma_ring);
+                       break;
+               }
+
+               ubi32_eth_devices[i] = dev;
+               printk(KERN_INFO "%s vp_base:0x%p, tio_int:%d irq:%d feature:0x%lx\n",
+                       dev->name, priv->regs, eth_node->dn.sendirq, dev->irq, dev->features);
+       }
+
+       if (err) {
+               ubi32_eth_cleanup();
+               return err;
+       }
+
+       if (!ubi32_eth_devices[0] && !ubi32_eth_devices[1]) {
+               return -ENODEV;
+       }
+
+#if defined(UBICOM32_USE_POLLING)
+       init_timer(&eth_poll_timer);
+       eth_poll_timer.function = ubi32_eth_poll;
+       eth_poll_timer.data = (unsigned long)0;
+       eth_poll_timer.expires = jiffies + 2;
+       add_timer(&eth_poll_timer);
+#endif
+
+       return 0;
+}
+
+module_init(ubi32_eth_init_module);
+module_exit(ubi32_eth_cleanup);
+
+MODULE_AUTHOR("Kan Yan, Greg Ren");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/drivers/net/ubi32-eth.h b/target/linux/ubicom32/files/drivers/net/ubi32-eth.h
new file mode 100644 (file)
index 0000000..c255001
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * drivers/net/ubi32-eth.h
+ *   Ubicom32 ethernet TIO interface driver definitions.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#ifndef _UBI32_ETH_H
+#define _UBI32_ETH_H
+
+#include <asm/devtree.h>
+
+#define UBI32_ETH_NUM_OF_DEVICES 2
+
+/*
+ * Number of bytes trashed beyond the packet data.
+ */
+#define UBI32_ETH_TRASHED_MEMORY       (CACHE_LINE_SIZE + ETH_HLEN - 1)
+
+/*
+ * Linux already reserves NET_SKB_PAD bytes of headroom in each sk_buff.
+ * We want to be able to reserve at least one cache line to align Ethernet
+ * and IP header to cache line.
+ * Note that the TIO expects a CACHE_LINE_SIZE - ETH_HLEN aligned Ethernet
+ * header, while satisfies NET_IP_ALIGN (= 2) automatically.
+ * (NET_SKB_PAD is 16, NET_IP_ALIGN is 2, CACHE_LINE_SIZE is 32).
+ * You can add more space by making UBI32_ETH_RESERVE_EXTRA != 0.
+ */
+#define UBI32_ETH_RESERVE_EXTRA (1 * CACHE_LINE_SIZE)
+#define UBI32_ETH_RESERVE_SPACE        (UBI32_ETH_RESERVE_EXTRA + CACHE_LINE_SIZE)
+
+struct ubi32_eth_dma_desc {
+       volatile void   *data_pointer;  /* pointer to the buffer */
+       volatile u16    buffer_len;     /* the buffer size */
+       volatile u16    data_len;       /* actual frame length */
+       volatile u32    status;         /* bit0: status to be update by VP; bit[31:1] time stamp */
+};
+
+#define TX_DMA_RING_SIZE (1<<8)
+#define TX_DMA_RING_MASK (TX_DMA_RING_SIZE - 1)
+#define RX_DMA_RING_SIZE (1<<8)
+#define RX_DMA_RING_MASK (RX_DMA_RING_SIZE - 1)
+
+#define RX_DMA_MAX_QUEUE_SIZE (RX_DMA_RING_SIZE - 1)   /* no more than (RX_DMA_RING_SIZE - 1) */
+#define RX_MAX_PKT_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN)
+#define RX_MIN_PKT_SIZE        ETH_ZLEN
+#define RX_BUF_SIZE (RX_MAX_PKT_SIZE + VLAN_HLEN)      /* allow double VLAN tag */
+
+#define UBI32_ETH_VP_TX_TIMEOUT (10*HZ)
+
+struct ubi32_eth_vp_stats {
+       u32     rx_alloc_err;
+       u32     tx_q_full_cnt;
+       u32     rx_q_full_cnt;
+       u32     rx_throttle;
+};
+
+struct ubi32_eth_private {
+       struct net_device *dev;
+       struct ubi32_eth_vp_stats vp_stats;
+       spinlock_t lock;
+#ifdef UBICOM32_USE_NAPI
+       struct napi_struct napi;
+#else
+       struct tasklet_struct tsk;
+#endif
+       struct ethtionode *regs;
+       u16     rx_tail;
+       u16     tx_tail;
+       u32     vp_int_bit;
+};
+
+struct ethtionode {
+       struct devtree_node dn;
+       volatile u16    command;
+       volatile u16    status;
+       volatile u16    int_mask;       /* interrupt mask */
+       volatile u16    int_status;     /* interrupt mask */
+       volatile u16    tx_in;          /* owned by driver */
+       volatile u16    tx_out;         /* owned by vp */
+       volatile u16    rx_in;          /* owned by driver */
+       volatile u16    rx_out;         /* owned by vp */
+       u16             tx_sz;          /* owned by driver */
+       u16             rx_sz;          /* owned by driver */
+       struct ubi32_eth_dma_desc **tx_dma_ring;
+       struct ubi32_eth_dma_desc **rx_dma_ring;
+};
+
+#define UBI32_ETH_VP_STATUS_LINK       (1<<0)
+#define UBI32_ETH_VP_STATUS_SPEED100   (0x1<<1)
+#define UBI32_ETH_VP_STATUS_SPEED1000  (0x1<<2)
+#define UBI32_ETH_VP_STATUS_DUPLEX     (0x1<<3)
+#define UBI32_ETH_VP_STATUS_FLOW_CTRL  (0x1<<4)
+
+#define UBI32_ETH_VP_STATUS_RX_STATE   (0x1<<5)
+#define UBI32_ETH_VP_STATUS_TX_STATE   (0x1<<6)
+
+#define UBI32_ETH_VP_STATUS_TX_Q_FULL  (1<<8)
+
+#define UBI32_ETH_VP_INT_RX    (1<<0)
+#define UBI32_ETH_VP_INT_TX    (1<<1)
+
+#define UBI32_ETH_VP_CMD_RX_ENABLE     (1<<0)
+#define UBI32_ETH_VP_CMD_TX_ENABLE     (1<<1)
+
+#define UBI32_ETH_VP_RX_OK             (1<<0)
+#define UBI32_ETH_VP_TX_OK             (1<<1)
+
+#define UBI32_TX_BOUND         TX_DMA_RING_SIZE
+#define UBI32_RX_BOUND         64
+#define UBI32_ETH_NAPI_WEIGHT  64              /* for GigE */
+#endif
diff --git a/target/linux/ubicom32/files/drivers/serial/ubi32_mailbox.c b/target/linux/ubicom32/files/drivers/serial/ubi32_mailbox.c
new file mode 100644 (file)
index 0000000..fc0d6d2
--- /dev/null
@@ -0,0 +1,928 @@
+/*
+ * drivers/serial/ubi32_mailbox.c
+ *   Ubicom32 On-Chip Mailbox Driver
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+
+#include <asm/ip5000.h>
+
+#define SERIAL_UBICOM_BAUDRATE 115200
+#define SERIAL_UBICOM_DATA_BIT 8       /* Fixed parameter - do not change */
+#define SERIAL_UBICOM_PAR_BIT  0       /* Fixed parameter - do not change */
+#define SERIAL_UBICOM_STOP_BIT 1       /* Fixed parameter - do not change */
+
+/* UART name and device definitions */
+#define UBI32_MAILBOX_NAME     "ttyUM" // XXX
+#define UBI32_MAILBOX_MAJOR    207 // XXX
+#define UBI32_MAILBOX_MINOR    64
+
+#define PORT_UBI32_MAILBOX     1235
+#define NR_PORTS 1
+
+#define get_sclk() 0
+
+struct ubi32_mailbox_port {
+       struct uart_port port;
+       /*
+        * NOTE (rkeller):
+        * the uart port is wrapped in another structure in case we need to hold more state than
+        * what we can hold in the uart_port.
+        * Not sure if we need this, I took over the concept from the blackfin driver.
+        */
+} ubi32_mailbox_ports[NR_PORTS];
+
+struct ubi32_mailbox_resource {
+       int uart_base_addr;
+       int uart_irq;
+} ubi32_mailbox_resource[NR_PORTS] = {
+       /*
+        * uart_base_addr has to be non-NULL because it is put in the uart_port membase.
+        * If membase if null the kernel skips the configuration and our port_type never gets set.
+        */
+       {ISD_MAILBOX_BASE, ISD_MAILBOX_INT}
+};
+
+static volatile struct ubicom32_isd_mailbox {
+       volatile u32_t in;
+       volatile u32_t out;
+       volatile u32_t status;
+} *ubi32_mailbox = (struct ubicom32_isd_mailbox *)ISD_MAILBOX_BASE;
+
+static void ubi32_mailbox_tx_chars(struct ubi32_mailbox_port *uart);
+
+static void ubi32_mailbox_mctrl_check(struct ubi32_mailbox_port *uart);
+
+#define TRUE 1
+#define FALSE 0
+
+static int mailbox_console_flg = TRUE;
+static int num_timeouts = 0;
+
+/*
+ * dummy functions and defined to be able to compile the Blackfin code
+ */
+#define UART_GET_LSR(port) (1)
+#define UART_PUT_LSR(port, bits)
+#define UART_CLEAR_LSR(port) (1)
+#define TEMT 1
+#define TFI 1
+#define BI 1
+#define PE 1
+#define OE 1
+#define FE 1
+#define THRE 1
+#define DR 1
+#define UART_GET_LCR(port) (1)
+#define UART_PUT_LCR(port, bits)
+#define SB 1
+#define STB 1
+#define PEN 1
+#define EPS 1
+#define STP 1
+#define WLS(n) 0
+#define UART_GET_IER(port) (1)
+#define UART_SET_IER(port, bits)
+#define UART_CLEAR_IER(port, bits)
+#define ETBEI 0
+#define ERBFI 0
+#define UART_GET_CHAR(port) ubi32_mailbox_get_char()
+#define UART_PUT_CHAR(port, ch) ubi32_mailbox_put_char(ch)
+#define SSYNC()
+#define UART_GET_DLL(port) 0
+#define UART_PUT_DLL(port, ch)
+#define UART_GET_DLH(port) 0
+#define UART_PUT_DLH(port, ch)
+#define UART_GET_GCTL(port) (0)
+#define UART_PUT_GCTL(port, ch)
+#define UCEN 1
+
+/*
+ * ubi32_mailbox_get_char_avail()
+ */
+static int ubi32_mailbox_get_char_avail(void)
+{
+       return !(ubi32_mailbox->status & ISD_MAILBOX_STATUS_IN_EMPTY);
+}
+
+/*
+ * ubi32_mailbox_get_char()
+ */
+static u32_t ubi32_mailbox_get_char(void)
+{
+       if (mailbox_console_flg == TRUE) {
+               /*
+                * Mailbox console is connected.
+                */
+               while (ubi32_mailbox->status & ISD_MAILBOX_STATUS_IN_EMPTY);
+               return ubi32_mailbox->in & 0xff;
+       }
+
+       /*
+        * Mailbox console was not connected.
+        */
+       if (ubi32_mailbox->status & ISD_MAILBOX_STATUS_IN_EMPTY) {
+               return 0xff;
+       }
+
+       /*
+        * Mailbox console is connecting.
+        */
+       mailbox_console_flg = TRUE;
+       num_timeouts = 0;
+       return ubi32_mailbox->in & 0xff;
+}
+
+#define MAILBOX_MAX_ATTEMPTS 1000000
+#define MAILBOX_MAX_TIMEOUTS 5
+/*
+ * ubi32_mailbox_put_char()
+ */
+static void ubi32_mailbox_put_char(u32_t v)
+{
+       /*
+        * Wait to be able to output.
+        */
+       u32_t num_attempts = 0;
+
+       if(mailbox_console_flg == TRUE) {
+               while(num_attempts++ < MAILBOX_MAX_ATTEMPTS) {
+                       if(ubi32_mailbox->status & ISD_MAILBOX_STATUS_OUT_EMPTY) {
+                               break;
+                       }
+               }
+
+               /*
+                * If timed out more than 5 times on send, mailbox console is disconnected now.
+                */
+               if (num_attempts > MAILBOX_MAX_ATTEMPTS) {
+                       if (num_timeouts++ > MAILBOX_MAX_TIMEOUTS) {
+                               mailbox_console_flg = FALSE;
+                       }
+               }
+       }
+
+       asm volatile(
+               "pipe_flush 0   \n\t"
+               "pipe_flush 0   \n\t"
+               "pipe_flush 0   \n\t"
+               "pipe_flush 0   \n\t"
+               "pipe_flush 0   \n\t"
+               "pipe_flush 0   \n\t"
+               "pipe_flush 0   \n\t"
+       );
+
+       ubi32_mailbox->out = v & 0xff;
+}
+
+static void ubi32_mailbox_hw_init(struct ubi32_mailbox_port *uart)
+{
+// NOTE: It does not do any good to do these here because we are running on the linux hardware thread,
+//     and these have to be called on the ldsr thread.
+//     ubicom32_clear_interrupt(ISD_MAILBOX_INT);
+//     ubicom32_enable_interrupt(ISD_MAILBOX_INT);
+}
+
+/*
+ * interrupts are disabled on entry
+ */
+static void ubi32_mailbox_stop_tx(struct uart_port *port)
+{
+//     struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
+//     struct circ_buf *xmit = &uart->port.info->xmit;
+
+       while (!(UART_GET_LSR(uart) & TEMT))
+               cpu_relax();
+
+       /* Clear TFI bit */
+       UART_PUT_LSR(uart, TFI);
+       UART_CLEAR_IER(uart, ETBEI);
+}
+
+/*
+ * port is locked and interrupts are disabled
+ */
+static void ubi32_mailbox_start_tx(struct uart_port *port)
+{
+       struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
+
+       UART_SET_IER(uart, ETBEI);
+
+       ubi32_mailbox_tx_chars(uart);
+}
+
+/*
+ * Interrupts are enabled
+ */
+static void ubi32_mailbox_stop_rx(struct uart_port *port)
+{
+//     struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
+       UART_CLEAR_IER(uart, ERBFI);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void ubi32_mailbox_enable_ms(struct uart_port *port)
+{
+}
+
+static void ubi32_mailbox_rx_chars(struct ubi32_mailbox_port *uart)
+{
+       struct uart_info *info = uart->port.info;
+       struct tty_struct *tty = info->port.tty;
+       unsigned int status, ch, flg;
+
+       status = 0; // XXX? UART_GET_LSR(uart);
+       UART_CLEAR_LSR(uart);
+
+       ch = UART_GET_CHAR(uart);
+
+       if(ch == 0xff)
+               return;
+
+       uart->port.icount.rx++;
+
+       if (status & BI) {
+               uart->port.icount.brk++;
+               if (uart_handle_break(&uart->port))
+                       goto ignore_char;
+               status &= ~(PE | FE);
+       }
+       if (status & PE)
+               uart->port.icount.parity++;
+       if (status & OE)
+               uart->port.icount.overrun++;
+       if (status & FE)
+               uart->port.icount.frame++;
+
+       status &= uart->port.read_status_mask;
+
+       if (status & BI)
+               flg = TTY_BREAK;
+       else if (status & PE)
+               flg = TTY_PARITY;
+       else if (status & FE)
+               flg = TTY_FRAME;
+       else
+               flg = TTY_NORMAL;
+
+       if (uart_handle_sysrq_char(&uart->port, ch))
+               goto ignore_char;
+
+       uart_insert_char(&uart->port, status, OE, ch, flg);
+
+ ignore_char:
+       tty_flip_buffer_push(tty);
+}
+
+static void ubi32_mailbox_tx_chars(struct ubi32_mailbox_port *uart)
+{
+       struct circ_buf *xmit = &uart->port.info->xmit;
+
+       if (uart->port.x_char) {
+               UART_PUT_CHAR(uart, uart->port.x_char);
+               uart->port.icount.tx++;
+               uart->port.x_char = 0;
+       }
+       /*
+        * Check the modem control lines before
+        * transmitting anything.
+        */
+       ubi32_mailbox_mctrl_check(uart);
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
+               ubi32_mailbox_stop_tx(&uart->port);
+               return;
+       }
+
+       while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {
+               UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               uart->port.icount.tx++;
+               SSYNC();
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&uart->port);
+
+       if (uart_circ_empty(xmit))
+               ubi32_mailbox_stop_tx(&uart->port);
+}
+
+static irqreturn_t ubi32_mailbox_isr(int irq, void *dev_id)
+{
+       struct ubi32_mailbox_port *uart = dev_id;
+
+       spin_lock(&uart->port.lock);
+
+       //XXX?while (UART_GET_LSR(uart) & DR)
+
+       /*
+        * RX process
+        */
+       while (ubi32_mailbox_get_char_avail()) {
+               ubi32_mailbox_rx_chars(uart);
+       }
+
+#if 0
+       /*
+        * TX process
+        */
+       if (this_uart.tx_in == this_uart.tx_out) {
+               UBICOM32_IO_PORT(SERIAL_UBICOM_PORT)->int_mask &= ~IO_PORTX_INT_SERDES_TXBE;
+       } else if (UBICOM32_IO_PORT(SERIAL_UBICOM_PORT)->int_status & IO_PORTX_INT_SERDES_TXBE) {
+               uart_ubicom32_send(this_uart.tx_buf[this_uart.tx_out & (SERIAL_UBICOM_BUF_SIZE - 1)]);
+               this_uart.tx_out++;
+               UBICOM32_IO_PORT(SERIAL_UBICOM_PORT)->int_mask |= IO_PORTX_INT_SERDES_TXBE;
+       }
+#endif
+
+       spin_unlock(&uart->port.lock);
+
+       return IRQ_HANDLED;
+}
+#if 0
+static irqreturn_t ubi32_mailbox_tx_int(int irq, void *dev_id)
+{
+       struct ubi32_mailbox_port *uart = dev_id;
+
+       spin_lock(&uart->port.lock);
+       if (UART_GET_LSR(uart) & THRE)
+               ubi32_mailbox_tx_chars(uart);
+       spin_unlock(&uart->port.lock);
+
+       return IRQ_HANDLED;
+}
+#endif
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int ubi32_mailbox_tx_empty(struct uart_port *port)
+{
+//     struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
+       unsigned short lsr;
+
+       lsr = UART_GET_LSR(uart);
+       if (lsr & TEMT)
+               return TIOCSER_TEMT;
+       else
+               return 0;
+}
+
+static unsigned int ubi32_mailbox_get_mctrl(struct uart_port *port)
+{
+               return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void ubi32_mailbox_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void ubi32_mailbox_mctrl_check(struct ubi32_mailbox_port *uart)
+{
+}
+
+/*
+ * Interrupts are always disabled.
+ */
+static void ubi32_mailbox_break_ctl(struct uart_port *port, int break_state)
+{
+//     struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
+       u16 lcr = UART_GET_LCR(uart);
+       if (break_state)
+               lcr |= SB;
+       else
+               lcr &= ~SB;
+       UART_PUT_LCR(uart, lcr);
+       SSYNC();
+}
+
+static int ubi32_mailbox_startup(struct uart_port *port)
+{
+       struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
+
+       if (request_irq(uart->port.irq, ubi32_mailbox_isr, IRQF_DISABLED,
+            "UBI32_MAILBOX", uart)) {
+               printk(KERN_NOTICE "Unable to attach Ubicom32 SERDES interrupt\n");
+               return -EBUSY;
+       }
+
+       UART_SET_IER(uart, ERBFI);
+       return 0;
+}
+
+static void ubi32_mailbox_shutdown(struct uart_port *port)
+{
+       struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
+
+       free_irq(uart->port.irq, uart);
+}
+
+static void
+ubi32_mailbox_set_termios(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old)
+{
+       struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
+       unsigned long flags;
+       unsigned int baud, quot;
+       unsigned short val, ier, lsr, lcr = 0;
+
+       switch (termios->c_cflag & CSIZE) {
+       case CS8:
+               lcr = WLS(8);
+               break;
+       case CS7:
+               lcr = WLS(7);
+               break;
+       case CS6:
+               lcr = WLS(6);
+               break;
+       case CS5:
+               lcr = WLS(5);
+               break;
+       default:
+               printk(KERN_ERR "%s: word lengh not supported\n",
+                       __FUNCTION__);
+       }
+
+       if (termios->c_cflag & CSTOPB)
+               lcr |= STB;
+       if (termios->c_cflag & PARENB)
+               lcr |= PEN;
+       if (!(termios->c_cflag & PARODD))
+               lcr |= EPS;
+       if (termios->c_cflag & CMSPAR)
+               lcr |= STP;
+
+       port->read_status_mask = OE;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= (FE | PE);
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= BI;
+
+       /*
+        * Characters to ignore
+        */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= FE | PE;
+       if (termios->c_iflag & IGNBRK) {
+               port->ignore_status_mask |= BI;
+               /*
+                * If we're ignoring parity and break indicators,
+                * ignore overruns too (for real raw support).
+                */
+               if (termios->c_iflag & IGNPAR)
+                       port->ignore_status_mask |= OE;
+       }
+
+       baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+       quot = uart_get_divisor(port, baud);
+       spin_lock_irqsave(&uart->port.lock, flags);
+
+       do {
+               lsr = UART_GET_LSR(uart);
+       } while (!(lsr & TEMT));
+
+       /* Disable UART */
+       ier = UART_GET_IER(uart);
+       UART_CLEAR_IER(uart, 0xF);
+
+       UART_PUT_DLL(uart, quot & 0xFF);
+       SSYNC();
+       UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
+       SSYNC();
+
+       UART_PUT_LCR(uart, lcr);
+
+       /* Enable UART */
+       UART_SET_IER(uart, ier);
+
+       val = UART_GET_GCTL(uart);
+       val |= UCEN;
+       UART_PUT_GCTL(uart, val);
+
+       spin_unlock_irqrestore(&uart->port.lock, flags);
+}
+
+static const char *ubi32_mailbox_type(struct uart_port *port)
+{
+       struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
+
+       return uart->port.type == PORT_UBI32_MAILBOX ? "UBI32_MAILBOX" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void ubi32_mailbox_release_port(struct uart_port *port)
+{
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int ubi32_mailbox_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void ubi32_mailbox_config_port(struct uart_port *port, int flags)
+{
+       struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
+
+       if (flags & UART_CONFIG_TYPE && ubi32_mailbox_request_port(&uart->port) == 0)
+               uart->port.type = PORT_UBI32_MAILBOX;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_UBI32_MAILBOX and PORT_UNKNOWN
+ */
+static int
+ubi32_mailbox_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return 0;
+}
+
+static struct uart_ops ubi32_mailbox_pops = {
+       .tx_empty       = ubi32_mailbox_tx_empty,
+       .set_mctrl      = ubi32_mailbox_set_mctrl,
+       .get_mctrl      = ubi32_mailbox_get_mctrl,
+       .stop_tx        = ubi32_mailbox_stop_tx,
+       .start_tx       = ubi32_mailbox_start_tx,
+       .stop_rx        = ubi32_mailbox_stop_rx,
+       .enable_ms      = ubi32_mailbox_enable_ms,
+       .break_ctl      = ubi32_mailbox_break_ctl,
+       .startup        = ubi32_mailbox_startup,
+       .shutdown       = ubi32_mailbox_shutdown,
+       .set_termios    = ubi32_mailbox_set_termios,
+       .type           = ubi32_mailbox_type,
+       .release_port   = ubi32_mailbox_release_port,
+       .request_port   = ubi32_mailbox_request_port,
+       .config_port    = ubi32_mailbox_config_port,
+       .verify_port    = ubi32_mailbox_verify_port,
+};
+
+static void __init ubi32_mailbox_init_ports(void)
+{
+       static int first = 1;
+       int i;
+
+       if (!first)
+               return;
+       first = 0;
+
+       for (i = 0; i < NR_PORTS; i++) {
+               ubi32_mailbox_ports[i].port.uartclk   = get_sclk();
+               ubi32_mailbox_ports[i].port.ops       = &ubi32_mailbox_pops;
+               ubi32_mailbox_ports[i].port.line      = i;
+               ubi32_mailbox_ports[i].port.iotype    = UPIO_MEM;
+               ubi32_mailbox_ports[i].port.membase   =
+                       (void __iomem *)ubi32_mailbox_resource[i].uart_base_addr;
+               ubi32_mailbox_ports[i].port.mapbase   =
+                       ubi32_mailbox_resource[i].uart_base_addr;
+               ubi32_mailbox_ports[i].port.irq       =
+                       ubi32_mailbox_resource[i].uart_irq;
+               ubi32_mailbox_ports[i].port.flags     = UPF_BOOT_AUTOCONF;
+               spin_lock_init(&ubi32_mailbox_ports[i].port.lock);
+
+               ubi32_mailbox_hw_init(&ubi32_mailbox_ports[i]);
+       }
+
+}
+
+#ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+ubi32_mailbox_console_get_options(struct ubi32_mailbox_port *uart, int *baud,
+                          int *parity, int *bits)
+{
+       unsigned short status;
+
+       status = UART_GET_IER(uart) & (ERBFI | ETBEI);
+       if (status == (ERBFI | ETBEI)) {
+               /* ok, the port was enabled */
+               unsigned short lcr;
+               unsigned short dlh, dll;
+
+               lcr = UART_GET_LCR(uart);
+
+               *parity = 'n';
+               if (lcr & PEN) {
+                       if (lcr & EPS)
+                               *parity = 'e';
+                       else
+                               *parity = 'o';
+               }
+               switch (lcr & 0x03) {
+                       case 0: *bits = 5; break;
+                       case 1: *bits = 6; break;
+                       case 2: *bits = 7; break;
+                       case 3: *bits = 8; break;
+               }
+
+               dll = UART_GET_DLL(uart);
+               dlh = UART_GET_DLH(uart);
+
+               *baud = get_sclk() / (16*(dll | dlh << 8));
+       }
+       pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
+}
+#endif
+
+#if defined(CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+static struct uart_driver ubi32_mailbox_reg;
+
+static int __init
+ubi32_mailbox_console_setup(struct console *co, char *options)
+{
+       struct ubi32_mailbox_port *uart;
+# ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE
+       int baud = SERIAL_UBICOM_BAUDRATE;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+# endif
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index == -1 || co->index >= NR_PORTS)
+               co->index = 0;
+       uart = &ubi32_mailbox_ports[co->index];
+
+# ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+       else
+               ubi32_mailbox_console_get_options(uart, &baud, &parity, &bits);
+
+       //JB return uart_set_options(&uart->port, co, baud, parity, bits, flow);
+       return 0;
+# else
+       return 0;
+# endif
+}
+#endif /* defined (CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE) ||
+                                defined (CONFIG_EARLY_PRINTK) */
+
+#ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE
+static void ubi32_mailbox_console_putchar(struct uart_port *port, int ch)
+{
+//     struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
+       while (!(UART_GET_LSR(uart) & THRE))
+               barrier();
+       UART_PUT_CHAR(uart, ch);
+       SSYNC();
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+ubi32_mailbox_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct ubi32_mailbox_port *uart = &ubi32_mailbox_ports[co->index];
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&uart->port.lock, flags);
+       uart_console_write(&uart->port, s, count, ubi32_mailbox_console_putchar);
+       spin_unlock_irqrestore(&uart->port.lock, flags);
+
+}
+
+static struct console ubi32_mailbox_console = {
+       .name           = UBI32_MAILBOX_NAME,
+       .write          = ubi32_mailbox_console_write,
+       .device         = uart_console_device,
+       .setup          = ubi32_mailbox_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &ubi32_mailbox_reg,
+};
+
+static int __init ubi32_mailbox_console_init(void)
+{
+       ubi32_mailbox_init_ports();
+       register_console(&ubi32_mailbox_console);
+       return 0;
+}
+console_initcall(ubi32_mailbox_console_init);
+
+#define UBI32_MAILBOX_CONSOLE  &ubi32_mailbox_console
+#else
+#define UBI32_MAILBOX_CONSOLE  NULL
+#endif /* CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE */
+
+
+#ifdef CONFIG_EARLY_PRINTK
+static __init void ubi32_mailbox_early_putc(struct uart_port *port, int ch)
+{
+       UART_PUT_CHAR(uart, ch);
+}
+
+static __init void ubi32_mailbox_early_write(struct console *con, const char *s,
+                                       unsigned int n)
+{
+       struct ubi32_mailbox_port *uart = &ubi32_mailbox_ports[con->index];
+       unsigned int i;
+
+       for (i = 0; i < n; i++, s++) {
+               if (*s == '\n')
+                       ubi32_mailbox_early_putc(&uart->port, '\r');
+               ubi32_mailbox_early_putc(&uart->port, *s);
+       }
+}
+
+static struct __init console ubi32_mailbox_early_console = {
+       .name = "early_UM",
+       .write = ubi32_mailbox_early_write,
+       .device = uart_console_device,
+       .flags = CON_PRINTBUFFER,
+       .setup = ubi32_mailbox_console_setup,
+       .index = -1,
+       .data  = &ubi32_mailbox_reg,
+};
+
+/*
+ * XXX Unused in our driver. Need to find out what the termios initialization is good/needed for.
+ */
+struct console __init *ubi32_mailbox_early_init(unsigned int port,
+                                               unsigned int cflag)
+{
+       struct ubi32_mailbox_port *uart;
+       struct ktermios t;
+
+       if (port == -1 || port >= NR_PORTS)
+               port = 0;
+       ubi32_mailbox_init_ports();
+       ubi32_mailbox_early_console.index = port;
+       uart = &ubi32_mailbox_ports[port];
+       t.c_cflag = cflag;
+       t.c_iflag = 0;
+       t.c_oflag = 0;
+       t.c_lflag = ICANON;
+       t.c_line = port;
+       ubi32_mailbox_set_termios(&uart->port, &t, &t);
+       return &ubi32_mailbox_early_console;
+}
+
+#endif /* CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE */
+
+static struct uart_driver ubi32_mailbox_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ubi32_mailbox",
+       .dev_name               = UBI32_MAILBOX_NAME,
+       .major                  = UBI32_MAILBOX_MAJOR,
+       .minor                  = UBI32_MAILBOX_MINOR,
+       .nr                     = NR_PORTS,
+       .cons                   = UBI32_MAILBOX_CONSOLE,
+};
+
+static int ubi32_mailbox_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct ubi32_mailbox_port *uart = platform_get_drvdata(dev);
+
+       if (uart)
+               uart_suspend_port(&ubi32_mailbox_reg, &uart->port);
+
+       return 0;
+}
+
+static int ubi32_mailbox_resume(struct platform_device *dev)
+{
+       struct ubi32_mailbox_port *uart = platform_get_drvdata(dev);
+
+       if (uart)
+               uart_resume_port(&ubi32_mailbox_reg, &uart->port);
+
+       return 0;
+}
+
+static int ubi32_mailbox_probe(struct platform_device *dev)
+{
+       struct resource *res = dev->resource;
+       int i;
+
+       for (i = 0; i < dev->num_resources; i++, res++)
+               if (res->flags & IORESOURCE_MEM)
+                       break;
+
+       if (i < dev->num_resources) {
+               for (i = 0; i < NR_PORTS; i++, res++) {
+                       if (ubi32_mailbox_ports[i].port.mapbase != res->start)
+                               continue;
+                       ubi32_mailbox_ports[i].port.dev = &dev->dev;
+                       uart_add_one_port(&ubi32_mailbox_reg, &ubi32_mailbox_ports[i].port);
+                       platform_set_drvdata(dev, &ubi32_mailbox_ports[i]);
+               }
+       }
+
+       return 0;
+}
+
+static int ubi32_mailbox_remove(struct platform_device *pdev)
+{
+       struct ubi32_mailbox_port *uart = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (uart)
+               uart_remove_one_port(&ubi32_mailbox_reg, &uart->port);
+
+       return 0;
+}
+
+static struct platform_driver ubi32_mailbox_driver = {
+       .probe          = ubi32_mailbox_probe,
+       .remove         = ubi32_mailbox_remove,
+       .suspend        = ubi32_mailbox_suspend,
+       .resume         = ubi32_mailbox_resume,
+       .driver         = {
+               .name   = "ubi32-mbox",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init ubi32_mailbox_init(void)
+{
+       int ret;
+
+       pr_info("Serial: Ubicom32 mailbox serial driver.\n");
+
+       mailbox_console_flg = TRUE;
+       num_timeouts = 0;
+       ubi32_mailbox_init_ports();
+
+       ret = uart_register_driver(&ubi32_mailbox_reg);
+       if (ret == 0) {
+               ret = platform_driver_register(&ubi32_mailbox_driver);
+               if (ret) {
+                       pr_debug("uart register failed\n");
+                       uart_unregister_driver(&ubi32_mailbox_reg);
+               }
+       }
+
+       /*
+        * XXX HACK: currently probe does not get called, but the port needs to be added to work.
+        */
+       uart_add_one_port(&ubi32_mailbox_reg, &ubi32_mailbox_ports[0].port);
+       return ret;
+}
+
+static void __exit ubi32_mailbox_exit(void)
+{
+       platform_driver_unregister(&ubi32_mailbox_driver);
+       uart_unregister_driver(&ubi32_mailbox_reg);
+}
+
+module_init(ubi32_mailbox_init);
+module_exit(ubi32_mailbox_exit);
+
+MODULE_ALIAS_CHARDEV_MAJOR(UBI32_MAILBOX_MAJOR);
+MODULE_ALIAS("platform:ubi32_mailbox");
diff --git a/target/linux/ubicom32/files/drivers/serial/ubi32_serdes.c b/target/linux/ubicom32/files/drivers/serial/ubi32_serdes.c
new file mode 100644 (file)
index 0000000..79037da
--- /dev/null
@@ -0,0 +1,817 @@
+/*
+ * drivers/serial/ubi32_serdes.c
+ *   Ubicom32 On-Chip Serial Driver
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+
+#include <asm/ip5000.h>
+#include <asm/ubicom32suart.h>
+
+
+#define SERIAL_UBICOM_PIN_RXD  (1 << 0)
+#define SERIAL_UBICOM_PIN_TXD  (1 << 6)
+#define SERIAL_UBICOM_CTL0     0x8b300000
+#define SERIAL_UBICOM_CTL1     0x00000009
+
+#define SERIAL_UBICOM_DATA_BIT 8       /* Fixed parameter - do not change */
+#define SERIAL_UBICOM_PAR_BIT  0       /* Fixed parameter - do not change */
+#define SERIAL_UBICOM_STOP_BIT 1       /* Fixed parameter - do not change */
+
+/* UART name and device definitions */
+#define UBI32_SERDES_NAME      "ttyUS" // XXX
+#define UBI32_SERDES_MAJOR     206 // XXX
+#define UBI32_SERDES_MINOR     64 // XXX
+
+#define PORT_UBI32_SERDES      1234
+#define NR_PORTS 1
+
+struct uart_port ubi32_serdes_ports[NR_PORTS];
+
+struct ubi32_serdes_resource {
+       void *uart_base_addr;
+       int uart_irq;
+       int uart_clock;
+} ubi32_serdes_resource[NR_PORTS] = {
+       /*
+        * Get params from kernel command line (required for early printk)
+        * or from platform resources.
+        */
+       {0, 0, 0}
+};
+
+/*
+ * Can get overridden by 'serdes=' kernel command line.
+ */
+static int ubi32_serdes_default_baud_rate = 115200;
+
+
+#define IO_PORT(port) ((struct ubicom32_io_port *)port->membase)
+#define IO_PORT_INT_STATUS(port) (IO_PORT(port)->int_status)
+#define IO_PORT_INT_MASK(port) (IO_PORT(port)->int_mask)
+#define IO_PORT_INT_CLR(port) (IO_PORT(port)->int_clr)
+
+
+/*
+ * ubi32_serdes_get_char()
+ */
+static u8_t ubi32_serdes_get_char(struct ubicom32_io_port *io_port)
+{
+       /*
+        * Read from hardware (forced 32-bit atomic read).
+        */
+       u32_t data = 0;
+
+       if ( io_port ) {
+               io_port->int_clr = IO_PORTX_INT_SERDES_RXBF;
+               asm volatile (
+                       "move.4         %0, %1          \n\t"
+                       : "=r" (data)
+                       : "m" (*(u32_t *)&(io_port->rx_fifo))
+                       );
+       }
+
+       return (u8_t)(data & 0x000000ff);
+}
+
+/*
+ * ubi32_serdes_put_char()
+ */
+static void ubi32_serdes_put_char(struct ubicom32_io_port *io_port, u8_t c)
+{
+       u32_t data = 0x0000fe00 | (c << 1);
+
+       if ( io_port ) {
+               /*
+                * Fixed data format:
+                * [LSB]1 start bit - 8 data bits - no parity - 1 stop bit[MSB]
+                */
+               io_port->int_clr = IO_PORTX_INT_SERDES_TXBE;
+               io_port->ctl2 = data;
+               io_port->int_set = IO_PORTX_INT_SERDES_TXBUF_VALID;
+       }
+}
+
+static void ubi32_serdes_hw_init(struct uart_port *port, int baud)
+{
+       struct ubicom32_io_port *io_port = IO_PORT(port);
+
+       if ( io_port ) {
+               /*
+                * Put port functions 1-4 into reset state.
+                * Function 0 (GPIO) does not need or have a reset bit.
+                *
+                * Select SERDES function for restart below.
+                */
+               io_port->function =
+                       IO_FUNC_FUNCTION_RESET(1) | IO_FUNC_FUNCTION_RESET(2) |
+                       IO_FUNC_FUNCTION_RESET(3) | IO_FUNC_FUNCTION_RESET(4) |
+                       IO_PORTX_FUNC_SERDES;
+
+               /*
+                * Configure SERDES baudrate
+                */
+               if ( baud == 0 ) {
+                       baud = ubi32_serdes_default_baud_rate;
+               }
+
+               io_port->ctl0 =
+                       SERIAL_UBICOM_CTL0 |
+                       ((port->uartclk / (16 * baud)) - 1);
+
+               io_port->ctl1 =
+                       SERIAL_UBICOM_CTL1;
+
+               /*
+                * don't interrupt until startup and start_tx
+                */
+               io_port->int_mask = 0;
+
+               /*
+                * Set TXD pin output, RXD input and prevent GPIO
+                * override on the TXD & RXD pins
+                */
+               io_port->gpio_ctl &= ~SERIAL_UBICOM_PIN_RXD;
+               io_port->gpio_ctl |= SERIAL_UBICOM_PIN_TXD;
+               io_port->gpio_mask &= ~(SERIAL_UBICOM_PIN_RXD | SERIAL_UBICOM_PIN_TXD);
+
+               /*
+                * Restart (un-reset) the port's SERDES function.
+                */
+               io_port->function &= ~(IO_FUNC_FUNCTION_RESET(IO_PORTX_FUNC_SERDES));
+       }
+}
+
+#define ULITE_STATUS_RXVALID IO_PORTX_INT_SERDES_RXBF
+#define ULITE_STATUS_OVERRUN 0
+#define ULITE_STATUS_FRAME 0
+#define ULITE_STATUS_PARITY 0
+#define ULITE_STATUS_TXEMPTY IO_PORTX_INT_SERDES_TXBE
+#define ULITE_STATUS_TXFULL 0
+
+static int ubi32_serdes_receive(struct uart_port *port, int stat)
+{
+       struct tty_struct *tty = port->info->port.tty;
+       unsigned char ch = 0;
+       char flag = TTY_NORMAL;
+
+       if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
+                    | ULITE_STATUS_FRAME)) == 0)
+               return 0;
+
+       /* stats */
+       if (stat & ULITE_STATUS_RXVALID) {
+               port->icount.rx++;
+               ch = ubi32_serdes_get_char((struct ubicom32_io_port *)port->membase);
+
+               if (stat & ULITE_STATUS_PARITY)
+                       port->icount.parity++;
+       }
+
+       if (stat & ULITE_STATUS_OVERRUN)
+               port->icount.overrun++;
+
+       if (stat & ULITE_STATUS_FRAME)
+               port->icount.frame++;
+
+
+       /* drop byte with parity error if IGNPAR specificed */
+       if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY)
+               stat &= ~ULITE_STATUS_RXVALID;
+
+       stat &= port->read_status_mask;
+
+       if (stat & ULITE_STATUS_PARITY)
+               flag = TTY_PARITY;
+
+       stat &= ~port->ignore_status_mask;
+
+       if (stat & ULITE_STATUS_RXVALID)
+               tty_insert_flip_char(tty, ch, flag);
+
+       if (stat & ULITE_STATUS_FRAME)
+               tty_insert_flip_char(tty, 0, TTY_FRAME);
+
+       if (stat & ULITE_STATUS_OVERRUN)
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+       return 1;
+}
+
+/*
+ * interrupts are disabled on entry
+ */
+static void ubi32_serdes_stop_tx(struct uart_port *port)
+{
+       IO_PORT_INT_MASK(port) = IO_PORT_INT_MASK(port) & ~IO_PORTX_INT_SERDES_TXBE;
+}
+
+static int ubi32_serdes_transmit(struct uart_port *port, int stat)
+{
+       struct circ_buf *xmit  = &port->info->xmit;
+
+       if (!(stat & IO_PORTX_INT_SERDES_TXBE))
+               return 0;
+
+       if (port->x_char) {
+               ubi32_serdes_put_char(IO_PORT(port), port->x_char);
+               port->x_char = 0;
+               port->icount.tx++;
+               return 1;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               ubi32_serdes_stop_tx(port);
+               return 0;
+       }
+
+       ubi32_serdes_put_char(IO_PORT(port), xmit->buf[xmit->tail]);
+       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
+       port->icount.tx++;
+
+       /* wake up */
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+       if (uart_circ_empty(xmit))
+               ubi32_serdes_stop_tx(port);
+
+       return 1;
+}
+
+/*
+ * port is locked and interrupts are disabled
+ */
+static void ubi32_serdes_start_tx(struct uart_port *port)
+{
+       IO_PORT_INT_MASK(port) = IO_PORT_INT_MASK(port) | IO_PORTX_INT_SERDES_TXBE;
+       ubi32_serdes_transmit(port, IO_PORT_INT_STATUS(port));
+}
+
+/*
+ * Interrupts are enabled
+ */
+static void ubi32_serdes_stop_rx(struct uart_port *port)
+{
+       /* don't forward any more data (like !CREAD) */
+       port->ignore_status_mask = IO_PORTX_INT_SERDES_RXBF;
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void ubi32_serdes_enable_ms(struct uart_port *port)
+{
+       /* N/A */
+}
+
+static irqreturn_t ubi32_serdes_isr(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       int busy;
+
+       spin_lock(&port->lock);
+
+       do {
+               int stat = IO_PORT_INT_STATUS(port);
+               busy  = ubi32_serdes_receive(port, stat);
+               busy |= ubi32_serdes_transmit(port, stat);
+       } while (busy);
+
+       tty_flip_buffer_push(port->info->port.tty);
+
+       spin_unlock(&port->lock);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int ubi32_serdes_tx_empty(struct uart_port *port)
+{
+       unsigned long flags;
+       unsigned int ret;
+
+       spin_lock_irqsave(&port->lock, flags);
+       ret = IO_PORT_INT_STATUS(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int ubi32_serdes_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void ubi32_serdes_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* N/A */
+}
+
+/*
+ * Interrupts are always disabled.
+ */
+static void ubi32_serdes_break_ctl(struct uart_port *port, int break_state)
+{
+       /* N/A */
+}
+
+static int ubi32_serdes_startup(struct uart_port *port)
+{
+       if (request_irq(port->irq, ubi32_serdes_isr, IRQF_DISABLED,
+            "UBI32_SERDES", port)) {
+               printk(KERN_NOTICE "Unable to attach port interrupt\n");
+               return -EBUSY;
+       }
+
+       IO_PORT_INT_CLR(port) = IO_PORTX_INT_SERDES_RXBF;
+       IO_PORT_INT_MASK(port) = IO_PORTX_INT_SERDES_RXBF;
+       return 0;
+}
+
+static void ubi32_serdes_shutdown(struct uart_port *port)
+{
+       struct ubi32_serdes_port *uart = (struct ubi32_serdes_port *)port;
+
+       IO_PORT_INT_MASK(port) = 0;
+       free_irq(port->irq, uart);
+}
+
+static void
+ubi32_serdes_set_termios(struct uart_port *port, struct ktermios *termios,
+                  struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
+               | ULITE_STATUS_TXFULL;
+
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |=
+                       ULITE_STATUS_PARITY | ULITE_STATUS_FRAME;
+
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR)
+               port->ignore_status_mask |= ULITE_STATUS_PARITY
+                       | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+
+       /* ignore all characters if CREAD is not set */
+       if ((termios->c_cflag & CREAD) == 0)
+               port->ignore_status_mask |=
+                       ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
+                       | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
+
+       /* update timeout */
+       baud = uart_get_baud_rate(port, termios, old, 0, 460800);
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       IO_PORT(port)->ctl0 = SERIAL_UBICOM_CTL0 |
+                       ((port->uartclk / (16 * baud)) - 1);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *ubi32_serdes_type(struct uart_port *port)
+{
+       return port->type == PORT_UBI32_SERDES ? "UBI32_SERDES" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void ubi32_serdes_release_port(struct uart_port *port)
+{
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int ubi32_serdes_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void ubi32_serdes_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE &&
+           ubi32_serdes_request_port(port) == 0)
+               port->type = PORT_UBI32_SERDES;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_UBI32_SERDES and PORT_UNKNOWN
+ */
+static int
+ubi32_serdes_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return 0;
+}
+
+static struct uart_ops ubi32_serdes_pops = {
+       .tx_empty       = ubi32_serdes_tx_empty,
+       .set_mctrl      = ubi32_serdes_set_mctrl,
+       .get_mctrl      = ubi32_serdes_get_mctrl,
+       .stop_tx        = ubi32_serdes_stop_tx,
+       .start_tx       = ubi32_serdes_start_tx,
+       .stop_rx        = ubi32_serdes_stop_rx,
+       .enable_ms      = ubi32_serdes_enable_ms,
+       .break_ctl      = ubi32_serdes_break_ctl,
+       .startup        = ubi32_serdes_startup,
+       .shutdown       = ubi32_serdes_shutdown,
+       .set_termios    = ubi32_serdes_set_termios,
+       .type           = ubi32_serdes_type,
+       .release_port   = ubi32_serdes_release_port,
+       .request_port   = ubi32_serdes_request_port,
+       .config_port    = ubi32_serdes_config_port,
+       .verify_port    = ubi32_serdes_verify_port,
+};
+
+static void __init ubi32_serdes_init_ports(void)
+{
+       int i;
+
+       for (i = 0; i < NR_PORTS; i++) {
+               ubi32_serdes_ports[i].uartclk   = ubi32_serdes_resource[i].uart_clock;
+               ubi32_serdes_ports[i].ops       = &ubi32_serdes_pops;
+               ubi32_serdes_ports[i].line      = i;
+               ubi32_serdes_ports[i].iotype    = UPIO_MEM;
+               ubi32_serdes_ports[i].membase   =
+                       (void __iomem *)ubi32_serdes_resource[i].uart_base_addr;
+               ubi32_serdes_ports[i].mapbase   =
+                       (resource_size_t)ubi32_serdes_resource[i].uart_base_addr;
+               ubi32_serdes_ports[i].irq       =
+                       ubi32_serdes_resource[i].uart_irq;
+               ubi32_serdes_ports[i].flags     = UPF_BOOT_AUTOCONF;
+
+               ubi32_serdes_hw_init(&ubi32_serdes_ports[i], 0);
+       }
+
+}
+
+#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+ubi32_serdes_console_get_options(struct uart_port *port, int *baud)
+{
+       u32 round_to = 1200;
+       u32 real_baud;
+
+       /*
+        * We might get called before platform init and with no
+        * kernel command line options, so port might be NULL.
+        */
+       *baud = ubi32_serdes_default_baud_rate;;
+       if ( IO_PORT(port) == 0 )
+               return;
+
+       real_baud = port->uartclk
+               / (16 * ((IO_PORT(port)->ctl0 & ~SERIAL_UBICOM_CTL0) + 1));
+
+       *baud = ((real_baud + round_to - 1) / round_to) * round_to;
+
+       pr_debug("%s:baud = %d, real_baud = %d\n", __FUNCTION__, *baud, real_baud);
+}
+#endif
+
+#if defined(CONFIG_SERIAL_UBI32_SERDES_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+static struct uart_driver ubi32_serdes_reg;
+
+static int __init
+ubi32_serdes_console_setup(struct console *co, char *options)
+{
+       struct uart_port *port;
+#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE
+       int baud = ubi32_serdes_default_baud_rate;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+#endif
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index == -1 || co->index >= NR_PORTS)
+               co->index = 0;
+       port = &ubi32_serdes_ports[co->index];
+
+#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE
+       if (options) {
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+               ubi32_serdes_hw_init(port, baud);
+       }
+       else
+               ubi32_serdes_console_get_options(port, &baud);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+#else
+       return 0;
+#endif
+}
+#endif /* defined (CONFIG_SERIAL_UBI32_SERDES_CONSOLE) ||
+                                defined (CONFIG_EARLY_PRINTK) */
+
+#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE
+static void
+ubi32_serdes_console_putchar(struct uart_port *port, int ch)
+{
+       if ( IO_PORT(port) ) {
+               while (!(IO_PORT_INT_STATUS(port) & IO_PORTX_INT_SERDES_TXBE))
+                       barrier();
+               ubi32_serdes_put_char(IO_PORT(port), ch);
+       }
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+ubi32_serdes_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_port *port = &ubi32_serdes_ports[co->index];
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&port->lock, flags);
+       uart_console_write(port, s, count, ubi32_serdes_console_putchar);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+}
+
+static struct console ubi32_serdes_console = {
+       .name           = UBI32_SERDES_NAME,
+       .write          = ubi32_serdes_console_write,
+       .device         = uart_console_device,
+       .setup          = ubi32_serdes_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &ubi32_serdes_reg,
+};
+
+static int __init ubi32_serdes_console_init(void)
+{
+       ubi32_serdes_init_ports();
+       register_console(&ubi32_serdes_console);
+       return 0;
+}
+console_initcall(ubi32_serdes_console_init);
+
+#define UBI32_SERDES_CONSOLE   &ubi32_serdes_console
+#else
+#define UBI32_SERDES_CONSOLE   NULL
+#endif /* CONFIG_SERIAL_UBI32_SERDES_CONSOLE */
+
+
+#ifdef CONFIG_EARLY_PRINTK
+static __init void ubi32_serdes_early_putc(struct uart_port *port, int ch)
+{
+       unsigned timeout = 0xffff;
+
+       while ((!(IO_PORT_INT_STATUS(port) & IO_PORTX_INT_SERDES_TXBE)) && --timeout)
+               cpu_relax();
+       ubi32_serdes_put_char(IO_PORT(port), ch);
+}
+
+static __init void ubi32_serdes_early_write(struct console *con, const char *s,
+                                       unsigned int n)
+{
+       struct uart_port *port = &ubi32_serdes_ports[con->index];
+       unsigned int i;
+
+       for (i = 0; i < n; i++, s++) {
+               if (*s == '\n')
+                       ubi32_serdes_early_putc(port, '\r');
+               ubi32_serdes_early_putc(port, *s);
+       }
+}
+
+static struct __init console ubi32_serdes_early_console = {
+       .name = "early_US",
+       .write = ubi32_serdes_early_write,
+       .device = uart_console_device,
+       .flags = CON_PRINTBUFFER,
+       .setup = ubi32_serdes_console_setup,
+       .index = -1,
+       .data  = &ubi32_serdes_reg,
+};
+
+/*
+ * XXX Unused in our driver. Need to find out what the termios initialization is good/needed for.
+ */
+struct console __init *ubi32_serdes_early_init(unsigned int port_index,
+                                               unsigned int cflag)
+{
+       struct uart_port *uart;
+       struct ktermios t;
+
+       if (port_index == -1 || port_index >= NR_PORTS)
+               port_index = 0;
+       ubi32_serdes_init_ports();
+       ubi32_serdes_early_console.index = port_index;
+       uart = &ubi32_serdes_ports[port_index];
+       t.c_cflag = cflag;
+       t.c_iflag = 0;
+       t.c_oflag = 0;
+       t.c_lflag = ICANON;
+       t.c_line = port_index;
+       ubi32_serdes_set_termios(uart, &t, &t);
+       return &ubi32_serdes_early_console;
+}
+
+#endif /* CONFIG_SERIAL_UBI32_SERDES_CONSOLE */
+
+static struct uart_driver ubi32_serdes_reg = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = "ubi32_serdes",
+       .dev_name               = UBI32_SERDES_NAME,
+       .major                  = UBI32_SERDES_MAJOR,
+       .minor                  = UBI32_SERDES_MINOR,
+       .nr                     = NR_PORTS,
+       .cons                   = UBI32_SERDES_CONSOLE,
+};
+
+static int ubi32_serdes_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct uart_port *port = platform_get_drvdata(dev);
+
+       if (port)
+               uart_suspend_port(&ubi32_serdes_reg, port);
+
+       return 0;
+}
+
+static int ubi32_serdes_resume(struct platform_device *dev)
+{
+       struct uart_port *port = platform_get_drvdata(dev);
+
+       if (port)
+               uart_resume_port(&ubi32_serdes_reg, port);
+
+       return 0;
+}
+
+static int ubi32_serdes_probe(struct platform_device *dev)
+{
+       struct resource *res = dev->resource;
+       int i;
+
+       for (i = 0; i < dev->num_resources; i++, res++) {
+               if (res->flags & IORESOURCE_MEM) {
+                       ubi32_serdes_resource[0].uart_base_addr = (void *) res->start;
+               }
+               else if (res->flags & IORESOURCE_IRQ) {
+                       ubi32_serdes_resource[0].uart_irq = res->start;
+               }
+               else if (res->flags & UBICOM32_SUART_IORESOURCE_CLOCK) {
+                       ubi32_serdes_resource[0].uart_clock = res->start;
+               }
+       }
+
+       ubi32_serdes_init_ports();
+
+       return 0;
+}
+
+static int ubi32_serdes_remove(struct platform_device *pdev)
+{
+       struct uart_port *port = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+
+       if (port)
+               uart_remove_one_port(&ubi32_serdes_reg, port);
+
+       return 0;
+}
+
+static struct platform_driver ubi32_serdes_driver = {
+       .remove         = ubi32_serdes_remove,
+       .suspend        = ubi32_serdes_suspend,
+       .resume         = ubi32_serdes_resume,
+       .driver         = {
+               .name   = "ubicom32suart",
+               .owner  = THIS_MODULE,
+       },
+};
+
+
+#ifndef MODULE
+/*
+ * Called at boot time.
+ *
+ * You can specify IO base, IRQ, and clock for the serdes serial port
+ * using kernel command line "serdes=0xiobase,irq,clock".  Values
+ * specified will be overwritten by platform device data, if present.
+ */
+static int __init ubi32_serdes_setup(char *str)
+{
+#define N_PARMS   (4+1)
+       int ints[N_PARMS];
+       int i;
+
+       str = get_options(str, ARRAY_SIZE(ints), ints);
+
+       for (i = 0; i < N_PARMS; i++) {
+               if (i < ints[0]) {
+                       if (i == 0) {
+                               ubi32_serdes_resource[0].uart_base_addr = (void *) ints[i+1];
+                       }
+                       else if (i == 1) {
+                               ubi32_serdes_resource[0].uart_irq = ints[i+1];
+                       }
+                       else if (i == 2) {
+                               ubi32_serdes_resource[0].uart_clock = ints[i+1];
+                       }
+                       else if (i == 3) {
+                               ubi32_serdes_default_baud_rate = ints[i+1];
+                       }
+               }
+       }
+       return 1;
+}
+
+__setup("serdes=", ubi32_serdes_setup);
+#endif
+
+static int __init ubi32_serdes_init(void)
+{
+       int ret;
+
+       pr_info("Serial: Ubicom32 serdes uart serial driver\n");
+
+       ret = platform_driver_probe(&ubi32_serdes_driver, ubi32_serdes_probe);
+       if (ret != 0) {
+               printk(KERN_INFO "serdes platform_driver_probe() failed: %d\n", ret);
+               return ret;
+       }
+
+       ubi32_serdes_init_ports();
+
+       ret = uart_register_driver(&ubi32_serdes_reg);
+       if ( ret == 0 ) {
+               ret = uart_add_one_port(&ubi32_serdes_reg, &ubi32_serdes_ports[0]);
+               if ( ret != 0 ) {
+                       uart_unregister_driver(&ubi32_serdes_reg);
+               }
+       }
+
+       return ret;
+}
+
+static void __exit ubi32_serdes_exit(void)
+{
+       platform_driver_unregister(&ubi32_serdes_driver);
+       uart_unregister_driver(&ubi32_serdes_reg);
+}
+
+module_init(ubi32_serdes_init);
+module_exit(ubi32_serdes_exit);
+
+MODULE_AUTHOR("Rainer Keller <rkeller@ubicom.com>");
+MODULE_DESCRIPTION("Ubicom generic serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(UBI32_SERDES_MAJOR);
+MODULE_ALIAS("platform:ubi32_serdes");
diff --git a/target/linux/ubicom32/files/drivers/serial/ubi32_uarttio.c b/target/linux/ubicom32/files/drivers/serial/ubi32_uarttio.c
new file mode 100644 (file)
index 0000000..7aa3742
--- /dev/null
@@ -0,0 +1,1172 @@
+/*
+ * drivers/serial/ubi32_uarttio.c
+ *   Ubicom32 Serial Virtual Peripherial Driver
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+
+#include <asm/ip5000.h>
+#include <asm/gpio.h>
+#include <asm/thread.h>
+#include <asm/uart_tio.h>
+
+#define DRIVER_NAME    "ubi32_uarttio"
+
+/*
+ * For storing the module parameters.
+ */
+#define UBI32_UARTTIO_MAX_PARAM_LEN    80
+static char utio_ports_param[UBI32_UARTTIO_MAX_PARAM_LEN];
+
+/*
+ * UART name and device definitions
+ */
+#define UBI32_UARTTIO_NAME     "ttyUV" // XXX
+#define UBI32_UARTTIO_MAJOR    206 // XXX
+#define UBI32_UARTTIO_MINOR    64 // XXX
+
+/*
+ * The following structures are allocated statically because the
+ * memory allocation subsystem is not initialized this early on
+ */
+
+/*
+ * Per port structure
+ */
+struct ubi32_uarttio_port {
+       struct uarttio_uart             *uart;
+       unsigned int                    tx_pin;
+       unsigned int                    rx_pin;
+
+       struct uart_port                port;
+
+       u8_t                            added;
+
+       /*
+        * If this value is set, the port has had its direction set already
+        */
+       u8_t                            port_init;
+};
+static struct ubi32_uarttio_port uarttio_ports[CONFIG_SERIAL_UBI32_UARTTIO_NR_UARTS];
+
+/*
+ * Number of ports currently initialized
+ */
+static int uarttio_nports;
+
+/*
+ * Per device structure
+ */
+struct ubi32_uarttio_instance {
+       struct uarttio_regs             *regs;
+       struct ubi32_uarttio_port       *ports;
+
+       u8_t                            irq_requested;
+       u8_t                            driver_registered;
+       u8_t                            irq;
+};
+static struct ubi32_uarttio_instance uarttio_inst;
+
+#ifdef CONFIG_SERIAL_UBI32_UARTTIO_CONSOLE
+static struct console ubi32_uarttio_console;
+#define UBI32_UARTTIO_CONSOLE  &ubi32_uarttio_console
+#else
+#define UBI32_UARTTIO_CONSOLE  NULL
+#endif
+
+static struct uart_driver ubi32_uarttio_uart_driver = {
+       .owner                  = THIS_MODULE,
+       .driver_name            = DRIVER_NAME,
+       .dev_name               = UBI32_UARTTIO_NAME,
+       .major                  = UBI32_UARTTIO_MAJOR,
+       .minor                  = UBI32_UARTTIO_MINOR,
+       .cons                   = UBI32_UARTTIO_CONSOLE,
+};
+
+#ifdef UBI32_UARTTIO_UNUSED
+/*
+ * ubi32_uarttio_get_send_space
+ */
+static int ubi32_uarttio_get_send_space(struct uarttio_uart *uart)
+{
+       int count = uart->tx_fifo_head - uart->tx_fifo_tail;
+       if (count < 0) {
+               count += uart->tx_fifo_size;
+       }
+       return uart->tx_fifo_size - count;
+}
+#endif
+
+/*
+ * ubi32_uarttio_get_recv_ready
+ */
+static int ubi32_uarttio_get_recv_ready(struct uarttio_uart *uart)
+{
+       int count = uart->rx_fifo_head - uart->rx_fifo_tail;
+       if (count < 0) {
+               count += uart->rx_fifo_size;
+       }
+       return count;
+}
+
+/*
+ * ubi32_uarttio_get_char()
+ */
+static u8_t ubi32_uarttio_get_char(struct uarttio_uart *uart)
+{
+       /*
+        * Retrieve byte
+        */
+       u32_t tail = uart->rx_fifo_tail;
+       u8_t data = uart->rx_fifo[tail];
+
+       if (++tail == uart->rx_fifo_size) {
+               tail = 0;
+       }
+       uart->rx_fifo_tail = tail;
+
+       return data;
+}
+
+/*
+ * ubi32_uarttio_put_char()
+ */
+static int ubi32_uarttio_put_char(struct uarttio_uart *uart, u8_t c)
+{
+       u32_t head = uart->tx_fifo_head;
+       u32_t prev = head;
+
+       /*
+        * Wrap
+        */
+       if (++head == uart->tx_fifo_size) {
+               head = 0;
+       }
+
+       /*
+        * If there isn't any space, return EBUSY
+        */
+       if (head == uart->tx_fifo_tail) {
+               return -EBUSY;
+       }
+
+       /*
+        * Put the character in the queue
+        */
+       uart->tx_fifo[prev] = c;
+       uart->tx_fifo_head = head;
+
+       return 0;
+}
+
+/*
+ * ubi32_uarttio_set_baud
+ */
+static int ubi32_uarttio_set_baud(struct ubi32_uarttio_port *uup, unsigned int baud)
+{
+       if (uup->uart->current_baud_rate == baud) {
+               return 0;
+       }
+
+       uup->uart->baud_rate = baud;
+       uup->uart->flags |= UARTTIO_UART_FLAG_SET_RATE;
+       while (uup->uart->flags & UARTTIO_UART_FLAG_SET_RATE) {
+               cpu_relax();
+       }
+
+       if (uup->uart->current_baud_rate != baud) {
+               /*
+                * Failed to set baud rate
+                */
+               printk(KERN_WARNING "Invalid baud rate %u, running at %u\n", baud, uup->uart->current_baud_rate);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * ubi32_uarttio_handle_receive
+ */
+static void ubi32_uarttio_handle_receive(struct ubi32_uarttio_port *uup, int stat)
+{
+       struct uarttio_uart *uart = uup->uart;
+       struct uart_port *port = &uup->port;
+       struct tty_struct *tty = port->info->port.tty;
+       unsigned char ch = 0;
+       char flag = TTY_NORMAL;
+       int count;
+
+       if ((stat & (UARTTIO_UART_INT_RX | UARTTIO_UART_INT_RXFRAME | UARTTIO_UART_INT_RXOVF)) == 0) {
+               return;
+       }
+
+       if (stat & UARTTIO_UART_INT_RX) {
+               count = ubi32_uarttio_get_recv_ready(uart);
+               port->icount.rx += count;
+       }
+
+       if (stat & UARTTIO_UART_INT_RXOVF) {
+               port->icount.overrun++;
+       }
+
+       if (stat & UARTTIO_UART_INT_RXFRAME) {
+               port->icount.frame++;
+       }
+
+       stat &= ~port->ignore_status_mask;
+
+       if (stat & UARTTIO_UART_INT_RX) {
+               int i;
+               for (i = 0; i < count; i++) {
+                       ch = ubi32_uarttio_get_char(uart);
+                       tty_insert_flip_char(tty, ch, flag);
+               }
+       }
+
+       if (stat & UARTTIO_UART_INT_RXFRAME) {
+               tty_insert_flip_char(tty, 0, TTY_FRAME);
+       }
+
+       if (stat & UARTTIO_UART_INT_RXOVF) {
+               tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+       }
+}
+
+/*
+ * ubi32_uarttio_stop_tx
+ *     interrupts are disabled on entry
+ */
+static void ubi32_uarttio_stop_tx(struct uart_port *port)
+{
+       struct ubi32_uarttio_port *uup = port->private_data;
+
+       uup->uart->int_mask &= ~UARTTIO_UART_INT_TXBE;
+}
+
+/*
+ * ubi32_uarttio_handle_transmit
+ */
+static void ubi32_uarttio_handle_transmit(struct ubi32_uarttio_port *uup, int stat)
+{
+       struct uarttio_uart *uart = uup->uart;
+       struct uart_port *port = &uup->port;
+       struct circ_buf *xmit  = &port->info->xmit;
+
+       if (!(stat & UARTTIO_UART_INT_TXBE)) {
+               return;
+       }
+
+       if (port->x_char) {
+               if (ubi32_uarttio_put_char(uart, port->x_char)) {
+                       return;
+               }
+               port->x_char = 0;
+               port->icount.tx++;
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+               ubi32_uarttio_stop_tx(port);
+               return;
+       }
+
+       /*
+        * Send as many characters as we can
+        */
+       while (ubi32_uarttio_put_char(uart, xmit->buf[xmit->tail]) == 0) {
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit)) {
+                       break;
+               }
+       }
+
+       /* wake up */
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
+               uart_write_wakeup(port);
+       }
+
+       if (uart_circ_empty(xmit)) {
+               ubi32_uarttio_stop_tx(port);
+       }
+}
+
+/*
+ * ubi32_uarttio_start_tx
+ *     port is locked and interrupts are disabled
+ */
+static void ubi32_uarttio_start_tx(struct uart_port *port)
+{
+       struct ubi32_uarttio_port *uup = port->private_data;
+       struct uarttio_uart *uart = uup->uart;
+
+       uart->int_mask |= UARTTIO_UART_INT_TXBE;
+}
+
+/*
+ * ubi32_uarttio_stop_rx
+ *     Interrupts are enabled
+ */
+static void ubi32_uarttio_stop_rx(struct uart_port *port)
+{
+       struct ubi32_uarttio_port *uup = port->private_data;
+       struct uarttio_uart *uart = uup->uart;
+
+       /*
+        * don't forward any more data (like !CREAD)
+        */
+       uart->int_mask &= ~UARTTIO_UART_INT_RX;
+       port->ignore_status_mask = UARTTIO_UART_INT_RX;
+}
+
+/*
+ * ubi32_uarttio_enable_ms
+ *     Set the modem control timer to fire immediately.
+ */
+static void ubi32_uarttio_enable_ms(struct uart_port *port)
+{
+       /* N/A */
+}
+
+/*
+ * ubi32_uarttio_isr
+ */
+static irqreturn_t ubi32_uarttio_isr(int irq, void *appdata)
+{
+       struct ubi32_uarttio_port *uup = uarttio_ports;
+       int i;
+
+       /*
+        * Service all of the ports
+        */
+       for (i = 0; i < uarttio_nports; i++) {
+               unsigned int flags;
+
+               if (!(uup->uart->flags & UARTTIO_UART_FLAG_ENABLED)) {
+                       uup++;
+                       continue;
+               }
+
+               spin_lock(&uup->port.lock);
+
+               flags = uup->uart->int_flags;
+
+               uup->uart->int_flags = 0;
+
+               ubi32_uarttio_handle_receive(uup, flags);
+               ubi32_uarttio_handle_transmit(uup, flags);
+
+               tty_flip_buffer_push(uup->port.info->port.tty);
+
+               spin_unlock(&uup->port.lock);
+
+               uup++;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * ubi32_uarttio_tx_empty
+ *     Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int ubi32_uarttio_tx_empty(struct uart_port *port)
+{
+       struct ubi32_uarttio_port *uup = port->private_data;
+
+       if (uup->uart->tx_fifo_head == uup->uart->tx_fifo_tail) {
+               return TIOCSER_TEMT;
+       }
+
+       return 0;
+}
+
+/*
+ * ubi32_uarttio_get_mctrl
+ */
+static unsigned int ubi32_uarttio_get_mctrl(struct uart_port *port)
+{
+       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+/*
+ * ubi32_uarttio_set_mctrl
+ */
+static void ubi32_uarttio_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* N/A */
+}
+
+/*
+ * ubi32_uarttio_break_ctl
+ */
+static void ubi32_uarttio_break_ctl(struct uart_port *port, int break_state)
+{
+       /* N/A */
+}
+
+/*
+ * ubi32_uarttio_startup
+ */
+static int ubi32_uarttio_startup(struct uart_port *port)
+{
+       struct ubi32_uarttio_port *uup = port->private_data;
+       struct uarttio_uart *uart = uup->uart;
+
+       uart->flags |= UARTTIO_UART_FLAG_ENABLED;
+
+       uart->int_mask |= UARTTIO_UART_INT_TXBE | UARTTIO_UART_INT_RX;
+
+       return 0;
+}
+
+/*
+ * ubi32_uarttio_shutdown
+ */
+static void ubi32_uarttio_shutdown(struct uart_port *port)
+{
+       struct ubi32_uarttio_port *uup = port->private_data;
+       struct uarttio_uart *uart = uup->uart;
+
+       uart->int_mask = 0;
+       uart->flags &= ~UARTTIO_UART_FLAG_ENABLED;
+}
+
+/*
+ * ubi32_uarttio_set_termios
+ */
+static void ubi32_uarttio_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
+{
+       struct ubi32_uarttio_port *uup = port->private_data;
+       unsigned long flags;
+       unsigned int baud;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+#if 0
+       port->read_status_mask = UBI32_UARTTIO_RX | UBI32_UARTTIO_RXOVF | UBI32_UARTTIO_TXOVF;
+
+       if (termios->c_iflag & INPCK) {
+               port->read_status_mask |= UBI32_UARTTIO_RXFRAME;
+       }
+#endif
+
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNPAR) {
+               port->ignore_status_mask |= UARTTIO_UART_INT_RXFRAME |
+                                           UARTTIO_UART_INT_RXOVF;
+       }
+
+       /*
+        * ignore all characters if CREAD is not set
+        */
+       if ((termios->c_cflag & CREAD) == 0) {
+               port->ignore_status_mask |= UARTTIO_UART_INT_RX |
+                                           UARTTIO_UART_INT_RXFRAME |
+                                           UARTTIO_UART_INT_RXOVF;
+       }
+
+       /* update timeout */
+       baud = uart_get_baud_rate(port, termios, old, 0, 460800);
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       ubi32_uarttio_set_baud(uup, baud);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * ubi32_uarttio_type
+ */
+static const char *ubi32_uarttio_type(struct uart_port *port)
+{
+       return (port->type == PORT_UBI32_UARTTIO) ? "UBI32_UARTTIO" : NULL;
+}
+
+/*
+ * ubi32_uarttio_release_port
+ *     Release the memory region(s) being used by 'port'.
+ */
+static void ubi32_uarttio_release_port(struct uart_port *port)
+{
+}
+
+/*
+ * ubi32_uarttio_request_port
+ *     Request the memory region(s) being used by 'port'.
+ */
+static int ubi32_uarttio_request_port(struct uart_port *port)
+{
+       return 0;
+}
+
+/*
+ * ubi32_uarttio_config_port
+ *     Configure/autoconfigure the port.
+ */
+static void ubi32_uarttio_config_port(struct uart_port *port, int flags)
+{
+       if ((flags & UART_CONFIG_TYPE) && (ubi32_uarttio_request_port(port) == 0)) {
+               port->type = PORT_UBI32_UARTTIO;
+       }
+}
+
+/*
+ * ubi32_uarttio_verify_port
+ *     Verify the new serial_struct (for TIOCSSERIAL).
+ *
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_UBI32_UARTTIO and PORT_UNKNOWN
+ */
+static int ubi32_uarttio_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       return 0;
+}
+
+static struct uart_ops ubi32_uarttio_pops = {
+       .tx_empty       = ubi32_uarttio_tx_empty,
+       .set_mctrl      = ubi32_uarttio_set_mctrl,
+       .get_mctrl      = ubi32_uarttio_get_mctrl,
+       .stop_tx        = ubi32_uarttio_stop_tx,
+       .start_tx       = ubi32_uarttio_start_tx,
+       .stop_rx        = ubi32_uarttio_stop_rx,
+       .enable_ms      = ubi32_uarttio_enable_ms,
+       .break_ctl      = ubi32_uarttio_break_ctl,
+       .startup        = ubi32_uarttio_startup,
+       .shutdown       = ubi32_uarttio_shutdown,
+       .set_termios    = ubi32_uarttio_set_termios,
+       .type           = ubi32_uarttio_type,
+       .release_port   = ubi32_uarttio_release_port,
+       .request_port   = ubi32_uarttio_request_port,
+       .config_port    = ubi32_uarttio_config_port,
+       .verify_port    = ubi32_uarttio_verify_port,
+};
+
+/*
+ * ubi32_uarttio_add_ports
+ */
+static int __init ubi32_uarttio_add_ports(void)
+{
+       int res = 0;
+       struct ubi32_uarttio_port *uup = uarttio_ports;
+       int i = 0;
+
+       for (i = 0; i < uarttio_nports; i++) {
+               /*
+                * Setup the GPIOs
+                */
+               res = gpio_request(uup->tx_pin, "ubi32_uarttio_tx");
+               if (res) {
+                       printk(KERN_WARNING "Failed to request GPIO %d\n", uup->tx_pin);
+                       res = -EBUSY;
+                       goto next;
+               }
+
+               res = gpio_request(uup->rx_pin, "ubi32_uarttio_rx");
+               if (res) {
+                       gpio_free(uup->tx_pin);
+                       printk(KERN_WARNING "Failed to request GPIO %d\n", uup->rx_pin);
+                       res = -EBUSY;
+                       goto next;
+               }
+
+               res = uart_add_one_port(&ubi32_uarttio_uart_driver, &uup->port);
+               if (res) {
+                       gpio_free(uup->rx_pin);
+                       gpio_free(uup->tx_pin);
+                       res = -ENODEV;
+                       printk(KERN_WARNING "Failed to add port %d,%d\n", uup->tx_pin, uup->rx_pin);
+                       goto next;
+               }
+               uup->added = 1;
+
+               /*
+                * Set the direction of the ports now, after we're sure that everything is ok
+                */
+               if (!uup->port_init) {
+                       gpio_direction_output(uup->tx_pin, 1);
+                       gpio_direction_input(uup->rx_pin);
+               }
+
+next:
+               uup++;
+       }
+       return res;
+}
+
+/*
+ * ubi32_uarttio_cleanup
+ */
+static void ubi32_uarttio_cleanup(void)
+{
+       struct ubi32_uarttio_port *uup;
+       int i;
+
+       /*
+        * Stop the hardware thread
+        */
+       if (uarttio_inst.regs) {
+               thread_disable(uarttio_inst.regs->thread);
+       }
+       if (uarttio_inst.irq_requested) {
+               free_irq(uarttio_inst.irq, NULL);
+       }
+
+       /*
+        * Get rid of the ports
+        */
+       uup = uarttio_inst.ports;
+       for (i = 0; i < uarttio_nports; i++) {
+               gpio_free(uup->tx_pin);
+               gpio_free(uup->rx_pin);
+               if (uup->added) {
+                       uart_remove_one_port(&ubi32_uarttio_uart_driver, &uup->port);
+               }
+               uup++;
+       }
+
+       if (uarttio_inst.driver_registered) {
+               uart_unregister_driver(&ubi32_uarttio_uart_driver);
+       }
+}
+
+/*
+ * ubi32_uarttio_setup_port
+ *     Setup a port in the TIO registers
+ */
+static int ubi32_uarttio_setup_port(int index,
+                                   struct uarttio_uart *uart,
+                                   unsigned int baud, unsigned int tx_pin,
+                                   unsigned int rx_pin)
+{
+       struct ubi32_uarttio_port *uup = &uarttio_ports[index];
+       void *tx_port = ubi_gpio_get_port(tx_pin);
+       void *rx_port = ubi_gpio_get_port(rx_pin);
+
+       /*
+        * Verify the ports are on chip
+        */
+       if (!tx_port || !rx_port) {
+               printk(KERN_WARNING "Invalid port(s) specified: %u or %u\n", tx_pin, rx_pin);
+               return -EINVAL;
+       }
+
+       uup->tx_pin = tx_pin;
+       uup->rx_pin = rx_pin;
+       uup->uart = uart;
+
+       /*
+        * Setup the port structure
+        */
+       uup->port.ops           = &ubi32_uarttio_pops;
+       uup->port.line          = index;
+       uup->port.iotype        = UPIO_MEM;
+       uup->port.flags         = UPF_BOOT_AUTOCONF;
+       uup->port.fifosize      = uup->uart->tx_fifo_size;
+       uup->port.private_data  = uup;
+
+       /*
+        * We share this IRQ across all ports
+        */
+       uup->port.irq           = uarttio_inst.irq;
+
+       /*
+        * We really don't have a mem/map base but without these variables
+        * set, the serial_core won't startup.
+        */
+       uup->port.membase       = (void __iomem *)uup;
+       uup->port.mapbase       = (resource_size_t)uup;
+       spin_lock_init(&uup->port.lock);
+
+       /*
+        * Set up the hardware
+        */
+       uart->flags = UARTTIO_UART_FLAG_SET_RATE | UARTTIO_UART_FLAG_RESET;
+
+       uart->tx_port = (unsigned int)tx_port;
+       uart->tx_pin = gpio_pin_index(tx_pin);
+       uart->tx_bits = 8;
+       uart->tx_stop_bits = 1;
+
+       uart->rx_port = (unsigned int)rx_port;
+       uart->rx_pin = gpio_pin_index(rx_pin);
+       uart->rx_bits = 8;
+       uart->rx_stop_bits = 1;
+
+       uart->baud_rate = baud;
+
+       return 0;
+}
+
+enum ubi32_uarttio_parse_states {
+       UBI32_UARTTIO_PARSE_STATE_BAUD,
+       UBI32_UARTTIO_PARSE_STATE_TX_PIN,
+       UBI32_UARTTIO_PARSE_STATE_RX_PIN,
+       UBI32_UARTTIO_PARSE_STATE_HS,
+       UBI32_UARTTIO_PARSE_STATE_CTS_PIN,
+       UBI32_UARTTIO_PARSE_STATE_RTS_PIN,
+};
+
+/*
+ * ubi32_uarttio_parse_param
+ */
+static int ubi32_uarttio_parse_param(char *str)
+{
+       int res;
+       int i;
+       int baud = 0;
+       int tx_pin = 0;
+       int rx_pin = 0;
+       int hs = 0;
+       int cts_pin = 0;
+       int rts_pin = 0;
+       int nfound = 0;
+       enum ubi32_uarttio_parse_states state = UBI32_UARTTIO_PARSE_STATE_BAUD;
+       struct uarttio_uart *uart = uarttio_inst.regs->uarts;
+
+       /*
+        * Run though the options and generate the proper structures
+        */
+       res = get_option(&str, &i);
+       while ((res == 2) || (res == 1)) {
+               switch (state) {
+               case UBI32_UARTTIO_PARSE_STATE_BAUD:
+                       /*
+                        * If we are here and nfound > 0 then create the port
+                        * based on the previous input
+                        */
+                       if (nfound) {
+                               /*
+                                * Create the port
+                                */
+                               if (ubi32_uarttio_setup_port(nfound - 1, uart, baud, tx_pin, rx_pin)) {
+                                       /*
+                                        * Port was invalid
+                                        */
+                                       goto fail;
+                               } else {
+                                       printk(KERN_INFO "Serial port %d: tx=%d:rx=%d @ %d\n", nfound, tx_pin, rx_pin, baud);
+                                       uart++;
+                               }
+                       }
+
+                       /*
+                        * Reset the variables and go to the next state
+                        */
+                       hs = 0;
+                       baud = i;
+                       state = UBI32_UARTTIO_PARSE_STATE_TX_PIN;
+                       break;
+
+               case UBI32_UARTTIO_PARSE_STATE_TX_PIN:
+                       tx_pin = i;
+                       state = UBI32_UARTTIO_PARSE_STATE_RX_PIN;
+                       break;
+
+               case UBI32_UARTTIO_PARSE_STATE_RX_PIN:
+                       rx_pin = i;
+                       state = UBI32_UARTTIO_PARSE_STATE_HS;
+                       break;
+
+               case UBI32_UARTTIO_PARSE_STATE_HS:
+                       hs = i;
+                       if (hs) {
+                               state = UBI32_UARTTIO_PARSE_STATE_CTS_PIN;
+                               break;
+                       }
+
+                       if (nfound == uarttio_inst.regs->max_uarts) {
+                               printk(KERN_WARNING "Maximum number of serial ports reached\n");
+                               goto done;
+                       }
+                       nfound++;
+                       state = UBI32_UARTTIO_PARSE_STATE_BAUD;
+                       break;
+
+               case UBI32_UARTTIO_PARSE_STATE_CTS_PIN:
+                       cts_pin = i;
+                       state = UBI32_UARTTIO_PARSE_STATE_RTS_PIN;
+                       break;
+
+               case UBI32_UARTTIO_PARSE_STATE_RTS_PIN:
+                       rts_pin = i;
+
+                       if (nfound == uarttio_inst.regs->max_uarts) {
+                               printk(KERN_WARNING "Maximum number of serial ports reached\n");
+                               goto done;
+                       }
+                       nfound++;
+                       state = UBI32_UARTTIO_PARSE_STATE_BAUD;
+                       break;
+               }
+               res = get_option(&str, &i);
+       }
+
+       if ((res > 2) || state != UBI32_UARTTIO_PARSE_STATE_BAUD) {
+               printk(KERN_WARNING "Parameter syntax error.\n");
+               res = -EINVAL;
+               goto fail;
+       }
+
+       /*
+        * Create the final port
+        */
+       if (ubi32_uarttio_setup_port(nfound - 1, uart, baud, tx_pin, rx_pin)) {
+               goto fail;
+       }
+       printk(KERN_INFO "Serial port %d: tx=%d:rx=%d @ %d\n", nfound, tx_pin, rx_pin, baud);
+
+done:
+       uarttio_nports = nfound;
+
+       return nfound ? 0 : -ENODEV;
+
+fail:
+       /*
+        * Reset the ports
+        */
+       uart = uarttio_inst.regs->uarts;
+       for (i = 0; i < uarttio_inst.regs->max_uarts; i++) {
+               uart->flags = 0;
+               uart++;
+       }
+
+       return res;
+}
+
+/*
+ * ubi32_uarttio_probe
+ */
+static int ubi32_uarttio_probe(void)
+{
+       int ret;
+       struct uarttio_node *uart_node;
+       char *str = utio_ports_param;
+       static int probed;
+       static int probe_result;
+
+       /*
+        * We only want to be probed once, we could be probed twice
+        * for example if we are used as a console
+        */
+       if (probed) {
+               return probe_result;
+       }
+       probed = 1;
+
+       /*
+        * Extract the TIO name from the setup string
+        */
+       while (*str) {
+               if (*str == ',') {
+                       *str++ = 0;
+                       break;
+               }
+               str++;
+       }
+
+       if (!*str) {
+               probe_result = -EINVAL;
+               return -EINVAL;
+       }
+
+       uart_node = (struct uarttio_node *)devtree_find_node(utio_ports_param);
+       if (!uart_node) {
+               probe_result = -ENODEV;
+               return -ENODEV;
+       }
+
+       uarttio_inst.irq = uart_node->dn.recvirq;
+       uarttio_inst.regs = uart_node->regs;
+
+       /*
+        * Parse module parameters.
+        */
+       ret = ubi32_uarttio_parse_param(str);
+       if (ret != 0) {
+               ubi32_uarttio_cleanup();
+               probe_result = ret;
+               return ret;
+       }
+
+       ubi32_uarttio_uart_driver.nr = uarttio_nports;
+
+       return 0;
+}
+
+#if defined(CONFIG_SERIAL_UBI32_UARTTIO_CONSOLE)
+/*
+ * ubi32_uarttio_console_setup
+ */
+static int __init ubi32_uarttio_console_setup(struct console *co, char *options)
+{
+       int baud;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+       struct ubi32_uarttio_port *uup;
+
+       /*
+        * Check whether an invalid uart number has been specified, and
+        * if so, search for the first available port that does have
+        * console support.
+        */
+       if (co->index == -1 || co->index >= uarttio_nports) {
+               co->index = 0;
+       }
+       uup = &uarttio_ports[co->index];
+       baud = uup->uart->baud_rate;
+       uup->uart->flags |= UARTTIO_UART_FLAG_ENABLED;
+
+       /*
+        * Setup the GPIOs
+        *      We have to use the direct interface because the gpio
+        *      subsystem is not available at this point.
+        */
+       uup->port_init = 1;
+       UBICOM32_GPIO_SET_PIN_HIGH(uup->tx_pin);
+       UBICOM32_GPIO_SET_PIN_OUTPUT(uup->tx_pin);
+       UBICOM32_GPIO_SET_PIN_INPUT(uup->rx_pin);
+
+       /*
+        * Start the thread
+        */
+       thread_enable(uarttio_inst.regs->thread);
+
+       /*
+        * Process options
+        */
+       if (options) {
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+               if (ubi32_uarttio_set_baud(uup, baud)) {
+                       baud = uup->uart->current_baud_rate;
+               }
+       }
+
+       return uart_set_options(&uup->port, co, baud, 'n', 8, 'n');
+}
+
+/*
+ * ubi32_uarttio_console_putchar
+ */
+static void ubi32_uarttio_console_putchar(struct uart_port *port, int ch)
+{
+       struct ubi32_uarttio_port *uup = port->private_data;
+
+       while (ubi32_uarttio_put_char(uup->uart, ch)) {
+               cpu_relax();
+       }
+}
+
+/*
+ * ubi32_uarttio_console_write
+ *     Interrupts are disabled on entering
+ */
+static void ubi32_uarttio_console_write(struct console *co, const char *s, unsigned int count)
+{
+       struct uart_port *port = &(uarttio_ports[co->index].port);
+       unsigned long flags = 0;
+
+       spin_lock_irqsave(&port->lock, flags);
+       uart_console_write(port, s, count, ubi32_uarttio_console_putchar);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static struct console ubi32_uarttio_console = {
+       .name           = UBI32_UARTTIO_NAME,
+       .write          = ubi32_uarttio_console_write,
+       .device         = uart_console_device,
+       .setup          = ubi32_uarttio_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &ubi32_uarttio_uart_driver,
+};
+
+static int __init ubi32_uarttio_console_init(void)
+{
+       int res;
+
+       res = ubi32_uarttio_probe();
+       if (res) {
+               return res;
+       }
+
+       register_console(&ubi32_uarttio_console);
+       return 0;
+}
+console_initcall(ubi32_uarttio_console_init);
+#endif /* CONFIG_SERIAL_UBI32_UARTTIO_CONSOLE */
+
+/*
+ * ubi32_serial_suspend
+ */
+static int ubi32_uarttio_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       int i;
+       for (i = 0; i < uarttio_nports; i++) {
+               uart_suspend_port(&ubi32_uarttio_uart_driver, &uarttio_ports[i].port);
+       }
+
+       return 0;
+}
+
+/*
+ * ubi32_serial_resume
+ */
+static int ubi32_uarttio_resume(struct platform_device *pdev)
+{
+       int i;
+       for (i = 0; i < uarttio_nports; i++) {
+               uart_resume_port(&ubi32_uarttio_uart_driver, &uarttio_ports[i].port);
+       }
+
+       return 0;
+}
+
+/*
+ * ubi32_uarttio_remove
+ */
+static int __devexit ubi32_uarttio_remove(struct platform_device *pdev)
+{
+       ubi32_uarttio_cleanup();
+
+       uart_unregister_driver(&ubi32_uarttio_uart_driver);
+
+       return 0;
+}
+
+static struct platform_driver ubi32_uarttio_platform_driver = {
+       .remove         = __devexit_p(ubi32_uarttio_remove),
+       .suspend        = ubi32_uarttio_suspend,
+       .resume         = ubi32_uarttio_resume,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+#ifndef MODULE
+/*
+ * Called at boot time.
+ *
+ * uarttio=TIONAME,(baud,tx_pin,rx_pin,handshake[,cts_pin,rts_pin],...)
+ *     TIONAME is the name of the devtree node which describes the UARTTIO
+ *     pin is the index of the pin, i.e. PA4 is 5 [(port * 32) + pin]
+ *     handshake = 1 to enable handshaking, provide cts_pin, rts_pin (UNSUPPORTED)
+ *     handshake = 0 to disable handshaking, do not provide cts_pin, rts_pin
+ *     Ex: uarttio=UARTTIO,57600,7,6,0,9600,8,9,0
+ */
+static int __init ubi32_uarttio_setup(char *str)
+{
+       strncpy(utio_ports_param, str, UBI32_UARTTIO_MAX_PARAM_LEN);
+       utio_ports_param[UBI32_UARTTIO_MAX_PARAM_LEN - 1] = 0;
+       return 1;
+}
+__setup("uarttio=", ubi32_uarttio_setup);
+#endif
+
+/*
+ * ubi32_uarttio_init
+ */
+static int __init ubi32_uarttio_init(void)
+{
+       int ret;
+       int i;
+
+       ret = ubi32_uarttio_probe();
+       if (ret) {
+               return ret;
+       }
+
+       /*
+        * Request the IRQ (do it here since many ports share the same IRQ)
+        */
+       ret = request_irq(uarttio_inst.irq, ubi32_uarttio_isr, IRQF_DISABLED, DRIVER_NAME, NULL);
+       if (ret != 0) {
+               printk(KERN_WARNING "Could not request IRQ %d\n", uarttio_inst.irq);
+               goto fail;
+       }
+       uarttio_inst.irq_requested = 1;
+
+       /*
+        * Register the UART driver and add the ports
+        */
+       ret = uart_register_driver(&ubi32_uarttio_uart_driver);
+       if (ret != 0) {
+               goto fail;
+       }
+       uarttio_inst.driver_registered = 1;
+
+       ret = ubi32_uarttio_add_ports();
+       if (ret != 0) {
+               ubi32_uarttio_cleanup();
+               return ret;
+       }
+
+       /*
+        * Start the thread
+        */
+       thread_enable(uarttio_inst.regs->thread);
+
+       for (i = 0; i < uarttio_nports; i++) {
+               pr_info("Serial: Ubicom32 uarttio #%d: tx:%d rx:%d baud:%d\n",
+                       i, uarttio_ports[i].tx_pin, uarttio_ports[i].rx_pin,
+                       uarttio_ports[i].uart->current_baud_rate);
+       }
+       pr_info("Serial: Ubicom32 uarttio started on thread:%d irq:%d\n", uarttio_inst.regs->thread, uarttio_inst.irq);
+
+       return ret;
+
+fail:
+       ubi32_uarttio_cleanup();
+       return ret;
+}
+module_init(ubi32_uarttio_init);
+
+/*
+ * ubi32_uarttio_exit
+ */
+static void __exit ubi32_uarttio_exit(void)
+{
+       platform_driver_unregister(&ubi32_uarttio_platform_driver);
+}
+module_exit(ubi32_uarttio_exit);
+
+module_param_string(ports, utio_ports_param, sizeof(utio_ports_param), 0444);
+MODULE_PARM_DESC(ports, "Sets the ports to allocate: ports=TIONAME,(baud,txpin,rxpin,handshake[,ctspin,rtspin],...)\n"
+                       "     TIONAME is the name of the devtree node which describes the UARTTIO\n"
+                       "     pin is the index of the pin, i.e. PA4 is 5 [(port * 32) + pin]\n"
+                       "     handshake = 1 to enable handshaking, provide ctspin, rtspin (UNSUPPORTED)\n"
+                       "     handshake = 0 to disable handshaking, do not provide ctspin, rtspin\n"
+                       "     Ex: ports=UARTTIO,57600,7,6,0,9600,8,9,0\n");
+MODULE_AUTHOR("Patrick Tjin <pat.tjin@ubicom.com>");
+MODULE_DESCRIPTION("Ubicom serial virtual peripherial driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(UBI32_UARTTIO_MAJOR);
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/target/linux/ubicom32/files/drivers/spi/spi_ubicom32_gpio.c b/target/linux/ubicom32/files/drivers/spi/spi_ubicom32_gpio.c
new file mode 100644 (file)
index 0000000..c41018a
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * drivers/spi_spi_ubicom32_gpio.c
+ *     Ubicom32 GPIO based SPI driver
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <linux/gpio.h>
+
+#include <asm/ubicom32-spi-gpio.h>
+
+#define DRIVER_NAME "ubicom32-spi-gpio"
+
+struct ubicom32_spi_gpio {
+       struct spi_bitbang                       bitbang;
+
+       struct ubicom32_spi_gpio_platform_data  *pdata;
+
+       struct platform_device                  *dev;
+};
+
+/*
+ * The following 4 functions are used by EXPAND_BITBANG_TXRX to bitbang the data out.
+ */
+static inline void setsck(struct spi_device *dev, int on)
+{
+       struct ubicom32_spi_gpio *usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(dev->master);
+       gpio_set_value(usg->pdata->pin_clk, on ? 1 : 0);
+}
+
+static inline void setmosi(struct spi_device *dev, int on)
+{
+       struct ubicom32_spi_gpio *usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(dev->master);
+       gpio_set_value(usg->pdata->pin_mosi, on ? 1 : 0);
+}
+
+static inline u32 getmiso(struct spi_device *dev)
+{
+       struct ubicom32_spi_gpio *usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(dev->master);
+       return gpio_get_value(usg->pdata->pin_miso) ? 1 : 0;
+}
+
+#define spidelay(x) ndelay(x)
+
+#define        EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+/*
+ * ubicom32_spi_gpio_txrx_mode0
+ */
+static u32 ubicom32_spi_gpio_txrx_mode0(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+}
+
+/*
+ * ubicom32_spi_gpio_txrx_mode1
+ */
+static u32 ubicom32_spi_gpio_txrx_mode1(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
+}
+
+/*
+ * ubicom32_spi_gpio_txrx_mode2
+ */
+static u32 ubicom32_spi_gpio_txrx_mode2(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
+}
+
+/*
+ * ubicom32_spi_gpio_txrx_mode3
+ */
+static u32 ubicom32_spi_gpio_txrx_mode3(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
+{
+       return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
+}
+
+/*
+ * ubicom32_spi_gpio_chipselect
+ */
+static void ubicom32_spi_gpio_chipselect(struct spi_device *dev, int value)
+{
+       struct ubicom32_spi_gpio_controller_data *cd = (struct ubicom32_spi_gpio_controller_data *)dev->controller_data;
+       unsigned int cs_polarity = dev->mode & SPI_CS_HIGH ? 1 : 0;
+
+       if (value == BITBANG_CS_ACTIVE) {
+               gpio_set_value(cd->pin_cs, cs_polarity);
+               return;
+       }
+       gpio_set_value(cd->pin_cs, !cs_polarity);
+}
+
+/*
+ * ubicom32_spi_gpio_probe
+ */
+static int ubicom32_spi_gpio_probe(struct platform_device *dev)
+{
+       struct ubicom32_spi_gpio_platform_data *pdata;
+       struct spi_master *master;
+       struct ubicom32_spi_gpio *usg;
+       int ret;
+
+       master = spi_alloc_master(&dev->dev, sizeof(struct ubicom32_spi_gpio));
+       if (master == NULL) {
+               dev_err(&dev->dev, "failed to allocate spi master\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(master);
+
+       platform_set_drvdata(dev, usg);
+
+       /*
+        * Copy in the platform data
+        */
+       pdata = dev->dev.platform_data;
+       usg->pdata = dev->dev.platform_data;
+
+       /*
+        * Request the GPIO lines
+        */
+       ret = gpio_request(pdata->pin_mosi, "spi-mosi");
+       if (ret) {
+               dev_err(&dev->dev, "Failed to allocate spi-mosi GPIO\n");
+               goto err;
+       }
+
+       ret = gpio_request(pdata->pin_miso, "spi-miso");
+       if (ret) {
+               dev_err(&dev->dev, "Failed to allocate spi-miso GPIO\n");
+               goto err_nomiso;
+       }
+
+       ret = gpio_request(pdata->pin_clk, "spi-clk");
+       if (ret) {
+               dev_err(&dev->dev, "Failed to allocate spi-clk GPIO\n");
+               goto err_noclk;
+       }
+
+       /*
+        * Setup spi-bitbang adaptor
+        */
+       usg->bitbang.flags |= SPI_CS_HIGH;
+       usg->bitbang.master = spi_master_get(master);
+       usg->bitbang.master->bus_num = pdata->bus_num;
+       usg->bitbang.master->num_chipselect = pdata->num_chipselect;
+       usg->bitbang.chipselect = ubicom32_spi_gpio_chipselect;
+
+       usg->bitbang.txrx_word[SPI_MODE_0] = ubicom32_spi_gpio_txrx_mode0;
+       usg->bitbang.txrx_word[SPI_MODE_1] = ubicom32_spi_gpio_txrx_mode1;
+       usg->bitbang.txrx_word[SPI_MODE_2] = ubicom32_spi_gpio_txrx_mode2;
+       usg->bitbang.txrx_word[SPI_MODE_3] = ubicom32_spi_gpio_txrx_mode3;
+
+       /*
+        * Setup the GPIO pins
+        */
+       gpio_direction_output(pdata->pin_clk, pdata->clk_default);
+       gpio_direction_output(pdata->pin_mosi, 0);
+       gpio_direction_input(pdata->pin_miso);
+
+       /*
+        * Ready to go
+        */
+       ret = spi_bitbang_start(&usg->bitbang);
+       if (ret) {
+               goto err_no_bitbang;
+       }
+
+       return 0;
+
+err_no_bitbang:
+       spi_master_put(usg->bitbang.master);
+
+       gpio_free(pdata->pin_clk);
+
+err_noclk:
+       gpio_free(pdata->pin_miso);
+
+err_nomiso:
+       gpio_free(pdata->pin_mosi);
+
+err:
+       return ret;
+}
+
+/*
+ * ubicom32_spi_gpio_remove
+ */
+static int ubicom32_spi_gpio_remove(struct platform_device *dev)
+{
+       struct ubicom32_spi_gpio *sp = platform_get_drvdata(dev);
+
+       spi_bitbang_stop(&sp->bitbang);
+       spi_master_put(sp->bitbang.master);
+
+       return 0;
+}
+
+/*
+ * Work with hotplug and coldplug
+ */
+MODULE_ALIAS("platform:ubicom32_spi_gpio");
+
+static struct platform_driver ubicom32_spi_gpio_drv = {
+       .probe          = ubicom32_spi_gpio_probe,
+        .remove                = ubicom32_spi_gpio_remove,
+        .driver                = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+        },
+};
+
+/*
+ * ubicom32_spi_gpio_init
+ */
+static int __init ubicom32_spi_gpio_init(void)
+{
+        return platform_driver_register(&ubicom32_spi_gpio_drv);
+}
+
+/*
+ * ubicom32_spi_gpio_exit
+ */
+static void __exit ubicom32_spi_gpio_exit(void)
+{
+        platform_driver_unregister(&ubicom32_spi_gpio_drv);
+}
+
+module_init(ubicom32_spi_gpio_init);
+module_exit(ubicom32_spi_gpio_exit);
+
+MODULE_DESCRIPTION("Ubicom32 SPI-GPIO Driver");
+MODULE_AUTHOR("Pat Tjin, <@ubicom.com>");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/drivers/uio/uio_ubicom32ring.c b/target/linux/ubicom32/files/drivers/uio/uio_ubicom32ring.c
new file mode 100644 (file)
index 0000000..654ac4c
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * drivers/uio/uio_ubicom32ring.c
+ *
+ * Userspace I/O platform driver for Ubicom32 ring buffers
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * Based on uio_ubicom32ring.c by Magnus Damm
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/uio_driver.h>
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/stringify.h>
+
+#include <asm/ip5000.h>
+#include <asm/ubicom32ring.h>
+
+#define DRIVER_NAME "uio_ubicom32ring"
+
+struct uio_ubicom32ring_data {
+       struct uio_info                 *uioinfo;
+
+       struct uio_ubicom32ring_regs    *regs;
+
+       /*
+        * IRQ used to kick the ring buffer
+        */
+       int                             irq_tx;
+       int                             irq_rx;
+
+       spinlock_t                      lock;
+
+       unsigned long                   flags;
+
+       char                            name[0];
+};
+
+static irqreturn_t uio_ubicom32ring_handler(int irq, struct uio_info *dev_info)
+{
+       struct uio_ubicom32ring_data *priv = dev_info->priv;
+
+       /* Just disable the interrupt in the interrupt controller, and
+        * remember the state so we can allow user space to enable it later.
+        */
+
+       if (!test_and_set_bit(0, &priv->flags))
+               disable_irq_nosync(irq);
+
+       return IRQ_HANDLED;
+}
+
+static int uio_ubicom32ring_irqcontrol(struct uio_info *dev_info, s32 irq_on)
+{
+       struct uio_ubicom32ring_data *priv = dev_info->priv;
+       unsigned long flags;
+
+       /* Allow user space to enable and disable the interrupt
+        * in the interrupt controller, but keep track of the
+        * state to prevent per-irq depth damage.
+        *
+        * Serialize this operation to support multiple tasks.
+        */
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       if (irq_on & 2) {
+               /*
+                * Kick the ring buffer (if we can)
+                */
+               if (priv->irq_tx != 0xFF) {
+                       ubicom32_set_interrupt(priv->irq_tx);
+               }
+       }
+
+       if (priv->irq_rx != 0xFF) {
+               if (irq_on & 1) {
+                       if (test_and_clear_bit(0, &priv->flags))
+                               enable_irq(dev_info->irq);
+               } else {
+                       if (!test_and_set_bit(0, &priv->flags))
+                               disable_irq(dev_info->irq);
+               }
+       }
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static int uio_ubicom32ring_probe(struct platform_device *pdev)
+{
+       struct uio_info *uioinfo;
+       struct uio_mem *uiomem;
+       struct uio_ubicom32ring_data *priv;
+       struct uio_ubicom32ring_regs *regs;
+       struct resource *mem_resource;
+       struct resource *irqtx_resource;
+       struct resource *irqrx_resource;
+       int ret = -EINVAL;
+       int i;
+
+       uioinfo = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+       if (!uioinfo) {
+               dev_err(&pdev->dev, "unable to kmalloc\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * Allocate private data with some string space after
+        */
+       i = sizeof(DRIVER_NAME) + 1;
+       i += pdev->dev.platform_data ? strlen(pdev->dev.platform_data) : 0;
+       priv = kzalloc(sizeof(struct uio_ubicom32ring_data) + i, GFP_KERNEL);
+       if (!priv) {
+               dev_err(&pdev->dev, "unable to kmalloc\n");
+               kfree(uioinfo);
+               return -ENOMEM;
+       }
+
+       strcpy(priv->name, DRIVER_NAME ":");
+       if (pdev->dev.platform_data) {
+               strcat(priv->name, pdev->dev.platform_data);
+       }
+       uioinfo->priv = priv;
+       uioinfo->name = priv->name;
+       uioinfo->version = "0.1";
+
+       priv->uioinfo = uioinfo;
+       spin_lock_init(&priv->lock);
+       priv->flags = 0; /* interrupt is enabled to begin with */
+
+       /*
+        * Get our resources, the IRQ_TX and IRQ_RX are optional.
+        */
+       priv->irq_tx = 0xFF;
+       irqtx_resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (irqtx_resource) {
+               priv->irq_tx = irqtx_resource->start;
+       }
+
+       uioinfo->irq = -1;
+       priv->irq_rx = 0xFF;
+       irqrx_resource = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+       if (irqrx_resource) {
+               priv->irq_rx = irqrx_resource->start;
+               uioinfo->irq = priv->irq_rx;
+               uioinfo->handler = uio_ubicom32ring_handler;
+       }
+
+       mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_resource || !mem_resource->start) {
+               dev_err(&pdev->dev, "No valid memory resource found\n");
+               ret = -ENODEV;
+               goto fail;
+       }
+       regs = (struct uio_ubicom32ring_regs *)mem_resource->start;
+       priv->regs = regs;
+
+       if (regs->version != UIO_UBICOM32RING_REG_VERSION) {
+               dev_err(&pdev->dev, "version %d not supported\n", regs->version);
+               ret = -ENODEV;
+               goto fail;
+       }
+
+       /*
+        * First range is the shared register space, if we have any
+        */
+       uiomem = &uioinfo->mem[0];
+       if (regs->regs_size) {
+               uiomem->memtype = UIO_MEM_PHYS;
+               uiomem->addr = (u32_t)regs->regs;
+               uiomem->size = regs->regs_size;
+               ++uiomem;
+               dev_info(&pdev->dev, "regs:%p (%u) / rings: %d found\n", regs->regs, regs->regs_size, regs->num_rings);
+       } else {
+               dev_info(&pdev->dev, "rings: %d found\n", regs->num_rings);
+       }
+
+       /*
+        * The rest of the range correspond to the rings
+        */
+       for (i = 0; i < regs->num_rings; i++) {
+               dev_info(&pdev->dev, "\t%d: entries:%d ring:%p\n",
+                        i, regs->rings[i]->entries, &(regs->rings[i]->ring));
+               if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) {
+                       dev_warn(&pdev->dev, "device has more than "
+                                       __stringify(MAX_UIO_MAPS)
+                                       " I/O memory resources.\n");
+                       break;
+               }
+
+               uiomem->memtype = UIO_MEM_PHYS;
+               uiomem->addr = (u32_t)&(regs->rings[i]->head);
+               uiomem->size = (regs->rings[i]->entries * sizeof(u32_t)) +
+                               sizeof(struct uio_ubicom32ring_desc);
+               ++uiomem;
+       }
+
+       while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) {
+               uiomem->size = 0;
+               ++uiomem;
+       }
+
+       /* This driver requires no hardware specific kernel code to handle
+        * interrupts. Instead, the interrupt handler simply disables the
+        * interrupt in the interrupt controller. User space is responsible
+        * for performing hardware specific acknowledge and re-enabling of
+        * the interrupt in the interrupt controller.
+        *
+        * Interrupt sharing is not supported.
+        */
+       uioinfo->irq_flags = IRQF_DISABLED;
+       uioinfo->irqcontrol = uio_ubicom32ring_irqcontrol;
+
+       ret = uio_register_device(&pdev->dev, priv->uioinfo);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to register uio device\n");
+               goto fail;
+       }
+
+       platform_set_drvdata(pdev, priv);
+
+       dev_info(&pdev->dev, "'%s' using irq: rx %d tx %d, regs %p\n",
+                priv->name, priv->irq_rx, priv->irq_tx, priv->regs);
+
+       return 0;
+
+fail:
+       kfree(uioinfo);
+       kfree(priv);
+       return ret;
+}
+
+static int uio_ubicom32ring_remove(struct platform_device *pdev)
+{
+       struct uio_ubicom32ring_data *priv = platform_get_drvdata(pdev);
+
+       uio_unregister_device(priv->uioinfo);
+       kfree(priv->uioinfo);
+       kfree(priv);
+       return 0;
+}
+
+static struct platform_driver uio_ubicom32ring = {
+       .probe = uio_ubicom32ring_probe,
+       .remove = uio_ubicom32ring_remove,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init uio_ubicom32ring_init(void)
+{
+       return platform_driver_register(&uio_ubicom32ring);
+}
+
+static void __exit uio_ubicom32ring_exit(void)
+{
+       platform_driver_unregister(&uio_ubicom32ring);
+}
+
+module_init(uio_ubicom32ring_init);
+module_exit(uio_ubicom32ring_exit);
+
+MODULE_AUTHOR("Patrick Tjin");
+MODULE_DESCRIPTION("Userspace I/O driver for Ubicom32 ring buffers");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/target/linux/ubicom32/files/drivers/usb/musb/ubi32_usb.c b/target/linux/ubicom32/files/drivers/usb/musb/ubi32_usb.c
new file mode 100644 (file)
index 0000000..d89e004
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * drivers/usb/musb/ubi32_usb.c
+ *   Ubicom32 usb controller driver.
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ * Copyright (C) 2005-2006 by Texas Instruments
+ *
+ * Derived from the Texas Instruments Inventra Controller Driver for Linux.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/io.h>
+#include <asm/ip5000.h>
+#include "musb_core.h"
+
+void musb_platform_enable(struct musb *musb)
+{
+}
+void musb_platform_disable(struct musb *musb)
+{
+}
+
+int musb_platform_set_mode(struct musb *musb, u8 musb_mode) {
+       return 0;
+}
+
+static void ip5k_usb_hcd_vbus_power(struct musb *musb, int is_on, int sleeping)
+{
+}
+
+static void ip5k_usb_hcd_set_vbus(struct musb *musb, int is_on)
+{
+       u8              devctl;
+       /* HDRC controls CPEN, but beware current surges during device
+        * connect.  They can trigger transient overcurrent conditions
+        * that must be ignored.
+        */
+
+       devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+       if (is_on) {
+               musb->is_active = 1;
+               musb->xceiv.default_a = 1;
+               musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+               devctl |= MUSB_DEVCTL_SESSION;
+
+               MUSB_HST_MODE(musb);
+       } else {
+               musb->is_active = 0;
+
+               /* NOTE:  we're skipping A_WAIT_VFALL -> A_IDLE and
+                * jumping right to B_IDLE...
+                */
+
+               musb->xceiv.default_a = 0;
+               musb->xceiv.state = OTG_STATE_B_IDLE;
+               devctl &= ~MUSB_DEVCTL_SESSION;
+
+               MUSB_DEV_MODE(musb);
+       }
+       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+       DBG(1, "VBUS %s, devctl %02x "
+               /* otg %3x conf %08x prcm %08x */ "\n",
+               otg_state_string(musb),
+               musb_readb(musb->mregs, MUSB_DEVCTL));
+}
+static int ip5k_usb_hcd_set_power(struct otg_transceiver *x, unsigned mA)
+{
+       return 0;
+}
+
+static int musb_platform_resume(struct musb *musb);
+
+int __init musb_platform_init(struct musb *musb)
+{
+
+#ifdef CONFIG_UBICOM32_V4
+       u32_t chip_id;
+       asm volatile (
+                     "move.4   %0, CHIP_ID     \n\t"
+                     : "=r" (chip_id)
+       );
+       if (chip_id == 0x30001) {
+               *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 30);
+               udelay(1);
+               *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 31);
+       } else {
+               *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 17);
+               udelay(1);
+               *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 14);
+       }
+#endif
+
+        *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_CFG)) |= ((1 << 14) | (1 <<15));
+
+       /* The i-clk is AUTO gated. Hence there is no need
+        * to disable it until the driver is shutdown */
+
+       clk_enable(musb->clock);
+       musb_platform_resume(musb);
+
+       ip5k_usb_hcd_vbus_power(musb, musb->board_mode == MUSB_HOST, 1);
+
+       if (is_host_enabled(musb))
+               musb->board_set_vbus = ip5k_usb_hcd_set_vbus;
+       if (is_peripheral_enabled(musb))
+               musb->xceiv.set_power = ip5k_usb_hcd_set_power;
+
+       return 0;
+}
+
+
+int musb_platform_suspend(struct musb *musb)
+{
+       return 0;
+}
+int musb_platform_resume(struct musb *musb)
+{
+       return 0;
+}
+
+int musb_platform_exit(struct musb *musb)
+{
+       ip5k_usb_hcd_vbus_power(musb, 0 /*off*/, 1);
+       musb_platform_suspend(musb);
+       return 0;
+}
diff --git a/target/linux/ubicom32/files/drivers/video/backlight/ubicom32bl.c b/target/linux/ubicom32/files/drivers/video/backlight/ubicom32bl.c
new file mode 100644 (file)
index 0000000..99538c3
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * drivers/video/backlight/ubicom32bl.c
+ *     Backlight driver for the Ubicom32 platform
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+
+#include <asm/ubicom32bl.h>
+#include <asm/ip5000.h>
+
+#define DRIVER_NAME                    "ubicom32bl"
+#define UBICOM32BL_MAX_BRIGHTNESS      255
+
+struct ubicom32bl_data {
+       /*
+        * Pointer to the platform data structure.  Keep this around since we need values
+        * from it to set the backlight intensity.
+        */
+       const struct ubicom32bl_platform_data   *pdata;
+
+       /*
+        * Backlight device, we have to save this for use when we remove ourselves.
+        */
+       struct backlight_device                 *bldev;
+
+       /*
+        * Current intensity, used for get_intensity.
+        */
+       int                                     cur_intensity;
+
+       /*
+        * Init function for PWM
+        */
+       int (*init_fn)(struct ubicom32bl_data *);
+
+       /*
+        * Set intensity function depending on the backlight type
+        */
+       int (*set_intensity_fn)(struct ubicom32bl_data *, int);
+};
+
+/*
+ * ubicom32bl_set_intensity_gpio
+ */
+static int ubicom32bl_set_intensity_gpio(struct ubicom32bl_data *ud, int intensity)
+{
+       ud->cur_intensity = intensity ? 255 : 0;
+
+       if (intensity) {
+               // set gpio
+               return 0;
+       }
+
+       // clear gpio
+       return 0;
+}
+
+/*
+ * ubicom32bl_set_intensity_hw
+ */
+static int ubicom32bl_set_intensity_hw(struct ubicom32bl_data *ud, int intensity)
+{
+       u16_t period = ud->pdata->pwm_period;
+       u16_t duty;
+
+       /*
+        * Calculate the new duty cycle
+        */
+       duty = (period * intensity) / (UBICOM32BL_MAX_BRIGHTNESS + 1);
+
+       /*
+        * Set the new duty cycle
+        */
+       switch (ud->pdata->pwm_channel) {
+       case 0:
+               /*
+                * Channel 0 is in the lower half of PORT C ctl0 and ctl1
+                */
+               UBICOM32_IO_PORT(RC)->ctl1 = (ud->pdata->pwm_period << 16) | duty;
+               break;
+
+       case 1:
+               /*
+                * Channel 1 is in the upper half of PORT C ctl0 and ctl2
+                */
+               UBICOM32_IO_PORT(RC)->ctl2 = (ud->pdata->pwm_period << 16) | duty;
+               break;
+
+       case 2:
+               /*
+                * Channel 2 is in PORT H ctl0 and ctl1
+                */
+               UBICOM32_IO_PORT(RH)->ctl1 = (ud->pdata->pwm_period << 16) | duty;
+               break;
+       }
+
+       ud->cur_intensity = intensity;
+
+       return 0;
+}
+
+/*
+ * ubicom32bl_set_intensity
+ */
+static int ubicom32bl_set_intensity(struct backlight_device *bd)
+{
+       struct ubicom32bl_data *ud = (struct ubicom32bl_data *)bl_get_data(bd);
+       int intensity = bd->props.brightness;
+
+       /*
+        * If we're blanked the the intensity doesn't matter.
+        */
+       if ((bd->props.power != FB_BLANK_UNBLANK) || (bd->props.fb_blank != FB_BLANK_UNBLANK)) {
+               intensity = 0;
+       }
+
+       /*
+        * Check for inverted backlight.
+        */
+       if (ud->pdata->invert) {
+               intensity = UBICOM32BL_MAX_BRIGHTNESS - intensity;
+       }
+
+       if (ud->set_intensity_fn) {
+               return ud->set_intensity_fn(ud, intensity);
+       }
+
+       return -ENXIO;
+}
+
+/*
+ * ubicom32bl_get_intensity
+ *     Return the current intensity of the backlight.
+ */
+static int ubicom32bl_get_intensity(struct backlight_device *bd)
+{
+       struct ubicom32bl_data *ud = (struct ubicom32bl_data *)bl_get_data(bd);
+
+       return ud->cur_intensity;
+}
+
+/*
+ * ubicom32bl_init_hw_pwm
+ *     Set the appropriate PWM registers
+ */
+static int ubicom32bl_init_hw_pwm(struct ubicom32bl_data *ud)
+{
+       /*
+        * bit 13: enable
+        */
+       u16_t pwm_cfg = (1 << 13) | (ud->pdata->pwm_prescale << 8) ;
+
+       switch (ud->pdata->pwm_channel) {
+       case 0:
+               /*
+                * Channel 0 is in the lower half of PORT C ctl0 and ctl1 (PA5)
+                */
+               UBICOM32_IO_PORT(RC)->ctl0 &= ~0xFFFF;
+               UBICOM32_IO_PORT(RC)->ctl0 |= pwm_cfg;
+               UBICOM32_IO_PORT(RC)->ctl1 = ud->pdata->pwm_period << 16;
+
+               /*
+                * If the port function is not set, set it to GPIO/PWM
+                */
+               if (!UBICOM32_IO_PORT(RA)->function) {
+                       UBICOM32_IO_PORT(RA)->function = 3;
+               }
+               break;
+
+       case 1:
+               /*
+                * Channel 1 is in the upper half of PORT C ctl0 and ctl2 (PE4)
+                */
+               UBICOM32_IO_PORT(RC)->ctl0 &= ~0xFFFF0000;
+               UBICOM32_IO_PORT(RC)->ctl0 |= (pwm_cfg << 16);
+               UBICOM32_IO_PORT(RC)->ctl2 = ud->pdata->pwm_period << 16;
+
+               /*
+                * If the port function is not set, set it to GPIO/ExtIOInt
+                */
+               if (!UBICOM32_IO_PORT(RE)->function) {
+                       UBICOM32_IO_PORT(RE)->function = 3;
+               }
+               break;
+
+       case 2:
+               /*
+                * Channel 2 is in PORT H ctl0 and ctl1 (PD0)
+                */
+               UBICOM32_IO_PORT(RH)->ctl0 &= ~0xFFFF0000;
+               UBICOM32_IO_PORT(RH)->ctl0 = pwm_cfg;
+               UBICOM32_IO_PORT(RH)->ctl1 = ud->pdata->pwm_period << 16;
+
+               /*
+                * If the port function is not set, set it to GPIO
+                */
+               if (!UBICOM32_IO_PORT(RD)->function) {
+                       UBICOM32_IO_PORT(RD)->function = 3;
+               }
+               break;
+       }
+
+       return 0;
+}
+
+/*
+ * ubicom32bl_init_gpio
+ *     Allocate the appropriate GPIO
+ */
+static int ubicom32bl_init_gpio(struct ubicom32bl_data *ud)
+{
+       return 0;
+}
+
+static struct backlight_ops ubicom32bl_ops = {
+       .get_brightness = ubicom32bl_get_intensity,
+       .update_status  = ubicom32bl_set_intensity,
+};
+
+/*
+ * ubicom32bl_probe
+ */
+static int ubicom32bl_probe(struct platform_device *pdev)
+{
+       const struct ubicom32bl_platform_data *pdata = pdev->dev.platform_data;
+       struct ubicom32bl_data *ud;
+       struct backlight_device *bldev;
+       int retval;
+
+       /*
+        * Check to see if we have any platform data, if we don't then the backlight is not
+        * configured on this device.
+        */
+       if (!pdata) {
+               return -ENODEV;
+       }
+
+       /*
+        * Allocate our private data
+        */
+       ud = kzalloc(sizeof(struct ubicom32bl_data), GFP_KERNEL);
+       if (!ud) {
+               return -ENOMEM;
+       }
+
+       ud->pdata = pdata;
+
+       /*
+        * Check to see that the platform data is valid for this driver
+        */
+       switch (pdata->type) {
+       case UBICOM32BL_TYPE_PWM:
+               {
+                       /*
+                        * Make sure we have a PWM peripheral
+                        */
+                       u32_t chipid;
+                       asm volatile (
+                               "move.4         %0, CHIP_ID     \n\t"
+                               : "=r" (chipid)
+                       );
+                       if (chipid != 0x00030001) {
+                               retval = -ENODEV;
+                               goto fail;
+                       }
+
+                       if (pdata->pwm_channel > 3) {
+                               retval = -ENODEV;
+                               goto fail;
+                       }
+                       if (pdata->pwm_prescale > 16) {
+                               retval = -EINVAL;
+                               goto fail;
+                       }
+
+                       ud->init_fn = ubicom32bl_init_hw_pwm;
+                       ud->set_intensity_fn = ubicom32bl_set_intensity_hw;
+                       break;
+               }
+
+       case UBICOM32BL_TYPE_PWM_HRT:
+               // For now, PWM HRT devices are treated as binary lights.
+
+       case UBICOM32BL_TYPE_BINARY:
+               ud->init_fn = ubicom32bl_init_gpio;
+               ud->set_intensity_fn = ubicom32bl_set_intensity_gpio;
+               break;
+       }
+
+       /*
+        * Register our backlight device
+        */
+       bldev = backlight_device_register(DRIVER_NAME, &pdev->dev, ud, &ubicom32bl_ops);
+       if (IS_ERR(bldev)) {
+               retval = PTR_ERR(bldev);
+               goto fail;
+       }
+
+       ud->bldev = bldev;
+       ud->cur_intensity = pdata->default_intensity;
+       platform_set_drvdata(pdev, ud);
+
+       /*
+        * Start up the backlight at the prescribed default intensity
+        */
+       bldev->props.power = FB_BLANK_UNBLANK;
+       bldev->props.max_brightness = UBICOM32BL_MAX_BRIGHTNESS;
+       bldev->props.brightness = pdata->default_intensity;
+
+       if (ud->init_fn) {
+               if (ud->init_fn(ud) != 0) {
+                       retval = -ENODEV;
+                       backlight_device_unregister(ud->bldev);
+                       goto fail;
+               }
+       }
+       ubicom32bl_set_intensity(bldev);
+
+       printk(KERN_INFO DRIVER_NAME ": Backlight driver started\n");
+
+       return 0;
+
+fail:
+       platform_set_drvdata(pdev, NULL);
+       kfree(ud);
+       return retval;
+}
+
+/*
+ * ubicom32bl_remove
+ */
+static int __exit ubicom32bl_remove(struct platform_device *pdev)
+{
+       struct ubicom32bl_data *ud = platform_get_drvdata(pdev);
+
+       backlight_device_unregister(ud->bldev);
+       platform_set_drvdata(pdev, NULL);
+       kfree(ud);
+
+       return 0;
+}
+
+static struct platform_driver ubicom32bl_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+
+       .remove = __exit_p(ubicom32bl_remove),
+};
+
+/*
+ * ubicom32bl_init
+ */
+static int __init ubicom32bl_init(void)
+{
+       return platform_driver_probe(&ubicom32bl_driver, ubicom32bl_probe);
+}
+module_init(ubicom32bl_init);
+
+/*
+ * ubicom32bl_exit
+ */
+static void __exit ubicom32bl_exit(void)
+{
+       platform_driver_unregister(&ubicom32bl_driver);
+}
+module_exit(ubicom32bl_exit);
+
+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
+MODULE_DESCRIPTION("Ubicom32 backlight driver");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcd.c b/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcd.c
new file mode 100644 (file)
index 0000000..e4f8c71
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * drivers/video/ubicom32lcd.c
+ *     LCD initilization code
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#include <asm/ip5000.h>
+#include <asm/gpio.h>
+#include <asm/ubicom32lcd.h>
+
+#include "ubicom32lcd.h"
+
+#define DRIVER_NAME                    "ubicom32lcd"
+
+struct ubicom32lcd_data {
+       const struct ubicom32lcd_panel  *panel;
+
+       int                             pin_cs;
+       int                             pin_rd;
+       int                             pin_rs;
+       int                             pin_wr;
+       int                             pin_reset;
+       struct ubicom32_io_port         *port_data;
+       int                             data_shift;
+};
+
+/*
+ * ubicom32lcd_write
+ *     Performs a write cycle on the bus (assumes CS asserted, RD & WR set)
+ */
+static void ubicom32lcd_write(struct ubicom32lcd_data *ud, int command, u16 data)
+{
+       if (command) {
+               UBICOM32_GPIO_SET_PIN_LOW(ud->pin_rs);
+       } else {
+               UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs);
+       }
+
+       asm volatile (
+               "or.4   4(%[port]), 4(%[port]), %[mask] \n\t"
+               "not.4  %[mask], %[mask]                \n\t"
+               "and.4  8(%[port]), 8(%[port]), %[mask] \n\t"
+               "or.4   8(%[port]), 8(%[port]), %[cmd]  \n\t"
+               :
+               : [port] "a" (ud->port_data),
+                 [mask] "d" (0xFFFF << ud->data_shift),
+                 [cmd] "d" (data << ud->data_shift)
+               : "cc"
+       );
+
+       UBICOM32_GPIO_SET_PIN_LOW(ud->pin_wr);
+
+       //ndelay(50);
+       udelay(1);
+
+       UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_wr);
+
+       udelay(1);
+       //ndelay(50);
+}
+
+/*
+ * ubicom32lcd_read_data
+ *     Performs a read cycle on the bus (assumes CS asserted, RD & WR set)
+ */
+static u16 ubicom32lcd_read_data(struct ubicom32lcd_data *ud)
+{
+       u32_t data;
+
+       UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs);
+
+       asm volatile (
+               "and.4  4(%[port]), 4(%[port]), %[mask]\n\t"
+               :
+               : [port] "a" (ud->port_data),
+                 [mask] "d" (~(0xFFFF << ud->data_shift))
+               : "cc"
+       );
+
+       UBICOM32_GPIO_SET_PIN_LOW(ud->pin_rd);
+
+       ndelay(300);
+
+       asm volatile (
+               "lsr.4  %[data], 12(%[port]), %[shamt]  \n\t"
+               "and.4  %[data], %[data], %[mask]       \n\t"
+               : [data] "=d" (data)
+               : [port] "a" (ud->port_data),
+                 [mask] "d" (0xFFFF),
+                 [shamt] "d" (ud->data_shift)
+               : "cc"
+       );
+
+       ndelay(200);
+
+       UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rd);
+
+       ndelay(500);
+
+       return data;
+}
+
+/*
+ * ubicom32lcd_execute
+ *     Executes a script for performing operations on the LCD (assumes CS set)
+ */
+static void ubicom32lcd_execute(struct ubicom32lcd_data *ud, const struct ubicom32lcd_step *script)
+{
+       while (1) {
+               switch (script->op) {
+               case LCD_STEP_CMD:
+                       ubicom32lcd_write(ud, 1, script->cmd);
+                       break;
+
+               case LCD_STEP_DATA:
+                       ubicom32lcd_write(ud, 0, script->data);
+                       break;
+
+               case LCD_STEP_CMD_DATA:
+                       ubicom32lcd_write(ud, 1, script->cmd);
+                       ubicom32lcd_write(ud, 0, script->data);
+                       break;
+
+               case LCD_STEP_SLEEP:
+                       udelay(script->data);
+                       break;
+
+               case LCD_STEP_DONE:
+                       return;
+               }
+               script++;
+       }
+}
+
+/*
+ * ubicom32lcd_goto
+ *     Places the gram pointer at a specific X, Y address
+ */
+static void ubicom32lcd_goto(struct ubicom32lcd_data *ud, int x, int y)
+{
+       ubicom32lcd_write(ud, 1, ud->panel->horz_reg);
+       ubicom32lcd_write(ud, 0, x);
+       ubicom32lcd_write(ud, 1, ud->panel->vert_reg);
+       ubicom32lcd_write(ud, 0, y);
+       ubicom32lcd_write(ud, 1, ud->panel->gram_reg);
+}
+
+/*
+ * ubicom32lcd_panel_init
+ *     Initializes the lcd panel.
+ */
+static int ubicom32lcd_panel_init(struct ubicom32lcd_data *ud)
+{
+       u16 id;
+
+       UBICOM32_GPIO_SET_PIN_LOW(ud->pin_reset);
+       UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_reset);
+       UBICOM32_GPIO_ENABLE(ud->pin_reset);
+
+       asm volatile (
+               "or.4   0x50(%[port]), 0x50(%[port]), %[mask]   \n\t"
+               "not.4  %[mask], %[mask]                        \n\t"
+               "and.4  0x04(%[port]), 0x04(%[port]), %[mask]   \n\t"
+               :
+               : [port] "a" (ud->port_data),
+                 [mask] "d" (0xFFFF << ud->data_shift)
+               : "cc"
+       );
+
+       UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs);
+       UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rd);
+       UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_wr);
+       UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_cs);
+
+       UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_rs);
+       UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_rd);
+       UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_wr);
+       UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_cs);
+
+       UBICOM32_GPIO_ENABLE(ud->pin_rs);
+       UBICOM32_GPIO_ENABLE(ud->pin_rd);
+       UBICOM32_GPIO_ENABLE(ud->pin_wr);
+       UBICOM32_GPIO_ENABLE(ud->pin_cs);
+
+       udelay(20);
+
+       UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_reset);
+
+       udelay(20);
+
+       UBICOM32_GPIO_SET_PIN_LOW(ud->pin_cs);
+
+       id = ubicom32lcd_read_data(ud);
+
+       /*
+        * We will try to figure out what kind of panel we have if we were not told.
+        */
+       if (!ud->panel) {
+               const struct ubicom32lcd_panel **p = ubicom32lcd_panels;
+               while (*p) {
+                       if ((*p)->id && ((*p)->id == id)) {
+                               break;
+                       }
+                       p++;
+               }
+               if (!*p) {
+                       printk(KERN_WARNING DRIVER_NAME ":Could not find compatible panel, id=%x\n", id);
+                       return -ENODEV;
+               }
+               ud->panel = *p;
+       }
+
+       /*
+        * Make sure panel ID matches if we were supplied a panel type
+        */
+       if (ud->panel->id && (ud->panel->id != id)) {
+               UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_cs);
+
+               return -ENODEV;
+       }
+
+       ubicom32lcd_execute(ud, ud->panel->init_seq);
+
+       ubicom32lcd_goto(ud, 0, 0);
+
+       UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_cs);
+       UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rd);
+       UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_wr);
+       UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs);
+
+       printk(KERN_INFO DRIVER_NAME ": Initialized panel %s\n", ud->panel->desc);
+
+       return 0;
+}
+
+/*
+ * ubicom32lcd_probe
+ */
+static int ubicom32lcd_probe(struct platform_device *pdev)
+{
+       const struct ubicom32lcd_platform_data *pdata = pdev->dev.platform_data;
+       struct ubicom32lcd_data *ud;
+       int retval;
+
+       /*
+        * Allocate our private data
+        */
+       ud = kzalloc(sizeof(struct ubicom32lcd_data), GFP_KERNEL);
+       if (!ud) {
+               return -ENOMEM;
+       }
+
+       if (pdata) {
+               ud->pin_cs = pdata->pin_cs;
+               ud->pin_rd = pdata->pin_rd;
+               ud->pin_wr = pdata->pin_wr;
+               ud->pin_rs = pdata->pin_rs;
+               ud->pin_reset = pdata->pin_reset;
+               ud->port_data = pdata->port_data;
+               ud->data_shift = pdata->data_shift;
+       } else {
+               /*
+                * Defaults
+                */
+               ud->pin_cs = GPIO_RD_4;
+               ud->pin_rd = GPIO_RD_5;
+               ud->pin_rs = GPIO_RD_3;
+               ud->pin_wr = GPIO_RD_2;
+               ud->pin_reset = GPIO_RD_7;
+               ud->port_data = (struct ubicom32_io_port *)RI;
+               ud->data_shift = 0;
+       }
+
+       /*
+        * Initialize the display
+        */
+       retval = ubicom32lcd_panel_init(ud);
+       if (retval) {
+               kfree(ud);
+               return retval;
+       }
+
+       printk(KERN_INFO DRIVER_NAME ": LCD initialized\n");
+
+       return 0;
+}
+
+/*
+ * ubicom32lcd_remove
+ */
+static int __exit ubicom32lcd_remove(struct platform_device *pdev)
+{
+       struct ubicom32lcd_data *ud = platform_get_drvdata(pdev);
+
+       kfree(ud);
+
+       return 0;
+}
+
+static struct platform_driver ubicom32lcd_driver = {
+       .probe          = ubicom32lcd_probe,
+       .remove         = ubicom32lcd_remove,
+
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+
+       .remove = __exit_p(ubicom32lcd_remove),
+};
+
+static struct platform_device *ubicom32lcd_device;
+
+/*
+ * ubicom32lcd_init
+ */
+static int __init ubicom32lcd_init(void)
+{
+       int res;
+
+       res = platform_driver_register(&ubicom32lcd_driver);
+       if (res == 0) {
+               ubicom32lcd_device = platform_device_alloc(DRIVER_NAME, 0);
+               if (ubicom32lcd_device) {
+                       res = platform_device_add(ubicom32lcd_device);
+               } else {
+                       res = -ENOMEM;
+               }
+               if (res) {
+                       platform_device_put(ubicom32lcd_device);
+                       platform_driver_unregister(&ubicom32lcd_driver);
+               }
+       }
+       return res;
+}
+module_init(ubicom32lcd_init);
+
+/*
+ * ubicom32lcd_exit
+ */
+static void __exit ubicom32lcd_exit(void)
+{
+       platform_device_unregister(ubicom32lcd_device);
+       platform_driver_unregister(&ubicom32lcd_driver);
+}
+module_exit(ubicom32lcd_exit);
+
+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
+MODULE_DESCRIPTION("Ubicom32 LCD driver");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcd.h b/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcd.h
new file mode 100644 (file)
index 0000000..07650ba
--- /dev/null
@@ -0,0 +1,546 @@
+/*
+ * ubicom32lcd.h
+ *     Ubicom32 lcd panel drivers
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * This Ubicom32 library 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 Ubicom32 library 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _UBICOM32LCD_H_
+#define _UBICOM32LCD_H_
+
+enum ubicom32lcd_op {
+       /*
+        * Sleep for (data) ms
+        */
+       LCD_STEP_SLEEP,
+
+       /*
+        * Execute write of command
+        */
+       LCD_STEP_CMD,
+
+       /*
+        * Execute write of data
+        */
+       LCD_STEP_DATA,
+
+       /*
+        * Execute write of command/data
+        */
+       LCD_STEP_CMD_DATA,
+
+       /*
+        * Script done
+        */
+       LCD_STEP_DONE,
+};
+
+struct ubicom32lcd_step {
+       enum ubicom32lcd_op             op;
+       u16                             cmd;
+       u16                             data;
+};
+
+struct ubicom32lcd_panel {
+       const struct ubicom32lcd_step   *init_seq;
+       const char                      *desc;
+
+       u32                             xres;
+       u32                             yres;
+       u32                             stride;
+       u32                             flags;
+
+       u16                             id;
+       u16                             horz_reg;
+       u16                             vert_reg;
+       u16                             gram_reg;
+};
+
+#ifdef CONFIG_LCD_UBICOM32_CFAF240320KTTS
+static const struct ubicom32lcd_step cfaf240320ktts_init_0[] = {
+       {LCD_STEP_CMD_DATA, 0x0001, 0x0000,}, // Driver Output Control Register (R01h)          Page 14, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0002, 0x0700,}, // LCD Driving Waveform Control (R02h)            Page 15, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0003, 0x50A0,}, // Entry Mode (R03h)                              0 degrees
+       {LCD_STEP_CMD_DATA, 0x0004, 0x0000,}, // Scaling Control register (R04h)                Page 16, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0008, 0x0207,}, // Display Control 2 (R08h)                       Page 17, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0009, 0x0000,}, // Display Control 3 (R09h)                       Page 18, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x000A, 0x0000,}, // Frame Cycle Control (R0Ah)                     Page 19, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x000C, 0x0000,}, // External Display Interface Control 1 (R0Ch)    Page 20, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x000D, 0x0000,}, // Frame Maker Position (R0Dh)                    Page 21, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x000F, 0x0000,}, // External Display Interface Control 2 (R0Fh)    Page 21, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0010, 0x0000,}, // Power Control 1 (R10h)                         Page 22, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h)                         Page 23, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0012, 0x0000,}, // Power Control 3 (R12h)                         Page 24, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0013, 0x0000,}, // Power Control 4 (R13h)                         Page 25, SPFD5408B Datasheet
+       {LCD_STEP_SLEEP, 0, 200},
+       {LCD_STEP_CMD_DATA, 0x0007, 0x0101,}, // Display Control (R07h)                         Page 16, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0010, 0x12B0,}, // Power Control 1 (R10h)                         Page 22, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h)                         Page 23, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0012, 0x01BB,}, // Power Control 3 (R12h)                         Page 24, SPFD5408B Datasheet
+       {LCD_STEP_SLEEP, 0, 50},
+       {LCD_STEP_CMD_DATA, 0x0013, 0x1300,}, // Power Control 4 (R13h)                         Page 25, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0029, 0x0010,}, // NVM read data 2 (R29h)                         Page 30, SPFD5408B Datasheet
+       {LCD_STEP_SLEEP, 0, 50},
+       {LCD_STEP_CMD_DATA, 0x0030, 0x000A,}, // Gamma Control 1                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0031, 0x1326,}, // Gamma Control 2                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0032, 0x0A29,}, // Gamma Control 3                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0033, 0x290A,}, // Gamma Control 4                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0034, 0x2613,}, // Gamma Control 5                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0035, 0x0A0A,}, // Gamma Control 6                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0036, 0x1E03,}, // Gamma Control 7                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0037, 0x031E,}, // Gamma Control 8                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0038, 0x0706,}, // Gamma Control 9                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0039, 0x0303,}, // Gamma Control 10                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x003A, 0x0E04,}, // Gamma Control 11                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x003B, 0x0E01,}, // Gamma Control 12                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x003C, 0x010E,}, // Gamma Control 13                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x003D, 0x040E,}, // Gamma Control 14                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x003E, 0x0303,}, // Gamma Control 15                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x003F, 0x0607,}, // Gamma Control 16                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0050, 0x0000,}, // Window Horizontal RAM Address Start (R50h)     Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0051, 0x00EF,}, // Window Horizontal RAM Address End (R51h)       Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0052, 0x0000,}, // Window Vertical RAM Address Start (R52h)       Page 33, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0053, 0x013F,}, // Window Vertical RAM Address End (R53h)         Page 33, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0060, 0x2700,}, // Driver Output Control (R60h)                   Page 33, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0061, 0x0001,}, // Driver Output Control (R61h)                   Page 35, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x006A, 0x0000,}, // Vertical Scroll Control (R6Ah)                 Page 35, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0080, 0x0000,}, // Display Position - Partial Display 1 (R80h)    Page 35, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0081, 0x0000,}, // RAM Address Start - Partial Display 1 (R81h)   Page 35, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0082, 0x0000,}, // RAM Address End - Partial Display 1 (R82h)     Page 36, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0083, 0x0000,}, // Display Position - Partial Display 2 (R83h)    Page 36, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0084, 0x0000,}, // RAM Address Start - Partial Display 2 (R84h)   Page 36, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0085, 0x0000,}, // RAM Address End - Partial Display 2 (R85h)     Page 36, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0090, 0x0010,}, // Panel Interface Control 1 (R90h)               Page 36, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0092, 0x0000,}, // Panel Interface Control 2 (R92h)               Page 37, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0093, 0x0103,}, // Panel Interface control 3 (R93h)               Page 38, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0095, 0x0210,}, // Panel Interface control 4 (R95h)               Page 38, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0097, 0x0000,}, // Panel Interface Control 5 (R97h)               Page 40, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0098, 0x0000,}, // Panel Interface Control 6 (R98h)               Page 41, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0007, 0x0173,}, // Display Control (R07h)                         Page 16, SPFD5408B Datasheet
+       {LCD_STEP_DONE, 0, 0},
+};
+
+const struct ubicom32lcd_panel cfaf240320ktts_0 = {
+       .desc           = "CFAF240320KTTS",
+       .init_seq       = cfaf240320ktts_init_0,
+       .horz_reg       = 0x20,
+       .vert_reg       = 0x21,
+       .gram_reg       = 0x22,
+       .xres           = 240,
+       .yres           = 320,
+       .stride         = 240,
+       .id             = 0x5408,
+};
+#endif
+
+#ifdef CONFIG_LCD_UBICOM32_CFAF240320KTTS_180
+static const struct ubicom32lcd_step cfaf240320ktts_init_180[] = {
+       {LCD_STEP_CMD_DATA, 0x0001, 0x0000,}, // Driver Output Control Register (R01h)          Page 14, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0002, 0x0700,}, // LCD Driving Waveform Control (R02h)            Page 15, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0003, 0x5000,}, // Entry Mode (R03h)                              180 degrees
+       {LCD_STEP_CMD_DATA, 0x0004, 0x0000,}, // Scaling Control register (R04h)                Page 16, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0008, 0x0207,}, // Display Control 2 (R08h)                       Page 17, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0009, 0x0000,}, // Display Control 3 (R09h)                       Page 18, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x000A, 0x0000,}, // Frame Cycle Control (R0Ah)                     Page 19, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x000C, 0x0000,}, // External Display Interface Control 1 (R0Ch)    Page 20, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x000D, 0x0000,}, // Frame Maker Position (R0Dh)                    Page 21, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x000F, 0x0000,}, // External Display Interface Control 2 (R0Fh)    Page 21, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0010, 0x0000,}, // Power Control 1 (R10h)                         Page 22, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h)                         Page 23, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0012, 0x0000,}, // Power Control 3 (R12h)                         Page 24, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0013, 0x0000,}, // Power Control 4 (R13h)                         Page 25, SPFD5408B Datasheet
+       {LCD_STEP_SLEEP, 0, 200},
+       {LCD_STEP_CMD_DATA, 0x0007, 0x0101,}, // Display Control (R07h)                         Page 16, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0010, 0x12B0,}, // Power Control 1 (R10h)                         Page 22, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h)                         Page 23, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0012, 0x01BB,}, // Power Control 3 (R12h)                         Page 24, SPFD5408B Datasheet
+       {LCD_STEP_SLEEP, 0, 50},
+       {LCD_STEP_CMD_DATA, 0x0013, 0x1300,}, // Power Control 4 (R13h)                         Page 25, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0029, 0x0010,}, // NVM read data 2 (R29h)                         Page 30, SPFD5408B Datasheet
+       {LCD_STEP_SLEEP, 0, 50},
+       {LCD_STEP_CMD_DATA, 0x0030, 0x000A,}, // Gamma Control 1                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0031, 0x1326,}, // Gamma Control 2                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0032, 0x0A29,}, // Gamma Control 3                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0033, 0x290A,}, // Gamma Control 4                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0034, 0x2613,}, // Gamma Control 5                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0035, 0x0A0A,}, // Gamma Control 6                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0036, 0x1E03,}, // Gamma Control 7                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0037, 0x031E,}, // Gamma Control 8                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0038, 0x0706,}, // Gamma Control 9                                Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0039, 0x0303,}, // Gamma Control 10                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x003A, 0x0E04,}, // Gamma Control 11                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x003B, 0x0E01,}, // Gamma Control 12                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x003C, 0x010E,}, // Gamma Control 13                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x003D, 0x040E,}, // Gamma Control 14                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x003E, 0x0303,}, // Gamma Control 15                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x003F, 0x0607,}, // Gamma Control 16                               Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0050, 0x0000,}, // Window Horizontal RAM Address Start (R50h)     Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0051, 0x00EF,}, // Window Horizontal RAM Address End (R51h)       Page 32, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0052, 0x0000,}, // Window Vertical RAM Address Start (R52h)       Page 33, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0053, 0x013F,}, // Window Vertical RAM Address End (R53h)         Page 33, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0060, 0x2700,}, // Driver Output Control (R60h)                   Page 33, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0061, 0x0001,}, // Driver Output Control (R61h)                   Page 35, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x006A, 0x0000,}, // Vertical Scroll Control (R6Ah)                 Page 35, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0080, 0x0000,}, // Display Position - Partial Display 1 (R80h)    Page 35, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0081, 0x0000,}, // RAM Address Start - Partial Display 1 (R81h)   Page 35, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0082, 0x0000,}, // RAM Address End - Partial Display 1 (R82h)     Page 36, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0083, 0x0000,}, // Display Position - Partial Display 2 (R83h)    Page 36, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0084, 0x0000,}, // RAM Address Start - Partial Display 2 (R84h)   Page 36, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0085, 0x0000,}, // RAM Address End - Partial Display 2 (R85h)     Page 36, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0090, 0x0010,}, // Panel Interface Control 1 (R90h)               Page 36, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0092, 0x0000,}, // Panel Interface Control 2 (R92h)               Page 37, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0093, 0x0103,}, // Panel Interface control 3 (R93h)               Page 38, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0095, 0x0210,}, // Panel Interface control 4 (R95h)               Page 38, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0097, 0x0000,}, // Panel Interface Control 5 (R97h)               Page 40, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0098, 0x0000,}, // Panel Interface Control 6 (R98h)               Page 41, SPFD5408B Datasheet
+       {LCD_STEP_CMD_DATA, 0x0007, 0x0173,}, // Display Control (R07h)                         Page 16, SPFD5408B Datasheet
+       {LCD_STEP_DONE, 0, 0},
+};
+
+const struct ubicom32lcd_panel cfaf240320ktts_180 = {
+       .desc           = "CFAF240320KTTS 180",
+       .init_seq       = cfaf240320ktts_init_180,
+       .horz_reg       = 0x20,
+       .vert_reg       = 0x21,
+       .gram_reg       = 0x22,
+       .xres           = 240,
+       .yres           = 320,
+       .stride         = 240,
+       .id             = 0x5408,
+};
+#endif
+
+#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_P
+static const struct ubicom32lcd_step tft2n0369ep_init[] = {
+       {LCD_STEP_CMD_DATA, 0x0028, 0x0006},
+       {LCD_STEP_CMD_DATA, 0x0000, 0x0001},
+       {LCD_STEP_SLEEP, 0, 15},
+       {LCD_STEP_CMD_DATA, 0x002B, 0x9532},
+       {LCD_STEP_CMD_DATA, 0x0003, 0xAAAC},
+       {LCD_STEP_CMD_DATA, 0x000C, 0x0002},
+       {LCD_STEP_CMD_DATA, 0x000D, 0x000A},
+       {LCD_STEP_CMD_DATA, 0x000E, 0x2C00},
+       {LCD_STEP_CMD_DATA, 0x001E, 0x00AA},
+       {LCD_STEP_CMD_DATA, 0x0025, 0x8000},
+       {LCD_STEP_SLEEP, 0, 15},
+       {LCD_STEP_CMD_DATA, 0x0001, 0x2B3F},
+       {LCD_STEP_CMD_DATA, 0x0002, 0x0600},
+       {LCD_STEP_CMD_DATA, 0x0010, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0011, 0x6030},
+       {LCD_STEP_SLEEP, 0, 20},
+       {LCD_STEP_CMD_DATA, 0x0005, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0006, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0016, 0xEF1C},
+       {LCD_STEP_CMD_DATA, 0x0017, 0x0003},
+       {LCD_STEP_CMD_DATA, 0x0007, 0x0233},
+       {LCD_STEP_CMD_DATA, 0x000B, 0x5312},
+       {LCD_STEP_CMD_DATA, 0x000F, 0x0000},
+       {LCD_STEP_SLEEP, 0, 20},
+       {LCD_STEP_CMD_DATA, 0x0041, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0042, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0048, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0049, 0x013F},
+       {LCD_STEP_CMD_DATA, 0x0044, 0xEF00},
+       {LCD_STEP_CMD_DATA, 0x0045, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0046, 0x013F},
+       {LCD_STEP_CMD_DATA, 0x004A, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x004B, 0x0000},
+       {LCD_STEP_SLEEP, 0, 20},
+       {LCD_STEP_CMD_DATA, 0x0030, 0x0707},
+       {LCD_STEP_CMD_DATA, 0x0031, 0x0704},
+       {LCD_STEP_CMD_DATA, 0x0032, 0x0204},
+       {LCD_STEP_CMD_DATA, 0x0033, 0x0201},
+       {LCD_STEP_CMD_DATA, 0x0034, 0x0203},
+       {LCD_STEP_CMD_DATA, 0x0035, 0x0204},
+       {LCD_STEP_CMD_DATA, 0x0036, 0x0204},
+       {LCD_STEP_CMD_DATA, 0x0037, 0x0502},
+       {LCD_STEP_CMD_DATA, 0x003A, 0x0302},
+       {LCD_STEP_CMD_DATA, 0x003B, 0x0500},
+       {LCD_STEP_SLEEP, 0, 20},
+       {LCD_STEP_CMD_DATA, 0x0044, 239 << 8 | 0},
+       {LCD_STEP_CMD_DATA, 0x0045, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0046, 319},
+       {LCD_STEP_DONE, 0, 0},
+};
+
+const struct ubicom32lcd_panel tft2n0369ep = {
+       .desc           = "TFT2N0369E-Portrait",
+       .init_seq       = tft2n0369ep_init,
+       .horz_reg       = 0x4e,
+       .vert_reg       = 0x4f,
+       .gram_reg       = 0x22,
+       .xres           = 240,
+       .yres           = 320,
+       .stride         = 240,
+       .id             = 0x8989,
+};
+#endif
+
+#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_L
+static const struct ubicom32lcd_step tft2n0369e_init[] = {
+       {LCD_STEP_CMD_DATA, 0x0028, 0x0006},
+       {LCD_STEP_CMD_DATA, 0x0000, 0x0001},
+       {LCD_STEP_SLEEP, 0, 15},
+       {LCD_STEP_CMD_DATA, 0x002B, 0x9532},
+       {LCD_STEP_CMD_DATA, 0x0003, 0xAAAC},
+       {LCD_STEP_CMD_DATA, 0x000C, 0x0002},
+       {LCD_STEP_CMD_DATA, 0x000D, 0x000A},
+       {LCD_STEP_CMD_DATA, 0x000E, 0x2C00},
+       {LCD_STEP_CMD_DATA, 0x001E, 0x00AA},
+       {LCD_STEP_CMD_DATA, 0x0025, 0x8000},
+       {LCD_STEP_SLEEP, 0, 15},
+       {LCD_STEP_CMD_DATA, 0x0001, 0x2B3F},
+       {LCD_STEP_CMD_DATA, 0x0002, 0x0600},
+       {LCD_STEP_CMD_DATA, 0x0010, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0011, 0x60A8},
+       {LCD_STEP_SLEEP, 0, 20},
+       {LCD_STEP_CMD_DATA, 0x0005, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0006, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0016, 0xEF1C},
+       {LCD_STEP_CMD_DATA, 0x0017, 0x0003},
+       {LCD_STEP_CMD_DATA, 0x0007, 0x0233},
+       {LCD_STEP_CMD_DATA, 0x000B, 0x5312},
+       {LCD_STEP_CMD_DATA, 0x000F, 0x0000},
+       {LCD_STEP_SLEEP, 0, 20},
+       {LCD_STEP_CMD_DATA, 0x0041, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0042, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0048, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0049, 0x013F},
+       {LCD_STEP_CMD_DATA, 0x0044, 0xEF00},
+       {LCD_STEP_CMD_DATA, 0x0045, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0046, 0x013F},
+       {LCD_STEP_CMD_DATA, 0x004A, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x004B, 0x0000},
+       {LCD_STEP_SLEEP, 0, 20},
+       {LCD_STEP_CMD_DATA, 0x0030, 0x0707},
+       {LCD_STEP_CMD_DATA, 0x0031, 0x0704},
+       {LCD_STEP_CMD_DATA, 0x0032, 0x0204},
+       {LCD_STEP_CMD_DATA, 0x0033, 0x0201},
+       {LCD_STEP_CMD_DATA, 0x0034, 0x0203},
+       {LCD_STEP_CMD_DATA, 0x0035, 0x0204},
+       {LCD_STEP_CMD_DATA, 0x0036, 0x0204},
+       {LCD_STEP_CMD_DATA, 0x0037, 0x0502},
+       {LCD_STEP_CMD_DATA, 0x003A, 0x0302},
+       {LCD_STEP_CMD_DATA, 0x003B, 0x0500},
+       {LCD_STEP_SLEEP, 0, 20},
+       {LCD_STEP_CMD_DATA, 0x0044, 239 << 8 | 0},
+       {LCD_STEP_CMD_DATA, 0x0045, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0046, 319},
+       {LCD_STEP_DONE, 0, 0},
+};
+
+const struct ubicom32lcd_panel tft2n0369e = {
+       .desc           = "TFT2N0369E-Landscape",
+       .init_seq       = tft2n0369e_init,
+       .horz_reg       = 0x4e,
+       .vert_reg       = 0x4f,
+       .gram_reg       = 0x22,
+       .xres           = 320,
+       .yres           = 240,
+       .stride         = 320,
+       .id             = 0x8989,
+};
+#endif
+
+#ifdef CONFIG_LCD_UBICOM32_CFAF240400D
+static const struct ubicom32lcd_step cfaf240400d_init[] = {
+       {LCD_STEP_CMD_DATA, 0x0606, 0x0000},    // Pin Control (R606h)          // Page 41 of SPFD5420A Datasheet
+       {LCD_STEP_SLEEP, 0, 50},
+       {LCD_STEP_CMD_DATA, 0x0007, 0x0001},    // Display Control 1 (R007h)    // Page 16 of SPFD5420A Datasheet
+       {LCD_STEP_SLEEP, 0, 50},
+       {LCD_STEP_CMD_DATA, 0x0110, 0x0001},    // Power Control 6(R110h)       // Page 30 of SPFD5420A Datasheet
+       {LCD_STEP_SLEEP, 0, 50},
+       {LCD_STEP_CMD_DATA, 0x0100, 0x17B0},    // Power Control 1 (R100h)      // Page 26 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0101, 0x0147},    // Power Control 2 (R101h)      // Page 27 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0102, 0x019D},    // Power Control 3 (R102h)      // Page 28 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0103, 0x3600},    // Power Control 4 (R103h)      // Page 29 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0281, 0x0010},    // NVM read data 2 (R281h)      // Page 34 of SPFD5420A Datasheet
+       {LCD_STEP_SLEEP, 0, 50},
+       {LCD_STEP_CMD_DATA, 0x0102, 0x01BD},    // Power Control 3 (R102h)      // Page 28 of SPFD5420A Datasheet
+       {LCD_STEP_SLEEP, 0, 50},
+
+       //--------------- Power control 1~6 ---------------//
+       {LCD_STEP_CMD_DATA, 0x0100, 0x16B0},    // Power Control 1 (R100h)      // Page 26 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0101, 0x0147},    // Power Control 2 (R101h)      // Page 27 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0102, 0x01BD},    // Power Control 3 (R102h)      // Page 28 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0103, 0x2d00},    // Power Control 4 (R103h)      // Page 29 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0107, 0x0000},    // Power Control 5 (R107h)      // Page 30 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0110, 0x0001},    // Power Control 6(R110h)       // Page 30 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0280, 0x0000},    // NVM read data 1 (R280h)      // Page 33 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0281, 0x0006},    // NVM read data 2 (R281h)      // Page 34 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0282, 0x0000},    // NVM read data 3 (R282h)      // Page 34 of SPFD5420A Datasheet
+
+       //------- Gamma 2.2 control (R300h to R30Fh) ------//
+       {LCD_STEP_CMD_DATA, 0x0300, 0x0101},
+       {LCD_STEP_CMD_DATA, 0x0301, 0x0b27},
+       {LCD_STEP_CMD_DATA, 0x0302, 0x132a},
+       {LCD_STEP_CMD_DATA, 0x0303, 0x2a13},
+       {LCD_STEP_CMD_DATA, 0x0304, 0x270b},
+       {LCD_STEP_CMD_DATA, 0x0305, 0x0101},
+       {LCD_STEP_CMD_DATA, 0x0306, 0x1205},
+       {LCD_STEP_CMD_DATA, 0x0307, 0x0512},
+       {LCD_STEP_CMD_DATA, 0x0308, 0x0005},
+       {LCD_STEP_CMD_DATA, 0x0309, 0x0003},
+       {LCD_STEP_CMD_DATA, 0x030A, 0x0f04},
+       {LCD_STEP_CMD_DATA, 0x030B, 0x0f00},
+       {LCD_STEP_CMD_DATA, 0x030C, 0x000f},
+       {LCD_STEP_CMD_DATA, 0x030D, 0x040f},
+       {LCD_STEP_CMD_DATA, 0x030E, 0x0300},
+       {LCD_STEP_CMD_DATA, 0x030F, 0x0500},
+
+       {LCD_STEP_CMD_DATA, 0x0400, 0x3500},    // Base Image Number of Line (R400h)            // Page 36 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0401, 0x0001},    // Base Image Display Control (R401h)           // Page 39 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0404, 0x0000},    // Based Image Vertical Scroll Control (R404h)  // Page 40 of SPFD5420A Datasheet
+
+       //--------------- Normal set ---------------//
+       {LCD_STEP_CMD_DATA, 0x0000, 0x0000},    // ID Read Register (R000h)                     // Page 13 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0001, 0x0100},    // Driver Output Control Register (R001h)       // Page 14 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0002, 0x0100},    // LCD Driving Waveform Control (R002h)         // Page 14 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0003, 0x1030},    // Entry Mode (R003h)                           // Page 15 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0006, 0x0000},    // Display Control 1 (R007h)                    // Page 16 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0008, 0x0808},    // Display Control 2 (R008h)                    // Page 17 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0009, 0x0001},    // Display Control 3 (R009h)                    // Page 18 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x000B, 0x0010},    // Low Power Control (R00Bh)                    // Page 19 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x000C, 0x0000},    // External Display Interface Control 1 (R00Ch) // Page 19 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x000F, 0x0000},    // External Display Interface Control 2 (R00Fh) // Page 20 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0007, 0x0001},    // Display Control 1 (R007h)                    // Page 16 of SPFD5420A Datasheet
+
+       //--------------- Panel interface control 1~6 ---------------//
+       {LCD_STEP_CMD_DATA, 0x0010, 0x0012},    // Panel Interface Control 1 (R010h)            // Page 20 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0011, 0x0202},    // Panel Interface Control 2 (R011h)            // Page 21 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0012, 0x0300},    // Panel Interface control 3 (R012h)            // Page 22 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0020, 0x021E},    // Panel Interface control 4 (R020h)            // Page 22 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0021, 0x0202},    // Panel Interface Control 5 (021Rh)            // Page 24 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0022, 0x0100},    // Panel Interface Control 6 (R022h)            // Page 25 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0090, 0x8000},    // Frame Marker Control (R090h)                 // Page 25 of SPFD5420A Datasheet
+
+       //--------------- Partial display ---------------//
+       {LCD_STEP_CMD_DATA, 0x0210, 0x0000},    // Window Horizontal RAM Address Start (R210h)  // Page 35 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0211, 0x00EF},    // Window Horziontal RAM Address End (R211h)    // Page 35 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0212, 0x0000},    // Window Vertical RAM Address Start (R212h)    // Page 35 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0213, 0x018F},    // Window Vertical RAM Address End (R213h)      // Page 35 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0500, 0x0000},    // Display Position - Partial Display 1 (R500h) // Page 40 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0501, 0x0000},    // RAM Address Start - Partial Display 1 (R501h)// Page 40 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0502, 0x0000},    // RAM Address End - Partail Display 1 (R502h)  // Page 40 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0503, 0x0000},    // Display Position - Partial Display 2 (R503h) // Page 40 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0504, 0x0000},    // RAM Address Start . Partial Display 2 (R504h)// Page 41 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0505, 0x0000},    // RAM Address End . Partial Display 2 (R505h)  // Page 41 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0606, 0x0000},    // Pin Control (R606h)                          // Page 41 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x06F0, 0x0000},    // NVM Access Control (R6F0h)                   // Page 41 of SPFD5420A Datasheet
+       {LCD_STEP_CMD_DATA, 0x0007, 0x0173},    // Display Control 1 (R007h)                    // Page 16 of SPFD5420A Datasheet
+       {LCD_STEP_SLEEP, 0, 50},
+       {LCD_STEP_CMD_DATA, 0x0007, 0x0171},    // Display Control 1 (R007h)                    // Page 16 of SPFD5420A Datasheet
+       {LCD_STEP_SLEEP, 0, 10},
+       {LCD_STEP_CMD_DATA, 0x0007, 0x0173},    // Display Control 1 (R007h)                    // Page 16 of SPFD5420A Datasheet
+       {LCD_STEP_DONE, 0, 0},
+};
+
+const struct ubicom32lcd_panel cfaf240400d = {
+       .desc           = "CFAF240400D",
+       .init_seq       = cfaf240400d_init,
+       .horz_reg       = 0x0200,
+       .vert_reg       = 0x0201,
+       .gram_reg       = 0x0202,
+       .xres           = 240,
+       .yres           = 400,
+       .stride         = 240,
+       .id             = 0x5420,
+};
+#endif
+
+#ifdef CONFIG_LCD_UBICOM32_CFAF240400F
+static const struct ubicom32lcd_step cfaf320240f_init[] = {
+       {LCD_STEP_CMD_DATA, 0x0028, 0x0006},    // VCOM OTP                             Page 55-56 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x0000, 0x0001},    // start Oscillator                     Page 36 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x0010, 0x0000},    // Sleep mode                           Page 49 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x0001, 0x32EF},    // Driver Output Control                Page 36-39 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x0002, 0x0600},    // LCD Driving Waveform Control         Page 40-42 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x0003, 0x6A38},    // Power Control 1                      Page 43-44 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x0011, 0x6870},    // Entry Mode                           Page 50-52 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0X000F, 0x0000},    // Gate Scan Position                   Page 49 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0X000B, 0x5308},    // Frame Cycle Control                  Page 45 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x000C, 0x0003},    // Power Control 2                      Page 47 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x000D, 0x000A},    // Power Control 3                      Page 48 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x000E, 0x2E00},    // Power Control 4                      Page 48 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x001E, 0x00BE},    // Power Control 5                      Page 53 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x0025, 0x8000},    // Frame Frequency Control              Page 53 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x0026, 0x7800},    // Analog setting                       Page 54 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x004E, 0x0000},    // Ram Address Set                      Page 58 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x004F, 0x0000},    // Ram Address Set                      Page 58 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x0012, 0x08D9},    // Sleep mode                           Page 49 of SSD2119 datasheet
+
+       // Gamma Control (R30h to R3Bh) -- Page 56 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x0030, 0x0000},
+       {LCD_STEP_CMD_DATA, 0x0031, 0x0104},
+       {LCD_STEP_CMD_DATA, 0x0032, 0x0100},
+       {LCD_STEP_CMD_DATA, 0x0033, 0x0305},
+       {LCD_STEP_CMD_DATA, 0x0034, 0x0505},
+       {LCD_STEP_CMD_DATA, 0x0035, 0x0305},
+       {LCD_STEP_CMD_DATA, 0x0036, 0x0707},
+       {LCD_STEP_CMD_DATA, 0x0037, 0x0300},
+       {LCD_STEP_CMD_DATA, 0x003A, 0x1200},
+       {LCD_STEP_CMD_DATA, 0x003B, 0x0800},
+
+       {LCD_STEP_CMD_DATA, 0x0007, 0x0033},    // Display Control                       Page 45 of SSD2119 datasheet
+
+       {LCD_STEP_CMD_DATA, 0x0044, 0xEF00},    // Vertical RAM address position         Page 57 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x0045, 0x0000},    // Horizontal RAM address position       Page 57 of SSD2119 datasheet
+       {LCD_STEP_CMD_DATA, 0x0046, 0x013F},    // Horizontal RAM address position       Page 57 of SSD2119 datasheet
+
+       {LCD_STEP_SLEEP, 0, 150},
+
+       {LCD_STEP_DONE, 0, 0},
+};
+
+const struct ubicom32lcd_panel cfaf320240f = {
+       .desc           = "CFAF320240F",
+       .init_seq       = cfaf320240f_init,
+       .horz_reg       = 0x4e,
+       .vert_reg       = 0x4f,
+       .gram_reg       = 0x22,
+       .xres           = 320,
+       .yres           = 240,
+       .stride         = 320,
+       .id             = 0x9919,
+};
+#endif
+
+const struct ubicom32lcd_panel *ubicom32lcd_panels[] = {
+#ifdef CONFIG_LCD_UBICOM32_CFAF240400KTTS_180
+       &cfaf240320ktts_180,
+#endif
+#ifdef CONFIG_LCD_UBICOM32_CFAF240400KTTS
+       &cfaf240320ktts_0,
+#endif
+#ifdef CONFIG_LCD_UBICOM32_CFAF240400D
+       &cfaf240400d,
+#endif
+#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_P
+       &tft2n0369ep,
+#endif
+#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_L
+       &tft2n0369e,
+#endif
+#ifdef CONFIG_LCD_UBICOM32_CFAF240400F
+       &cfaf320240f,
+#endif
+       NULL,
+};
+
+#endif
diff --git a/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcdpower.c b/target/linux/ubicom32/files/drivers/video/backlight/ubicom32lcdpower.c
new file mode 100644 (file)
index 0000000..6aeed43
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * drivers/video/backlight/ubicom32lcdpowerpower.c
+ *     LCD power driver for the Ubicom32 platform
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/lcd.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+
+#include <asm/ubicom32lcdpower.h>
+#include <asm/ip5000.h>
+
+#define DRIVER_NAME                    "ubicom32lcdpower"
+
+struct ubicom32lcdpower_data {
+       /*
+        * Pointer to the platform data structure.  Keep this around since we need values
+        * from it to set the backlight intensity.
+        */
+       const struct ubicom32lcdpower_platform_data     *pdata;
+
+       /*
+        * LCD device, we have to save this for use when we remove ourselves.
+        */
+       struct lcd_device                       *lcddev;
+};
+
+/*
+ * ubicom32lcdpower_set_power
+ */
+static int ubicom32lcdpower_set_power(struct lcd_device *ld, int power)
+{
+       struct ubicom32lcdpower_data *ud = (struct ubicom32lcdpower_data *)lcd_get_data(ld);
+       if (power == FB_BLANK_UNBLANK) {
+               gpio_direction_output(ud->pdata->vgh_gpio, ud->pdata->vgh_polarity);
+               return 0;
+       }
+
+       gpio_direction_output(ud->pdata->vgh_gpio, !ud->pdata->vgh_polarity);
+       return 0;
+}
+
+/*
+ * ubicom32lcdpower_get_power
+ */
+static int ubicom32lcdpower_get_power(struct lcd_device *ld)
+{
+       struct ubicom32lcdpower_data *ud = (struct ubicom32lcdpower_data *)lcd_get_data(ld);
+       int vgh = gpio_get_value(ud->pdata->vgh_gpio);
+       if ((vgh && ud->pdata->vgh_polarity) || (!vgh && !ud->pdata->vgh_polarity)) {
+               return 1;
+       }
+
+       return 0;
+}
+
+static struct lcd_ops ubicom32lcdpower_ops = {
+       .get_power = ubicom32lcdpower_get_power,
+       .set_power = ubicom32lcdpower_set_power,
+};
+
+/*
+ * ubicom32lcdpower_probe
+ */
+static int ubicom32lcdpower_probe(struct platform_device *pdev)
+{
+       const struct ubicom32lcdpower_platform_data *pdata = pdev->dev.platform_data;
+       struct ubicom32lcdpower_data *ud;
+       struct lcd_device *lcddev;
+       int retval;
+
+       /*
+        * Check to see if we have any platform data, if we don't have a LCD to control
+        */
+       if (!pdata) {
+               return -ENODEV;
+       }
+
+       /*
+        * Allocate our private data
+        */
+       ud = kzalloc(sizeof(struct ubicom32lcdpower_data), GFP_KERNEL);
+       if (!ud) {
+               return -ENOMEM;
+       }
+
+       ud->pdata = pdata;
+
+       /*
+        * Request our GPIOs
+        */
+       retval = gpio_request(pdata->vgh_gpio, "vgh");
+       if (retval) {
+               dev_err(&pdev->dev, "Failed to allocate vgh GPIO\n");
+               goto fail_gpio;
+       }
+
+       /*
+        * Register our lcd device
+        */
+       lcddev = lcd_device_register(DRIVER_NAME, &pdev->dev, ud, &ubicom32lcdpower_ops);
+       if (IS_ERR(lcddev)) {
+               retval = PTR_ERR(lcddev);
+               goto fail;
+       }
+
+       ud->lcddev = lcddev;
+       platform_set_drvdata(pdev, ud);
+
+       ubicom32lcdpower_set_power(lcddev, FB_BLANK_UNBLANK);
+
+       printk(KERN_INFO DRIVER_NAME ": LCD driver started\n");
+
+       return 0;
+
+fail:
+       gpio_free(pdata->vgh_gpio);
+
+fail_gpio:
+       platform_set_drvdata(pdev, NULL);
+       kfree(ud);
+       return retval;
+}
+
+/*
+ * ubicom32lcdpower_remove
+ */
+static int __exit ubicom32lcdpower_remove(struct platform_device *pdev)
+{
+       struct ubicom32lcdpower_data *ud = platform_get_drvdata(pdev);
+
+       lcd_device_unregister(ud->lcddev);
+       platform_set_drvdata(pdev, NULL);
+       kfree(ud);
+
+       return 0;
+}
+
+static struct platform_driver ubicom32lcdpower_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+
+       .remove = __exit_p(ubicom32lcdpower_remove),
+};
+
+/*
+ * ubicom32lcdpower_init
+ */
+static int __init ubicom32lcdpower_init(void)
+{
+       return platform_driver_probe(&ubicom32lcdpower_driver, ubicom32lcdpower_probe);
+}
+module_init(ubicom32lcdpower_init);
+
+/*
+ * ubicom32lcdpower_exit
+ */
+static void __exit ubicom32lcdpower_exit(void)
+{
+       platform_driver_unregister(&ubicom32lcdpower_driver);
+}
+module_exit(ubicom32lcdpower_exit);
+
+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
+MODULE_DESCRIPTION("Ubicom32 lcd power driver");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/drivers/video/ubicom32fb.c b/target/linux/ubicom32/files/drivers/video/ubicom32fb.c
new file mode 100644 (file)
index 0000000..4193560
--- /dev/null
@@ -0,0 +1,779 @@
+/*
+ * drivers/video/ubicom32fb.c
+ *     Ubicom32 frame buffer driver
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+/*
+ * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by
+ * Geert Uytterhoeven.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/ip5000.h>
+#include <asm/vdc_tio.h>
+#include <asm/ubicom32fb.h>
+
+#define DRIVER_NAME            "ubicom32fb"
+#define DRIVER_DESCRIPTION     "Ubicom32 frame buffer driver"
+
+#define PALETTE_ENTRIES_NO     16
+
+/*
+ * Option variables
+ *
+ * vram_size:  VRAM size in kilobytes, subject to alignment
+ */
+static int vram_size = 0;
+module_param(vram_size, int, 0);
+MODULE_PARM_DESC(vram, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment");
+static int init_value = 0;
+module_param(init_value, int, 0);
+MODULE_PARM_DESC(init, "Initial value of the framebuffer (16-bit number).");
+
+/*
+ * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in.
+ */
+static struct fb_fix_screeninfo ubicom32fb_fix = {
+       .id =           "Ubicom32",
+       .type =         FB_TYPE_PACKED_PIXELS,
+       .visual =       FB_VISUAL_TRUECOLOR,
+       .accel =        FB_ACCEL_UBICOM32,
+};
+
+/*
+ * Filled in at probe time when we find out what the hardware supports
+ */
+static struct fb_var_screeninfo ubicom32fb_var;
+
+/*
+ * Private data structure
+ */
+struct ubicom32fb_drvdata {
+       struct fb_info                  *fbinfo;
+       bool                            cmap_alloc;
+
+       /*
+        * The address of the framebuffer in memory
+        */
+       void                            *fb;
+       void                            *fb_aligned;
+
+       /*
+        * Total size of vram including alignment allowance
+        */
+       u32                             total_vram_size;
+
+       /*
+        * Interrupt to set when changing registers
+        */
+       u32                             vp_int;
+
+       /*
+        * Optional: Interrupt used by TIO to signal us
+        */
+       u32                             rx_int;
+
+       /*
+        * Base address of the regs for VDC_TIO
+        */
+       volatile struct vdc_tio_vp_regs *regs;
+
+       /*
+        * non-zero if we are in yuv mode
+        */
+       u8_t                            is_yuv;
+
+       /*
+        * Fake palette of 16 colors
+        */
+       u32                             pseudo_palette[PALETTE_ENTRIES_NO];
+
+       /*
+        * Wait queue and lock used to block when we need to wait
+        * for something to happen.
+        */
+       wait_queue_head_t               waitq;
+       struct mutex                    lock;
+
+};
+
+/*
+ * ubicom32fb_set_next_frame
+ *     Sets the next frame buffer to display
+ *
+ * if sync is TRUE then this function will block until the hardware
+ * acknowledges the change
+ */
+static inline void ubicom32fb_set_next_frame(struct ubicom32fb_drvdata *ud, void *fb, u8_t sync)
+{
+       ud->regs->next_frame_flags = ud->is_yuv ? VDCTIO_NEXT_FRAME_FLAG_YUV : 0;
+       ud->regs->next_frame = (void *)((u32_t)fb | 1);
+
+       /*
+        * If we have interrupts, then we can wait on it
+        */
+       if (ud->rx_int != -1) {
+               DEFINE_WAIT(wait);
+               unsigned long flags;
+
+               spin_lock_irqsave(&ud->lock, flags);
+               prepare_to_wait(&ud->waitq, &wait, TASK_INTERRUPTIBLE);
+               spin_unlock_irqrestore(&ud->lock, flags);
+               schedule();
+               finish_wait(&ud->waitq, &wait);
+               return;
+       }
+
+       /*
+        * No interrupt, we will just spin here
+        */
+       while (sync && ((u32_t)ud->regs->next_frame & 1));
+}
+
+/*
+ * ubicom32fb_send_command
+ *     Sends a command/data pair to the VDC
+ */
+static inline void ubicom32fb_send_command(struct ubicom32fb_drvdata *ud, u16 command, u8_t block)
+{
+       ud->regs->command = command;
+       ubicom32_set_interrupt(ud->vp_int);
+       while (block && ud->regs->command);
+}
+
+/*
+ * ubicom32fb_ioctl
+ *     Handles any ioctls sent to us
+ */
+static int ubicom32fb_ioctl(struct fb_info *fbi, unsigned int cmd,
+                      unsigned long arg)
+{
+       struct ubicom32fb_drvdata *ud = (struct ubicom32fb_drvdata *)fbi->par;
+       void __user *argp = (void __user *)arg;
+       int retval = -EFAULT;
+
+       switch (cmd) {
+       case UBICOM32FB_IOCTL_SET_NEXT_FRAME_SYNC:
+               // check alignment, return -EINVAL if necessary
+               ubicom32fb_set_next_frame(ud, argp, 1);
+               retval = 0;
+               break;
+
+       case UBICOM32FB_IOCTL_SET_NEXT_FRAME:
+               // check alignment, return -EINVAL if necessary
+               ubicom32fb_set_next_frame(ud, argp, 0);
+               retval = 0;
+               break;
+
+       case UBICOM32FB_IOCTL_SET_MODE:
+               if (!(ud->regs->caps & VDCTIO_CAPS_SUPPORTS_SCALING)) {
+                       break;
+               } else {
+                       struct ubicom32fb_mode mode;
+                       volatile struct vdc_tio_vp_regs *regs = ud->regs;
+                       u32_t flags = 0;
+
+                       if (copy_from_user(&mode, argp, sizeof(mode))) {
+                               break;
+                       }
+
+                       regs->x_in = mode.width;
+                       regs->y_in = mode.height;
+                       regs->x_out = regs->xres;
+                       regs->y_out = regs->yres;
+                       if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_SCAN_ORDER) {
+                               flags |= VDCTIO_SCALE_FLAG_YUV_SCAN_ORDER;
+                       }
+                       if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_BLOCK_ORDER) {
+                               flags |= VDCTIO_SCALE_FLAG_YUV_BLOCK_ORDER;
+                       }
+                       ud->is_yuv = mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV;
+                       if (ud->is_yuv) {
+                               flags |= VDCTIO_SCALE_FLAG_YUV;
+                       }
+                       if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_16_255) {
+                               flags |= VDCTIO_SCALE_FLAG_VRANGE_16_255;
+                       }
+                       if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_0_255) {
+                               flags |= VDCTIO_SCALE_FLAG_VRANGE_0_255;
+                       }
+                       if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_VSUB) {
+                               flags |= VDCTIO_SCALE_FLAG_VSUB;
+                       }
+                       if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_2_1) {
+                               flags |= VDCTIO_SCALE_FLAG_HSUB_2_1;
+                       }
+                       if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_1_1) {
+                               flags |= VDCTIO_SCALE_FLAG_HSUB_1_1;
+                       }
+                       if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_SCALE_ENABLE) {
+                               flags |= VDCTIO_SCALE_FLAG_ENABLE;
+                       }
+                       if (mode.next_frame) {
+                               flags |= VDCTIO_SCALE_FLAG_SET_FRAME_BUFFER;
+                               regs->next_frame = mode.next_frame;
+                       }
+
+                       regs->scale_flags = flags;
+                       ubicom32fb_send_command(ud, VDCTIO_COMMAND_SET_SCALE_MODE, 1);
+                       retval = 0;
+                       break;
+               }
+
+       default:
+               retval = -ENOIOCTLCMD;
+               break;
+       }
+
+       return retval;
+}
+
+/*
+ * ubicom32fb_interrupt
+ *     Called by the OS when the TIO has set the rx_int
+ */
+static irqreturn_t ubicom32fb_interrupt(int vec, void *appdata)
+{
+       struct ubicom32fb_drvdata *ud = (struct ubicom32fb_drvdata *)appdata;
+
+       spin_lock(&ud->lock);
+       if (waitqueue_active(&ud->waitq)) {
+               wake_up(&ud->waitq);
+       }
+       spin_unlock(&ud->lock);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * ubicom32fb_pan_display
+ *     Pans the display to a given location.  Supports only y direction panning.
+ */
+static int ubicom32fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
+{
+       struct ubicom32fb_drvdata *ud = (struct ubicom32fb_drvdata *)fbi->par;
+       void *new_addr;
+
+       /*
+        * Get the last y line that would be displayed.  Since we don't support YWRAP,
+        * it must be less than our virtual y size.
+        */
+       u32 lasty = var->yoffset + var->yres;
+       if (lasty > fbi->var.yres_virtual) {
+               /*
+                * We would fall off the end of our frame buffer if we panned here.
+                */
+               return -EINVAL;
+       }
+
+       if (var->xoffset) {
+               /*
+                * We don't support panning in the x direction
+                */
+               return -EINVAL;
+       }
+
+       /*
+        * Everything looks sane, go ahead and pan
+        *
+        * We have to calculate a new address for the VDC to look at
+        */
+       new_addr = ud->fb_aligned + (var->yoffset * fbi->fix.line_length);
+
+       /*
+        * Send down the command.  The buffer will switch at the next vertical blank
+        */
+       ubicom32fb_set_next_frame(ud, (void *)new_addr, 0);
+
+       return 0;
+}
+
+/*
+ * ubicom32fb_setcolreg
+ *     Sets a color in our virtual palette
+ */
+static int ubicom32fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi)
+{
+       u32 *palette = fbi->pseudo_palette;
+
+       if (regno >= PALETTE_ENTRIES_NO) {
+               return -EINVAL;
+       }
+
+       /*
+        * We only use 8 bits from each color
+        */
+       red >>= 8;
+       green >>= 8;
+       blue >>= 8;
+
+       /*
+        * Convert any grayscale values
+        */
+       if (fbi->var.grayscale) {
+               u16 gray = red + green + blue;
+               gray += (gray >> 2) + (gray >> 3) - (gray >> 7);
+               gray >>= 2;
+               if (gray > 255) {
+                       gray = 255;
+               }
+               red = gray;
+               blue = gray;
+               green = gray;
+       }
+
+       palette[regno] = (red << fbi->var.red.offset) | (green << fbi->var.green.offset) |
+                        (blue << fbi->var.blue.offset);
+
+       return 0;
+}
+
+/*
+ * ubicom32fb_mmap
+ */
+static int ubicom32fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+       struct ubicom32fb_drvdata *drvdata = (struct ubicom32fb_drvdata *)info->par;
+
+       vma->vm_start = (unsigned long)(drvdata->fb_aligned);
+
+       vma->vm_end = vma->vm_start + info->fix.smem_len;
+
+       /* For those who don't understand how mmap works, go read
+        *   Documentation/nommu-mmap.txt.
+        * For those that do, you will know that the VM_MAYSHARE flag
+        * must be set in the vma->vm_flags structure on noMMU
+        *   Other flags can be set, and are documented in
+        *   include/linux/mm.h
+        */
+
+       vma->vm_flags |=  VM_MAYSHARE | VM_SHARED;
+
+       return 0;
+}
+
+/*
+ * ubicom32fb_blank
+ */
+static int ubicom32fb_blank(int blank_mode, struct fb_info *fbi)
+{
+       return 0;
+#if 0
+       struct ubicom32fb_drvdata *drvdata = to_ubicom32fb_drvdata(fbi);
+
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:
+               /* turn on panel */
+               ubicom32fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
+               break;
+
+       case FB_BLANK_NORMAL:
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       case FB_BLANK_POWERDOWN:
+               /* turn off panel */
+               ubicom32fb_out_be32(drvdata, REG_CTRL, 0);
+       default:
+               break;
+
+       }
+       return 0; /* success */
+#endif
+}
+
+static struct fb_ops ubicom32fb_ops =
+{
+       .owner                  = THIS_MODULE,
+       .fb_pan_display         = ubicom32fb_pan_display,
+       .fb_setcolreg           = ubicom32fb_setcolreg,
+       .fb_blank               = ubicom32fb_blank,
+       .fb_mmap                = ubicom32fb_mmap,
+       .fb_ioctl               = ubicom32fb_ioctl,
+       .fb_fillrect            = cfb_fillrect,
+       .fb_copyarea            = cfb_copyarea,
+       .fb_imageblit           = cfb_imageblit,
+};
+
+/*
+ * ubicom32fb_release
+ */
+static int ubicom32fb_release(struct device *dev)
+{
+       struct ubicom32fb_drvdata *ud = dev_get_drvdata(dev);
+
+#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
+       //ubicom32fb_blank(VESA_POWERDOWN, &drvdata->info);
+#endif
+
+       unregister_framebuffer(ud->fbinfo);
+
+       if (ud->cmap_alloc) {
+               fb_dealloc_cmap(&ud->fbinfo->cmap);
+       }
+
+       if (ud->fb) {
+               kfree(ud->fb);
+       }
+
+       if (ud->rx_int != -1) {
+               free_irq(ud->rx_int, ud);
+       }
+
+       /*
+        * Turn off the display
+        */
+       //ubicom32fb_out_be32(drvdata, REG_CTRL, 0);
+       //iounmap(drvdata->regs);
+
+       framebuffer_release(ud->fbinfo);
+       dev_set_drvdata(dev, NULL);
+
+       return 0;
+}
+
+/*
+ * ubicom32fb_platform_probe
+ */
+static int __init ubicom32fb_platform_probe(struct platform_device *pdev)
+{
+       struct ubicom32fb_drvdata *ud;
+       struct resource *irq_resource_rx;
+       struct resource *irq_resource_tx;
+       struct resource *mem_resource;
+       struct fb_info *fbinfo;
+       int rc;
+       size_t fbsize;
+       struct device *dev = &pdev->dev;
+       int offset;
+       struct vdc_tio_vp_regs *regs;
+
+       /*
+        * Get our resources
+        */
+       irq_resource_tx = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq_resource_tx) {
+               dev_err(dev, "No tx IRQ resource assigned\n");
+               return -ENODEV;
+       }
+
+       irq_resource_rx = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+       if (!irq_resource_rx) {
+               dev_err(dev, "No rx IRQ resource assigned\n");
+               return -ENODEV;
+       }
+
+       mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!mem_resource || !mem_resource->start) {
+               dev_err(dev, "No mem resource assigned\n");
+               return -ENODEV;
+       }
+       regs = (struct vdc_tio_vp_regs *)mem_resource->start;
+       if (regs->version != VDCTIO_VP_VERSION) {
+               dev_err(dev, "VDCTIO is not compatible with this driver tio:%x drv:%x\n",
+                       regs->version, VDCTIO_VP_VERSION);
+               return -ENODEV;
+       }
+
+       /*
+        * This is the minimum VRAM size
+        */
+       fbsize = regs->xres * regs->yres * (regs->bpp / 8);
+       if (!vram_size) {
+               vram_size = (fbsize + 1023) / 1024;
+       } else {
+               if (fbsize > (vram_size * 1024)) {
+                       dev_err(dev, "Not enough VRAM for display, need >= %u bytes\n", fbsize);
+                       return -ENOMEM; // should be ebadparam?
+               }
+       }
+
+       /*
+        * Allocate the framebuffer instance + our private data
+        */
+       fbinfo = framebuffer_alloc(sizeof(struct ubicom32fb_drvdata), &pdev->dev);
+       if (!fbinfo) {
+               dev_err(dev, "Not enough memory to allocate instance.\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * Fill in our private data.
+        */
+       ud = (struct ubicom32fb_drvdata *)fbinfo->par;
+       ud->fbinfo = fbinfo;
+       ud->regs = (struct vdc_tio_vp_regs *)(mem_resource->start);
+       dev_set_drvdata(dev, ud);
+
+       ud->vp_int = irq_resource_tx->start;
+
+       /*
+        * If we were provided an rx_irq then we need to init the appropriate
+        * queues, locks, and functions.
+        */
+       ud->rx_int = -1;
+       if (irq_resource_rx->start != DEVTREE_IRQ_NONE) {
+               init_waitqueue_head(&ud->waitq);
+               mutex_init(&ud->lock);
+               if (request_irq(ud->rx_int, ubicom32fb_interrupt, IRQF_SHARED, "ubicom32fb_rx", ud)) {
+                       dev_err(dev, "Couldn't request rx IRQ\n");
+                       rc = -ENOMEM;
+                       goto fail;
+               }
+               ud->rx_int = irq_resource_rx->start;
+       }
+
+       /*
+        * Allocate and align the requested amount of VRAM
+        */
+       ud->total_vram_size = (vram_size * 1024) + regs->fb_align;
+       ud->fb = kmalloc(ud->total_vram_size, GFP_KERNEL);
+       if (ud->fb == NULL) {
+               dev_err(dev, "Couldn't allocate VRAM\n");
+               rc = -ENOMEM;
+               goto fail;
+       }
+
+       offset = (u32_t)ud->fb & (regs->fb_align - 1);
+       if (!offset) {
+               ud->fb_aligned = ud->fb;
+       } else {
+               offset = regs->fb_align - offset;
+               ud->fb_aligned = ud->fb + offset;
+       }
+
+       /*
+        * Clear the entire frame buffer
+        */
+       if (!init_value) {
+               memset(ud->fb_aligned, 0, vram_size * 1024);
+       } else {
+               unsigned short *p = ud->fb_aligned;
+               int i;
+               for (i = 0; i < ((vram_size * 1024) / sizeof(u16_t)); i++) {
+                       *p++ = init_value;
+               }
+       }
+
+       /*
+        * Fill in the fb_var_screeninfo structure
+        */
+       memset(&ubicom32fb_var, 0, sizeof(ubicom32fb_var));
+       ubicom32fb_var.bits_per_pixel = regs->bpp;
+       ubicom32fb_var.red.offset = regs->rshift;
+       ubicom32fb_var.green.offset = regs->gshift;
+       ubicom32fb_var.blue.offset = regs->bshift;
+       ubicom32fb_var.red.length = regs->rbits;
+       ubicom32fb_var.green.length = regs->gbits;
+       ubicom32fb_var.blue.length = regs->bbits;
+       ubicom32fb_var.activate = FB_ACTIVATE_NOW;
+
+#if 0
+       /*
+        * Turn on the display
+        */
+       ud->reg_ctrl_default = REG_CTRL_ENABLE;
+       if (regs->rotate_screen)
+               ud->reg_ctrl_default |= REG_CTRL_ROTATE;
+       ubicom32fb_out_be32(ud, REG_CTRL, ud->reg_ctrl_default);
+#endif
+
+       /*
+        * Fill in the fb_info structure
+        */
+       ud->fbinfo->device = dev;
+       ud->fbinfo->screen_base = (void *)ud->fb_aligned;
+       ud->fbinfo->fbops = &ubicom32fb_ops;
+       ud->fbinfo->fix = ubicom32fb_fix;
+       ud->fbinfo->fix.smem_start = (u32)ud->fb_aligned;
+       ud->fbinfo->fix.smem_len = vram_size * 1024;
+       ud->fbinfo->fix.line_length = regs->xres * (regs->bpp / 8);
+       ud->fbinfo->fix.mmio_start = (u32)regs;
+       ud->fbinfo->fix.mmio_len = sizeof(struct vdc_tio_vp_regs);
+
+       /*
+        * We support panning in the y direction only
+        */
+       ud->fbinfo->fix.xpanstep = 0;
+       ud->fbinfo->fix.ypanstep = 1;
+
+       ud->fbinfo->pseudo_palette = ud->pseudo_palette;
+       ud->fbinfo->flags = FBINFO_DEFAULT;
+       ud->fbinfo->var = ubicom32fb_var;
+       ud->fbinfo->var.xres = regs->xres;
+       ud->fbinfo->var.yres = regs->yres;
+
+       /*
+        * We cannot pan in the X direction, so xres_virtual is regs->xres
+        * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length
+        */
+       ud->fbinfo->var.xres_virtual = regs->xres;
+       ud->fbinfo->var.yres_virtual = (vram_size * 1024) / ud->fbinfo->fix.line_length;
+
+       //ud->fbinfo->var.height = regs->height_mm;
+       //ud->fbinfo->var.width = regs->width_mm;
+
+       /*
+        * Allocate a color map
+        */
+       rc = fb_alloc_cmap(&ud->fbinfo->cmap, PALETTE_ENTRIES_NO, 0);
+       if (rc) {
+               dev_err(dev, "Fail to allocate colormap (%d entries)\n",
+                       PALETTE_ENTRIES_NO);
+               goto fail;
+       }
+       ud->cmap_alloc = true;
+
+       /*
+        * Register new frame buffer
+        */
+       rc = register_framebuffer(ud->fbinfo);
+       if (rc) {
+               dev_err(dev, "Could not register frame buffer\n");
+               goto fail;
+       }
+
+       /*
+        * Start up the VDC
+        */
+       ud->regs->next_frame = ud->fb;
+       ubicom32fb_send_command(ud, VDCTIO_COMMAND_START, 0);
+
+       /*
+        * Tell the log we are here
+        */
+       dev_info(dev, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u), regs=%p irqtx=%u irqrx=%u\n",
+               ud->fb, ud->fb_aligned, vram_size, ud->fbinfo->var.xres, ud->fbinfo->var.yres,
+               ud->fbinfo->var.xres_virtual, ud->fbinfo->var.yres_virtual, ud->regs,
+               irq_resource_tx->start, irq_resource_rx->start);
+
+       /*
+        * Success
+        */
+       return 0;
+
+fail:
+       ubicom32fb_release(dev);
+       return rc;
+}
+
+/*
+ * ubicom32fb_platform_remove
+ */
+static int ubicom32fb_platform_remove(struct platform_device *pdev)
+{
+       dev_info(&(pdev->dev), "Ubicom32 FB Driver Remove\n");
+       return ubicom32fb_release(&pdev->dev);
+}
+
+static struct platform_driver ubicom32fb_platform_driver = {
+       .probe          = ubicom32fb_platform_probe,
+       .remove         = ubicom32fb_platform_remove,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+#ifndef MODULE
+/*
+ * ubicom32fb_setup
+ *     Process kernel boot options
+ */
+static int __init ubicom32fb_setup(char *options)
+{
+       char *this_opt;
+
+       if (!options || !*options) {
+               return 0;
+       }
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               if (!*this_opt) {
+                       continue;
+               }
+
+               if (!strncmp(this_opt, "init_value=", 10)) {
+                       init_value = simple_strtoul(this_opt + 11, NULL, 0);
+                       continue;
+               }
+
+               if (!strncmp(this_opt, "vram_size=", 10)) {
+                       vram_size = simple_strtoul(this_opt + 10, NULL, 0);
+                       continue;
+               }
+       }
+       return 0;
+}
+#endif /* MODULE */
+
+/*
+ * ubicom32fb_init
+ */
+static int __devinit ubicom32fb_init(void)
+{
+#ifndef MODULE
+       /*
+        * Get kernel boot options (in 'video=ubicom32fb:<options>')
+        */
+       char *option = NULL;
+
+       if (fb_get_options(DRIVER_NAME, &option)) {
+               return -ENODEV;
+       }
+       ubicom32fb_setup(option);
+#endif /* MODULE */
+
+       return platform_driver_register(&ubicom32fb_platform_driver);
+}
+module_init(ubicom32fb_init);
+
+/*
+ * ubicom32fb_exit
+ */
+static void __exit ubicom32fb_exit(void)
+{
+       platform_driver_unregister(&ubicom32fb_platform_driver);
+}
+module_exit(ubicom32fb_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
diff --git a/target/linux/ubicom32/files/drivers/video/ubicom32plio80.c b/target/linux/ubicom32/files/drivers/video/ubicom32plio80.c
new file mode 100644 (file)
index 0000000..2e13fd7
--- /dev/null
@@ -0,0 +1,780 @@
+/*
+ * drivers/video/ubicom32plio80.c
+ *     Ubicom32 80 bus PLIO buffer driver
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by
+ * Geert Uytterhoeven.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <asm/plio.h>
+
+#define DRIVER_NAME            "ubicom32plio80"
+#define DRIVER_DESCRIPTION     "Ubicom32 80 bus PLIO frame buffer driver"
+
+#define PALETTE_ENTRIES_NO     16
+
+/*
+ * Option variables
+ *
+ * vram_size:  VRAM size in kilobytes, subject to alignment
+ */
+static int vram_size = 0;
+module_param(vram_size, int, 0);
+MODULE_PARM_DESC(vram_size, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment");
+
+static int xres = 240;
+module_param(xres, int, 0);
+MODULE_PARM_DESC(xres, "x (horizontal) resolution");
+
+static int yres = 320;
+module_param(yres, int, 0);
+MODULE_PARM_DESC(yres, "y (vertical) resolution");
+
+static int bgr = 0;
+module_param(bgr, int, 0);
+MODULE_PARM_DESC(bgr, "display is BGR (Blue is MSB)");
+
+#define BITS_PER_PIXEL 16
+
+/*
+ * Buffer alignment, must not be 0
+ */
+#define UBICOM32PLIO80_ALIGNMENT 4
+
+/*
+ * PLIO FSM
+ *     16-bit data bus on port I
+ *     CS on EXTCTL[6]
+ *     WR on EXTCTL[4]
+ */
+static const plio_fctl_t plio_fctl = {
+       .fctl0 = {
+               .ptif_port_mode = PLIO_PORT_MODE_DI,
+               .ptif_portd_cfg = 0,
+               .ptif_porti_cfg = 3,
+               .edif_ds = 6,
+               .edif_cmp_mode = 1,
+               .ecif_extclk_ena = 0, // enable clock output on PD7 table 2.65/p111 says extctl[0]?
+               .icif_clk_src_sel = PLIO_CLK_IO,
+       },
+       .fctl2 = {
+               .icif_eclk_div = 10,
+               .icif_iclk_div = 10,
+       },
+
+       };
+
+       static const plio_config_t plio_config = {
+       .pfsm = {
+               /*
+                * Table 12.63
+                */
+               .grpsel[0] = {1,1,1,1,1,1,1,1,1,1},
+
+               /*
+               * Table 12.66 Counter load value
+               */
+               .cs_lut[0] = {0,0,0,0,0,0,0,0},
+
+               /*
+                * Table 2.75 PLIO PFSM Configuration Registers
+                */
+               //                      3     2     1     0
+               .extctl_o_lut[0] = {0x3f, 0x2f, 0x3f, 0x3f},
+               //                      7     6     5     4
+               .extctl_o_lut[1] = {0x3f, 0x3f, 0x3f, 0x2f},
+       },
+       .edif = {
+               .odr_oe = 0xffff,
+       },
+       .ecif = {
+               .output_ena = (1 << 6) | (1 << 4),
+       },
+};
+
+static const u32_t ubicom32plio80_plio_fsm[] = {
+       // 0-F
+       0x00070007, 0x00070007,
+       0x00070007, 0x00070007,
+       0x00070007, 0x00070007,
+       0x00070007, 0x00070007,
+
+       0x16260806, 0x16260806,
+       0x16260806, 0x16260806,
+       0x16260806, 0x16260806,
+       0x16260806, 0x16260806,
+
+       // 10 - 1f
+       0x22061806, 0x22061806,
+       0x22061806, 0x22061806,
+       0x22061806, 0x22061806,
+       0x22061806, 0x22061806,
+
+       0x22061806, 0x22061806,
+       0x22061806, 0x22061806,
+       0x22061806, 0x22061806,
+       0x22061806, 0x22061806,
+
+       // 20 - 2f
+       0x00070806, 0x00070806,
+       0x00070806, 0x00070806,
+       0x00070806, 0x00070806,
+       0x00070806, 0x00070806,
+
+       0x00070806, 0x00070806,
+       0x00070806, 0x00070806,
+       0x00070806, 0x00070806,
+       0x00070806, 0x00070806,
+};
+
+/*
+ * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in.
+ */
+static struct fb_fix_screeninfo ubicom32plio80_fix = {
+       .id =           "Ubicom32",
+       .type =         FB_TYPE_PACKED_PIXELS,
+       .visual =       FB_VISUAL_TRUECOLOR,
+       .accel =        FB_ACCEL_UBICOM32_PLIO80,
+};
+
+/*
+ * Filled in at probe time when we find out what the hardware supports
+ */
+static struct fb_var_screeninfo ubicom32plio80_var;
+
+/*
+ * Private data structure
+ */
+struct ubicom32plio80_drvdata {
+       struct fb_info                  *fbinfo;
+       bool                            cmap_alloc;
+
+       /*
+        * The address of the framebuffer in memory
+        */
+       void                            *fb;
+       void                            *fb_aligned;
+
+       /*
+        * Total size of vram including alignment allowance
+        */
+       u32                             total_vram_size;
+
+       /*
+        * Fake palette of 16 colors
+        */
+       u32                             pseudo_palette[PALETTE_ENTRIES_NO];
+
+       int                             irq_req;
+
+       /*
+        * Current pointer and bytes left to transfer with the PLIO
+        */
+       void                            *xfer_ptr;
+       u32                             bytes_to_xfer;
+       u32                             busy;
+};
+
+static struct platform_device *ubicom32plio80_platform_device;
+
+/*
+ * ubicom32plio80_isr
+ */
+static int ubicom32plio80_isr(int irq, void *appdata)
+{
+       struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)appdata;
+
+       if (!ud->bytes_to_xfer) {
+               ubicom32_disable_interrupt(TX_FIFO_INT(PLIO_PORT));
+               PLIO_NBR->intmask.txfifo_wm = 0;
+               ud->busy = 0;
+               return IRQ_HANDLED;
+       }
+
+       asm volatile (
+               ".rept 8                                \n\t"
+               "move.4 (%[fifo]), (%[data])4++         \n\t"
+               ".endr                                  \n\t"
+               : [data] "+a" (ud->xfer_ptr)
+               : [fifo] "a" (&PLIO_NBR->tx_lo)
+       );
+
+       ud->bytes_to_xfer -= 32;
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * ubicom32plio80_update
+ */
+static void ubicom32plio80_update(struct ubicom32plio80_drvdata *ud, u32 *fb)
+{
+       struct ubicom32_io_port *ri = (struct ubicom32_io_port *)RI;
+       struct ubicom32_io_port *rd = (struct ubicom32_io_port *)RD;
+
+       ud->xfer_ptr = fb;
+       ud->bytes_to_xfer = (xres * yres * 2) - 64;
+       ud->busy = 1;
+
+       ri->gpio_mask = 0;
+       rd->gpio_mask &= ~((1 << 4) | (1 << 2));
+
+       *(u32 *)(&PLIO_NBR->intclr) = ~0;
+       PLIO_NBR->intmask.txfifo_wm = 1;
+       PLIO_NBR->fifo_wm.tx = 8;
+       ubicom32_enable_interrupt(TX_FIFO_INT(PLIO_PORT));
+
+       asm volatile (
+               ".rept 16                               \n\t"
+               "move.4 (%[fifo]), (%[data])4++         \n\t"
+               ".endr                                  \n\t"
+               : [data] "+a" (ud->xfer_ptr)
+               : [fifo] "a" (&PLIO_NBR->tx_lo)
+       );
+}
+
+/*
+ * ubicom32plio80_pan_display
+ *     Pans the display to a given location.  Supports only y direction panning.
+ */
+static int ubicom32plio80_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
+{
+       struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)fbi->par;
+       void *new_addr;
+
+       /*
+        * Get the last y line that would be displayed.  Since we don't support YWRAP,
+        * it must be less than our virtual y size.
+        */
+       u32 lasty = var->yoffset + var->yres;
+       if (lasty > fbi->var.yres_virtual) {
+               /*
+                * We would fall off the end of our frame buffer if we panned here.
+                */
+               return -EINVAL;
+       }
+
+       if (var->xoffset) {
+               /*
+                * We don't support panning in the x direction
+                */
+               return -EINVAL;
+       }
+
+       /*
+        * Everything looks sane, go ahead and pan
+        *
+        * We have to calculate a new address for the VDC to look at
+        */
+       new_addr = ud->fb_aligned + (var->yoffset * fbi->fix.line_length);
+
+       return 0;
+}
+
+/*
+ * ubicom32plio80_setcolreg
+ *     Sets a color in our virtual palette
+ */
+static int ubicom32plio80_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi)
+{
+       u32 *palette = fbi->pseudo_palette;
+
+       if (regno >= PALETTE_ENTRIES_NO) {
+               return -EINVAL;
+       }
+
+       /*
+        * We only use 8 bits from each color
+        */
+       red >>= 8;
+       green >>= 8;
+       blue >>= 8;
+
+       /*
+        * Convert any grayscale values
+        */
+       if (fbi->var.grayscale) {
+               u16 gray = red + green + blue;
+               gray += (gray >> 2) + (gray >> 3) - (gray >> 7);
+               gray >>= 2;
+               if (gray > 255) {
+                       gray = 255;
+               }
+               red = gray;
+               blue = gray;
+               green = gray;
+       }
+
+       palette[regno] = (red << fbi->var.red.offset) | (green << fbi->var.green.offset) |
+                        (blue << fbi->var.blue.offset);
+
+       return 0;
+}
+
+/*
+ * ubicom32plio80_mmap
+ */
+static int ubicom32plio80_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+       struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)info->par;
+
+       vma->vm_start = (unsigned long)(ud->fb_aligned);
+
+       vma->vm_end = vma->vm_start + info->fix.smem_len;
+
+       /* For those who don't understand how mmap works, go read
+        *   Documentation/nommu-mmap.txt.
+        * For those that do, you will know that the VM_MAYSHARE flag
+        * must be set in the vma->vm_flags structure on noMMU
+        *   Other flags can be set, and are documented in
+        *   include/linux/mm.h
+        */
+
+       vma->vm_flags |=  VM_MAYSHARE | VM_SHARED;
+
+       return 0;
+}
+
+/*
+ * ubicom32plio80_check_var
+ *     Check the var, tweak it but don't change operational parameters.
+ */
+static int ubicom32plio80_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)info->par;
+       u32 line_size = var->xres * (BITS_PER_PIXEL / 8);
+
+       /*
+        * See if we can handle this bpp
+        */
+       if (var->bits_per_pixel > BITS_PER_PIXEL) {
+               return -EINVAL;
+       }
+       var->bits_per_pixel = BITS_PER_PIXEL;
+
+       /*
+        * See if we have enough memory to handle this resolution
+        */
+       if ((line_size * var->yres * BITS_PER_PIXEL / 8) > ud->total_vram_size) {
+               return -EINVAL;
+       }
+
+       var->xres_virtual = var->xres;
+       var->yres_virtual = ud->total_vram_size / line_size;
+
+       var->red.length = 5;
+       var->green.length = 6;
+       var->green.offset = 5;
+       var->blue.length = 5;
+       var->transp.offset = var->transp.length = 0;
+
+       if (bgr) {
+               var->red.offset = 0;
+               var->blue.offset = 11;
+       } else {
+               var->red.offset = 11;
+               var->blue.offset = 0;
+       }
+
+       var->nonstd = 0;
+       var->height = -1;
+       var->width = -1;
+       var->vmode = FB_VMODE_NONINTERLACED;
+       var->sync = 0;
+
+       return 0;
+}
+
+/*
+ * ubicom32plio80_set_par
+ *     Set the video mode according to info->var
+ */
+static int ubicom32plio80_set_par(struct fb_info *info)
+{
+       /*
+        * Anything changed?
+        */
+       if ((xres == info->var.xres) && (yres == info->var.yres)) {
+               return 0;
+       }
+
+       /*
+        * Implement changes
+        */
+       xres = info->var.xres;
+       yres = info->var.yres;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.xpanstep = 0;
+       info->fix.ypanstep = 1;
+       info->fix.line_length = xres * (BITS_PER_PIXEL / 8);
+
+       return 0;
+}
+
+/*
+ * ubicom32plio80_ops
+ *     List of supported operations
+ */
+static struct fb_ops ubicom32plio80_ops =
+{
+       .owner                  = THIS_MODULE,
+       .fb_pan_display         = ubicom32plio80_pan_display,
+       .fb_setcolreg           = ubicom32plio80_setcolreg,
+       .fb_mmap                = ubicom32plio80_mmap,
+       .fb_check_var           = ubicom32plio80_check_var,
+       .fb_set_par             = ubicom32plio80_set_par,
+       .fb_fillrect            = cfb_fillrect,
+       .fb_copyarea            = cfb_copyarea,
+       .fb_imageblit           = cfb_imageblit,
+};
+
+/*
+ * ubicom32plio80_release
+ */
+static int ubicom32plio80_release(struct device *dev)
+{
+       struct ubicom32plio80_drvdata *ud = dev_get_drvdata(dev);
+
+       unregister_framebuffer(ud->fbinfo);
+
+       if (ud->irq_req) {
+               free_irq(TX_FIFO_INT(PLIO_PORT), ud);
+       }
+       if (ud->cmap_alloc) {
+               fb_dealloc_cmap(&ud->fbinfo->cmap);
+       }
+
+       if (ud->fb) {
+               kfree(ud->fb);
+       }
+
+       framebuffer_release(ud->fbinfo);
+       dev_set_drvdata(dev, NULL);
+
+       return 0;
+}
+
+/*
+ * ubicom32plio80_platform_probe
+ */
+static int __init ubicom32plio80_platform_probe(struct platform_device *pdev)
+{
+       struct ubicom32plio80_drvdata *ud;
+       struct fb_info *fbinfo;
+       int rc;
+       size_t fbsize;
+       struct device *dev = &pdev->dev;
+       int offset;
+
+       /*
+        * This is the minimum VRAM size
+        */
+       fbsize = xres * yres * 2;
+       if (!vram_size) {
+               vram_size = (fbsize + 1023) / 1024;
+       } else {
+               if (fbsize > (vram_size * 1024)) {
+                       dev_err(dev, "Not enough VRAM for display, need >= %u bytes\n", fbsize);
+                       return -ENOMEM; // should be ebadparam?
+               }
+       }
+
+       /*
+        * Allocate the framebuffer instance + our private data
+        */
+       fbinfo = framebuffer_alloc(sizeof(struct ubicom32plio80_drvdata), &pdev->dev);
+       if (!fbinfo) {
+               dev_err(dev, "Not enough memory to allocate instance.\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * Fill in our private data.
+        */
+       ud = (struct ubicom32plio80_drvdata *)fbinfo->par;
+       ud->fbinfo = fbinfo;
+       dev_set_drvdata(dev, ud);
+
+       /*
+        * Allocate and align the requested amount of VRAM
+        */
+       ud->total_vram_size = (vram_size * 1024) + UBICOM32PLIO80_ALIGNMENT;
+       ud->fb = kmalloc(ud->total_vram_size, GFP_KERNEL);
+       if (ud->fb == NULL) {
+               dev_err(dev, "Couldn't allocate VRAM\n");
+               rc = -ENOMEM;
+               goto fail;
+       }
+
+       offset = (u32_t)ud->fb & (UBICOM32PLIO80_ALIGNMENT - 1);
+       if (!offset) {
+               ud->fb_aligned = ud->fb;
+       } else {
+               offset =  UBICOM32PLIO80_ALIGNMENT - offset;
+               ud->fb_aligned = ud->fb + offset;
+       }
+
+       /*
+        * Clear the entire frame buffer
+        */
+       memset(ud->fb_aligned, 0, vram_size * 1024);
+
+       /*
+        * Fill in the fb_var_screeninfo structure
+        */
+       memset(&ubicom32plio80_var, 0, sizeof(ubicom32plio80_var));
+       ubicom32plio80_var.bits_per_pixel = BITS_PER_PIXEL;
+       ubicom32plio80_var.red.length = 5;
+       ubicom32plio80_var.green.length = 6;
+       ubicom32plio80_var.green.offset = 5;
+       ubicom32plio80_var.blue.length = 5;
+       ubicom32plio80_var.activate = FB_ACTIVATE_NOW;
+
+       if (bgr) {
+               ubicom32plio80_var.red.offset = 0;
+               ubicom32plio80_var.blue.offset = 11;
+       } else {
+               ubicom32plio80_var.red.offset = 11;
+               ubicom32plio80_var.blue.offset = 0;
+       }
+
+       /*
+        * Fill in the fb_info structure
+        */
+       ud->fbinfo->device = dev;
+       ud->fbinfo->screen_base = (void *)ud->fb_aligned;
+       ud->fbinfo->fbops = &ubicom32plio80_ops;
+       ud->fbinfo->fix = ubicom32plio80_fix;
+       ud->fbinfo->fix.smem_start = (u32)ud->fb_aligned;
+       ud->fbinfo->fix.smem_len = vram_size * 1024;
+       ud->fbinfo->fix.line_length = xres * 2;
+       ud->fbinfo->fix.mmio_start = (u32)ud;
+       ud->fbinfo->fix.mmio_len = sizeof(struct ubicom32plio80_drvdata);
+
+       /*
+        * We support panning in the y direction only
+        */
+       ud->fbinfo->fix.xpanstep = 0;
+       ud->fbinfo->fix.ypanstep = 1;
+
+       ud->fbinfo->pseudo_palette = ud->pseudo_palette;
+       ud->fbinfo->flags = FBINFO_DEFAULT;
+       ud->fbinfo->var = ubicom32plio80_var;
+       ud->fbinfo->var.xres = xres;
+       ud->fbinfo->var.yres = yres;
+
+       /*
+        * We cannot pan in the X direction, so xres_virtual is xres
+        * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length
+        */
+       ud->fbinfo->var.xres_virtual = xres;
+       ud->fbinfo->var.yres_virtual = (vram_size * 1024) / ud->fbinfo->fix.line_length;
+
+       /*
+        * Allocate a color map
+        */
+       rc = fb_alloc_cmap(&ud->fbinfo->cmap, PALETTE_ENTRIES_NO, 0);
+       if (rc) {
+               dev_err(dev, "Fail to allocate colormap (%d entries)\n",
+                       PALETTE_ENTRIES_NO);
+               goto fail;
+       }
+       ud->cmap_alloc = true;
+
+       /*
+        * Register new frame buffer
+        */
+       rc = register_framebuffer(ud->fbinfo);
+       if (rc) {
+               dev_err(dev, "Could not register frame buffer\n");
+               goto fail;
+       }
+
+       /*
+        * request the PLIO IRQ
+        */
+       rc = request_irq(TX_FIFO_INT(PLIO_PORT), ubicom32plio80_isr, IRQF_DISABLED, "ubicom32plio80", ud);
+       if (rc) {
+               dev_err(dev, "Could not request IRQ\n");
+               goto fail;
+       }
+       ud->irq_req = 1;
+
+       /*
+        * Clear any garbage out of the TX FIFOs (idif_txfifo_flush)
+        *
+        * cast through ubicom32_io_port to make sure the compiler does a word write
+        */
+       ((struct ubicom32_io_port *)PLIO_NBR)->int_set = (1 << 18);
+
+       /*
+        * Start up the state machine
+        */
+       plio_init(&plio_fctl, &plio_config, (plio_sram_t *)ubicom32plio80_plio_fsm, sizeof(ubicom32plio80_plio_fsm));
+       PLIO_NBR->fctl0.pfsm_cmd = 0;
+
+       ubicom32plio80_update(ud, ud->fb_aligned);
+
+       /*
+        * Tell the log we are here
+        */
+       dev_info(dev, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u)\n",
+               ud->fb, ud->fb_aligned, vram_size, ud->fbinfo->var.xres, ud->fbinfo->var.yres,
+               ud->fbinfo->var.xres_virtual, ud->fbinfo->var.yres_virtual);
+
+       /*
+        * Success
+        */
+       return 0;
+
+fail:
+       ubicom32plio80_release(dev);
+       return rc;
+}
+
+/*
+ * ubicom32plio80_platform_remove
+ */
+static int ubicom32plio80_platform_remove(struct platform_device *pdev)
+{
+       dev_info(&(pdev->dev), "Ubicom32 FB Driver Remove\n");
+       return ubicom32plio80_release(&pdev->dev);
+}
+
+static struct platform_driver ubicom32plio80_platform_driver = {
+       .probe          = ubicom32plio80_platform_probe,
+       .remove         = ubicom32plio80_platform_remove,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+#ifndef MODULE
+/*
+ * ubicom32plio80_setup
+ *     Process kernel boot options
+ */
+static int __init ubicom32plio80_setup(char *options)
+{
+       char *this_opt;
+
+       if (!options || !*options) {
+               return 0;
+       }
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               if (!*this_opt) {
+                       continue;
+               }
+
+               if (!strncmp(this_opt, "vram_size=", 10)) {
+                       vram_size = simple_strtoul(this_opt + 10, NULL, 0);
+                       continue;
+               }
+
+               if (!strncmp(this_opt, "bgr=", 4)) {
+                       bgr = simple_strtoul(this_opt + 4, NULL, 0);
+                       continue;
+               }
+
+               if (!strncmp(this_opt, "xres=", 5)) {
+                       xres = simple_strtoul(this_opt + 5, NULL, 0);
+                       continue;
+               }
+
+               if (!strncmp(this_opt, "yres=", 5)) {
+                       yres = simple_strtoul(this_opt + 5, NULL, 0);
+                       continue;
+               }
+       }
+       return 0;
+}
+#endif /* MODULE */
+
+/*
+ * ubicom32plio80_init
+ */
+static int __devinit ubicom32plio80_init(void)
+{
+       int ret;
+
+#ifndef MODULE
+       /*
+        * Get kernel boot options (in 'video=ubicom32plio80:<options>')
+        */
+       char *option = NULL;
+
+       if (fb_get_options(DRIVER_NAME, &option)) {
+               return -ENODEV;
+       }
+       ubicom32plio80_setup(option);
+#endif /* MODULE */
+
+       ret = platform_driver_register(&ubicom32plio80_platform_driver);
+
+       if (!ret) {
+               ubicom32plio80_platform_device = platform_device_alloc(DRIVER_NAME, 0);
+
+               if (ubicom32plio80_platform_device)
+                       ret = platform_device_add(ubicom32plio80_platform_device);
+               else
+                       ret = -ENOMEM;
+
+               if (ret) {
+                       platform_device_put(ubicom32plio80_platform_device);
+                       platform_driver_unregister(&ubicom32plio80_platform_driver);
+               }
+       }
+
+       return ret;
+}
+module_init(ubicom32plio80_init);
+
+/*
+ * ubicom32plio80_exit
+ */
+static void __exit ubicom32plio80_exit(void)
+{
+       platform_device_unregister(ubicom32plio80_platform_device);
+       platform_driver_unregister(&ubicom32plio80_platform_driver);
+}
+module_exit(ubicom32plio80_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
diff --git a/target/linux/ubicom32/files/drivers/video/ubicom32vfb.c b/target/linux/ubicom32/files/drivers/video/ubicom32vfb.c
new file mode 100644 (file)
index 0000000..8478273
--- /dev/null
@@ -0,0 +1,603 @@
+/*
+ * drivers/video/ubicom32vfb.c
+ *     Ubicom32 virtual frame buffer driver
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by
+ * Geert Uytterhoeven.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+
+#define DRIVER_NAME            "ubicom32vfb"
+#define DRIVER_DESCRIPTION     "Ubicom32 virtual frame buffer driver"
+
+#define PALETTE_ENTRIES_NO     16
+
+/*
+ * Option variables
+ *
+ * vram_size:  VRAM size in kilobytes, subject to alignment
+ */
+static int vram_size = 0;
+module_param(vram_size, int, 0);
+MODULE_PARM_DESC(vram_size, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment");
+
+static int xres = 320;
+module_param(xres, int, 0);
+MODULE_PARM_DESC(xres, "x (horizontal) resolution");
+
+static int yres = 240;
+module_param(yres, int, 0);
+MODULE_PARM_DESC(yres, "y (vertical) resolution");
+
+static int bgr = 0;
+module_param(bgr, int, 0);
+MODULE_PARM_DESC(bgr, "display is BGR (Blue is MSB)");
+
+#define BITS_PER_PIXEL 16
+
+/*
+ * Buffer alignment, must not be 0
+ */
+#define UBICOM32VFB_ALIGNMENT 4
+
+/*
+ * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in.
+ */
+static struct fb_fix_screeninfo ubicom32vfb_fix = {
+       .id =           "Ubicom32",
+       .type =         FB_TYPE_PACKED_PIXELS,
+       .visual =       FB_VISUAL_TRUECOLOR,
+       .accel =        FB_ACCEL_UBICOM32_VFB,
+};
+
+/*
+ * Filled in at probe time when we find out what the hardware supports
+ */
+static struct fb_var_screeninfo ubicom32vfb_var;
+
+/*
+ * Private data structure
+ */
+struct ubicom32vfb_drvdata {
+       struct fb_info                  *fbinfo;
+       bool                            cmap_alloc;
+
+       /*
+        * The address of the framebuffer in memory
+        */
+       void                            *fb;
+       void                            *fb_aligned;
+
+       /*
+        * Total size of vram including alignment allowance
+        */
+       u32                             total_vram_size;
+
+       /*
+        * Fake palette of 16 colors
+        */
+       u32                             pseudo_palette[PALETTE_ENTRIES_NO];
+};
+
+static struct platform_device *ubicom32vfb_platform_device;
+
+/*
+ * ubicom32vfb_pan_display
+ *     Pans the display to a given location.  Supports only y direction panning.
+ */
+static int ubicom32vfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
+{
+       struct ubicom32vfb_drvdata *ud = (struct ubicom32vfb_drvdata *)fbi->par;
+       void *new_addr;
+
+       /*
+        * Get the last y line that would be displayed.  Since we don't support YWRAP,
+        * it must be less than our virtual y size.
+        */
+       u32 lasty = var->yoffset + var->yres;
+       if (lasty > fbi->var.yres_virtual) {
+               /*
+                * We would fall off the end of our frame buffer if we panned here.
+                */
+               return -EINVAL;
+       }
+
+       if (var->xoffset) {
+               /*
+                * We don't support panning in the x direction
+                */
+               return -EINVAL;
+       }
+
+       /*
+        * Everything looks sane, go ahead and pan
+        *
+        * We have to calculate a new address for the VDC to look at
+        */
+       new_addr = ud->fb_aligned + (var->yoffset * fbi->fix.line_length);
+
+       return 0;
+}
+
+/*
+ * ubicom32vfb_setcolreg
+ *     Sets a color in our virtual palette
+ */
+static int ubicom32vfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi)
+{
+       u32 *palette = fbi->pseudo_palette;
+
+       if (regno >= PALETTE_ENTRIES_NO) {
+               return -EINVAL;
+       }
+
+       /*
+        * We only use 8 bits from each color
+        */
+       red >>= 8;
+       green >>= 8;
+       blue >>= 8;
+
+       /*
+        * Convert any grayscale values
+        */
+       if (fbi->var.grayscale) {
+               u16 gray = red + green + blue;
+               gray += (gray >> 2) + (gray >> 3) - (gray >> 7);
+               gray >>= 2;
+               if (gray > 255) {
+                       gray = 255;
+               }
+               red = gray;
+               blue = gray;
+               green = gray;
+       }
+
+       palette[regno] = (red << fbi->var.red.offset) | (green << fbi->var.green.offset) |
+                        (blue << fbi->var.blue.offset);
+
+       return 0;
+}
+
+/*
+ * ubicom32vfb_mmap
+ */
+static int ubicom32vfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+       struct ubicom32vfb_drvdata *ud = (struct ubicom32vfb_drvdata *)info->par;
+
+       vma->vm_start = (unsigned long)(ud->fb_aligned);
+
+       vma->vm_end = vma->vm_start + info->fix.smem_len;
+
+       /* For those who don't understand how mmap works, go read
+        *   Documentation/nommu-mmap.txt.
+        * For those that do, you will know that the VM_MAYSHARE flag
+        * must be set in the vma->vm_flags structure on noMMU
+        *   Other flags can be set, and are documented in
+        *   include/linux/mm.h
+        */
+
+       vma->vm_flags |=  VM_MAYSHARE | VM_SHARED;
+
+       return 0;
+}
+
+/*
+ * ubicom32vfb_check_var
+ *     Check the var, tweak it but don't change operational parameters.
+ */
+static int ubicom32vfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct ubicom32vfb_drvdata *ud = (struct ubicom32vfb_drvdata *)info->par;
+       u32 line_size = var->xres * (BITS_PER_PIXEL / 8);
+
+       /*
+        * See if we can handle this bpp
+        */
+       if (var->bits_per_pixel > BITS_PER_PIXEL) {
+               return -EINVAL;
+       }
+       var->bits_per_pixel = BITS_PER_PIXEL;
+
+       /*
+        * See if we have enough memory to handle this resolution
+        */
+       if ((line_size * var->yres * BITS_PER_PIXEL / 8) > ud->total_vram_size) {
+               return -EINVAL;
+       }
+
+       var->xres_virtual = var->xres;
+       var->yres_virtual = ud->total_vram_size / line_size;
+
+       var->red.length = 5;
+       var->green.length = 6;
+       var->green.offset = 5;
+       var->blue.length = 5;
+       var->transp.offset = var->transp.length = 0;
+
+       if (bgr) {
+               var->red.offset = 0;
+               var->blue.offset = 11;
+       } else {
+               var->red.offset = 11;
+               var->blue.offset = 0;
+       }
+
+       var->nonstd = 0;
+       var->height = -1;
+       var->width = -1;
+       var->vmode = FB_VMODE_NONINTERLACED;
+       var->sync = 0;
+
+       return 0;
+}
+
+/*
+ * ubicom32vfb_set_par
+ *     Set the video mode according to info->var
+ */
+static int ubicom32vfb_set_par(struct fb_info *info)
+{
+       /*
+        * Anything changed?
+        */
+       if ((xres == info->var.xres) && (yres == info->var.yres)) {
+               return 0;
+       }
+
+       /*
+        * Implement changes
+        */
+       xres = info->var.xres;
+       yres = info->var.yres;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.xpanstep = 0;
+       info->fix.ypanstep = 1;
+       info->fix.line_length = xres * (BITS_PER_PIXEL / 8);
+
+       return 0;
+}
+
+/*
+ * ubicom32vfb_ops
+ *     List of supported operations
+ */
+static struct fb_ops ubicom32vfb_ops =
+{
+       .owner                  = THIS_MODULE,
+       .fb_pan_display         = ubicom32vfb_pan_display,
+       .fb_setcolreg           = ubicom32vfb_setcolreg,
+       .fb_mmap                = ubicom32vfb_mmap,
+       .fb_check_var           = ubicom32vfb_check_var,
+       .fb_set_par             = ubicom32vfb_set_par,
+       .fb_fillrect            = cfb_fillrect,
+       .fb_copyarea            = cfb_copyarea,
+       .fb_imageblit           = cfb_imageblit,
+};
+
+/*
+ * ubicom32vfb_release
+ */
+static int ubicom32vfb_release(struct device *dev)
+{
+       struct ubicom32vfb_drvdata *ud = dev_get_drvdata(dev);
+
+       unregister_framebuffer(ud->fbinfo);
+
+       if (ud->cmap_alloc) {
+               fb_dealloc_cmap(&ud->fbinfo->cmap);
+       }
+
+       if (ud->fb) {
+               kfree(ud->fb);
+       }
+
+       framebuffer_release(ud->fbinfo);
+       dev_set_drvdata(dev, NULL);
+
+       return 0;
+}
+
+/*
+ * ubicom32vfb_platform_probe
+ */
+static int __init ubicom32vfb_platform_probe(struct platform_device *pdev)
+{
+       struct ubicom32vfb_drvdata *ud;
+       struct fb_info *fbinfo;
+       int rc;
+       size_t fbsize;
+       struct device *dev = &pdev->dev;
+       int offset;
+
+       /*
+        * This is the minimum VRAM size
+        */
+       fbsize = xres * yres * 2;
+       if (!vram_size) {
+               vram_size = (fbsize + 1023) / 1024;
+       } else {
+               if (fbsize > (vram_size * 1024)) {
+                       dev_err(dev, "Not enough VRAM for display, need >= %u bytes\n", fbsize);
+                       return -ENOMEM; // should be ebadparam?
+               }
+       }
+
+       /*
+        * Allocate the framebuffer instance + our private data
+        */
+       fbinfo = framebuffer_alloc(sizeof(struct ubicom32vfb_drvdata), &pdev->dev);
+       if (!fbinfo) {
+               dev_err(dev, "Not enough memory to allocate instance.\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * Fill in our private data.
+        */
+       ud = (struct ubicom32vfb_drvdata *)fbinfo->par;
+       ud->fbinfo = fbinfo;
+       dev_set_drvdata(dev, ud);
+
+       /*
+        * Allocate and align the requested amount of VRAM
+        */
+       ud->total_vram_size = (vram_size * 1024) + UBICOM32VFB_ALIGNMENT;
+       ud->fb = kmalloc(ud->total_vram_size, GFP_KERNEL);
+       if (ud->fb == NULL) {
+               dev_err(dev, "Couldn't allocate VRAM\n");
+               rc = -ENOMEM;
+               goto fail;
+       }
+
+       offset = (u32_t)ud->fb & (UBICOM32VFB_ALIGNMENT - 1);
+       if (!offset) {
+               ud->fb_aligned = ud->fb;
+       } else {
+               offset =  UBICOM32VFB_ALIGNMENT - offset;
+               ud->fb_aligned = ud->fb + offset;
+       }
+
+       /*
+        * Clear the entire frame buffer
+        */
+       memset(ud->fb_aligned, 0, vram_size * 1024);
+
+       /*
+        * Fill in the fb_var_screeninfo structure
+        */
+       memset(&ubicom32vfb_var, 0, sizeof(ubicom32vfb_var));
+       ubicom32vfb_var.bits_per_pixel = BITS_PER_PIXEL;
+       ubicom32vfb_var.red.length = 5;
+       ubicom32vfb_var.green.length = 6;
+       ubicom32vfb_var.green.offset = 5;
+       ubicom32vfb_var.blue.length = 5;
+       ubicom32vfb_var.activate = FB_ACTIVATE_NOW;
+
+       if (bgr) {
+               ubicom32vfb_var.red.offset = 0;
+               ubicom32vfb_var.blue.offset = 11;
+       } else {
+               ubicom32vfb_var.red.offset = 11;
+               ubicom32vfb_var.blue.offset = 0;
+       }
+
+       /*
+        * Fill in the fb_info structure
+        */
+       ud->fbinfo->device = dev;
+       ud->fbinfo->screen_base = (void *)ud->fb_aligned;
+       ud->fbinfo->fbops = &ubicom32vfb_ops;
+       ud->fbinfo->fix = ubicom32vfb_fix;
+       ud->fbinfo->fix.smem_start = (u32)ud->fb_aligned;
+       ud->fbinfo->fix.smem_len = vram_size * 1024;
+       ud->fbinfo->fix.line_length = xres * 2;
+       ud->fbinfo->fix.mmio_start = (u32)ud;
+       ud->fbinfo->fix.mmio_len = sizeof(struct ubicom32vfb_drvdata);
+
+       /*
+        * We support panning in the y direction only
+        */
+       ud->fbinfo->fix.xpanstep = 0;
+       ud->fbinfo->fix.ypanstep = 1;
+
+       ud->fbinfo->pseudo_palette = ud->pseudo_palette;
+       ud->fbinfo->flags = FBINFO_DEFAULT;
+       ud->fbinfo->var = ubicom32vfb_var;
+       ud->fbinfo->var.xres = xres;
+       ud->fbinfo->var.yres = yres;
+
+       /*
+        * We cannot pan in the X direction, so xres_virtual is xres
+        * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length
+        */
+       ud->fbinfo->var.xres_virtual = xres;
+       ud->fbinfo->var.yres_virtual = (vram_size * 1024) / ud->fbinfo->fix.line_length;
+
+       /*
+        * Allocate a color map
+        */
+       rc = fb_alloc_cmap(&ud->fbinfo->cmap, PALETTE_ENTRIES_NO, 0);
+       if (rc) {
+               dev_err(dev, "Fail to allocate colormap (%d entries)\n",
+                       PALETTE_ENTRIES_NO);
+               goto fail;
+       }
+       ud->cmap_alloc = true;
+
+       /*
+        * Register new frame buffer
+        */
+       rc = register_framebuffer(ud->fbinfo);
+       if (rc) {
+               dev_err(dev, "Could not register frame buffer\n");
+               goto fail;
+       }
+
+       /*
+        * Tell the log we are here
+        */
+       dev_info(dev, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u)\n",
+               ud->fb, ud->fb_aligned, vram_size, ud->fbinfo->var.xres, ud->fbinfo->var.yres,
+               ud->fbinfo->var.xres_virtual, ud->fbinfo->var.yres_virtual);
+
+       /*
+        * Success
+        */
+       return 0;
+
+fail:
+       ubicom32vfb_release(dev);
+       return rc;
+}
+
+/*
+ * ubicom32vfb_platform_remove
+ */
+static int ubicom32vfb_platform_remove(struct platform_device *pdev)
+{
+       dev_info(&(pdev->dev), "Ubicom32 FB Driver Remove\n");
+       return ubicom32vfb_release(&pdev->dev);
+}
+
+static struct platform_driver ubicom32vfb_platform_driver = {
+       .probe          = ubicom32vfb_platform_probe,
+       .remove         = ubicom32vfb_platform_remove,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+#ifndef MODULE
+/*
+ * ubicom32vfb_setup
+ *     Process kernel boot options
+ */
+static int __init ubicom32vfb_setup(char *options)
+{
+       char *this_opt;
+
+       if (!options || !*options) {
+               return 0;
+       }
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               if (!*this_opt) {
+                       continue;
+               }
+
+               if (!strncmp(this_opt, "vram_size=", 10)) {
+                       vram_size = simple_strtoul(this_opt + 10, NULL, 0);
+                       continue;
+               }
+
+               if (!strncmp(this_opt, "bgr=", 4)) {
+                       bgr = simple_strtoul(this_opt + 4, NULL, 0);
+                       continue;
+               }
+
+               if (!strncmp(this_opt, "xres=", 5)) {
+                       xres = simple_strtoul(this_opt + 5, NULL, 0);
+                       continue;
+               }
+
+               if (!strncmp(this_opt, "yres=", 5)) {
+                       yres = simple_strtoul(this_opt + 5, NULL, 0);
+                       continue;
+               }
+       }
+       return 0;
+}
+#endif /* MODULE */
+
+/*
+ * ubicom32vfb_init
+ */
+static int __devinit ubicom32vfb_init(void)
+{
+       int ret;
+
+#ifndef MODULE
+       /*
+        * Get kernel boot options (in 'video=ubicom32vfb:<options>')
+        */
+       char *option = NULL;
+
+       if (fb_get_options(DRIVER_NAME, &option)) {
+               return -ENODEV;
+       }
+       ubicom32vfb_setup(option);
+#endif /* MODULE */
+
+       ret = platform_driver_register(&ubicom32vfb_platform_driver);
+
+#ifdef CONFIG_FB_UBICOM32_VIRTUAL_NOAUTO
+       return ret;
+#else
+       if (!ret) {
+               ubicom32vfb_platform_device = platform_device_alloc(DRIVER_NAME, 0);
+
+               if (ubicom32vfb_platform_device)
+                       ret = platform_device_add(ubicom32vfb_platform_device);
+               else
+                       ret = -ENOMEM;
+
+               if (ret) {
+                       platform_device_put(ubicom32vfb_platform_device);
+                       platform_driver_unregister(&ubicom32vfb_platform_driver);
+               }
+       }
+
+       return ret;
+#endif
+}
+module_init(ubicom32vfb_init);
+
+/*
+ * ubicom32vfb_exit
+ */
+static void __exit ubicom32vfb_exit(void)
+{
+       platform_device_unregister(ubicom32vfb_platform_device);
+       platform_driver_unregister(&ubicom32vfb_platform_driver);
+}
+module_exit(ubicom32vfb_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
diff --git a/target/linux/ubicom32/files/drivers/watchdog/ubi32_wdt.c b/target/linux/ubicom32/files/drivers/watchdog/ubi32_wdt.c
new file mode 100644 (file)
index 0000000..2c5b921
--- /dev/null
@@ -0,0 +1,630 @@
+/*
+ * drivers/watchdog/ubi32_wdt.c
+ *   Ubicom32 Watchdog Driver
+ *
+ * Originally based on softdog.c
+ * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2007 Michele d'Amico
+ * Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <asm/ip5000.h>
+
+#define WATCHDOG_NAME "ubi32-wdt"
+#define PFX WATCHDOG_NAME ": "
+
+#define OSC1_FREQ 12000000
+#define WATCHDOG_SEC_TO_CYC(x) (OSC1_FREQ * (x))
+#define WATCHDOG_MAX_SEC (0xffffffff / OSC1_FREQ)
+
+#define MIN_PROCESSOR_ADDRESS 0x03000000
+
+static DEFINE_SPINLOCK(ubi32_wdt_spinlock);
+
+#define WATCHDOG_TIMEOUT 20
+
+#if defined(CONFIG_WATCHDOG_NOWAYOUT)
+#define WATCHDOG_NOWAYOUT 1
+#else
+#define WATCHDOG_NOWAYOUT 0
+#endif
+
+static unsigned int timeout = WATCHDOG_TIMEOUT;
+static int nowayout = WATCHDOG_NOWAYOUT;
+static struct watchdog_info ubi32_wdt_info;
+static unsigned long open_check;
+static char expect_close;
+
+#if !defined(CONFIG_SMP)
+#define UBI32_WDT_LOCK(lock, flags) local_irq_save(flags)
+#define UBI32_WDT_UNLOCK(lock, flags) local_irq_restore(flags)
+#define UBI32_WDT_LOCK_CHECK()
+#else
+#define UBI32_WDT_LOCK(lock, flags) spin_lock_irqsave((lock), (flags));
+#define UBI32_WDT_UNLOCK(lock, flags) spin_unlock_irqrestore((lock), (flags));
+#define UBI32_WDT_LOCK_CHECK() BUG_ON(!spin_is_locked(&ubi32_wdt_spinlock));
+#endif
+
+/*
+ * ubi32_wdt_remaining()
+ *     Return the approximate number of seconds remaining
+ */
+static int ubi32_wdt_remaining(void)
+{
+       int compare;
+       int curr;
+
+       UBI32_WDT_LOCK_CHECK();
+
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL);
+       compare = ubicom32_read_reg(&UBICOM32_IO_TIMER->wdcom);
+       curr = ubicom32_read_reg(&UBICOM32_IO_TIMER->mptval);
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0);
+       return (compare - curr) / OSC1_FREQ;
+
+}
+
+/*
+ * ubi32_wdt_keepalive()
+ *     Keep the Userspace Watchdog Alive
+ *
+ * The Userspace watchdog got a KeepAlive: schedule the next timeout.
+ */
+static int ubi32_wdt_keepalive(void)
+{
+       UBI32_WDT_LOCK_CHECK();
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL);
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcom,
+                       ubicom32_read_reg(&UBICOM32_IO_TIMER->mptval)
+                       + WATCHDOG_SEC_TO_CYC(timeout));
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0);
+       return 0;
+}
+
+/*
+ * ubi32_wdt_stop()
+ *     Stop the on-chip Watchdog
+ */
+static int ubi32_wdt_stop(void)
+{
+       UBI32_WDT_LOCK_CHECK();
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL);
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcfg, TIMER_WATCHDOG_DISABLE);
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0);
+       return 0;
+}
+
+/*
+ * ubi32_wdt_start()
+ *     Start the on-chip Watchdog
+ */
+static int ubi32_wdt_start(void)
+{
+       UBI32_WDT_LOCK_CHECK();
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL);
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcom,
+                       ubicom32_read_reg(&UBICOM32_IO_TIMER->mptval)
+                       + WATCHDOG_SEC_TO_CYC(timeout));
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcfg, ~TIMER_WATCHDOG_DISABLE);
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0);
+       return 0;
+}
+
+/*
+ * ubi32_wdt_running()
+ *     Return true if the watchdog is configured
+ */
+static int ubi32_wdt_running(void)
+{
+       int enabled;
+
+       UBI32_WDT_LOCK_CHECK();
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL);
+       enabled = ubicom32_read_reg(&UBICOM32_IO_TIMER->wdcfg) == ~TIMER_WATCHDOG_DISABLE;
+       ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0);
+       return enabled;
+}
+
+/*
+ * ubi32_wdt_set_timeout()
+ *     Set the Userspace Watchdog timeout
+ *
+ * - @t: new timeout value (in seconds)
+ */
+static int ubi32_wdt_set_timeout(unsigned long t)
+{
+       UBI32_WDT_LOCK_CHECK();
+
+       if (t > WATCHDOG_MAX_SEC) {
+               printk(KERN_WARNING PFX "request to large: %ld [1-%d] sec)\n", t, WATCHDOG_MAX_SEC);
+               return -EINVAL;
+       }
+
+       /*
+        * If we are running, then reset the time value so
+        * that the new value has an immediate effect.
+        */
+       timeout = t;
+       if (ubi32_wdt_running()) {
+               ubi32_wdt_keepalive();
+       }
+       return 0;
+}
+
+/*
+ * ubi32_wdt_open()
+ *     Open the Device
+ */
+static int ubi32_wdt_open(struct inode *inode, struct file *file)
+{
+       unsigned long flags;
+
+       if (test_and_set_bit(0, &open_check))
+               return -EBUSY;
+
+       if (nowayout)
+               __module_get(THIS_MODULE);
+
+       spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+       ubi32_wdt_start();
+       spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+
+       return nonseekable_open(inode, file);
+}
+
+/*
+ * ubi32_wdt_close()
+ *     Close the Device
+ */
+static int ubi32_wdt_release(struct inode *inode, struct file *file)
+{
+       unsigned long flags;
+
+       /*
+        * If we don't expect a close, then the watchdog continues
+        * even though the device is closed.  The caller will have
+        * a full timeout value to reopen the device and continue
+        * stroking it.
+        */
+       if (expect_close != 42) {
+               printk(KERN_CRIT PFX
+                       "Unexpected close, not stopping watchdog!\n");
+               spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+               ubi32_wdt_keepalive();
+               spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+       } else {
+               spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+               ubi32_wdt_stop();
+               spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+       }
+
+       expect_close = 0;
+       clear_bit(0, &open_check);
+       return 0;
+}
+
+/*
+ * ubi32_wdt_write()
+ *     Write to Device
+ *
+ * If the user writes nothing, nothing happens.
+ * If the user writes a V, then we expect a close and allow a release.
+ * If the user writes anything else, it is ignored.
+ */
+static ssize_t ubi32_wdt_write(struct file *file, const char __user *data,
+                                               size_t len, loff_t *ppos)
+{
+       size_t i;
+       unsigned long flags;
+
+       /*
+        * Every write resets the expect_close.  The last write
+        * must be a V to allow shutdown on close.
+        */
+       expect_close = 0;
+
+       /*
+        * Empty writes still ping.
+        */
+       if (!len) {
+               goto ping;
+       }
+
+       /*
+        * If nowayout is set, it does not matter if the caller
+        * is trying to send the magic 'V' we will not allow a
+        * close to stop us.
+        */
+       if (nowayout) {
+               goto ping;
+       }
+
+       /*
+        * See if the program wrote a 'V' and if so disable
+        * the watchdog on release.
+        */
+       for (i = 0; i < len; i++) {
+               char c;
+               if (get_user(c, data + i)) {
+                       return -EFAULT;
+               }
+
+               if (c == 'V') {
+                       expect_close = 42;
+               }
+       }
+
+ping:
+       spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+       ubi32_wdt_keepalive();
+       spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+       return len;
+}
+
+/*
+ * ubi32_wdt_ioctl()
+ *     Query the watchdog device.
+ *
+ * Query basic information from the device or ping it, as outlined by the
+ * watchdog API.
+ */
+static long ubi32_wdt_ioctl(struct file *file,
+                               unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user(argp, &ubi32_wdt_info, sizeof(ubi32_wdt_info))) {
+                       return -EFAULT;
+               }
+               return 0;
+
+       case WDIOC_GETSTATUS: {
+               unsigned long flags;
+               int running;
+
+               spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+               running = ubi32_wdt_running();
+               spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+               return running;
+       }
+
+       case WDIOC_GETBOOTSTATUS:
+               return ubicom32_get_reset_reason();
+
+       case WDIOC_SETOPTIONS: {
+               unsigned long flags;
+               int options, ret = -EINVAL;
+
+               /*
+                * The sample application does not pass a pointer
+                * but directly passes a value of 1 or 2; however
+                * all of the implementations (and thus probably
+                * the real applications) pass a pointer to a value.
+                *
+                * It should be noted that  WDIOC_SETOPTIONS is defined as
+                * _IOR(WATCHDOG_IOCTL_BASE, 4, int), which means
+                * that it should be an int and NOT a pointer.
+                *
+                * TODO: Examine this code for future chips.
+                * TODO: Report the sample code defect.
+                */
+               if ((int)p < MIN_PROCESSOR_ADDRESS) {
+                       options = (int)p;
+               } else {
+                       if (get_user(options, p))
+                       return -EFAULT;
+               }
+
+               spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+               if (options & WDIOS_DISABLECARD) {
+                       ubi32_wdt_stop();
+                       ret = 0;
+               }
+               if (options & WDIOS_ENABLECARD) {
+                       ubi32_wdt_start();
+                       ret = 0;
+               }
+               spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+               return ret;
+       }
+
+       case WDIOC_KEEPALIVE: {
+               unsigned long flags;
+
+               spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+               ubi32_wdt_keepalive();
+               spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+               return 0;
+       }
+
+       case WDIOC_SETTIMEOUT: {
+               int new_timeout;
+               unsigned long flags;
+               int ret  = 0;
+
+               if (get_user(new_timeout, p))
+                       return -EFAULT;
+
+               spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+               ret = ubi32_wdt_set_timeout(new_timeout);
+               spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+               return ret;
+
+       }
+
+       case WDIOC_GETTIMEOUT:
+               return put_user(timeout, p);
+
+       case WDIOC_GETTIMELEFT: {
+               unsigned long flags;
+               int remaining = 0;
+
+               spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+               remaining = ubi32_wdt_remaining();
+               spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+               return put_user(remaining, p);
+       }
+
+       default:
+               return -ENOTTY;
+       }
+}
+
+/*
+ * ubi32_wdt_notify_sys()
+ *     Notification callback function for system events.
+ *
+ * Turn off the watchdog during a SYS_DOWN or SYS_HALT.
+ */
+static int ubi32_wdt_notify_sys(struct notifier_block *this,
+                                       unsigned long code, void *unused)
+{
+       if (code == SYS_DOWN || code == SYS_HALT) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+               ubi32_wdt_stop();
+               spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+       }
+
+       return NOTIFY_DONE;
+}
+
+#ifdef CONFIG_PM
+static int state_before_suspend;
+
+/*
+ * ubi32_wdt_suspend()
+ *     suspend the watchdog
+ *
+ * Remember if the watchdog was running and stop it.
+ */
+static int ubi32_wdt_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+       state_before_suspend = ubi32_wdt_running();
+       ubi32_wdt_stop();
+       spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+
+       return 0;
+}
+
+/*
+ * ubi32_wdt_resume()
+ *     Resume the watchdog
+ *
+ * If the watchdog was running, turn it back on.
+ */
+static int ubi32_wdt_resume(struct platform_device *pdev)
+{
+       if (state_before_suspend) {
+               unsigned long flags;
+               spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+               ubi32_wdt_set_timeout(timeout);
+               ubi32_wdt_start();
+               spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+       }
+
+       return 0;
+}
+#else
+# define ubi32_wdt_suspend NULL
+# define ubi32_wdt_resume NULL
+#endif
+
+static const struct file_operations ubi32_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = ubi32_wdt_write,
+       .unlocked_ioctl = ubi32_wdt_ioctl,
+       .open           = ubi32_wdt_open,
+       .release        = ubi32_wdt_release,
+};
+
+static struct miscdevice ubi32_wdt_miscdev = {
+       .minor    = WATCHDOG_MINOR,
+       .name     = "watchdog",
+       .fops     = &ubi32_wdt_fops,
+};
+
+static struct watchdog_info ubi32_wdt_info = {
+       .identity = "Ubicom32 Watchdog",
+       .options  = WDIOF_SETTIMEOUT |
+                   WDIOF_KEEPALIVEPING |
+                   WDIOF_MAGICCLOSE,
+};
+
+static struct notifier_block ubi32_wdt_notifier = {
+       .notifier_call = ubi32_wdt_notify_sys,
+};
+
+/*
+ * ubi32_wdt_probe()
+ *     Probe/register the watchdog module
+ *
+ * Registers the misc device and notifier handler.  Actual device
+ * initialization is handled by ubi32_wdt_open().
+ */
+static int __devinit ubi32_wdt_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       ret = register_reboot_notifier(&ubi32_wdt_notifier);
+       if (ret) {
+               printk(KERN_ERR PFX
+                       "cannot register reboot notifier (err=%d)\n", ret);
+               return ret;
+       }
+
+       ret = misc_register(&ubi32_wdt_miscdev);
+       if (ret) {
+               printk(KERN_ERR PFX
+                       "cannot register miscdev on minor=%d (err=%d)\n",
+                               WATCHDOG_MINOR, ret);
+               unregister_reboot_notifier(&ubi32_wdt_notifier);
+               return ret;
+       }
+
+       printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
+              timeout, nowayout);
+
+       return 0;
+}
+
+/*
+ * ubi32_wdt_remove()
+ *     Uninstall the module
+ *
+ * Unregisters the misc device and notifier handler.  Actual device
+ * deinitialization is handled by ubi32_wdt_close().
+ */
+static int __devexit ubi32_wdt_remove(struct platform_device *pdev)
+{
+       misc_deregister(&ubi32_wdt_miscdev);
+       unregister_reboot_notifier(&ubi32_wdt_notifier);
+       return 0;
+}
+
+static struct platform_device *ubi32_wdt_device;
+
+static struct platform_driver ubi32_wdt_driver = {
+       .probe     = ubi32_wdt_probe,
+       .remove    = __devexit_p(ubi32_wdt_remove),
+       .suspend   = ubi32_wdt_suspend,
+       .resume    = ubi32_wdt_resume,
+       .driver    = {
+               .name  = WATCHDOG_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+/*
+ * ubi32_wdt_init()
+ *     Initialize the watchdog.
+ *
+ * Checks the module params and registers the platform device & driver.
+ * Real work is in the platform probe function.
+ */
+static int __init ubi32_wdt_init(void)
+{
+       unsigned long flags;
+       int ret;
+
+       /*
+        * Check that the timeout value is within range
+        */
+       spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
+       ret = ubi32_wdt_set_timeout(timeout);
+       spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
+       if (ret) {
+               return ret;
+       }
+
+       /*
+        * Since this is an on-chip device and needs no board-specific
+        * resources, we'll handle all the platform device stuff here.
+        */
+       ret = platform_driver_register(&ubi32_wdt_driver);
+       if (ret) {
+               printk(KERN_ERR PFX "unable to register driver\n");
+               return ret;
+       }
+
+       ubi32_wdt_device = platform_device_register_simple(WATCHDOG_NAME, -1, NULL, 0);
+       if (IS_ERR(ubi32_wdt_device)) {
+               printk(KERN_ERR PFX "unable to register device\n");
+               platform_driver_unregister(&ubi32_wdt_driver);
+               return PTR_ERR(ubi32_wdt_device);
+       }
+
+       return 0;
+}
+
+/*
+ * ubi32_wdt_exit()
+ *     Deinitialize module
+ *
+ * Back out the platform device & driver steps.  Real work is in the
+ * platform remove function.
+ */
+static void __exit ubi32_wdt_exit(void)
+{
+       platform_device_unregister(ubi32_wdt_device);
+       platform_driver_unregister(&ubi32_wdt_driver);
+}
+
+module_init(ubi32_wdt_init);
+module_exit(ubi32_wdt_exit);
+
+MODULE_AUTHOR("Sol Kavy<sol@ubicom.com>");
+MODULE_DESCRIPTION("Ubicom32 Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout,
+       "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default="
+               __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+       "Watchdog cannot be stopped once started (default="
+               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/target/linux/ubicom32/files/sound/ubicom32/Kconfig b/target/linux/ubicom32/files/sound/ubicom32/Kconfig
new file mode 100644 (file)
index 0000000..c57bd34
--- /dev/null
@@ -0,0 +1,42 @@
+# ALSA Ubicom32 drivers
+
+menuconfig SND_UBI32
+       tristate "Ubicom32 sound devices"
+       select SND_PCM
+       default n
+       help
+         Say Y here to include support for audio on the Ubicom32 platform.
+         To compile this driver as a module, say M here: the module will be
+         called snd_ubi32.
+
+if SND_UBI32
+
+config SND_UBI32_AUDIO_GENERIC_CAPTURE
+       bool "Generic Capture Support"
+       default n
+       help
+         Use this option to support ADCs which don't require special drivers.
+
+config SND_UBI32_AUDIO_GENERIC
+       bool "Generic Playback Support"
+       default n
+       help
+         Use this option to support DACs which don't require special drivers.
+
+comment "I2C Based Codecs"
+
+config SND_UBI32_AUDIO_CS4350
+       bool "Cirrus Logic CS4350 DAC"
+       depends on I2C
+       default n
+       help
+         Support for the Cirrus Logic CS4350 DAC.
+
+config SND_UBI32_AUDIO_CS4384
+       bool "Cirrus Logic CS4384 DAC"
+       depends on I2C
+       default n
+       help
+         Support for the Cirrus Logic CS4384 DAC.
+
+endif #SND_UBI32
diff --git a/target/linux/ubicom32/files/sound/ubicom32/Makefile b/target/linux/ubicom32/files/sound/ubicom32/Makefile
new file mode 100644 (file)
index 0000000..ffdcc29
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# sound/ubicom32/Makefile
+#      Makefile for ALSA
+#
+# (C) Copyright 2009, Ubicom, Inc.
+#
+# This file is part of the Ubicom32 Linux Kernel Port.
+#
+# The Ubicom32 Linux Kernel Port 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.
+#
+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+# see <http://www.gnu.org/licenses/>.
+#
+# Ubicom32 implementation derived from (with many thanks):
+#   arch/m68knommu
+#   arch/blackfin
+#   arch/parisc
+#
+
+CFLAGS_ubi32.o += -O2
+snd-ubi32-pcm-objs := ubi32-pcm.o
+snd-ubi32-generic-objs := ubi32-generic.o
+snd-ubi32-generic-capture-objs := ubi32-generic-capture.o
+snd-ubi32-cs4350-objs := ubi32-cs4350.o
+snd-ubi32-cs4384-objs := ubi32-cs4384.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_UBI32) += snd-ubi32-pcm.o
+obj-$(CONFIG_SND_UBI32_AUDIO_GENERIC) += snd-ubi32-generic.o
+obj-$(CONFIG_SND_UBI32_AUDIO_GENERIC_CAPTURE) += snd-ubi32-generic-capture.o
+obj-$(CONFIG_SND_UBI32_AUDIO_CS4350) += snd-ubi32-cs4350.o
+obj-$(CONFIG_SND_UBI32_AUDIO_CS4384) += snd-ubi32-cs4384.o
diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4350.c b/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4350.c
new file mode 100644 (file)
index 0000000..7e6f9ac
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+ * sound/ubicom32/ubi32-cs4350.c
+ *     Interface to ubicom32 virtual audio peripheral - using CS4350 DAC
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include "ubi32.h"
+
+#define DRIVER_NAME "snd-ubi32-cs4350"
+
+/*
+ * Module properties
+ */
+static const struct i2c_device_id snd_ubi32_cs4350_id[] = {
+       {"cs4350", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ubicom32audio_id);
+
+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
+
+/*
+ * The dB scale for the Cirrus Logic cs4350.  The output range is from
+ * -127.5 dB to 0 dB.
+ */
+static const DECLARE_TLV_DB_SCALE(snd_ubi32_cs4350_db, -12750, 50, 0);
+
+#define ubi32_cs4350_mute_info snd_ctl_boolean_stereo_info
+
+/*
+ * Private data for cs4350 chip
+ */
+struct ubi32_cs4350_priv {
+       /*
+        * The current volume settings
+        */
+       uint8_t volume[2];
+
+       /*
+        * Bitmask of mutes MSB (unused, ..., unused, right_ch, left_ch) LSB
+        */
+       uint8_t mute;
+
+       /*
+        * Lock to protect this struct because callbacks are not atomic.
+        */
+       spinlock_t lock;
+};
+
+/*
+ * The info for the cs4350.  The volume currently has one channel,
+ * and 255 possible settings.
+ */
+static int ubi32_cs4350_volume_info(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 255; // 8 bits in cirrus logic cs4350 volume register
+       return 0;
+}
+
+static int ubi32_cs4350_volume_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol);
+       struct ubi32_cs4350_priv *cs4350_priv;
+       unsigned long flags;
+
+       cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv);
+
+       spin_lock_irqsave(&cs4350_priv->lock, flags);
+
+       ucontrol->value.integer.value[0] = cs4350_priv->volume[0];
+       ucontrol->value.integer.value[1] = cs4350_priv->volume[1];
+
+       spin_unlock_irqrestore(&cs4350_priv->lock, flags);
+
+       return 0;
+}
+
+static int ubi32_cs4350_volume_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol);
+       struct i2c_client *client = (struct i2c_client *)ubi32_priv->client;
+       struct ubi32_cs4350_priv *cs4350_priv;
+       unsigned long flags;
+       int ret, changed;
+       char send[2];
+       uint8_t volume_reg_value_left, volume_reg_value_right;
+
+       changed = 0;
+
+       cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv);
+       volume_reg_value_left = 255 - (ucontrol->value.integer.value[0] & 0xFF);
+       volume_reg_value_right = 255 - (ucontrol->value.integer.value[1] & 0xFF);
+
+#if SND_UBI32_DEBUG
+       snd_printk(KERN_INFO "Setting volume: writing %d,%d to CS4350 volume registers\n", volume_reg_value_left, volume_reg_value_right);
+#endif
+       spin_lock_irqsave(&cs4350_priv->lock, flags);
+
+       if (cs4350_priv->volume[0] != ucontrol->value.integer.value[0]) {
+               send[0] = 0x05; // left channel
+               send[1] = volume_reg_value_left;
+               ret = i2c_master_send(client, send, 2);
+               if (ret != 2) {
+                       snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n");
+                       return changed;
+               }
+               cs4350_priv->volume[0] = ucontrol->value.integer.value[0];
+               changed = 1;
+       }
+
+       if (cs4350_priv->volume[1] != ucontrol->value.integer.value[1]) {
+               send[0] = 0x06; // right channel
+               send[1] = volume_reg_value_right;
+               ret = i2c_master_send(client, send, 2);
+               if (ret != 2) {
+                       snd_printk(KERN_ERR "Failed to set channel B volume on CS4350\n");
+                       return changed;
+               }
+               cs4350_priv->volume[1] = ucontrol->value.integer.value[1];
+               changed = 1;
+       }
+
+       spin_unlock_irqrestore(&cs4350_priv->lock, flags);
+
+       return changed;
+}
+
+static struct snd_kcontrol_new ubi32_cs4350_volume __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                 SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+       .name = "PCM Playback Volume",
+       .info = ubi32_cs4350_volume_info,
+       .get = ubi32_cs4350_volume_get,
+       .put = ubi32_cs4350_volume_put,
+       .tlv.p = snd_ubi32_cs4350_db,
+};
+
+static int ubi32_cs4350_mute_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol);
+       struct ubi32_cs4350_priv *cs4350_priv;
+       unsigned long flags;
+
+       cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv);
+
+       spin_lock_irqsave(&cs4350_priv->lock, flags);
+
+       ucontrol->value.integer.value[0] = cs4350_priv->mute & 1;
+       ucontrol->value.integer.value[1] = (cs4350_priv->mute & (1 << 1)) ? 1 : 0;
+
+       spin_unlock_irqrestore(&cs4350_priv->lock, flags);
+
+       return 0;
+}
+
+static int ubi32_cs4350_mute_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol);
+       struct i2c_client *client = (struct i2c_client *)ubi32_priv->client;
+       struct ubi32_cs4350_priv *cs4350_priv;
+       unsigned long flags;
+       int ret, changed;
+       char send[2];
+       char recv[1];
+       uint8_t mute;
+
+        changed = 0;
+
+       cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv);
+
+       spin_lock_irqsave(&cs4350_priv->lock, flags);
+
+       if ((cs4350_priv->mute & 1) != ucontrol->value.integer.value[0]) {
+               send[0] = 0x04;
+               ret = i2c_master_send(client, send, 1);
+               if (ret != 1) {
+                       snd_printk(KERN_ERR "Failed to write to mute register: channel 0\n");
+                       return changed;
+               }
+
+               ret = i2c_master_recv(client, recv, 1);
+               if (ret != 1) {
+                       snd_printk(KERN_ERR "Failed to read mute register: channel 0\n");
+                       return changed;
+               }
+
+               mute = recv[0];
+
+               if (ucontrol->value.integer.value[0]) {
+                       cs4350_priv->mute |= 1;
+                       mute &= ~(1 << 4);
+#if SND_UBI32_DEBUG
+                       snd_printk(KERN_INFO "Unmuted channel A\n");
+#endif
+               } else {
+                       cs4350_priv->mute &= ~1;
+                       mute |= (1 << 4);
+#if SND_UBI32_DEBUG
+                       snd_printk(KERN_INFO "Muted channel A\n");
+#endif
+               }
+
+               send[0] = 0x04;
+               send[1] = mute;
+               ret = i2c_master_send(client, send, 2);
+               if (ret != 2) {
+                       snd_printk(KERN_ERR "Failed to set channel A mute on CS4350\n");
+                       return changed;
+               }
+               changed = 1;
+       }
+
+       if (((cs4350_priv->mute & 2) >> 1) != ucontrol->value.integer.value[1]) {
+               send[0] = 0x04;
+               ret = i2c_master_send(client, send, 1);
+               if (ret != 1) {
+                       snd_printk(KERN_ERR "Failed to write to mute register: channel 1\n");
+                       return changed;
+               }
+
+               ret = i2c_master_recv(client, recv, 1);
+               if (ret != 1) {
+                       snd_printk(KERN_ERR "Failed to read mute register: channel 1\n");
+                       return changed;
+               }
+
+               mute = recv[0];
+
+               if (ucontrol->value.integer.value[1]) {
+                       cs4350_priv->mute |= (1 << 1);
+                       mute &= ~(1 << 3);
+#if SND_UBI32_DEBUG
+                       snd_printk(KERN_INFO "Unmuted channel B\n");
+#endif
+               } else {
+                       cs4350_priv->mute &= ~(1 << 1);
+                       mute |= (1 << 3);
+#if SND_UBI32_DEBUG
+                       snd_printk(KERN_INFO "Muted channel B\n");
+#endif
+               }
+
+               send[0] = 0x04;
+               send[1] = mute;
+               ret = i2c_master_send(client, send, 2);
+               if (ret != 2) {
+                       snd_printk(KERN_ERR "Failed to set channel A mute on CS4350\n");
+                       return changed;
+               }
+               changed = 1;
+       }
+
+       spin_unlock_irqrestore(&cs4350_priv->lock, flags);
+
+       return changed;
+}
+
+static struct snd_kcontrol_new ubi32_cs4350_mute __devinitdata = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .name = "PCM Playback Switch",
+       .info = ubi32_cs4350_mute_info,
+       .get = ubi32_cs4350_mute_get,
+       .put = ubi32_cs4350_mute_put,
+};
+
+/*
+ * snd_ubi32_cs4350_free
+ *     Card private data free function
+ */
+void snd_ubi32_cs4350_free(struct snd_card *card)
+{
+       struct ubi32_snd_priv *ubi32_priv;
+       struct ubi32_cs4350_priv *cs4350_priv;
+
+       ubi32_priv = card->private_data;
+       cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv);
+       if (cs4350_priv) {
+               kfree(cs4350_priv);
+       }
+}
+
+/*
+ * snd_ubi32_cs4350_dac_init
+ */
+static int snd_ubi32_cs4350_dac_init(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       int ret;
+       char send[2];
+       char recv[8];
+
+       /*
+        * Initialize the CS4350 DAC over the I2C interface
+        */
+       snd_printk(KERN_INFO "Initializing CS4350 DAC\n");
+
+       /*
+        * Register 0x01: device/revid
+        */
+       send[0] = 0x01;
+       ret = i2c_master_send(client, send, 1);
+       if (ret != 1) {
+               snd_printk(KERN_ERR "Failed 1st attempt to write to CS4350 register 0x01\n");
+               goto fail;
+       }
+       ret = i2c_master_recv(client, recv, 1);
+       if (ret != 1) {
+               snd_printk(KERN_ERR "Failed initial read of CS4350 registers\n");
+               goto fail;
+       }
+       snd_printk(KERN_INFO "CS4350 DAC Device/Rev: %08x\n", recv[0]);
+
+       /*
+        * Register 0x02: Mode control
+        *      I2S DIF[2:0] = 001, no De-Emphasis, Auto speed mode
+        */
+       send[0] = 0x02;
+       send[1] = 0x10;
+       ret = i2c_master_send(client, send, 2);
+       if (ret != 2) {
+               snd_printk(KERN_ERR "Failed to set CS4350 to I2S mode\n");
+               goto fail;
+       }
+
+       /*
+        * Register 0x05/0x06: Volume control
+        *      Channel A volume set to 0 dB
+        *      Channel B volume set to 0 dB
+        */
+       send[0] = 0x05;
+       send[1] = 0x00;
+       ret = i2c_master_send(client, send, 2);
+       if (ret != 2) {
+               snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n");
+               goto fail;
+       }
+
+       send[0] = 0x06;
+       send[1] = 0x00;
+       ret = i2c_master_send(client, send, 2);
+       if (ret != 2) {
+               snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n");
+               goto fail;
+       }
+
+       /*
+        * Make sure the changes took place, this helps verify we are talking to
+        * the correct chip.
+        */
+       send[0] = 0x81;
+       ret = i2c_master_send(client, send, 1);
+       if (ret != 1) {
+               snd_printk(KERN_ERR "Failed to initiate readback\n");
+               goto fail;
+       }
+
+       ret = i2c_master_recv(client, recv, 8);
+       if (ret != 8) {
+               snd_printk(KERN_ERR "Failed second read of CS4350 registers\n");
+               goto fail;
+       }
+
+       if ((recv[1] != 0x10) || (recv[4] != 0x00) || (recv[5] != 0x00)) {
+               snd_printk(KERN_ERR "Failed to initialize CS4350 DAC\n");
+               goto fail;
+       }
+
+       snd_printk(KERN_INFO "CS4350 DAC Initialized\n");
+       return 0;
+
+fail:
+       return -ENODEV;
+}
+
+/*
+ * snd_ubi32_cs4350_i2c_probe
+ */
+static int snd_ubi32_cs4350_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct snd_card *card;
+       struct ubi32_snd_priv *ubi32_priv;
+       struct ubi32_cs4350_priv *cs4350_priv;
+       int err, ret;
+       struct platform_device *pdev;
+
+       pdev = client->dev.platform_data;
+       if (!pdev) {
+               return -ENODEV;
+       }
+
+       /*
+        * Initialize the CS4350 DAC
+        */
+       ret = snd_ubi32_cs4350_dac_init(client, id);
+       if (ret < 0) {
+               /*
+                * Initialization failed.  Propagate the error.
+                */
+               return ret;
+       }
+
+       /*
+        * Create a snd_card structure
+        */
+       card = snd_card_new(index, "Ubi32-CS4350", THIS_MODULE, sizeof(struct ubi32_snd_priv));
+       if (card == NULL) {
+               return -ENOMEM;
+       }
+
+       card->private_free = snd_ubi32_cs4350_free; /* Not sure if correct */
+       ubi32_priv = card->private_data;
+
+       /*
+        * CS4350 DAC has a minimum sample rate of 30khz and an
+        * upper limit of 216khz for it's auto-detect.
+        */
+       ubi32_priv->min_sample_rate = 30000;
+       ubi32_priv->max_sample_rate = 216000;
+
+       /*
+        * Initialize the snd_card's private data structure
+        */
+       ubi32_priv->card = card;
+       ubi32_priv->client = client;
+
+       /*
+        * Create our private data structure
+        */
+       cs4350_priv = kzalloc(sizeof(struct ubi32_cs4350_priv), GFP_KERNEL);
+       if (!cs4350_priv) {
+               snd_card_free(card);
+               return -ENOMEM;
+       }
+       snd_ubi32_priv_set_drv(ubi32_priv, cs4350_priv);
+       spin_lock_init(&cs4350_priv->lock);
+
+       /*
+        * Initial volume is set to max by probe function
+        */
+       cs4350_priv->volume[0] = 0xFF;
+       cs4350_priv->volume[1] = 0xFF;
+
+       /*
+        * The CS4350 starts off unmuted (bit set = not muted)
+        */
+       cs4350_priv->mute = 3;
+
+       /*
+        * Create the new PCM instance
+        */
+       err = snd_ubi32_pcm_probe(ubi32_priv, pdev);
+       if (err < 0) {
+               snd_card_free(card);
+               return err; /* What is err?  Need to include correct file */
+       }
+
+       strcpy(card->driver, "Ubi32-CS4350");
+       strcpy(card->shortname, "Ubi32-CS4350");
+       snprintf(card->longname, sizeof(card->longname),
+               "%s at sendirq=%d.%d recvirq=%d.%d regs=%p",
+               card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx,
+               ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr);
+
+       snd_card_set_dev(card, &client->dev);
+
+       /*
+        * Set up the mixer components
+        */
+       err = snd_ctl_add(card, snd_ctl_new1(&ubi32_cs4350_volume, ubi32_priv));
+       if (err) {
+               snd_printk(KERN_WARNING "Failed to add volume mixer control\n");
+       }
+       err = snd_ctl_add(card, snd_ctl_new1(&ubi32_cs4350_mute, ubi32_priv));
+       if (err) {
+               snd_printk(KERN_WARNING "Failed to add mute mixer control\n");
+       }
+
+       /*
+        * Register the sound card
+        */
+       if ((err = snd_card_register(card)) != 0) {
+               snd_printk(KERN_WARNING "snd_card_register error\n");
+       }
+
+       /*
+        * Store card for access from other methods
+        */
+       i2c_set_clientdata(client, card);
+
+       return 0;
+}
+
+/*
+ * snd_ubi32_cs4350_i2c_remove
+ */
+static int __devexit snd_ubi32_cs4350_i2c_remove(struct i2c_client *client)
+{
+       struct snd_card *card;
+       struct ubi32_snd_priv *ubi32_priv;
+
+       card = i2c_get_clientdata(client);
+
+       ubi32_priv = card->private_data;
+       snd_ubi32_pcm_remove(ubi32_priv);
+
+       snd_card_free(i2c_get_clientdata(client));
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+/*
+ * I2C driver description
+ */
+static struct i2c_driver snd_ubi32_cs4350_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+       .id_table       = snd_ubi32_cs4350_id,
+       .probe          = snd_ubi32_cs4350_i2c_probe,
+       .remove         = __devexit_p(snd_ubi32_cs4350_i2c_remove),
+};
+
+/*
+ * Driver init
+ */
+static int __init snd_ubi32_cs4350_init(void)
+{
+       return i2c_add_driver(&snd_ubi32_cs4350_driver);
+}
+module_init(snd_ubi32_cs4350_init);
+
+/*
+ * snd_ubi32_cs4350_exit
+ */
+static void __exit snd_ubi32_cs4350_exit(void)
+{
+       i2c_del_driver(&snd_ubi32_cs4350_driver);
+}
+module_exit(snd_ubi32_cs4350_exit);
+
+/*
+ * Module properties
+ */
+MODULE_ALIAS("i2c:" DRIVER_NAME);
+MODULE_AUTHOR("Patrick Tjin");
+MODULE_DESCRIPTION("Driver for Ubicom32 audio devices CS4350");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4384.c b/target/linux/ubicom32/files/sound/ubicom32/ubi32-cs4384.c
new file mode 100644 (file)
index 0000000..2679267
--- /dev/null
@@ -0,0 +1,996 @@
+/*
+ * sound/ubicom32/ubi32-cs4384.c
+ *     Interface to ubicom32 virtual audio peripheral - using CS4384 DAC
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/tlv.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <asm/ip5000.h>
+#include <asm/gpio.h>
+#include <asm/audio.h>
+#include <asm/ubi32-cs4384.h>
+#include "ubi32.h"
+
+#define DRIVER_NAME "snd-ubi32-cs4384"
+
+/*
+ * Module properties
+ */
+static const struct i2c_device_id snd_ubi32_cs4384_id[] = {
+       {"cs4384", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ubicom32audio_id);
+
+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
+
+/*
+ * Mixer properties
+ */
+enum {
+       /*
+        * Be careful of changing the order of these IDs, they
+        * are used to index the volume array.
+        */
+       SND_UBI32_CS4384_FRONT_ID,
+       SND_UBI32_CS4384_SURROUND_ID,
+       SND_UBI32_CS4384_CENTER_ID,
+       SND_UBI32_CS4384_LFE_ID,
+       SND_UBI32_CS4384_REAR_ID,
+
+       /*
+        * This should be the last ID
+        */
+       SND_UBI32_CS4384_LAST_ID,
+};
+static const u8_t snd_ubi32_cs4384_ch_ofs[] = {0, 2, 4, 5, 6};
+
+static const DECLARE_TLV_DB_SCALE(snd_ubi32_cs4384_db, -12750, 50, 0);
+
+#define snd_ubi32_cs4384_info_mute     snd_ctl_boolean_stereo_info
+#define snd_ubi32_cs4384_info_mute_mono        snd_ctl_boolean_mono_info
+
+/*
+ * Mixer controls
+ */
+static int snd_ubi32_cs4384_info_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
+static int snd_ubi32_cs4384_get_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+static int snd_ubi32_cs4384_put_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+static int snd_ubi32_cs4384_get_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+static int snd_ubi32_cs4384_put_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
+
+/*
+ * Make sure to update these if the structure below is changed
+ */
+#define SND_UBI32_MUTE_CTL_START       5
+#define SND_UBI32_MUTE_CTL_END         9
+static struct snd_kcontrol_new snd_ubi32_cs4384_controls[] __devinitdata = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .name = "Front Playback Volume",
+               .info = snd_ubi32_cs4384_info_volume,
+               .get = snd_ubi32_cs4384_get_volume,
+               .put = snd_ubi32_cs4384_put_volume,
+               .private_value = SND_UBI32_CS4384_FRONT_ID,
+               .tlv = {
+                       .p = snd_ubi32_cs4384_db,
+               },
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .name = "Surround Playback Volume",
+               .info = snd_ubi32_cs4384_info_volume,
+               .get = snd_ubi32_cs4384_get_volume,
+               .put = snd_ubi32_cs4384_put_volume,
+               .private_value = SND_UBI32_CS4384_SURROUND_ID,
+               .tlv = {
+                       .p = snd_ubi32_cs4384_db,
+               },
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .name = "Center Playback Volume",
+               .info = snd_ubi32_cs4384_info_volume,
+               .get = snd_ubi32_cs4384_get_volume,
+               .put = snd_ubi32_cs4384_put_volume,
+               .private_value = SND_UBI32_CS4384_CENTER_ID,
+               .tlv = {
+                       .p = snd_ubi32_cs4384_db,
+               },
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .name = "LFE Playback Volume",
+               .info = snd_ubi32_cs4384_info_volume,
+               .get = snd_ubi32_cs4384_get_volume,
+               .put = snd_ubi32_cs4384_put_volume,
+               .private_value = SND_UBI32_CS4384_LFE_ID,
+               .tlv = {
+                       .p = snd_ubi32_cs4384_db,
+               },
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .name = "Rear Playback Volume",
+               .info = snd_ubi32_cs4384_info_volume,
+               .get = snd_ubi32_cs4384_get_volume,
+               .put = snd_ubi32_cs4384_put_volume,
+               .private_value = SND_UBI32_CS4384_REAR_ID,
+               .tlv = {
+                       .p = snd_ubi32_cs4384_db,
+               },
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .name = "Front Playback Switch",
+               .info = snd_ubi32_cs4384_info_mute,
+               .get = snd_ubi32_cs4384_get_mute,
+               .put = snd_ubi32_cs4384_put_mute,
+               .private_value = SND_UBI32_CS4384_FRONT_ID,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .name = "Surround Playback Switch",
+               .info = snd_ubi32_cs4384_info_mute,
+               .get = snd_ubi32_cs4384_get_mute,
+               .put = snd_ubi32_cs4384_put_mute,
+               .private_value = SND_UBI32_CS4384_SURROUND_ID,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .name = "Center Playback Switch",
+               .info = snd_ubi32_cs4384_info_mute_mono,
+               .get = snd_ubi32_cs4384_get_mute,
+               .put = snd_ubi32_cs4384_put_mute,
+               .private_value = SND_UBI32_CS4384_CENTER_ID,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .name = "LFE Playback Switch",
+               .info = snd_ubi32_cs4384_info_mute_mono,
+               .get = snd_ubi32_cs4384_get_mute,
+               .put = snd_ubi32_cs4384_put_mute,
+               .private_value = SND_UBI32_CS4384_LFE_ID,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .name = "Rear Playback Switch",
+               .info = snd_ubi32_cs4384_info_mute,
+               .get = snd_ubi32_cs4384_get_mute,
+               .put = snd_ubi32_cs4384_put_mute,
+               .private_value = SND_UBI32_CS4384_REAR_ID,
+       },
+};
+
+/*
+ * Our private data
+ */
+struct snd_ubi32_cs4384_priv {
+       /*
+        * Array of current volumes
+        *      (L, R, SL, SR, C, LFE, RL, RR)
+        */
+       uint8_t volume[8];
+
+       /*
+        * Bitmask of mutes
+        *      MSB (RR, RL, LFE, C, SR, SL, R, L) LSB
+        */
+       uint8_t mute;
+
+       /*
+        * Array of controls
+        */
+       struct snd_kcontrol *kctls[ARRAY_SIZE(snd_ubi32_cs4384_controls)];
+
+       /*
+        * Lock to protect our card
+        */
+       spinlock_t lock;
+};
+
+/*
+ * snd_ubi32_cs4384_info_volume
+ */
+static int snd_ubi32_cs4384_info_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+       unsigned int id = (unsigned int)kcontrol->private_value;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       if ((id != SND_UBI32_CS4384_LFE_ID) &&
+           (id != SND_UBI32_CS4384_CENTER_ID)) {
+               uinfo->count = 2;
+       }
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 255;
+       return 0;
+}
+
+/*
+ * snd_ubi32_cs4384_get_volume
+ */
+static int snd_ubi32_cs4384_get_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol);
+       struct snd_ubi32_cs4384_priv *cs4384_priv;
+       unsigned int id = (unsigned int)kcontrol->private_value;
+       int ch = snd_ubi32_cs4384_ch_ofs[id];
+       unsigned long flags;
+
+       if (id >= SND_UBI32_CS4384_LAST_ID) {
+               return -EINVAL;
+       }
+
+       cs4384_priv = snd_ubi32_priv_get_drv(priv);
+
+       spin_lock_irqsave(&cs4384_priv->lock, flags);
+
+       ucontrol->value.integer.value[0] = cs4384_priv->volume[ch];
+       if ((id != SND_UBI32_CS4384_LFE_ID) &&
+           (id != SND_UBI32_CS4384_CENTER_ID)) {
+               ch++;
+               ucontrol->value.integer.value[1] = cs4384_priv->volume[ch];
+       }
+
+       spin_unlock_irqrestore(&cs4384_priv->lock, flags);
+
+       return 0;
+}
+
+/*
+ * snd_ubi32_cs4384_put_volume
+ */
+static int snd_ubi32_cs4384_put_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol);
+       struct i2c_client *client = (struct i2c_client *)priv->client;
+       struct snd_ubi32_cs4384_priv *cs4384_priv;
+       unsigned int id = (unsigned int)kcontrol->private_value;
+       int ch = snd_ubi32_cs4384_ch_ofs[id];
+       unsigned long flags;
+       unsigned char send[3];
+       int nch;
+       int ret = -EINVAL;
+
+       if (id >= SND_UBI32_CS4384_LAST_ID) {
+               return -EINVAL;
+       }
+
+       cs4384_priv = snd_ubi32_priv_get_drv(priv);
+
+       spin_lock_irqsave(&cs4384_priv->lock, flags);
+
+       send[0] = 0;
+       switch (id) {
+       case SND_UBI32_CS4384_REAR_ID:
+               send[0] = 0x06;
+
+               /*
+                * Fall through
+                */
+
+       case SND_UBI32_CS4384_SURROUND_ID:
+               send[0] += 0x03;
+
+               /*
+                * Fall through
+                */
+
+       case SND_UBI32_CS4384_FRONT_ID:
+               send[0] += 0x8B;
+               nch = 2;
+               send[1] = 255 - (ucontrol->value.integer.value[0] & 0xFF);
+               send[2] = 255 - (ucontrol->value.integer.value[1] & 0xFF);
+               cs4384_priv->volume[ch++] = send[1];
+               cs4384_priv->volume[ch] = send[2];
+               break;
+
+       case SND_UBI32_CS4384_LFE_ID:
+               send[0] = 0x81;
+
+               /*
+                * Fall through
+                */
+
+       case SND_UBI32_CS4384_CENTER_ID:
+               send[0] += 0x11;
+               nch = 1;
+               send[1] = 255 - (ucontrol->value.integer.value[0] & 0xFF);
+               cs4384_priv->volume[ch] = send[1];
+               break;
+
+       default:
+               spin_unlock_irqrestore(&cs4384_priv->lock, flags);
+               goto done;
+
+       }
+
+       /*
+        * Send the volume to the chip
+        */
+       nch++;
+       ret = i2c_master_send(client, send, nch);
+       if (ret != nch) {
+               snd_printk(KERN_ERR "Failed to set volume on CS4384\n");
+       }
+
+done:
+       spin_unlock_irqrestore(&cs4384_priv->lock, flags);
+
+       return ret;
+}
+
+/*
+ * snd_ubi32_cs4384_get_mute
+ */
+static int snd_ubi32_cs4384_get_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol);
+       struct snd_ubi32_cs4384_priv *cs4384_priv;
+       unsigned int id = (unsigned int)kcontrol->private_value;
+       int ch = snd_ubi32_cs4384_ch_ofs[id];
+       unsigned long flags;
+
+       if (id >= SND_UBI32_CS4384_LAST_ID) {
+               return -EINVAL;
+       }
+
+       cs4384_priv = snd_ubi32_priv_get_drv(priv);
+
+       spin_lock_irqsave(&cs4384_priv->lock, flags);
+
+       ucontrol->value.integer.value[0] = !(cs4384_priv->mute & (1 << ch));
+
+       if ((id != SND_UBI32_CS4384_LFE_ID) &&
+           (id != SND_UBI32_CS4384_CENTER_ID)) {
+               ch++;
+               ucontrol->value.integer.value[1] = !(cs4384_priv->mute & (1 << ch));
+       }
+
+       spin_unlock_irqrestore(&cs4384_priv->lock, flags);
+
+       return 0;
+}
+
+/*
+ * snd_ubi32_cs4384_put_mute
+ */
+static int snd_ubi32_cs4384_put_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+{
+       struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol);
+       struct i2c_client *client = (struct i2c_client *)priv->client;
+       struct snd_ubi32_cs4384_priv *cs4384_priv;
+       unsigned int id = (unsigned int)kcontrol->private_value;
+       int ch = snd_ubi32_cs4384_ch_ofs[id];
+       unsigned long flags;
+       unsigned char send[2];
+       int ret = -EINVAL;
+
+       if (id >= SND_UBI32_CS4384_LAST_ID) {
+               return -EINVAL;
+       }
+
+       cs4384_priv = snd_ubi32_priv_get_drv(priv);
+
+       spin_lock_irqsave(&cs4384_priv->lock, flags);
+
+       if (ucontrol->value.integer.value[0]) {
+               cs4384_priv->mute &= ~(1 << ch);
+       } else {
+               cs4384_priv->mute |= (1 << ch);
+       }
+
+       if ((id != SND_UBI32_CS4384_LFE_ID) && (id != SND_UBI32_CS4384_CENTER_ID)) {
+               ch++;
+               if (ucontrol->value.integer.value[1]) {
+                       cs4384_priv->mute &= ~(1 << ch);
+               } else {
+                       cs4384_priv->mute |= (1 << ch);
+               }
+       }
+
+       /*
+        * Update the chip's mute reigster
+        */
+       send[0] = 0x09;
+       send[1] = cs4384_priv->mute;
+       ret = i2c_master_send(client, send, 2);
+       if (ret != 2) {
+               snd_printk(KERN_ERR "Failed to set mute on CS4384\n");
+       }
+
+       spin_unlock_irqrestore(&cs4384_priv->lock, flags);
+
+       return ret;
+}
+
+/*
+ * snd_ubi32_cs4384_mixer
+ *     Setup the mixer controls
+ */
+static int __devinit snd_ubi32_cs4384_mixer(struct ubi32_snd_priv *priv)
+{
+       struct snd_card *card = priv->card;
+       struct snd_ubi32_cs4384_priv *cs4384_priv;
+       int i;
+
+       cs4384_priv = snd_ubi32_priv_get_drv(priv);
+       for (i = 0; i < ARRAY_SIZE(snd_ubi32_cs4384_controls); i++) {
+               int err;
+
+               cs4384_priv->kctls[i] = snd_ctl_new1(&snd_ubi32_cs4384_controls[i], priv);
+               err = snd_ctl_add(card, cs4384_priv->kctls[i]);
+               if (err) {
+                       snd_printk(KERN_WARNING "Failed to add control %d\n", i);
+                       return err;
+               }
+       }
+       return 0;
+}
+
+/*
+ * snd_ubi32_cs4384_free
+ *     Card private data free function
+ */
+void snd_ubi32_cs4384_free(struct snd_card *card)
+{
+       struct snd_ubi32_cs4384_priv *cs4384_priv;
+       struct ubi32_snd_priv *ubi32_priv;
+
+       ubi32_priv = card->private_data;
+       cs4384_priv = snd_ubi32_priv_get_drv(ubi32_priv);
+       if (cs4384_priv) {
+               kfree(cs4384_priv);
+       }
+}
+
+/*
+ * snd_ubi32_cs4384_setup_mclk
+ */
+static int snd_ubi32_cs4384_setup_mclk(struct ubi32_cs4384_platform_data *pdata)
+{
+       struct ubicom32_io_port *ioa = (struct ubicom32_io_port *)RA;
+       struct ubicom32_io_port *ioc = (struct ubicom32_io_port *)RC;
+       struct ubicom32_io_port *iod = (struct ubicom32_io_port *)RD;
+       struct ubicom32_io_port *ioe = (struct ubicom32_io_port *)RE;
+       struct ubicom32_io_port *ioh = (struct ubicom32_io_port *)RH;
+       unsigned int ctl0;
+       unsigned int ctlx;
+       unsigned int div;
+
+       div = pdata->mclk_entries[0].div;
+
+       ctl0 = (1 << 13);
+       ctlx = ((div - 1) << 16) | (div / 2);
+
+       switch (pdata->mclk_src) {
+       case UBI32_CS4384_MCLK_PWM_0:
+               ioc->function |= 2;
+               ioc->ctl0 |= ctl0;
+               ioc->ctl1 = ctlx;
+               if (!ioa->function) {
+                       ioa->function = 3;
+               }
+               return 0;
+
+       case UBI32_CS4384_MCLK_PWM_1:
+               ioc->function |= 2;
+               ioc->ctl0 |= ctl0 << 16;
+               ioc->ctl2 = ctlx;
+               if (!ioe->function) {
+                       ioe->function = 3;
+               }
+               return 0;
+
+       case UBI32_CS4384_MCLK_PWM_2:
+               ioh->ctl0 |= ctl0;
+               ioh->ctl1 = ctlx;
+               if (!iod->function) {
+                       iod->function = 3;
+               }
+               return 0;
+
+       case UBI32_CS4384_MCLK_CLKDIV_1:
+               ioa->gpio_mask &= (1 << 7);
+               ioa->ctl1 &= ~(0x7F << 14);
+               ioa->ctl1 |= ((div - 1) << 14);
+               return 0;
+
+       case UBI32_CS4384_MCLK_OTHER:
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * snd_ubi32_cs4384_set_rate
+ */
+static int snd_ubi32_cs4384_set_rate(struct ubi32_snd_priv *priv, int rate)
+{
+       struct ubi32_cs4384_platform_data *cpd = priv->pdata->priv_data;
+       struct ubicom32_io_port *ioa = (struct ubicom32_io_port *)RA;
+       struct ubicom32_io_port *ioc = (struct ubicom32_io_port *)RC;
+       struct ubicom32_io_port *ioh = (struct ubicom32_io_port *)RH;
+       unsigned int ctl;
+       unsigned int div = 0;
+       const u16_t mult[] = {64, 96, 128, 192, 256, 384, 512, 768, 1024};
+       int i;
+       int j;
+
+
+       for (i = 0; i < sizeof(mult) / sizeof(u16_t); i++) {
+               for (j = 0; j < cpd->n_mclk; j++) {
+                       if (((unsigned int)rate * (unsigned int)mult[i]) ==
+                            cpd->mclk_entries[j].rate) {
+                               div = cpd->mclk_entries[j].div;
+                               break;
+                       }
+               }
+       }
+
+       ctl = ((div - 1) << 16) | (div / 2);
+
+       switch (cpd->mclk_src) {
+       case UBI32_CS4384_MCLK_PWM_0:
+               ioc->ctl1 = ctl;
+               return 0;
+
+       case UBI32_CS4384_MCLK_PWM_1:
+               ioc->ctl2 = ctl;
+               return 0;
+
+       case UBI32_CS4384_MCLK_PWM_2:
+               ioh->ctl1 = ctl;
+               return 0;
+
+       case UBI32_CS4384_MCLK_CLKDIV_1:
+               ioa->ctl1 &= ~(0x7F << 14);
+               ioa->ctl1 |= ((div - 1) << 14);
+               return 0;
+
+       case UBI32_CS4384_MCLK_OTHER:
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * snd_ubi32_cs4384_set_channels
+ *     Mute unused channels
+ */
+static int snd_ubi32_cs4384_set_channels(struct ubi32_snd_priv *priv, int channels)
+{
+       struct i2c_client *client = (struct i2c_client *)priv->client;
+       struct snd_ubi32_cs4384_priv *cs4384_priv;
+       unsigned char send[2];
+       int ret;
+       int i;
+       unsigned long flags;
+
+       /*
+        * Only support 0, 2, 4, 6, 8 channels
+        */
+       if ((channels > 8) || (channels & 1)) {
+               return -EINVAL;
+       }
+
+       cs4384_priv = snd_ubi32_priv_get_drv(priv);
+       spin_lock_irqsave(&cs4384_priv->lock, flags);
+
+       /*
+        * Address 09h, Mute control
+        */
+       send[0] = 0x09;
+       send[1] = (unsigned char)(0xFF << channels);
+
+       ret = i2c_master_send(client, send, 2);
+
+       spin_unlock_irqrestore(&cs4384_priv->lock, flags);
+
+       /*
+        * Notify the system that we changed the mutes
+        */
+       cs4384_priv->mute = (unsigned char)(0xFF << channels);
+
+       for (i = SND_UBI32_MUTE_CTL_START; i < SND_UBI32_MUTE_CTL_END; i++) {
+               snd_ctl_notify(priv->card, SNDRV_CTL_EVENT_MASK_VALUE,
+                              &cs4384_priv->kctls[i]->id);
+       }
+
+       if (ret != 2) {
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+/*
+ * snd_ubi32_cs4384_dac_init
+ */
+static int snd_ubi32_cs4384_dac_init(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       int ret;
+       unsigned char send[2];
+       unsigned char recv[2];
+
+       /*
+        * Initialize the CS4384 DAC over the I2C interface
+        */
+       snd_printk(KERN_INFO "Initializing CS4384 DAC\n");
+
+       /*
+        * Register 0x01: device/revid
+        */
+       send[0] = 0x01;
+       ret = i2c_master_send(client, send, 1);
+       if (ret != 1) {
+               snd_printk(KERN_ERR "Failed 1st attempt to write to CS4384 register 0x01\n");
+               goto fail;
+       }
+       ret = i2c_master_recv(client, recv, 1);
+       if (ret != 1) {
+               snd_printk(KERN_ERR "Failed initial read of CS4384 registers\n");
+               goto fail;
+       }
+       snd_printk(KERN_INFO "CS4384 DAC Device/Rev: %08x\n", recv[0]);
+
+       /*
+        * Register 0x02: Mode Control 1
+        *      Control Port Enable, PCM, All DACs enabled, Power Down
+        */
+       send[0] = 0x02;
+       send[1] = 0x81;
+       ret = i2c_master_send(client, send, 2);
+       if (ret != 2) {
+               snd_printk(KERN_ERR "Failed to set CPEN CS4384\n");
+               goto fail;
+       }
+
+       /*
+        * Register 0x08: Ramp and Mute
+        *      RMP_UP, RMP_DN, PAMUTE, DAMUTE
+        */
+       send[0] = 0x08;
+       send[1] = 0xBC;
+       ret = i2c_master_send(client, send, 2);
+       if (ret != 2) {
+               snd_printk(KERN_ERR "Failed to set CPEN CS4384\n");
+               goto fail;
+       }
+
+       /*
+        * Register 0x03: PCM Control
+        *      I2S DIF[3:0] = 0001, no De-Emphasis, Auto speed mode
+        */
+       send[0] = 0x03;
+       send[1] = 0x13;
+       ret = i2c_master_send(client, send, 2);
+       if (ret != 2) {
+               snd_printk(KERN_ERR "Failed to set CS4384 to I2S mode\n");
+               goto fail;
+       }
+
+       /*
+        * Register 0x0B/0x0C: Volume control A1/B1
+        * Register 0x0E/0x0F: Volume control A2/B2
+        * Register 0x11/0x12: Volume control A3/B3
+        * Register 0x14/0x15: Volume control A4/B4
+        */
+       send[0] = 0x80 | 0x0B;
+       send[1] = 0x00;
+       send[2] = 0x00;
+       ret = i2c_master_send(client, send, 3);
+       if (ret != 3) {
+               snd_printk(KERN_ERR "Failed to set ch1 volume on CS4384\n");
+               goto fail;
+       }
+
+       send[0] = 0x80 | 0x0E;
+       send[1] = 0x00;
+       send[2] = 0x00;
+       ret = i2c_master_send(client, send, 3);
+       if (ret != 3) {
+               snd_printk(KERN_ERR "Failed to set ch2 volume on CS4384\n");
+               goto fail;
+       }
+
+       send[0] = 0x80 | 0x11;
+       send[1] = 0x00;
+       send[2] = 0x00;
+       ret = i2c_master_send(client, send, 3);
+       if (ret != 3) {
+               snd_printk(KERN_ERR "Failed to set ch3 volume on CS4384\n");
+               goto fail;
+       }
+
+       send[0] = 0x80 | 0x14;
+       send[1] = 0x00;
+       send[2] = 0x00;
+       ret = i2c_master_send(client, send, 3);
+       if (ret != 3) {
+               snd_printk(KERN_ERR "Failed to set ch4 volume on CS4384\n");
+               goto fail;
+       }
+
+       /*
+        * Register 09h: Mute control
+        *      Mute all (we will unmute channels as needed)
+        */
+       send[0] = 0x09;
+       send[1] = 0xFF;
+       ret = i2c_master_send(client, send, 2);
+       if (ret != 2) {
+               snd_printk(KERN_ERR "Failed to power up CS4384\n");
+               goto fail;
+       }
+
+       /*
+        * Register 0x02: Mode Control 1
+        *      Control Port Enable, PCM, All DACs enabled, Power Up
+        */
+       send[0] = 0x02;
+       send[1] = 0x80;
+       ret = i2c_master_send(client, send, 2);
+       if (ret != 2) {
+               snd_printk(KERN_ERR "Failed to power up CS4384\n");
+               goto fail;
+       }
+
+       /*
+        * Make sure the changes took place, this helps verify we are talking to
+        * the correct chip.
+        */
+       send[0] = 0x80 | 0x03;
+       ret = i2c_master_send(client, send, 1);
+       if (ret != 1) {
+               snd_printk(KERN_ERR "Failed to initiate readback\n");
+               goto fail;
+       }
+
+       ret = i2c_master_recv(client, recv, 1);
+       if (ret != 1) {
+               snd_printk(KERN_ERR "Failed second read of CS4384 registers\n");
+               goto fail;
+       }
+
+       if (recv[0] != 0x13) {
+               snd_printk(KERN_ERR "Failed to initialize CS4384 DAC\n");
+               goto fail;
+       }
+
+       snd_printk(KERN_INFO "CS4384 DAC Initialized\n");
+       return 0;
+
+fail:
+       return -ENODEV;
+}
+
+/*
+ * snd_ubi32_cs4384_i2c_probe
+ */
+static int snd_ubi32_cs4384_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct snd_card *card;
+       struct ubi32_snd_priv *ubi32_priv;
+       int err, ret;
+       struct platform_device *pdev;
+       struct ubi32_cs4384_platform_data *pdata;
+       struct snd_ubi32_cs4384_priv *cs4384_priv;
+
+       /*
+        * pdev is audio device
+        */
+       pdev = client->dev.platform_data;
+       if (!pdev) {
+               return -ENODEV;
+       }
+
+       /*
+        * pdev->dev.platform_data is ubi32-pcm platform_data
+        */
+       pdata = audio_device_priv(pdev);
+       if (!pdata) {
+               return -ENODEV;
+       }
+
+       /*
+        * Initialize the CS4384 DAC
+        */
+       ret = snd_ubi32_cs4384_dac_init(client, id);
+       if (ret < 0) {
+               /*
+                * Initialization failed.  Propagate the error.
+                */
+               return ret;
+       }
+
+       if (snd_ubi32_cs4384_setup_mclk(pdata)) {
+               return -EINVAL;
+       }
+
+       /*
+        * Create a snd_card structure
+        */
+       card = snd_card_new(index, "Ubi32-CS4384", THIS_MODULE, sizeof(struct ubi32_snd_priv));
+       if (card == NULL) {
+               return -ENOMEM;
+       }
+
+       card->private_free = snd_ubi32_cs4384_free;
+       ubi32_priv = card->private_data;
+
+       /*
+        * Initialize the snd_card's private data structure
+        */
+       ubi32_priv->card = card;
+       ubi32_priv->client = client;
+       ubi32_priv->set_channels = snd_ubi32_cs4384_set_channels;
+       ubi32_priv->set_rate = snd_ubi32_cs4384_set_rate;
+
+       /*
+        * CS4384 DAC has a minimum sample rate of 4khz and an
+        * upper limit of 216khz for it's auto-detect.
+        */
+       ubi32_priv->min_sample_rate = 4000;
+       ubi32_priv->max_sample_rate = 216000;
+
+       /*
+        * Create our private data (to manage volume, etc)
+        */
+       cs4384_priv = kzalloc(sizeof(struct snd_ubi32_cs4384_priv), GFP_KERNEL);
+       if (!cs4384_priv) {
+               snd_card_free(card);
+               return -ENOMEM;
+       }
+       snd_ubi32_priv_set_drv(ubi32_priv, cs4384_priv);
+       spin_lock_init(&cs4384_priv->lock);
+
+       /*
+        * We start off all muted and max volume
+        */
+       cs4384_priv->mute = 0xFF;
+       memset(cs4384_priv->volume, 0xFF, 8);
+
+       /*
+        * Create the new PCM instance
+        */
+       err = snd_ubi32_pcm_probe(ubi32_priv, pdev);
+       if (err < 0) {
+               snd_card_free(card);
+               return err; /* What is err?  Need to include correct file */
+       }
+
+       strcpy(card->driver, "Ubi32-CS4384");
+       strcpy(card->shortname, "Ubi32-CS4384");
+       snprintf(card->longname, sizeof(card->longname),
+               "%s at sendirq=%d.%d recvirq=%d.%d regs=%p",
+               card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx,
+               ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr);
+
+       snd_card_set_dev(card, &client->dev);
+
+       /*
+        * Set up the mixer
+        */
+       snd_ubi32_cs4384_mixer(ubi32_priv);
+
+       /*
+        * Register the sound card
+        */
+       if ((err = snd_card_register(card)) != 0) {
+               snd_printk(KERN_INFO "snd_card_register error\n");
+       }
+
+       /*
+        * Store card for access from other methods
+        */
+       i2c_set_clientdata(client, card);
+
+       return 0;
+}
+
+/*
+ * snd_ubi32_cs4384_i2c_remove
+ */
+static int __devexit snd_ubi32_cs4384_i2c_remove(struct i2c_client *client)
+{
+       struct snd_card *card;
+       struct ubi32_snd_priv *ubi32_priv;
+
+       card = i2c_get_clientdata(client);
+
+       ubi32_priv = card->private_data;
+       snd_ubi32_pcm_remove(ubi32_priv);
+
+       snd_card_free(i2c_get_clientdata(client));
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+/*
+ * I2C driver description
+ */
+static struct i2c_driver snd_ubi32_cs4384_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+       .id_table       = snd_ubi32_cs4384_id,
+       .probe          = snd_ubi32_cs4384_i2c_probe,
+       .remove         = __devexit_p(snd_ubi32_cs4384_i2c_remove),
+};
+
+/*
+ * Driver init
+ */
+static int __init snd_ubi32_cs4384_init(void)
+{
+       return i2c_add_driver(&snd_ubi32_cs4384_driver);
+}
+module_init(snd_ubi32_cs4384_init);
+
+/*
+ * snd_ubi32_cs4384_exit
+ */
+static void __exit snd_ubi32_cs4384_exit(void)
+{
+       i2c_del_driver(&snd_ubi32_cs4384_driver);
+}
+module_exit(snd_ubi32_cs4384_exit);
+
+/*
+ * Module properties
+ */
+MODULE_ALIAS("i2c:" DRIVER_NAME);
+MODULE_AUTHOR("Patrick Tjin");
+MODULE_DESCRIPTION("Driver for Ubicom32 audio devices CS4384");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32-generic-capture.c b/target/linux/ubicom32/files/sound/ubicom32/ubi32-generic-capture.c
new file mode 100644 (file)
index 0000000..a911cc6
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * sound/ubicom32/ubi32-generic-capture.c
+ *     Interface to ubicom32 virtual audio peripheral
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include "ubi32.h"
+
+#define DRIVER_NAME "snd-ubi32-generic-capture"
+
+/*
+ * Module properties
+ */
+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
+
+/*
+ * Card private data free function
+ */
+void snd_ubi32_generic_capture_free(struct snd_card *card)
+{
+       /*
+        * Free all the fields in the snd_ubi32_priv struct
+        */
+       // Nothing to free at this time because ubi32_priv just maintains pointers
+}
+
+/*
+ * Ubicom audio driver probe() method.  Args change depending on whether we use
+ * platform_device or i2c_device.
+ */
+static int snd_ubi32_generic_capture_probe(struct platform_device *dev)
+{
+       struct snd_card *card;
+       struct ubi32_snd_priv *ubi32_priv;
+       int err;
+
+       /*
+        * Create a snd_card structure
+        */
+       card = snd_card_new(index, "Ubi32-Generic-C", THIS_MODULE, sizeof(struct ubi32_snd_priv));
+
+       if (card == NULL) {
+               return -ENOMEM;
+       }
+
+       card->private_free = snd_ubi32_generic_capture_free; /* Not sure if correct */
+       ubi32_priv = card->private_data;
+
+       /*
+        * Initialize the snd_card's private data structure
+        */
+       ubi32_priv->card = card;
+       ubi32_priv->is_capture = 1;
+
+       /*
+        * Create the new PCM instance
+        */
+       err = snd_ubi32_pcm_probe(ubi32_priv, dev);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+
+       strcpy(card->driver, "Ubi32-Generic-C");
+       strcpy(card->shortname, "Ubi32-Generic-C");
+       snprintf(card->longname, sizeof(card->longname),
+               "%s at sendirq=%d.%d recvirq=%d.%d regs=%p",
+               card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx,
+               ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr);
+
+       snd_card_set_dev(card, &dev->dev);
+
+       /* Register the sound card */
+       if ((err = snd_card_register(card)) != 0) {
+               snd_printk(KERN_INFO "snd_card_register error\n");
+       }
+
+       /* Store card for access from other methods */
+       platform_set_drvdata(dev, card);
+
+       return 0;
+}
+
+/*
+ * Ubicom audio driver remove() method
+ */
+static int __devexit snd_ubi32_generic_capture_remove(struct platform_device *dev)
+{
+       struct snd_card *card;
+       struct ubi32_snd_priv *ubi32_priv;
+
+       card = platform_get_drvdata(dev);
+       ubi32_priv = card->private_data;
+       snd_ubi32_pcm_remove(ubi32_priv);
+
+       snd_card_free(platform_get_drvdata(dev));
+       platform_set_drvdata(dev, NULL);
+       return 0;
+}
+
+/*
+ * Platform driver definition
+ */
+static struct platform_driver snd_ubi32_generic_capture_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = snd_ubi32_generic_capture_probe,
+       .remove = __devexit_p(snd_ubi32_generic_capture_remove),
+};
+
+/*
+ * snd_ubi32_generic_capture_init
+ */
+static int __init snd_ubi32_generic_capture_init(void)
+{
+       return platform_driver_register(&snd_ubi32_generic_capture_driver);
+}
+module_init(snd_ubi32_generic_capture_init);
+
+/*
+ * snd_ubi32_generic_capture_exit
+ */
+static void __exit snd_ubi32_generic_capture_exit(void)
+{
+       platform_driver_unregister(&snd_ubi32_generic_capture_driver);
+}
+module_exit(snd_ubi32_generic_capture_exit);
+
+/*
+ * Module properties
+ */
+//#if defined(CONFIG_SND_UBI32_AUDIO_I2C)
+//MODULE_ALIAS("i2c:snd-ubi32");
+//#endif
+MODULE_AUTHOR("Patrick Tjin");
+MODULE_DESCRIPTION("Driver for Ubicom32 audio devices");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32-generic.c b/target/linux/ubicom32/files/sound/ubicom32/ubi32-generic.c
new file mode 100644 (file)
index 0000000..eee6066
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * sound/ubicom32/ubi32-generic.c
+ *     Interface to ubicom32 virtual audio peripheral
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include "ubi32.h"
+
+#define DRIVER_NAME "snd-ubi32-generic"
+
+/*
+ * Module properties
+ */
+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
+
+/*
+ * Card private data free function
+ */
+void snd_ubi32_generic_free(struct snd_card *card)
+{
+       /*
+        * Free all the fields in the snd_ubi32_priv struct
+        */
+       // Nothing to free at this time because ubi32_priv just maintains pointers
+}
+
+/*
+ * Ubicom audio driver probe() method.  Args change depending on whether we use
+ * platform_device or i2c_device.
+ */
+static int snd_ubi32_generic_probe(struct platform_device *dev)
+{
+       struct snd_card *card;
+       struct ubi32_snd_priv *ubi32_priv;
+       int err;
+
+       /*
+        * Create a snd_card structure
+        */
+       card = snd_card_new(index, "Ubi32-Generic", THIS_MODULE, sizeof(struct ubi32_snd_priv));
+
+       if (card == NULL) {
+               return -ENOMEM;
+       }
+
+       card->private_free = snd_ubi32_generic_free; /* Not sure if correct */
+       ubi32_priv = card->private_data;
+
+       /*
+        * Initialize the snd_card's private data structure
+        */
+       ubi32_priv->card = card;
+
+       /*
+        * Create the new PCM instance
+        */
+       err = snd_ubi32_pcm_probe(ubi32_priv, dev);
+       if (err < 0) {
+               snd_card_free(card);
+               return err;
+       }
+
+       strcpy(card->driver, "Ubi32-Generic");
+       strcpy(card->shortname, "Ubi32-Generic");
+       snprintf(card->longname, sizeof(card->longname),
+               "%s at sendirq=%d.%d recvirq=%d.%d regs=%p",
+               card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx,
+               ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr);
+
+       snd_card_set_dev(card, &dev->dev);
+
+       /* Register the sound card */
+       if ((err = snd_card_register(card)) != 0) {
+               snd_printk(KERN_INFO "snd_card_register error\n");
+       }
+
+       /* Store card for access from other methods */
+       platform_set_drvdata(dev, card);
+
+       return 0;
+}
+
+/*
+ * Ubicom audio driver remove() method
+ */
+static int __devexit snd_ubi32_generic_remove(struct platform_device *dev)
+{
+       struct snd_card *card;
+       struct ubi32_snd_priv *ubi32_priv;
+
+       card = platform_get_drvdata(dev);
+       ubi32_priv = card->private_data;
+       snd_ubi32_pcm_remove(ubi32_priv);
+
+       snd_card_free(platform_get_drvdata(dev));
+       platform_set_drvdata(dev, NULL);
+       return 0;
+}
+
+/*
+ * Platform driver definition
+ */
+static struct platform_driver snd_ubi32_generic_driver = {
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = snd_ubi32_generic_probe,
+       .remove = __devexit_p(snd_ubi32_generic_remove),
+};
+
+/*
+ * snd_ubi32_generic_init
+ */
+static int __init snd_ubi32_generic_init(void)
+{
+       return platform_driver_register(&snd_ubi32_generic_driver);
+}
+module_init(snd_ubi32_generic_init);
+
+/*
+ * snd_ubi32_generic_exit
+ */
+static void __exit snd_ubi32_generic_exit(void)
+{
+       platform_driver_unregister(&snd_ubi32_generic_driver);
+}
+module_exit(snd_ubi32_generic_exit);
+
+/*
+ * Module properties
+ */
+//#if defined(CONFIG_SND_UBI32_AUDIO_I2C)
+//MODULE_ALIAS("i2c:snd-ubi32");
+//#endif
+MODULE_AUTHOR("Aaron Jow, Patrick Tjin");
+MODULE_DESCRIPTION("Driver for Ubicom32 audio devices");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32-pcm.c b/target/linux/ubicom32/files/sound/ubicom32/ubi32-pcm.c
new file mode 100644 (file)
index 0000000..2bc300b
--- /dev/null
@@ -0,0 +1,711 @@
+/*
+ * sound/ubicom32/ubi32-pcm.c
+ *     Interface to ubicom32 virtual audio peripheral
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ *
+ * Ubicom32 implementation derived from (with many thanks):
+ *   arch/m68knommu
+ *   arch/blackfin
+ *   arch/parisc
+ */
+
+#include <linux/interrupt.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <asm/ip5000.h>
+#include <asm/ubi32-pcm.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include "ubi32.h"
+
+struct ubi32_snd_runtime_data {
+       dma_addr_t dma_buffer;          /* Physical address of DMA buffer */
+       dma_addr_t dma_buffer_end;      /* First address beyond end of DMA buffer */
+       size_t period_size;
+       dma_addr_t period_ptr;          /* Physical address of next period */
+       unsigned int flags;
+};
+
+static void snd_ubi32_vp_int_set(struct snd_pcm *pcm)
+{
+       struct ubi32_snd_priv *ubi32_priv = pcm->private_data;
+       ubi32_priv->ar->int_req |= (1 << ubi32_priv->irq_idx);
+       ubicom32_set_interrupt(ubi32_priv->tx_irq);
+}
+
+static snd_pcm_uframes_t snd_ubi32_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+       struct ubi32_snd_priv *ubi32_priv = snd_pcm_substream_chip(substream);
+       struct audio_dev_regs *adr = ubi32_priv->adr;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data;
+
+       dma_addr_t read_pos;
+
+       snd_pcm_uframes_t frames;
+       if (!adr->primary_os_buffer_ptr) {
+               /*
+                * If primary_os_buffer_ptr is NULL (e.g. right after the HW is started or
+                * when the HW is stopped), then handle this case separately.
+                */
+               return 0;
+       }
+
+       read_pos = (dma_addr_t)adr->primary_os_buffer_ptr;
+       frames = bytes_to_frames(runtime, read_pos - ubi32_rd->dma_buffer);
+       if (frames == runtime->buffer_size) {
+               frames = 0;
+       }
+       return frames;
+}
+
+/*
+ * Audio trigger
+ */
+static int snd_ubi32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       struct ubi32_snd_priv *ubi32_priv = substream->pcm->private_data;
+       struct audio_dev_regs *adr = ubi32_priv->adr;
+       struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data;
+       int ret = 0;
+
+#ifdef CONFIG_SND_DEBUG
+       snd_printk(KERN_INFO "snd_ubi32_pcm_trigger cmd=%d=", cmd);
+#endif
+
+       if (adr->command != AUDIO_CMD_NONE) {
+               snd_printk(KERN_WARNING "Can't send command to audio device at this time\n");
+               // Set a timer to call this function back later.  How to do this?
+               return 0;
+       }
+
+       /*
+        * Set interrupt flag to indicate that we interrupted audio device
+        * to send a command
+        */
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+
+#ifdef CONFIG_SND_DEBUG
+               snd_printk(KERN_INFO "START\n");
+#endif
+               /*
+                * Ready the DMA transfer
+                */
+               ubi32_rd->period_ptr = ubi32_rd->dma_buffer;
+
+#ifdef CONFIG_SND_DEBUG
+               snd_printk(KERN_INFO "trigger period_ptr=%lx\n", (unsigned long)ubi32_rd->period_ptr);
+#endif
+               adr->dma_xfer_requests[0].ptr = (void *)ubi32_rd->period_ptr;
+               adr->dma_xfer_requests[0].ctr = ubi32_rd->period_size;
+               adr->dma_xfer_requests[0].active = 1;
+
+#ifdef CONFIG_SND_DEBUG
+               snd_printk(KERN_INFO "xfer_request 0 ptr=0x%x ctr=%u\n", ubi32_rd->period_ptr, ubi32_rd->period_size);
+#endif
+
+               ubi32_rd->period_ptr += ubi32_rd->period_size;
+               adr->dma_xfer_requests[1].ptr = (void *)ubi32_rd->period_ptr;
+               adr->dma_xfer_requests[1].ctr = ubi32_rd->period_size;
+               adr->dma_xfer_requests[1].active = 1;
+
+#ifdef CONFIG_SND_DEBUG
+               snd_printk(KERN_INFO "xfer_request 1 ptr=0x%x ctr=%u\n", ubi32_rd->period_ptr, ubi32_rd->period_size);
+#endif
+
+               /*
+                * Tell the VP that we want to begin playback by filling in the
+                * command field and then interrupting the audio VP
+                */
+               adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
+               adr->command = AUDIO_CMD_START;
+               snd_ubi32_vp_int_set(substream->pcm);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+
+#ifdef CONFIG_SND_DEBUG
+               snd_printk(KERN_INFO "STOP\n");
+#endif
+
+               /*
+                * Tell the VP that we want to stop playback by filling in the
+                * command field and then interrupting the audio VP
+                */
+               adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
+               adr->command = AUDIO_CMD_STOP;
+               snd_ubi32_vp_int_set(substream->pcm);
+               break;
+
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+
+#ifdef CONFIG_SND_DEBUG
+               snd_printk(KERN_INFO "PAUSE_PUSH\n");
+#endif
+
+               /*
+                * Tell the VP that we want to pause playback by filling in the
+                * command field and then interrupting the audio VP
+                */
+               adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
+               adr->command = AUDIO_CMD_PAUSE;
+               snd_ubi32_vp_int_set(substream->pcm);
+               break;
+
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+
+#ifdef CONFIG_SND_DEBUG
+               snd_printk(KERN_INFO "PAUSE_RELEASE\n");
+#endif
+               /*
+                * Tell the VP that we want to resume paused playback by filling
+                * in the command field and then interrupting the audio VP
+                */
+               adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
+               adr->command = AUDIO_CMD_RESUME;
+               snd_ubi32_vp_int_set(substream->pcm);
+               break;
+
+       default:
+               snd_printk(KERN_WARNING "Unhandled trigger\n");
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ * Prepare to transfer an audio stream to the codec
+ */
+static int snd_ubi32_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       /*
+        * Configure registers and setup the runtime instance for DMA transfers
+        */
+       struct ubi32_snd_priv *ubi32_priv = substream->pcm->private_data;
+       struct audio_dev_regs *adr = ubi32_priv->adr;
+
+#ifdef CONFIG_SND_DEBUG
+       snd_printk(KERN_INFO "snd_ubi32_pcm_prepare: sending STOP command to audio device\n");
+#endif
+
+       /*
+        * Make sure the audio device is stopped
+        */
+
+       /*
+        * Set interrupt flag to indicate that we interrupted audio device
+        * to send a command
+        */
+       adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
+       adr->command = AUDIO_CMD_STOP;
+       snd_ubi32_vp_int_set(substream->pcm);
+
+       return 0;
+}
+
+/*
+ * Allocate DMA buffers from preallocated memory.
+ * Preallocation was done in snd_ubi32_pcm_new()
+ */
+static int snd_ubi32_pcm_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ubi32_snd_priv *ubi32_priv = substream->pcm->private_data;
+       struct audio_dev_regs *adr = ubi32_priv->adr;
+       struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data;
+
+       /*
+        * Use pre-allocated memory from ubi32_snd_pcm_new() to satisfy
+        * this memory request.
+        */
+       int ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+       if (ret < 0) {
+               return ret;
+       }
+
+#ifdef CONFIG_SND_DEBUG
+       snd_printk(KERN_INFO "snd_ubi32_pcm_hw_params\n");
+#endif
+
+       if (!(adr->channel_mask & (1 << params_channels(hw_params)))) {
+               snd_printk(KERN_INFO "snd_ubi32_pcm_hw_params unsupported number of channels %d mask %08x\n", params_channels(hw_params), adr->channel_mask);
+               return -EINVAL;
+       }
+
+       if (ubi32_priv->set_channels) {
+               int ret = ubi32_priv->set_channels(ubi32_priv, params_channels(hw_params));
+               if (ret) {
+                       snd_printk(KERN_WARNING "Unable to set channels to %d, ret=%d\n", params_channels(hw_params), ret);
+                       return ret;
+               }
+       }
+
+       if (ubi32_priv->set_rate) {
+               int ret = ubi32_priv->set_rate(ubi32_priv, params_rate(hw_params));
+               if (ret) {
+                       snd_printk(KERN_WARNING "Unable to set rate to %d, ret=%d\n", params_rate(hw_params), ret);
+                       return ret;
+               }
+       }
+
+       if (ubi32_priv->pdata->set_rate) {
+               int ret = ubi32_priv->pdata->set_rate(ubi32_priv->pdata->appdata, params_rate(hw_params));
+               if (ret) {
+                       snd_printk(KERN_WARNING "Unable to set rate to %d, ret=%d\n", params_rate(hw_params), ret);
+                       return ret;
+               }
+       }
+
+       if (adr->command != AUDIO_CMD_NONE) {
+               snd_printk(KERN_WARNING "snd_ubi32_pcm_hw_params: tio busy\n");
+               return -EAGAIN;
+       }
+
+       if (params_format(hw_params) == SNDRV_PCM_FORMAT_S16_LE) {
+               adr->flags |= CMD_START_FLAG_LE;
+       } else {
+               adr->flags &= ~CMD_START_FLAG_LE;
+       }
+       adr->channels = params_channels(hw_params);
+       adr->sample_rate = params_rate(hw_params);
+       adr->command = AUDIO_CMD_SETUP;
+       adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
+       snd_ubi32_vp_int_set(substream->pcm);
+
+       /*
+        * Wait for the command to complete
+        */
+       while (adr->command != AUDIO_CMD_NONE) {
+               udelay(1);
+       }
+
+       /*
+        * Put the DMA info into the DMA descriptor that we will
+        * use to do transfers to our audio VP "hardware"
+        */
+
+       /*
+        * Mark both DMA transfers as not ready/inactive
+        */
+       adr->dma_xfer_requests[0].active = 0;
+       adr->dma_xfer_requests[1].active = 0;
+
+       /*
+        * Put the location of the buffer into the runtime data instance
+        */
+       ubi32_rd->dma_buffer = (dma_addr_t)runtime->dma_area;
+       ubi32_rd->dma_buffer_end = (dma_addr_t)(runtime->dma_area + runtime->dma_bytes);
+
+       /*
+        * Get the period size
+        */
+       ubi32_rd->period_size = params_period_bytes(hw_params);
+
+#ifdef CONFIG_SND_DEBUG
+       snd_printk(KERN_INFO "DMA for ubi32 audio initialized dma_area=0x%x dma_bytes=%d, period_size=%d\n", (unsigned int)runtime->dma_area, (unsigned int)runtime->dma_bytes, ubi32_rd->period_size);
+       snd_printk(KERN_INFO "Private buffer ubi32_rd: dma_buffer=0x%x dma_buffer_end=0x%x ret=%d\n", ubi32_rd->dma_buffer, ubi32_rd->dma_buffer_end, ret);
+#endif
+
+       return ret;
+}
+
+/*
+ * This is the reverse of snd_ubi32_pcm_hw_params
+ */
+static int snd_ubi32_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+#ifdef CONFIG_SND_DEBUG
+       snd_printk(KERN_INFO "snd_ubi32_pcm_hw_free\n");
+#endif
+       return snd_pcm_lib_free_pages(substream);
+}
+
+/*
+ * Audio virtual peripheral capabilities (capture and playback are identical)
+ */
+static struct snd_pcm_hardware snd_ubi32_pcm_hw =
+{
+       .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+       .buffer_bytes_max = (64*1024),
+       .period_bytes_min       = 64,
+       .period_bytes_max       = 8184,//8184,//8176,
+       .periods_min = 2,
+       .periods_max = 255,
+       .fifo_size = 0, // THIS IS IGNORED BY ALSA
+};
+
+/*
+ * We fill this in later
+ */
+static struct snd_pcm_hw_constraint_list ubi32_pcm_rates;
+
+/*
+ * snd_ubi32_pcm_close
+ */
+static int snd_ubi32_pcm_close(struct snd_pcm_substream *substream)
+{
+       /* Disable codec, stop DMA, free private data structures */
+       //struct ubi32_snd_priv *ubi32_priv = snd_pcm_substream_chip(substream);
+       struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data;
+
+#ifdef CONFIG_SND_DEBUG
+       snd_printk(KERN_INFO "snd_ubi32_pcm_close\n");
+#endif
+
+       substream->runtime->private_data = NULL;
+
+       kfree(ubi32_rd);
+
+       return 0;
+}
+
+/*
+ * snd_ubi32_pcm_open
+ */
+static int snd_ubi32_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ubi32_snd_runtime_data *ubi32_rd;
+       int ret = 0;
+
+#ifdef CONFIG_SND_DEBUG
+       snd_printk(KERN_INFO "ubi32 pcm open\n");
+#endif
+
+       /* Associate capabilities with component */
+       runtime->hw = snd_ubi32_pcm_hw;
+
+       /*
+        * Inform ALSA about constraints of the audio device
+        */
+       ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &ubi32_pcm_rates);
+       if (ret < 0) {
+               snd_printk(KERN_INFO "invalid rate\n");
+               goto out;
+       }
+
+       /* Force the buffer size to be an integer multiple of period size */
+       ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0) {
+               snd_printk(KERN_INFO "invalid period\n");
+               goto out;
+       }
+       /* Initialize structures/registers */
+       ubi32_rd = kzalloc(sizeof(struct ubi32_snd_runtime_data), GFP_KERNEL);
+       if (ubi32_rd == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       runtime->private_data = ubi32_rd;
+
+#ifdef CONFIG_SND_DEBUG
+       snd_printk(KERN_INFO "snd_ubi32_pcm_open returned 0\n");
+#endif
+
+       return 0;
+out:
+#ifdef CONFIG_SND_DEBUG
+       snd_printk(KERN_INFO "snd_ubi32_pcm_open returned %d\n", ret);
+#endif
+
+       return ret;
+}
+
+static struct snd_pcm_ops snd_ubi32_pcm_ops = {
+       .open =         snd_ubi32_pcm_open, /* Open */
+       .close =        snd_ubi32_pcm_close, /* Close */
+       .ioctl =        snd_pcm_lib_ioctl, /* Generic IOCTL handler */
+       .hw_params =    snd_ubi32_pcm_hw_params, /* Hardware parameters/capabilities */
+       .hw_free =      snd_ubi32_pcm_hw_free, /* Free function for hw_params */
+       .prepare =      snd_ubi32_pcm_prepare,
+       .trigger =      snd_ubi32_pcm_trigger,
+       .pointer =      snd_ubi32_pcm_pointer,
+};
+
+/*
+ * Interrupt handler that gets called when the audio device
+ * interrupts Linux
+ */
+static irqreturn_t snd_ubi32_pcm_interrupt(int irq, void *appdata)
+{
+       struct snd_pcm *pcm = (struct snd_pcm *)appdata;
+       struct ubi32_snd_priv *ubi32_priv = pcm->private_data;
+       struct audio_dev_regs *adr = ubi32_priv->adr;
+       struct snd_pcm_substream *substream;
+       struct ubi32_snd_runtime_data *ubi32_rd;
+       int dma_to_fill = 0;
+
+       /*
+        * Check to see if the interrupt is for us
+        */
+       if (!(ubi32_priv->ar->int_status & (1 << ubi32_priv->irq_idx))) {
+               return IRQ_NONE;
+       }
+
+       /*
+        * Clear the interrupt
+        */
+       ubi32_priv->ar->int_status &= ~(1 << ubi32_priv->irq_idx);
+
+       /*
+        * We only have one stream since we don't mix.  Therefore
+        * we don't need to search through substreams.
+        */
+       if (ubi32_priv->is_capture) {
+               substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+       } else {
+               substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+       }
+
+       if (!substream->runtime) {
+               snd_printk(KERN_WARNING "No runtime data\n");
+               return IRQ_NONE;
+       }
+
+       ubi32_rd = substream->runtime->private_data;
+
+#ifdef CONFIG_SND_DEBUG
+       snd_printk(KERN_INFO "Ubi32 ALSA interrupt\n");
+#endif
+
+       if (ubi32_rd == NULL) {
+               snd_printk(KERN_WARNING "No private data\n");
+               return IRQ_NONE;
+       }
+
+       // Check interrupt cause
+       if (0) {
+               // Handle the underflow case
+       } else if ((adr->status & AUDIO_STATUS_PLAY_DMA0_REQUEST) ||
+                  (adr->status & AUDIO_STATUS_PLAY_DMA1_REQUEST)) {
+               if (adr->status & AUDIO_STATUS_PLAY_DMA0_REQUEST) {
+                       dma_to_fill = 0;
+                       adr->status &= ~AUDIO_STATUS_PLAY_DMA0_REQUEST;
+               } else if (adr->status & AUDIO_STATUS_PLAY_DMA1_REQUEST) {
+                       dma_to_fill = 1;
+                       adr->status &= ~AUDIO_STATUS_PLAY_DMA1_REQUEST;
+               }
+               ubi32_rd->period_ptr += ubi32_rd->period_size;
+               if (ubi32_rd->period_ptr >= ubi32_rd->dma_buffer_end) {
+                       ubi32_rd->period_ptr = ubi32_rd->dma_buffer;
+               }
+               adr->dma_xfer_requests[dma_to_fill].ptr = (void *)ubi32_rd->period_ptr;
+               adr->dma_xfer_requests[dma_to_fill].ctr = ubi32_rd->period_size;
+               adr->dma_xfer_requests[dma_to_fill].active = 1;
+#ifdef CONFIG_SND_DEBUG
+               snd_printk(KERN_INFO "xfer_request %d ptr=0x%x ctr=%u\n", dma_to_fill, ubi32_rd->period_ptr, ubi32_rd->period_size);
+#endif
+               adr->int_flags |= AUDIO_INT_FLAG_MORE_SAMPLES;
+               snd_ubi32_vp_int_set(substream->pcm);
+       }
+       // If we are interrupted by the VP, that means we completed
+       // processing one period of audio.  We need to inform the upper
+       // layers of ALSA of this.
+       snd_pcm_period_elapsed(substream);
+
+       return IRQ_HANDLED;
+}
+
+void __devexit snd_ubi32_pcm_remove(struct ubi32_snd_priv *ubi32_priv)
+{
+       struct snd_pcm *pcm = ubi32_priv->pcm;
+       free_irq(ubi32_priv->rx_irq, pcm);
+}
+
+#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12
+#error "Change this table to match pcm.h"
+#endif
+static unsigned int rates[] __initdata = {5512, 8000, 11025, 16000, 22050,
+                                         32000, 44100, 48000, 64000, 88200,
+                                         96000, 176400, 192000};
+
+/*
+ * snd_ubi32_pcm_probe
+ */
+int __devinit snd_ubi32_pcm_probe(struct ubi32_snd_priv *ubi32_priv, struct platform_device *pdev)
+{
+       struct snd_pcm *pcm;
+       int ret, err;
+       int i;
+       int j;
+       int nrates;
+       unsigned int rate_max = 0;
+       unsigned int rate_min = 0xFFFFFFFF;
+       unsigned int rate_mask = 0;
+       struct audio_dev_regs *adr;
+       struct resource *res_adr;
+       struct resource *res_irq_tx;
+       struct resource *res_irq_rx;
+       struct ubi32pcm_platform_data *pdata;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               return -ENODEV;
+       }
+
+       /*
+        * Get our resources, adr is the hardware driver base address
+        * and the tx and rx irqs are used to communicate with the
+        * hardware driver.
+        */
+       res_adr = platform_get_resource(pdev, IORESOURCE_MEM, AUDIO_MEM_RESOURCE);
+       res_irq_tx = platform_get_resource(pdev, IORESOURCE_IRQ, AUDIO_TX_IRQ_RESOURCE);
+       res_irq_rx = platform_get_resource(pdev, IORESOURCE_IRQ, AUDIO_RX_IRQ_RESOURCE);
+       if (!res_adr || !res_irq_tx || !res_irq_rx) {
+               snd_printk(KERN_WARNING "Could not get resources");
+               return -ENODEV;
+       }
+
+       ubi32_priv->ar = (struct audio_regs *)res_adr->start;
+       ubi32_priv->tx_irq = res_irq_tx->start;
+       ubi32_priv->rx_irq = res_irq_rx->start;
+       ubi32_priv->irq_idx = pdata->inst_num;
+       ubi32_priv->adr = &(ubi32_priv->ar->adr[pdata->inst_num]);
+
+       /*
+        * Check the version
+        */
+       adr = ubi32_priv->adr;
+       if (adr->version != AUDIO_DEV_REGS_VERSION) {
+               snd_printk(KERN_WARNING "This audio_dev_reg is not compatible with this driver\n");
+               return -ENODEV;
+       }
+
+       /*
+        * Find out the standard rates, also find max and min rates
+        */
+       for (i = 0; i < ARRAY_SIZE(rates); i++) {
+               int found = 0;
+               for (j = 0; j < adr->n_sample_rates; j++) {
+                       if (rates[i] == adr->sample_rates[j]) {
+                               /*
+                                * Check to see if it is supported by the dac
+                                */
+                               if ((rates[i] >= ubi32_priv->min_sample_rate) &&
+                                   (!ubi32_priv->max_sample_rate ||
+                                    (ubi32_priv->max_sample_rate && (rates[i] <= ubi32_priv->max_sample_rate)))) {
+                                       found = 1;
+                                       rate_mask |= (1 << i);
+                                       nrates++;
+                                       if (rates[i] < rate_min) {
+                                               rate_min = rates[i];
+                                       }
+                                       if (rates[i] > rate_max) {
+                                               rate_max = rates[i];
+                                       }
+                                       break;
+                               }
+                       }
+               }
+               if (!found) {
+                       rate_mask |= SNDRV_PCM_RATE_KNOT;
+               }
+       }
+
+       snd_ubi32_pcm_hw.rates = rate_mask;
+       snd_ubi32_pcm_hw.rate_min = rate_min;
+       snd_ubi32_pcm_hw.rate_max = rate_max;
+       ubi32_pcm_rates.count = adr->n_sample_rates;
+       ubi32_pcm_rates.list = (unsigned int *)adr->sample_rates;
+       ubi32_pcm_rates.mask = 0;
+
+       for (i = 0; i < 32; i++) {
+               if (adr->channel_mask & (1 << i)) {
+                       if (!snd_ubi32_pcm_hw.channels_min) {
+                               snd_ubi32_pcm_hw.channels_min = i;
+                       }
+                       snd_ubi32_pcm_hw.channels_max = i;
+               }
+       }
+       snd_printk(KERN_INFO "Ubi32PCM: channels_min:%u channels_max:%u\n",
+                  snd_ubi32_pcm_hw.channels_min,
+                  snd_ubi32_pcm_hw.channels_max);
+
+       if (adr->caps & AUDIONODE_CAP_BE) {
+               snd_ubi32_pcm_hw.formats |= SNDRV_PCM_FMTBIT_S16_BE;
+       }
+       if (adr->caps & AUDIONODE_CAP_LE) {
+               snd_ubi32_pcm_hw.formats |= SNDRV_PCM_FMTBIT_S16_LE;
+       }
+
+       snd_printk(KERN_INFO "Ubi32PCM: rates:%08x min:%u max:%u count:%d fmts:%016llx (%s)\n",
+                  snd_ubi32_pcm_hw.rates,
+                  snd_ubi32_pcm_hw.rate_min,
+                  snd_ubi32_pcm_hw.rate_max,
+                  ubi32_pcm_rates.count,
+                  snd_ubi32_pcm_hw.formats,
+                  ubi32_priv->is_capture ? "capture" : "playback");
+
+       if (ubi32_priv->is_capture) {
+               ret = snd_pcm_new(ubi32_priv->card, "Ubi32 PCM", 0, 0, 1, &pcm);
+       } else {
+               ret = snd_pcm_new(ubi32_priv->card, "Ubi32 PCM", 0, 1, 0, &pcm);
+       }
+
+       if (ret < 0) {
+               return ret;
+       }
+
+       pcm->private_data = ubi32_priv;
+       ubi32_priv->pcm = pcm;
+       ubi32_priv->pdata = pdata;
+
+       pcm->info_flags = 0;
+
+       strcpy(pcm->name, "Ubi32-PCM");
+
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+                                             snd_dma_continuous_data(GFP_KERNEL),
+                                             45*1024, 64*1024);
+
+       if (ubi32_priv->is_capture) {
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ubi32_pcm_ops);
+       } else {
+               snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ubi32_pcm_ops);
+       }
+
+       /*
+        * Start up the audio device
+        */
+       adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
+       adr->command = AUDIO_CMD_ENABLE;
+       snd_ubi32_vp_int_set(pcm);
+
+       /*
+        * Request IRQ
+        */
+       err = request_irq(ubi32_priv->rx_irq, snd_ubi32_pcm_interrupt, IRQF_SHARED | IRQF_DISABLED, pcm->name, pcm);
+       if (err) {
+               snd_printk(KERN_WARNING "request_irq failed: irq=%d err=%d\n", ubi32_priv->rx_irq, err);
+               return -ENODEV;
+       }
+
+       return ret;
+
+}
diff --git a/target/linux/ubicom32/files/sound/ubicom32/ubi32.h b/target/linux/ubicom32/files/sound/ubicom32/ubi32.h
new file mode 100644 (file)
index 0000000..f43a215
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * sound/ubicom32/ubi32.h
+ *     Common header file for all ubi32- sound drivers
+ *
+ * (C) Copyright 2009, Ubicom, Inc.
+ *
+ * This file is part of the Ubicom32 Linux Kernel Port.
+ *
+ * The Ubicom32 Linux Kernel Port 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.
+ *
+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
+ * see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _UBI32_H
+#define _UBI32_H
+
+#define SND_UBI32_DEBUG 0 // Debug flag
+
+#include <linux/platform_device.h>
+#include <asm/devtree.h>
+#include <asm/audio.h>
+#include <asm/ubi32-pcm.h>
+
+struct ubi32_snd_priv;
+
+typedef int (*set_channels_t)(struct ubi32_snd_priv *priv, int channels);
+typedef int (*set_rate_t)(struct ubi32_snd_priv *priv, int rate);
+
+struct ubi32_snd_priv {
+       /*
+        * Any variables that are needed locally here but NOT in
+        * the VP itself should go in here.
+        */
+       struct snd_card *card;
+       struct snd_pcm *pcm;
+
+       /*
+        * capture (1) or playback (0)
+        */
+       int is_capture;
+       /*
+        * DAC parameters.  These are the parameters for the specific
+        * DAC we are driving.  The I2S component can run at a range
+        * of frequencies, but the DAC may be limited.  We may want
+        * to make this an array of some sort in the future?
+        *
+        * min/max_sample_rate if set to 0 are ignored.
+        */
+       int max_sample_rate;
+       int min_sample_rate;
+
+       /*
+        * The size a period (group) of audio samples.  The VP does
+        * not need to know this; each DMA transfer is made to be
+        * one period.
+        */
+       u32_t period_size;
+
+       spinlock_t ubi32_lock;
+
+       struct audio_regs *ar;
+       struct audio_dev_regs *adr;
+       u32 irq_idx;
+       u8 tx_irq;
+       u8 rx_irq;
+
+       void *client;
+
+       /*
+        * Operations which the base DAC driver can implement
+        */
+       set_channels_t set_channels;
+       set_rate_t set_rate;
+
+       /*
+        * platform data
+        */
+       struct ubi32pcm_platform_data *pdata;
+
+       /*
+        * Private driver data (used for DAC driver control, etc)
+        */
+       void *drvdata;
+};
+
+#define snd_ubi32_priv_get_drv(priv) ((priv)->drvdata)
+#define snd_ubi32_priv_set_drv(priv, data) (((priv)->drvdata) = (void *)(data))
+
+extern int snd_ubi32_pcm_probe(struct ubi32_snd_priv *ubi32_priv, struct platform_device *pdev);
+extern void snd_ubi32_pcm_remove(struct ubi32_snd_priv *ubi32_priv);
+
+#endif
index 04dec6bbd13cbd34f2e1a179a71b0b852ec48199..eca2740a8c704c5901b9c6c75895d666b3b45f6c 100644 (file)
---- /dev/null
-+++ b/arch/ubicom32/crypto/aes_ubicom32.c
-@@ -0,0 +1,458 @@
-+/*
-+ * arch/ubicom32/crypto/aes_ubicom32.c
-+ *   Ubicom32 implementation of the AES Cipher Algorithm.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <crypto/aes.h>
-+#include <crypto/algapi.h>
-+#include <linux/err.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/spinlock.h>
-+#include "crypto_ubicom32.h"
-+#include <asm/linkage.h>
-+
-+struct ubicom32_aes_ctx {
-+      u8 key[AES_MAX_KEY_SIZE];
-+      u32 ctrl;
-+      int key_len;
-+};
-+
-+static inline void aes_hw_set_key(const u8 *key, u8 key_len)
-+{
-+      /*
-+       * switch case has more overhead than 4 move.4 instructions, so just copy 256 bits
-+       */
-+      SEC_SET_KEY_256(key);
-+}
-+
-+static inline void aes_hw_set_iv(const u8 *iv)
-+{
-+      SEC_SET_IV_4W(iv);
-+}
-+
-+static inline void aes_hw_cipher(u8 *out, const u8 *in)
-+{
-+      SEC_SET_INPUT_4W(in);
-+
-+      asm volatile (
-+      "       ; start AES by writing 0x40(SECURITY_BASE)      \n\t"
-+      "       move.4 0x40(%0), #0x01                          \n\t"
-+      "       pipe_flush 0                                    \n\t"
-+      "                                                       \n\t"
-+      "       ; wait for the module to calculate the output   \n\t"
-+      "       btst 0x04(%0), #0                               \n\t"
-+      "       jmpne.f .-4                                     \n\t"
-+              :
-+              : "a" (SEC_BASE)
-+              : "cc"
-+      );
-+
-+      SEC_GET_OUTPUT_4W(out);
-+}
-+
-+static int __ocm_text aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
-+                     unsigned int key_len)
-+{
-+      struct ubicom32_aes_ctx *uctx = crypto_tfm_ctx(tfm);
-+
-+      uctx->key_len = key_len;
-+      memcpy(uctx->key, in_key, key_len);
-+
-+      /*
-+       * leave out HASH_ALG (none = 0), CBC (no = 0), DIR (unknown) yet
-+       */
-+      switch (uctx->key_len) {
-+      case 16:
-+              uctx->ctrl = SEC_KEY_128_BITS | SEC_ALG_AES;
-+              break;
-+      case 24:
-+              uctx->ctrl = SEC_KEY_192_BITS | SEC_ALG_AES;
-+              break;
-+      case 32:
-+              uctx->ctrl = SEC_KEY_256_BITS | SEC_ALG_AES;
-+              break;
-+      }
-+
-+      return 0;
-+}
-+
-+static inline void aes_cipher(struct crypto_tfm *tfm, u8 *out, const u8 *in, u32 extra_flags)
-+{
-+      const struct ubicom32_aes_ctx *uctx = crypto_tfm_ctx(tfm);
-+
-+      hw_crypto_lock();
-+      hw_crypto_check();
-+      hw_crypto_set_ctrl(uctx->ctrl | extra_flags);
-+
-+      aes_hw_set_key(uctx->key, uctx->key_len);
-+      aes_hw_cipher(out, in);
-+
-+      hw_crypto_unlock();
-+}
-+
-+static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
-+{
-+      aes_cipher(tfm, out, in, SEC_DIR_ENCRYPT);
-+}
-+
-+static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
-+{
-+      aes_cipher(tfm, out, in, SEC_DIR_DECRYPT);
-+}
-+
-+static struct crypto_alg aes_alg = {
-+      .cra_name               =       "aes",
-+      .cra_driver_name        =       "aes-ubicom32",
-+      .cra_priority           =       CRYPTO_UBICOM32_PRIORITY,
-+      .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
-+      .cra_blocksize          =       AES_BLOCK_SIZE,
-+      .cra_ctxsize            =       sizeof(struct ubicom32_aes_ctx),
-+      .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
-+      .cra_module             =       THIS_MODULE,
-+      .cra_list               =       LIST_HEAD_INIT(aes_alg.cra_list),
-+      .cra_u                  =       {
-+              .cipher = {
-+                      .cia_min_keysize        =       AES_MIN_KEY_SIZE,
-+                      .cia_max_keysize        =       AES_MAX_KEY_SIZE,
-+                      .cia_setkey             =       aes_set_key,
-+                      .cia_encrypt            =       aes_encrypt,
-+                      .cia_decrypt            =       aes_decrypt,
-+              }
-+      }
-+};
-+
-+static void __ocm_text ecb_aes_crypt_loop(u8 *out, u8 *in, unsigned int n)
-+{
-+      while (likely(n)) {
-+              aes_hw_cipher(out, in);
-+              out += AES_BLOCK_SIZE;
-+              in += AES_BLOCK_SIZE;
-+              n -= AES_BLOCK_SIZE;
-+      }
-+}
+--- a/drivers/char/hw_random/Kconfig
++++ b/drivers/char/hw_random/Kconfig
+@@ -148,3 +148,16 @@ config HW_RANDOM_VIRTIO
+         To compile this driver as a module, choose M here: the
+         module will be called virtio-rng.  If unsure, say N.
 +
-+static int __ocm_text ecb_aes_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
-+                       struct scatterlist *src, unsigned int nbytes, u32 extra_flags)
-+{
-+      const struct ubicom32_aes_ctx *uctx = crypto_blkcipher_ctx(desc->tfm);
-+      int ret;
++config HW_RANDOM_UBICOM32
++      tristate "Ubicom32 HW Random Number Generator support"
++      depends on HW_RANDOM && UBICOM32
++      default HW_RANDOM
++      ---help---
++        This driver provides kernel-side support for the Random Number
++        Generator hardware found on Ubicom32 processors.
 +
-+      struct blkcipher_walk walk;
-+      blkcipher_walk_init(&walk, dst, src, nbytes);
-+      ret = blkcipher_walk_virt(desc, &walk);
-+        if (ret) {
-+                return ret;
-+        }
++        To compile this driver as a module, choose M here: the
++        module will be called pasemi-rng.
 +
-+      hw_crypto_lock();
-+      hw_crypto_check();
++        If unsure, say Y.
+--- a/drivers/char/hw_random/Makefile
++++ b/drivers/char/hw_random/Makefile
+@@ -15,3 +15,4 @@ obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx
+ obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
+ obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
+ obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
++obj-$(CONFIG_HW_RANDOM_UBICOM32) += ubicom32-rng.o
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -61,6 +61,40 @@ config CRYPTO_DEV_GEODE
+         To compile this driver as a module, choose M here: the module
+         will be called geode-aes.
++config CRYPTO_UBICOM32
++        bool "Ubicom32 Security Module"
++        depends on UBICOM32
++        help
++          This is the ubicom32 hardware acceleration common code.
 +
-+        hw_crypto_set_ctrl(uctx->ctrl | extra_flags);
-+        aes_hw_set_key(uctx->key, uctx->key_len);
++config CRYPTO_AES_UBICOM32
++        tristate "Ubicom32 AES implementation"
++        depends on CRYPTO_UBICOM32
++        select CRYPTO_ALGAPI
++        help
++          This is the ubicom32 hardware AES implementation.
 +
-+      while (likely((nbytes = walk.nbytes))) {
-+              /* only use complete blocks */
-+              unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
-+              u8 *out = walk.dst.virt.addr;
-+              u8 *in = walk.src.virt.addr;
++config CRYPTO_DES_UBICOM32
++        tristate "Ubicom32 DES implementation"
++        depends on CRYPTO_UBICOM32
++        select CRYPTO_ALGAPI
++        help
++          This is the ubicom32 hardware DES and 3DES implementation.
 +
-+              /* finish n/16 blocks */
-+              ecb_aes_crypt_loop(out, in, n);
++config CRYPTO_SHA1_UBICOM32
++        tristate "Ubicom32 SHA1 implementation"
++        depends on CRYPTO_UBICOM32
++        select CRYPTO_ALGAPI
++        help
++          This is the ubicom32 hardware SHA1 implementation.
 +
-+              nbytes &= AES_BLOCK_SIZE - 1;
-+              ret = blkcipher_walk_done(desc, &walk, nbytes);
-+      }
++config CRYPTO_MD5_UBICOM32
++        tristate "Ubicom32 MD5 implementation"
++        depends on CRYPTO_UBICOM32
++        select CRYPTO_ALGAPI
++        help
++          This is the ubicom32 hardware MD5 implementation.
 +
-+      hw_crypto_unlock();
-+      return ret;
-+}
+ config ZCRYPT
+       tristate "Support for PCI-attached cryptographic adapters"
+       depends on S390
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -266,3 +266,10 @@ config GPIOMMC_CONFIGFS
+       help
+         This option automatically enables configfs support for gpiommc
+         if configfs is available.
 +
-+static int ecb_aes_encrypt(struct blkcipher_desc *desc,
-+                         struct scatterlist *dst, struct scatterlist *src,
-+                         unsigned int nbytes)
-+{
-+      return ecb_aes_crypt(desc, dst, src, nbytes, SEC_DIR_ENCRYPT);
-+}
++config MMC_UBICOM32
++      tristate "Ubicom32 MMC/SD host controller"
++      depends on UBICOM32
++      help
++        This provides support for the SD/MMC hardware found on Ubicom32
++        IP7K processors
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -30,4 +30,5 @@ obj-$(CONFIG_MMC_S3C)        += s3cmci.o
+ obj-$(CONFIG_MMC_SDRICOH_CS)  += sdricoh_cs.o
+ obj-$(CONFIG_MMC_TMIO)                += tmio_mmc.o
+ obj-$(CONFIG_GPIOMMC)         += gpiommc.o
++obj-$(CONFIG_MMC_UBICOM32)    += ubicom32sd.o
+--- a/drivers/mtd/devices/Kconfig
++++ b/drivers/mtd/devices/Kconfig
+@@ -104,6 +104,31 @@ config M25PXX_USE_FAST_READ
+       help
+         This option enables FAST_READ access supported by ST M25Pxx.
++config MTD_UBI32_NAND_SPI_ER
++      tristate "UBI32_NAND SPI-ER support"
++      help
++        This driver supports the Micron MT29F1G01 SPI-ER NAND flash chip
++        using the built in flash controller on the Ubicom32 architecture.
++        Partial page writes are not supported by this driver.
 +
-+static int ecb_aes_decrypt(struct blkcipher_desc *desc,
-+                         struct scatterlist *dst, struct scatterlist *src,
-+                         unsigned int nbytes)
-+{
-+      return ecb_aes_crypt(desc, dst, src, nbytes, SEC_DIR_DECRYPT);
-+}
++config MTD_NAND_SPI_ER
++      tristate "NAND SPI-ER support"
++      help
++        This driver supports the Micron MT29F1G01 SPI-ER NAND flash chip
++        using a generic SPI bus.  Partial page writes are supported
++        by this driver.
 +
-+static struct crypto_alg ecb_aes_alg = {
-+      .cra_name               =       "ecb(aes)",
-+      .cra_driver_name        =       "ecb-aes-ubicom32",
-+      .cra_priority           =       CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
-+      .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
-+      .cra_blocksize          =       AES_BLOCK_SIZE,
-+      .cra_ctxsize            =       sizeof(struct ubicom32_aes_ctx),
-+      .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
-+      .cra_type               =       &crypto_blkcipher_type,
-+      .cra_module             =       THIS_MODULE,
-+      .cra_list               =       LIST_HEAD_INIT(ecb_aes_alg.cra_list),
-+      .cra_u                  =       {
-+              .blkcipher = {
-+                      .min_keysize            =       AES_MIN_KEY_SIZE,
-+                      .max_keysize            =       AES_MAX_KEY_SIZE,
-+                      .setkey                 =       aes_set_key,
-+                      .encrypt                =       ecb_aes_encrypt,
-+                      .decrypt                =       ecb_aes_decrypt,
-+              }
-+      }
-+};
++config MTD_UBI32_M25P80
++      tristate "Ubicom processor support for most SPI Flash chips (AT26DF, M25P, W25X, ...)"
++      depends on UBICOM32
++      default y
++      help
++        This enables access to most modern SPI flash chips, used for
++        program and data storage.   Series supported include Atmel AT26DF,
++        Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X.  Other chips
++        are supported as well.  See the driver source for the current list,
++        or to add other chips.
 +
-+#if CRYPTO_UBICOM32_LOOP_ASM
-+void __ocm_text cbc_aes_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
-+{
-+      asm volatile (
-+      "; set init. iv 4w                      \n\t"
-+      "       move.4 0x50(%0), 0x0(%3)        \n\t"
-+      "       move.4 0x54(%0), 0x4(%3)        \n\t"
-+      "       move.4 0x58(%0), 0x8(%3)        \n\t"
-+      "       move.4 0x5c(%0), 0xc(%3)        \n\t"
-+      "                                       \n\t"
-+      "; we know n > 0, so we can always      \n\t"
-+      "; load the first block                 \n\t"
-+      "; set input 4w                         \n\t"
-+      "       move.4 0x30(%0), 0x0(%2)        \n\t"
-+      "       move.4 0x34(%0), 0x4(%2)        \n\t"
-+      "       move.4 0x38(%0), 0x8(%2)        \n\t"
-+      "       move.4 0x3c(%0), 0xc(%2)        \n\t"
-+      "                                       \n\t"
-+      "; kickoff hw                           \n\t"
-+      "       move.4 0x40(%0), %2             \n\t"
-+      "                                       \n\t"
-+      "; update n & flush                     \n\t"
-+      "       add.4 %4, #-16, %4              \n\t"
-+      "       pipe_flush 0                    \n\t"
-+      "                                       \n\t"
-+      "; while (n):  work on 2nd block        \n\t"
-+      " 1:    lsl.4 d15, %4, #0x0             \n\t"
-+      "       jmpeq.f 5f                      \n\t"
-+      "                                       \n\t"
-+      "; set input 4w (2nd)                   \n\t"
-+      "       move.4 0x30(%0), 0x10(%2)       \n\t"
-+      "       move.4 0x34(%0), 0x14(%2)       \n\t"
-+      "       move.4 0x38(%0), 0x18(%2)       \n\t"
-+      "       move.4 0x3c(%0), 0x1c(%2)       \n\t"
-+      "                                       \n\t"
-+      "; update n/in asap while waiting       \n\t"
-+      "       add.4 %4, #-16, %4              \n\t"
-+      "       move.4 d15, 16(%2)++            \n\t"
-+      "                                       \n\t"
-+      "; wait for the previous output         \n\t"
-+      "       btst 0x04(%0), #0               \n\t"
-+      "       jmpne.f -4                      \n\t"
-+      "                                       \n\t"
-+      "; read previous output                 \n\t"
-+      "       move.4 0x0(%1), 0x50(%0)        \n\t"
-+      "       move.4 0x4(%1), 0x54(%0)        \n\t"
-+      "       move.4 0x8(%1), 0x58(%0)        \n\t"
-+      "       move.4 0xc(%1), 0x5c(%0)        \n\t"
-+      "                                       \n\t"
-+      "; kick off hw for 2nd input            \n\t"
-+      "       move.4 0x40(%0), %2             \n\t"
-+      "                                       \n\t"
-+      "; update out asap                      \n\t"
-+      "       move.4 d15, 16(%1)++            \n\t"
-+      "                                       \n\t"
-+      "; go back to loop                      \n\t"
-+      "       jmpt 1b                         \n\t"
-+      "                                       \n\t"
-+      "; wait for last output                 \n\t"
-+      " 5:    btst 0x04(%0), #0               \n\t"
-+        "       jmpne.f -4                      \n\t"
-+        "                                       \n\t"
-+      "; read last output                     \n\t"
-+      "       move.4 0x0(%1), 0x50(%0)        \n\t"
-+      "       move.4 0x4(%1), 0x54(%0)        \n\t"
-+      "       move.4 0x8(%1), 0x58(%0)        \n\t"
-+      "       move.4 0xc(%1), 0x5c(%0)        \n\t"
-+        "                                       \n\t"
-+      "; copy out iv                          \n\t"
-+      "       move.4 0x0(%3), 0x50(%0)        \n\t"
-+      "       move.4 0x4(%3), 0x54(%0)        \n\t"
-+      "       move.4 0x8(%3), 0x58(%0)        \n\t"
-+      "       move.4 0xc(%3), 0x5c(%0)        \n\t"
-+        "                                       \n\t"
-+              :
-+              : "a" (SEC_BASE), "a" (out), "a" (in), "a" (iv), "d" (n)
-+              : "d15", "cc"
-+      );
-+}
+ config MTD_SLRAM
+       tristate "Uncached system RAM"
+       help
+--- a/drivers/mtd/devices/Makefile
++++ b/drivers/mtd/devices/Makefile
+@@ -16,3 +16,6 @@ obj-$(CONFIG_MTD_LART)               += lart.o
+ obj-$(CONFIG_MTD_BLOCK2MTD)   += block2mtd.o
+ obj-$(CONFIG_MTD_DATAFLASH)   += mtd_dataflash.o
+ obj-$(CONFIG_MTD_M25P80)      += m25p80.o
++obj-$(CONFIG_MTD_UBI32_M25P80)        += ubi32-m25p80.o
++obj-$(CONFIG_MTD_NAND_SPI_ER) += nand-spi-er.o
++obj-$(CONFIG_MTD_UBI32_NAND_SPI_ER)   += ubi32-nand-spi-er.o
+--- a/drivers/net/Kconfig
++++ b/drivers/net/Kconfig
+@@ -2540,6 +2540,19 @@ config JME
+         To compile this driver as a module, choose M here. The module
+         will be called jme.
++config UBICOM32_GMAC
++      tristate "Ubicom Gigabit Ethernet support"
++      depends on UBICOM32
++      help
++        Gigabit Ethernet support for ubicom32 processors
 +
-+#else
++config UBICOM32_OCM_FOR_SKB
++        bool  "USE OCM for SKB (EXPERIMENTAL)"
++        depends on UBICOM32_GMAC
++      default n
++        help
++          Allocate skb from OCM for Ethernet Receive when possible
 +
-+static void __ocm_text cbc_aes_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
-+{
-+      aes_hw_set_iv(iv);
-+      while (likely(n)) {
-+              aes_hw_cipher(out, in);
-+              out += AES_BLOCK_SIZE;
-+              in += AES_BLOCK_SIZE;
-+              n -= AES_BLOCK_SIZE;
-+      }
-+      SEC_COPY_4W(iv, out - AES_BLOCK_SIZE);
-+}
+ endif # NETDEV_1000
+ #
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -272,3 +272,5 @@ obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
+ obj-$(CONFIG_SFC) += sfc/
+ obj-$(CONFIG_WIMAX) += wimax/
 +
++obj-$(CONFIG_UBICOM32_GMAC) += ubi32-eth.o
+--- a/drivers/net/usb/asix.c
++++ b/drivers/net/usb/asix.c
+@@ -319,14 +319,33 @@ static int asix_rx_fixup(struct usbnet *
+               /* get the packet length */
+               size = (u16) (header & 0x0000ffff);
+-              if ((skb->len) - ((size + 1) & 0xfffe) == 0)
++              if ((skb->len) - ((size + 1) & 0xfffe) == 0) {
++#ifndef HAVE_EFFICIENT_UNALIGNED_ACCESS
++                      if (((u32)packet & 0x02) == 0) {
++                              memmove(packet - 2, packet, size);
++                              skb->data -= 2;
++                              skb->tail -= 2;
++                      }
 +#endif
+                       return 2;
++              }
 +
-+static void __ocm_text cbc_aes_decrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
-+{
-+        while (likely(n)) {
-+                aes_hw_set_iv(iv);
-+              SEC_COPY_4W(iv, in);
-+                aes_hw_cipher(out, in);
-+                out += AES_BLOCK_SIZE;
-+                in += AES_BLOCK_SIZE;
-+                n -= AES_BLOCK_SIZE;
-+        }
-+}
-+
-+static int __ocm_text cbc_aes_crypt(struct blkcipher_desc *desc,
-+                           struct scatterlist *dst, struct scatterlist *src,
-+                           unsigned int nbytes, u32 extra_flags)
-+{
-+      struct ubicom32_aes_ctx *uctx = crypto_blkcipher_ctx(desc->tfm);
-+      int ret;
-+
-+        struct blkcipher_walk walk;
-+        blkcipher_walk_init(&walk, dst, src, nbytes);
-+      ret = blkcipher_walk_virt(desc, &walk);
-+      if (unlikely(ret)) {
-+              return ret;
-+      }
-+
-+        hw_crypto_lock();
-+      hw_crypto_check();
-+
-+        hw_crypto_set_ctrl(uctx->ctrl | extra_flags);
-+        aes_hw_set_key(uctx->key, uctx->key_len);
-+
-+      while (likely((nbytes = walk.nbytes))) {
-+                /* only use complete blocks */
-+                unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
-+              if (likely(n)) {
-+                      u8 *out = walk.dst.virt.addr;
-+                      u8 *in = walk.src.virt.addr;
-+
-+                      if (extra_flags & SEC_DIR_ENCRYPT) {
-+                              cbc_aes_encrypt_loop(out, in, walk.iv, n);
+               if (size > ETH_FRAME_LEN) {
+                       deverr(dev,"asix_rx_fixup() Bad RX Length %d", size);
+                       return 0;
+               }
+               ax_skb = skb_clone(skb, GFP_ATOMIC);
+               if (ax_skb) {
++#ifndef HAVE_EFFICIENT_UNALIGNED_ACCESS
++                      if (((u32)packet & 0x02) == 0) {
++                              memmove(packet - 2, packet, size);
++                              ax_skb->data = packet - 2;
 +                      } else {
-+                              cbc_aes_decrypt_loop(out, in, walk.iv, n);
++                              ax_skb->data = packet;
 +                      }
-+              }
-+
-+              nbytes &= AES_BLOCK_SIZE - 1;
-+                ret = blkcipher_walk_done(desc, &walk, nbytes);
-+      }
-+      hw_crypto_unlock();
-+
-+      return ret;
-+}
-+
-+static int __ocm_text cbc_aes_encrypt(struct blkcipher_desc *desc,
-+                         struct scatterlist *dst, struct scatterlist *src,
-+                         unsigned int nbytes)
-+{
-+      return cbc_aes_crypt(desc, dst, src, nbytes, SEC_DIR_ENCRYPT | SEC_CBC_SET);
-+}
-+
-+static int __ocm_text cbc_aes_decrypt(struct blkcipher_desc *desc,
-+                         struct scatterlist *dst, struct scatterlist *src,
-+                         unsigned int nbytes)
-+{
-+      return cbc_aes_crypt(desc, dst, src, nbytes, SEC_DIR_DECRYPT | SEC_CBC_SET);
-+}
-+
-+static struct crypto_alg cbc_aes_alg = {
-+      .cra_name               =       "cbc(aes)",
-+      .cra_driver_name        =       "cbc-aes-ubicom32",
-+      .cra_priority           =       CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
-+      .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
-+      .cra_blocksize          =       AES_BLOCK_SIZE,
-+      .cra_ctxsize            =       sizeof(struct ubicom32_aes_ctx),
-+      .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
-+      .cra_type               =       &crypto_blkcipher_type,
-+      .cra_module             =       THIS_MODULE,
-+      .cra_list               =       LIST_HEAD_INIT(cbc_aes_alg.cra_list),
-+      .cra_u                  =       {
-+              .blkcipher = {
-+                      .min_keysize            =       AES_MIN_KEY_SIZE,
-+                      .max_keysize            =       AES_MAX_KEY_SIZE,
-+                      .ivsize                 =       AES_BLOCK_SIZE,
-+                      .setkey                 =       aes_set_key,
-+                      .encrypt                =       cbc_aes_encrypt,
-+                      .decrypt                =       cbc_aes_decrypt,
-+              }
-+      }
-+};
-+
-+static int __init aes_init(void)
-+{
-+      int ret;
-+
-+      hw_crypto_init();
++#else
++                      ax_skb->data = packet;
++#endif
+                       ax_skb->len = size;
+                       ax_skb->data = packet;
+                       skb_set_tail_pointer(ax_skb, size);
+@@ -1125,13 +1144,19 @@ static int ax88178_link_reset(struct usb
+       mode = AX88178_MEDIUM_DEFAULT;
+       if (ecmd.speed == SPEED_1000)
++#ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS
+               mode |= AX_MEDIUM_GM;
++#else
++              mode |= AX_MEDIUM_GM | AX_MEDIUM_ENCK;
++#endif
+       else if (ecmd.speed == SPEED_100)
+               mode |= AX_MEDIUM_PS;
+       else
+               mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM);
++#ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS
+       mode |= AX_MEDIUM_ENCK;
++#endif
+       if (ecmd.duplex == DUPLEX_FULL)
+               mode |= AX_MEDIUM_FD;
+--- a/drivers/oprofile/cpu_buffer.c
++++ b/drivers/oprofile/cpu_buffer.c
+@@ -328,10 +328,10 @@ static inline void oprofile_end_trace(st
+ }
+ static inline void
+-__oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
+-                        unsigned long event, int is_kernel)
++__oprofile_add_ext_sample_cpu(unsigned long pc, struct pt_regs * const regs,
++                            unsigned long event, int is_kernel, int cpu)
+ {
+-      struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
++      struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
+       unsigned long backtrace = oprofile_backtrace_depth;
+       /*
+@@ -353,7 +353,8 @@ __oprofile_add_ext_sample(unsigned long 
+ void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
+                            unsigned long event, int is_kernel)
+ {
+-      __oprofile_add_ext_sample(pc, regs, event, is_kernel);
++      __oprofile_add_ext_sample_cpu(pc, regs, event,
++                                    is_kernel, smp_processor_id());
+ }
+ void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
+@@ -361,7 +362,8 @@ void oprofile_add_sample(struct pt_regs 
+       int is_kernel = !user_mode(regs);
+       unsigned long pc = profile_pc(regs);
+-      __oprofile_add_ext_sample(pc, regs, event, is_kernel);
++      __oprofile_add_ext_sample_cpu(pc, regs, event,
++                                    is_kernel, smp_processor_id());
+ }
+ /*
+--- a/drivers/pci/Makefile
++++ b/drivers/pci/Makefile
+@@ -44,8 +44,8 @@ obj-$(CONFIG_PPC) += setup-bus.o
+ obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
+ obj-$(CONFIG_X86_VISWS) += setup-irq.o
+ obj-$(CONFIG_MN10300) += setup-bus.o
++obj-$(CONFIG_UBICOM32) += setup-bus.o setup-irq.o
+-#
+ # ACPI Related PCI FW Functions
+ #
+ obj-$(CONFIG_ACPI)    += pci-acpi.o
+--- a/drivers/serial/Kconfig
++++ b/drivers/serial/Kconfig
+@@ -871,6 +871,57 @@ config SERIAL_UARTLITE_CONSOLE
+         console (the system console is the device which receives all kernel
+         messages and warnings and which allows logins in single user mode).
++config SERIAL_UBI32_UARTTIO
++        tristate "Ubicom UARTTIO support"
++        depends on UBICOM32=y
++        select SERIAL_CORE
++      default y
++        help
++          Add support for the Ubicom virtual peripherial serial interface.
 +
-+      ret = crypto_register_alg(&aes_alg);
-+      if (ret)
-+              goto aes_err;
++config SERIAL_UBI32_UARTTIO_NR_UARTS
++      int "Maximum number of UARTTIO virtual serial ports"
++      depends on SERIAL_UBI32_UARTTIO
++      default "4"
++      help
++        Set this to the maximum number of serial ports you want the driver to support.
 +
-+      ret = crypto_register_alg(&ecb_aes_alg);
-+      if (ret)
-+              goto ecb_aes_err;
++config SERIAL_UBI32_UARTTIO_CONSOLE
++        tristate "Ubicom UARTTIO console support"
++        depends on SERIAL_UBI32_UARTTIO=y
++        select SERIAL_CORE_CONSOLE
++      default y
++        help
++          Add support for console on the Ubicom virtual peripherial serial interface.
 +
-+      ret = crypto_register_alg(&cbc_aes_alg);
-+      if (ret)
-+              goto cbc_aes_err;
++config SERIAL_UBI32_SERDES
++        bool "Ubicom serial port support"
++        depends on UBICOM32=y
++        select SERIAL_CORE
++      default y
++        help
++          Add support for the Ubicom serial interface.
 +
-+out:
-+      return ret;
++config SERIAL_UBI32_SERDES_CONSOLE
++        bool "Ubicom serial console support"
++        depends on SERIAL_UBI32_SERDES=y
++        select SERIAL_CORE_CONSOLE
++      default y
 +
-+cbc_aes_err:
-+      crypto_unregister_alg(&ecb_aes_alg);
-+ecb_aes_err:
-+      crypto_unregister_alg(&aes_alg);
-+aes_err:
-+      goto out;
-+}
++config SERIAL_UBI32_MAILBOX
++        bool "Ubicom mailbox support"
++        depends on UBICOM32=y
++        select SERIAL_CORE
++      default n
++        help
++          Add support for the Ubicom mailbox interface.
 +
-+static void __exit aes_fini(void)
-+{
-+      crypto_unregister_alg(&cbc_aes_alg);
-+      crypto_unregister_alg(&ecb_aes_alg);
-+      crypto_unregister_alg(&aes_alg);
-+}
++config SERIAL_UBI32_MAILBOX_CONSOLE
++        bool "Ubicom mailbox console support"
++        depends on SERIAL_UBI32_MAILBOX=y
++        select SERIAL_CORE_CONSOLE
++      default y
 +
-+module_init(aes_init);
-+module_exit(aes_fini);
+ config SERIAL_SUNCORE
+       bool
+       depends on SPARC
+--- a/drivers/serial/Makefile
++++ b/drivers/serial/Makefile
+@@ -77,3 +77,6 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIA
+ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
+ obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
+ obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
++obj-$(CONFIG_SERIAL_UBI32_SERDES) += ubi32_serdes.o
++obj-$(CONFIG_SERIAL_UBI32_UARTTIO) += ubi32_uarttio.o
++obj-$(CONFIG_SERIAL_UBI32_MAILBOX) += ubi32_mailbox.o
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -196,6 +196,15 @@ config SPI_S3C24XX
+       help
+         SPI driver for Samsung S3C24XX series ARM SoCs
++config SPI_UBICOM32_GPIO
++      tristate "Ubicom32 SPI over GPIO"
++      depends on SPI_MASTER && UBICOM32 && EXPERIMENTAL
++      select SPI_BITBANG
++      select HAS_DMA
++      help
++        SPI driver for the Ubicom32 architecture using
++        GPIO lines to provide the SPI bus.
 +
-+MODULE_ALIAS("aes");
+ config SPI_S3C24XX_GPIO
+       tristate "Samsung S3C24XX series SPI by GPIO"
+       depends on ARCH_S3C2410 && EXPERIMENTAL
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_ORION)                      += orion_spi.o
+ obj-$(CONFIG_SPI_MPC52xx_PSC)         += mpc52xx_psc_spi.o
+ obj-$(CONFIG_SPI_MPC83xx)             += spi_mpc83xx.o
+ obj-$(CONFIG_SPI_S3C24XX_GPIO)                += spi_s3c24xx_gpio.o
++obj-$(CONFIG_SPI_UBICOM32_GPIO)               += spi_ubicom32_gpio.o
+ obj-$(CONFIG_SPI_S3C24XX)             += spi_s3c24xx.o
+ obj-$(CONFIG_SPI_TXX9)                        += spi_txx9.o
+ obj-$(CONFIG_SPI_XILINX)              += xilinx_spi.o
+--- a/drivers/uio/Kconfig
++++ b/drivers/uio/Kconfig
+@@ -89,4 +89,12 @@ config UIO_SERCOS3
+         If you compile this as a module, it will be called uio_sercos3.
++config UIO_UBICOM32RING
++      tristate "Ubicom32 Ring Buffer driver"
++      default n
++      help
++        Userspace I/O interface for a Ubicom32 Ring Buffer.
 +
-+MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/arch/ubicom32/crypto/crypto_des.h
-@@ -0,0 +1,34 @@
-+/*
-+ * arch/ubicom32/crypto/crypto_des.h
-+ *   Function for checking keys for the DES and Triple DES Encryption
-+ *   algorithms.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef __CRYPTO_DES_H__
-+#define __CRYPTO_DES_H__
++        If you compile this as a module, it will be called uio_ubicom32ring
 +
-+extern int crypto_des_check_key(const u8*, unsigned int, u32*);
+ endif
+--- a/drivers/uio/Makefile
++++ b/drivers/uio/Makefile
+@@ -5,3 +5,4 @@ obj-$(CONFIG_UIO_PDRV_GENIRQ)  += uio_pdr
+ obj-$(CONFIG_UIO_SMX) += uio_smx.o
+ obj-$(CONFIG_UIO_AEC) += uio_aec.o
+ obj-$(CONFIG_UIO_SERCOS3)     += uio_sercos3.o
++obj-$(CONFIG_UIO_UBICOM32RING)        += uio_ubicom32ring.o
+--- a/drivers/usb/gadget/epautoconf.c
++++ b/drivers/usb/gadget/epautoconf.c
+@@ -154,6 +154,10 @@ ep_matches (
+                       /* configure your hardware with enough buffering!! */
+               }
+               break;
 +
-+#endif /* __CRYPTO_DES_H__ */
---- /dev/null
-+++ b/arch/ubicom32/crypto/crypto_ubicom32.c
-@@ -0,0 +1,50 @@
-+/*
-+ * arch/ubicom32/crypto/crypto_ubicom32.c
-+ *   Generic code to support ubicom32 hardware crypto accelerator
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include "crypto_ubicom32.h"
++      case USB_ENDPOINT_XFER_BULK:
++              if ((gadget->is_dualspeed) && (ep->maxpacket < 512))
++                      return 0;
+       }
+       /* MATCH!! */
+--- a/drivers/usb/Kconfig
++++ b/drivers/usb/Kconfig
+@@ -22,6 +22,7 @@ config USB_ARCH_HAS_HCD
+       default y if PCMCIA && !M32R                    # sl811_cs
+       default y if ARM                                # SL-811
+       default y if SUPERH                             # r8a66597-hcd
++      default y if UBICOM32                           # Ubicom's onchip USB Duial role controller
+       default PCI
+ # many non-PCI SOC chips embed OHCI
+--- a/drivers/usb/musb/Kconfig
++++ b/drivers/usb/musb/Kconfig
+@@ -12,7 +12,7 @@ config USB_MUSB_HDRC
+       depends on !SUPERH
+       select TWL4030_USB if MACH_OMAP_3430SDP
+       select USB_OTG_UTILS
+-      tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
++      tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, Ubicom, ...)'
+       help
+         Say Y here if your system has a dual role high speed USB
+         controller based on the Mentor Graphics silicon IP.  Then
+--- a/drivers/usb/musb/Makefile
++++ b/drivers/usb/musb/Makefile
+@@ -30,6 +30,10 @@ ifeq ($(CONFIG_BF52x),y)
+       musb_hdrc-objs  += blackfin.o
+ endif
++ifeq ($(CONFIG_UBICOM32), y)
++        musb_hdrc-objs  += ubi32_usb.o
++endif
 +
-+spinlock_t crypto_ubicom32_lock;
-+bool crypto_ubicom32_inited = false;
-+volatile bool crypto_ubicom32_on = false;
-+volatile unsigned long crypto_ubicom32_last_use;
+ ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y)
+       musb_hdrc-objs          += musb_gadget_ep0.o musb_gadget.o
+ endif
+--- a/drivers/usb/musb/musb_core.c
++++ b/drivers/usb/musb/musb_core.c
+@@ -105,6 +105,13 @@
+ #include <asm/mach-types.h>
+ #endif
++#ifdef CONFIG_UBICOM32
++#include <asm/ip5000.h>
++#include <asm/ubicom32-tio.h>
++extern void ubi32_usb_init(void);
++extern void ubi32_usb_int_clr(void);
++#endif
 +
-+struct timer_list crypto_ubicom32_ps_timer;
-+void crypto_ubicom32_ps_check(unsigned long data)
-+{
-+      unsigned long idle_time = msecs_to_jiffies(HW_CRYPTO_PS_MAX_IDLE_MS);
-+
-+      BUG_ON(!crypto_ubicom32_on);
-+
-+      if (((jiffies - crypto_ubicom32_last_use) > idle_time) && spin_trylock_bh(&crypto_ubicom32_lock)) {
-+                hw_crypto_turn_off();
-+                spin_unlock_bh(&crypto_ubicom32_lock);
-+              return;
-+      }
+ #include "musb_core.h"
+@@ -147,8 +154,37 @@ static inline struct musb *dev_to_musb(s
+ }
+ /*-------------------------------------------------------------------------*/
++#if defined(CONFIG_UBICOM32)
 +
-+      /* keep monitoring */
-+      hw_crypto_ps_start();
-+}
---- /dev/null
-+++ b/arch/ubicom32/crypto/crypto_ubicom32.h
-@@ -0,0 +1,346 @@
 +/*
-+ * arch/ubicom32/crypto/crypto_ubicom32.h
-+ *   Support for Ubicom32 cryptographic instructions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
++ * Load an endpoint's FIFO
 + */
-+#ifndef _CRYPTO_ARCH_UBICOM32_CRYPT_H
-+#define _CRYPTO_ARCH_UBICOM32_CRYPT_H
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/jiffies.h>
-+#include <linux/timer.h>
-+#include <linux/spinlock.h>
-+#include <asm/errno.h>
-+#include <asm/io.h>
-+#include <asm/ip5000.h>
-+
-+#define CRYPTO_UBICOM32_LOOP_ASM 1
-+#define CRYPTO_UBICOM32_ALIGNMENT 4
-+#define SEC_ALIGNED(p) (((u32)p & 3) == 0)
-+
-+#define SEC_BASE              SECURITY_BASE
-+#define SEC_KEY_OFFSET                SECURITY_KEY_VALUE(0)
-+#define SEC_INPUT_OFFSET      SECURITY_KEY_IN(0)
-+#define SEC_OUTPUT_OFFSET     SECURITY_KEY_OUT(0)
-+#define SEC_HASH_OFFSET               SECURITY_KEY_HASH(0)
-+
-+#define SEC_KEY_128_BITS      SECURITY_CTRL_KEY_SIZE(0)
-+#define SEC_KEY_192_BITS      SECURITY_CTRL_KEY_SIZE(1)
-+#define SEC_KEY_256_BITS      SECURITY_CTRL_KEY_SIZE(2)
-+
-+#define SEC_HASH_NONE         SECURITY_CTRL_HASH_ALG_NONE
-+#define SEC_HASH_MD5          SECURITY_CTRL_HASH_ALG_MD5
-+#define SEC_HASH_SHA1         SECURITY_CTRL_HASH_ALG_SHA1
-+
-+#define SEC_CBC_SET           SECURITY_CTRL_CBC
-+#define SEC_CBC_NONE          0
-+
-+#define SEC_ALG_AES           SECURITY_CTRL_CIPHER_ALG_AES
-+#define SEC_ALG_NONE          SECURITY_CTRL_CIPHER_ALG_NONE
-+#define SEC_ALG_DES           SECURITY_CTRL_CIPHER_ALG_DES
-+#define SEC_ALG_3DES          SECURITY_CTRL_CIPHER_ALG_3DES
-+
-+#define SEC_DIR_ENCRYPT               SECURITY_CTRL_ENCIPHER
-+#define SEC_DIR_DECRYPT               0
-+
-+#define CRYPTO_UBICOM32_PRIORITY 300
-+#define CRYPTO_UBICOM32_COMPOSITE_PRIORITY 400
-+
-+#define HW_CRYPTO_PS_MAX_IDLE_MS 100    /* idle time (ms) before shuting down sm */
-+
-+extern spinlock_t crypto_ubicom32_lock;
-+extern bool crypto_ubicom32_inited;
-+extern volatile bool crypto_ubicom32_on;
-+extern volatile unsigned long crypto_ubicom32_last_use;
-+extern struct timer_list crypto_ubicom32_ps_timer;
-+extern void crypto_ubicom32_ps_check(unsigned long data);
-+
-+#define SEC_COPY_2W(t, s)                             \
-+      asm volatile (                                  \
-+      "       move.4 0(%0), 0(%1)             \n\t"   \
-+      "       move.4 4(%0), 4(%1)             \n\t"   \
-+                                                      \
-+              :                                       \
-+              : "a" (t), "a" (s)                      \
-+      )
-+
-+#define SEC_COPY_4W(t, s)                             \
-+      asm volatile (                                  \
-+      "       move.4 0(%0), 0(%1)             \n\t"   \
-+      "       move.4 4(%0), 4(%1)             \n\t"   \
-+      "       move.4 8(%0), 8(%1)             \n\t"   \
-+      "       move.4 12(%0), 12(%1)           \n\t"   \
-+              :                                       \
-+              : "a" (t), "a" (s)                      \
-+      )
-+
-+#define SEC_COPY_5W(t, s)                             \
-+      asm volatile (                                  \
-+      "       move.4 0(%0), 0(%1)             \n\t"   \
-+      "       move.4 4(%0), 4(%1)             \n\t"   \
-+      "       move.4 8(%0), 8(%1)             \n\t"   \
-+      "       move.4 12(%0), 12(%1)           \n\t"   \
-+      "       move.4 16(%0), 16(%1)           \n\t"   \
-+              :                                       \
-+              : "a" (t), "a" (s)                      \
-+      )
-+
-+#define SEC_SET_KEY_2W(x)                             \
-+      asm volatile (                                  \
-+      "       ; write key to Security Keyblock \n\t"  \
-+      "       move.4 0x10(%0), 0(%1)          \n\t"   \
-+      "       move.4 0x14(%0), 4(%1)          \n\t"   \
-+              :                                       \
-+              : "a" (SECURITY_BASE), "a" (x)          \
-+      )
-+
-+#define SEC_SET_KEY_4W(x) \
-+      asm volatile ( \
-+      "       ; write key to Security Keyblock \n\t"  \
-+      "       move.4 0x10(%0), 0(%1)          \n\t"   \
-+      "       move.4 0x14(%0), 4(%1)          \n\t"   \
-+      "       move.4 0x18(%0), 8(%1)          \n\t"   \
-+      "       move.4 0x1c(%0), 12(%1)         \n\t"   \
-+              :                                       \
-+              : "a"(SECURITY_BASE), "a"(x)            \
-+      )
-+
-+#define SEC_SET_KEY_6W(x)                             \
-+      asm volatile (                                  \
-+      "       ; write key to Security Keyblock \n\t"  \
-+      "       move.4 0x10(%0), 0(%1)          \n\t"   \
-+      "       move.4 0x14(%0), 4(%1)          \n\t"   \
-+      "       move.4 0x18(%0), 8(%1)          \n\t"   \
-+      "       move.4 0x1c(%0), 12(%1)         \n\t"   \
-+      "       move.4 0x20(%0), 16(%1)         \n\t"   \
-+      "       move.4 0x24(%0), 20(%1)         \n\t"   \
-+              :                                       \
-+              : "a" (SECURITY_BASE), "a" (x)          \
-+      )
-+
-+#define SEC_SET_KEY_8W(x)                             \
-+      asm volatile (                                  \
-+      "       ; write key to Security Keyblock \n\t"  \
-+      "       move.4 0x10(%0), 0(%1)          \n\t"   \
-+      "       move.4 0x14(%0), 4(%1)          \n\t"   \
-+      "       move.4 0x18(%0), 8(%1)          \n\t"   \
-+      "       move.4 0x1c(%0), 12(%1)         \n\t"   \
-+      "       move.4 0x20(%0), 16(%1)         \n\t"   \
-+      "       move.4 0x24(%0), 20(%1)         \n\t"   \
-+      "       move.4 0x28(%0), 24(%1)         \n\t"   \
-+      "       move.4 0x2c(%0), 28(%1)         \n\t"   \
-+              :                                       \
-+              : "a" (SECURITY_BASE), "a" (x)          \
-+      )
-+
-+#define SEC_SET_KEY_64(k)     SEC_SET_KEY_2W(k)
-+#define SEC_SET_KEY_128(k)    SEC_SET_KEY_4W(k)
-+#define SEC_SET_KEY_192(k)    SEC_SET_KEY_6W(k)
-+#define SEC_SET_KEY_256(k)    SEC_SET_KEY_8W(k)
-+
-+#define DES_SET_KEY(x)                SEC_SET_KEY_64(x)
-+#define DES3_SET_KEY(x)       SEC_SET_KEY_192(x)
-+
-+#define SEC_SET_INPUT_2W(x)                           \
-+      asm volatile (                                  \
-+      "       ; write key to Security Keyblock \n\t"  \
-+      "       move.4 0x30(%0), 0(%1)          \n\t"   \
-+      "       move.4 0x34(%0), 4(%1)          \n\t"   \
-+              :                                       \
-+              : "a" (SECURITY_BASE), "a" (x)          \
-+      )
-+
-+#define SEC_GET_OUTPUT_2W(x)                          \
-+      asm volatile (                                  \
-+      "       ; write key to Security Keyblock \n\t"  \
-+      "       move.4 0(%1), 0x50(%0)          \n\t"   \
-+      "       move.4 4(%1), 0x54(%0)          \n\t"   \
-+              :                                       \
-+              : "a" (SECURITY_BASE), "a" (x)          \
-+      )
-+
-+#define SEC_SET_INPUT_4W(x) \
-+      asm volatile ( \
-+      "       ; write key to Security Keyblock \n\t"  \
-+      "       move.4 0x30(%0), 0(%1)          \n\t"   \
-+      "       move.4 0x34(%0), 4(%1)          \n\t"   \
-+      "       move.4 0x38(%0), 8(%1)          \n\t"   \
-+      "       move.4 0x3c(%0), 12(%1)         \n\t"   \
-+              :                                       \
-+              : "a" (SECURITY_BASE), "a" (x)          \
-+      )
-+
-+#define SEC_GET_OUTPUT_4W(x)                          \
-+      asm volatile (                                  \
-+      "       ; read output from Security Keyblock \n\t" \
-+      "       move.4 0(%1), 0x50(%0)          \n\t"   \
-+      "       move.4 4(%1), 0x54(%0)          \n\t"   \
-+      "       move.4 8(%1), 0x58(%0)          \n\t"   \
-+      "       move.4 12(%1), 0x5c(%0)         \n\t"   \
-+              :                                       \
-+              : "a" (SECURITY_BASE), "a" (x)          \
-+      )
-+
-+#define SEC_SET_IV_4W(x)                              \
-+      asm volatile (                                  \
-+      "       ; write IV to Security Keyblock  \n\t"  \
-+      "       move.4 0x50(%0), 0(%1)          \n\t"   \
-+      "       move.4 0x54(%0), 4(%1)          \n\t"   \
-+      "       move.4 0x58(%0), 8(%1)          \n\t"   \
-+      "       move.4 0x5c(%0), 12(%1)         \n\t"   \
-+              :                                       \
-+              : "a" (SECURITY_BASE), "a" (x)          \
-+      )
-+
-+#define SEC_PIPE_FLUSH() asm volatile ( " pipe_flush 0 \n\t" )
-+
-+static inline void hw_crypto_set_ctrl(uint32_t c)
-+{
-+      asm volatile (
-+      "       move.4  0(%0), %1               \n\t"
-+              :
-+              : "a" (SECURITY_BASE + SECURITY_CTRL), "d" (c)
-+      );
-+}
-+
-+static inline void hw_crypto_ps_start(void)
-+{
-+      crypto_ubicom32_ps_timer.expires = jiffies + msecs_to_jiffies(HW_CRYPTO_PS_MAX_IDLE_MS >> 1);
-+      add_timer(&crypto_ubicom32_ps_timer);
-+}
-+
-+static inline void hw_crypto_turn_on(void)
-+{
-+      asm volatile (
-+      "       moveai  A4, %0                  \n\t"
-+      "       bset    0x0(A4), 0x0(A4), %1    \n\t"
-+      "       cycles 11                       \n\t"
-+              :
-+              : "i" (OCP_BASE >> 7), "i" (GEN_CLK_PLL_SECURITY_BIT_NO)
-+              : "a4", "cc"
-+      );
-+      crypto_ubicom32_on = true;
-+}
-+
-+static inline void hw_crypto_turn_off(void)
++void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 wCount, const u8 *pSource)
 +{
-+      asm volatile (
-+      "       moveai  A4, %0                  \n\t"
-+      "       bclr    0x0(A4), 0x0(A4), %1    \n\t"
-+              :
-+              : "i" (OCP_BASE >> 7), "i" (GEN_CLK_PLL_SECURITY_BIT_NO)
-+              : "a4", "cc"
-+      );
-+      crypto_ubicom32_on = false;
-+}
++      void __iomem *fifo = hw_ep->fifo;
 +
-+/*
-+ * hw_crypto_check
-+ *    Most probably hw crypto is called in clusters and it makes no sense to turn it off
-+ *    and on and waster 13 cycles every time.
-+ */
-+static inline void hw_crypto_check(void)
-+{
-+      if (likely(crypto_ubicom32_on)) {
-+              return;
-+      }
-+      crypto_ubicom32_last_use = jiffies;
-+      hw_crypto_turn_on();
-+      hw_crypto_ps_start();
-+}
++      prefetch((u8 *)pSource);
 +
-+/*
-+ * hw_crypto_ps_init
-+ *    Init power save timer
-+ */
-+static inline void hw_crypto_ps_init(void)
-+{
-+      init_timer_deferrable(&crypto_ubicom32_ps_timer);
-+      crypto_ubicom32_ps_timer.function = crypto_ubicom32_ps_check;
-+      crypto_ubicom32_ps_timer.data = 0;
-+}
++      DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
++                      'T', hw_ep->epnum, fifo, wCount, pSource);
 +
-+/*
-+ * hw_crypto_init()
-+ *      Initialize OCP security module lock and disables its clock.
-+ */
-+static inline void hw_crypto_init(void)
-+{
-+      if (!crypto_ubicom32_inited) {
-+              crypto_ubicom32_inited = true;
-+              spin_lock_init(&crypto_ubicom32_lock);
-+              hw_crypto_ps_init();
-+              hw_crypto_turn_off();
-+      }
-+}
++      usb_tio_write_fifo((u32)fifo, (u32)pSource, wCount);
 +
-+/*
-+ * hw_crypto_lock()
-+ *      Locks the OCP security module and enables its clock.
-+ */
-+static inline void hw_crypto_lock(void)
-+{
-+      spin_lock_bh(&crypto_ubicom32_lock);
 +}
 +
 +/*
-+ * hw_crypto_unlock()
-+ *      Unlocks the OCP security module and disables its clock.
++ * Unload an endpoint's FIFO
 + */
-+static inline void hw_crypto_unlock(void)
-+{
-+      crypto_ubicom32_last_use = jiffies;
-+      spin_unlock_bh(&crypto_ubicom32_lock);
-+}
-+
-+#define CONFIG_CRYPTO_UBICOM32_DEBUG 1
-+
-+#ifdef CONFIG_CRYPTO_UBICOM32_DEBUG
-+static inline void hex_dump(void *buf, int b_size, const char *msg)
++void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 wCount, u8 *pDest)
 +{
-+      u8 *b = (u8 *)buf;
-+      int i;
-+      if (msg) {
-+              printk("%s:\t", msg);
-+      }
 +
-+      for (i=0; i < b_size; i++) {
-+              printk("%02x ", b[i]);
-+              if ((i & 3) == 3) {
-+                      printk(" ");
-+              }
-+              if ((i & 31) == 31) {
-+                      printk("\n");
-+              }
-+      }
-+      printk("\n");
++      void __iomem *fifo = hw_ep->fifo;
++      DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
++                      'R', hw_ep->epnum, fifo, wCount, pDest);
++      usb_tio_read_fifo((u32)fifo, (u32)pDest, wCount);
 +}
-+#define UBICOM32_SEC_DUMP(a, b, c) hex_dump(a, b, c)
+-#if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN)
++#elif !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN)
+ /*
+  * Load an endpoint's FIFO
+@@ -227,8 +263,7 @@ void musb_read_fifo(struct musb_hw_ep *h
+               readsb(fifo, dst, len);
+       }
+ }
+-
+-#endif        /* normal PIO */
++#endif /* !T6010 && !BLACKFIN */
+ /*-------------------------------------------------------------------------*/
+@@ -874,12 +909,19 @@ void musb_start(struct musb *musb)
+       musb_writeb(regs, MUSB_TESTMODE, 0);
+       /* put into basic highspeed mode and start session */
++#ifndef CONFIG_UBICOM32
+       musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE
+                                               | MUSB_POWER_SOFTCONN
+                                               | MUSB_POWER_HSENAB
+                                               /* ENSUSPEND wedges tusb */
+                                               /* | MUSB_POWER_ENSUSPEND */
+                                               );
 +#else
-+#define UBICOM32_SEC_DUMP(a, b, c)
++      musb_writeb(regs, MUSB_POWER,  MUSB_POWER_HSENAB
++                                              /* ENSUSPEND wedges tusb */
++                                              /* | MUSB_POWER_ENSUSPEND */
++                                              );
 +#endif
-+
-+#endif        /* _CRYPTO_ARCH_UBICOM32_CRYPT_H */
---- /dev/null
-+++ b/arch/ubicom32/crypto/des_check_key.c
-@@ -0,0 +1,148 @@
-+/*
-+ * arch/ubicom32/crypto/des_check_key.c
-+ *   Ubicom32 architecture function for checking keys for the DES and
-+ *   Tripple DES Encryption algorithms.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * Originally released as descore by Dana L. How <how@isl.stanford.edu>.
-+ * Modified by Raimar Falke <rf13@inf.tu-dresden.de> for the Linux-Kernel.
-+ * Derived from Cryptoapi and Nettle implementations, adapted for in-place
-+ * scatterlist interface.  Changed LGPL to GPL per section 3 of the LGPL.
-+ *
-+ * s390 Version:
-+ *   Copyright IBM Corp. 2003
-+ *   Author(s): Thomas Spatzier
-+ *            Jan Glauber (jan.glauber@de.ibm.com)
-+ *
-+ * Derived from "crypto/des.c"
-+ *   Copyright (c) 1992 Dana L. How.
-+ *   Copyright (c) Raimar Falke <rf13@inf.tu-dresden.de>
-+ *   Copyright (c) Gisle Sflensminde <gisle@ii.uib.no>
-+ *   Copyright (C) 2001 Niels Mvller.
-+ *   Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/crypto.h>
-+#include "crypto_des.h"
-+
-+#define ROR(d,c,o)    ((d) = (d) >> (c) | (d) << (o))
-+
-+static const u8 parity[] = {
-+      8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3,
-+      0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
-+      0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
-+      8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
-+      0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
-+      8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
-+      8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
-+      4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8,
-+};
-+
-+/*
-+ * RFC2451: Weak key checks SHOULD be performed.
-+ */
-+int
-+crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags)
-+{
-+      u32 n, w;
-+
-+      n  = parity[key[0]]; n <<= 4;
-+      n |= parity[key[1]]; n <<= 4;
-+      n |= parity[key[2]]; n <<= 4;
-+      n |= parity[key[3]]; n <<= 4;
-+      n |= parity[key[4]]; n <<= 4;
-+      n |= parity[key[5]]; n <<= 4;
-+      n |= parity[key[6]]; n <<= 4;
-+      n |= parity[key[7]];
-+      w = 0x88888888L;
-+
-+      if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY)
-+          && !((n - (w >> 3)) & w)) {  /* 1 in 10^10 keys passes this test */
-+              if (n < 0x41415151) {
-+                      if (n < 0x31312121) {
-+                              if (n < 0x14141515) {
-+                                      /* 01 01 01 01 01 01 01 01 */
-+                                      if (n == 0x11111111) goto weak;
-+                                      /* 01 1F 01 1F 01 0E 01 0E */
-+                                      if (n == 0x13131212) goto weak;
-+                              } else {
-+                                      /* 01 E0 01 E0 01 F1 01 F1 */
-+                                      if (n == 0x14141515) goto weak;
-+                                      /* 01 FE 01 FE 01 FE 01 FE */
-+                                      if (n == 0x16161616) goto weak;
-+                              }
-+                      } else {
-+                              if (n < 0x34342525) {
-+                                      /* 1F 01 1F 01 0E 01 0E 01 */
-+                                      if (n == 0x31312121) goto weak;
-+                                      /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */
-+                                      if (n == 0x33332222) goto weak;
-+                              } else {
-+                                      /* 1F E0 1F E0 0E F1 0E F1 */
-+                                      if (n == 0x34342525) goto weak;
-+                                      /* 1F FE 1F FE 0E FE 0E FE */
-+                                      if (n == 0x36362626) goto weak;
-+                              }
-+                      }
-+              } else {
-+                      if (n < 0x61616161) {
-+                              if (n < 0x44445555) {
-+                                      /* E0 01 E0 01 F1 01 F1 01 */
-+                                      if (n == 0x41415151) goto weak;
-+                                      /* E0 1F E0 1F F1 0E F1 0E */
-+                                      if (n == 0x43435252) goto weak;
-+                              } else {
-+                                      /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */
-+                                      if (n == 0x44445555) goto weak;
-+                                      /* E0 FE E0 FE F1 FE F1 FE */
-+                                      if (n == 0x46465656) goto weak;
-+                              }
-+                      } else {
-+                              if (n < 0x64646565) {
-+                                      /* FE 01 FE 01 FE 01 FE 01 */
-+                                      if (n == 0x61616161) goto weak;
-+                                      /* FE 1F FE 1F FE 0E FE 0E */
-+                                      if (n == 0x63636262) goto weak;
-+                              } else {
-+                                      /* FE E0 FE E0 FE F1 FE F1 */
-+                                      if (n == 0x64646565) goto weak;
-+                                      /* FE FE FE FE FE FE FE FE */
-+                                      if (n == 0x66666666) goto weak;
-+                              }
+       musb->is_active = 0;
+       devctl = musb_readb(regs, MUSB_DEVCTL);
+@@ -1081,6 +1123,7 @@ static struct fifo_cfg __initdata mode_4
+ };
++#ifndef CONFIG_UBICOM32
+ /*
+  * configure a fifo; for non-shared endpoints, this may be called
+  * once for a tx fifo and once for an rx fifo.
+@@ -1240,7 +1283,7 @@ static int __init ep_config_from_table(s
+       return 0;
+ }
+-
++#endif /* CONFIG_UBICOM32 */
+ /*
+  * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false
+@@ -1256,6 +1299,11 @@ static int __init ep_config_from_hw(stru
+       DBG(2, "<== static silicon ep config\n");
+       /* FIXME pick up ep0 maxpacket size */
++#ifdef CONFIG_UBICOM32
++      /* set ep0 to shared_fifo, otherwise urb will be put to out_qh but ep0_irq try to get the urb from in_qh*/
++      hw_ep = musb->endpoints;
++      hw_ep->is_shared_fifo = true;
++#endif
+       for (epnum = 1; epnum < musb->config->num_eps; epnum++) {
+               musb_ep_select(mbase, epnum);
+@@ -1276,14 +1324,27 @@ static int __init ep_config_from_hw(stru
+               /* REVISIT:  this algorithm is lazy, we should at least
+                * try to pick a double buffered endpoint.
+                */
++#ifndef CONFIG_UBICOM32
+               if (musb->bulk_ep)
+                       continue;
+               musb->bulk_ep = hw_ep;
++#else
++              if ((musb->bulk_ep_in) && (musb->bulk_ep_out))
++                      continue;
++              /* Save theEP with 1024 Bytes FIFO for ISO */
++              if(hw_ep->max_packet_sz_tx == 512) {
++                      if (!musb->bulk_ep_in) {
++                              musb->bulk_ep_in = hw_ep;
++                      } else if (!musb->bulk_ep_out) {
++                              musb->bulk_ep_out = hw_ep;
 +                      }
 +              }
-+      }
-+      return 0;
-+weak:
-+      *flags |= CRYPTO_TFM_RES_WEAK_KEY;
-+      return -EINVAL;
-+}
-+
-+EXPORT_SYMBOL(crypto_des_check_key);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Key Check function for DES &  DES3 Cipher Algorithms");
---- /dev/null
-+++ b/arch/ubicom32/crypto/des_ubicom32.c
-@@ -0,0 +1,761 @@
-+/*
-+ * arch/ubicom32/crypto/des_ubicom32.c
-+ *   Ubicom32 implementation of the DES Cipher Algorithm.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <crypto/algapi.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+
-+#include "crypto_ubicom32.h"
-+extern int crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags);
-+
-+#define DES_BLOCK_SIZE 8
-+#define DES_KEY_SIZE 8
-+
-+#define DES3_192_KEY_SIZE     (3 * DES_KEY_SIZE)
-+#define DES3_192_BLOCK_SIZE   DES_BLOCK_SIZE
-+
-+#define DES3_SUB_KEY(key, i)  (((u8 *)key) + (i * DES_KEY_SIZE))
-+
-+enum des_ops {
-+      DES_ENCRYPT,
-+      DES_DECRYPT,
-+
-+      DES3_EDE_ENCRYPT,
-+      DES3_EDE_DECRYPT,
-+
-+#ifdef DES3_EEE
-+      DES3_EEE_ENCRYPT,
-+      DES3_EEE_DECRYPT,
-+#endif
-+};
-+
-+struct ubicom32_des_ctx {
-+      u8 key[3 * DES_KEY_SIZE];
-+      u32 ctrl;
-+      int key_len;
-+};
-+
-+static inline void des_hw_set_key(const u8 *key, u8 key_len)
-+{
-+      /*
-+       * HW 3DES is not tested yet, use DES just as ipOS
-+       */
-+      DES_SET_KEY(key);
-+}
-+
-+static inline void des_hw_cipher(u8 *out, const u8 *in)
-+{
-+      SEC_SET_INPUT_2W(in);
-+
-+      asm volatile (
-+      "       ; start DES by writing 0x38(SECURITY_BASE)      \n\t"
-+      "       move.4 0x38(%0), #0x01                          \n\t"
-+      "       pipe_flush 0                                    \n\t"
-+      "                                                       \n\t"
-+      "       ; wait for the module to calculate the output   \n\t"
-+      "       btst 0x04(%0), #0                               \n\t"
-+      "       jmpne.f .-4                                     \n\t"
-+              :
-+              : "a" (SEC_BASE)
-+              : "cc"
-+      );
-+
-+      SEC_GET_OUTPUT_2W(out);
-+}
-+
-+
-+static void inline des3_hw_ede_encrypt(u8 *keys, u8 *out, const u8 *in)
-+{
-+      hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
-+      des_hw_set_key(DES3_SUB_KEY(keys, 0), DES_KEY_SIZE);
-+      des_hw_cipher(out, in);
-+
-+      hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
-+      des_hw_set_key(DES3_SUB_KEY(keys, 1), DES_KEY_SIZE);
-+      des_hw_cipher(out, out);
-+
-+      hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
-+      des_hw_set_key(DES3_SUB_KEY(keys, 2), DES_KEY_SIZE);
-+      des_hw_cipher(out, out);
-+}
-+
-+static void inline des3_hw_ede_decrypt(u8 *keys, u8 *out, const u8 *in)
-+{
-+      hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
-+      des_hw_set_key(DES3_SUB_KEY(keys, 2), DES_KEY_SIZE);
-+      des_hw_cipher(out, in);
-+
-+      hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
-+      des_hw_set_key(DES3_SUB_KEY(keys, 1), DES_KEY_SIZE);
-+      des_hw_cipher(out, out);
-+
-+      hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
-+      des_hw_set_key(DES3_SUB_KEY(keys, 0), DES_KEY_SIZE);
-+      des_hw_cipher(out, out);
-+}
-+
-+#ifdef DES3_EEE
-+static void inline des3_hw_eee_encrypt(u8 *keys, u8 *out, const u8 *in)
-+{
-+      hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
-+      des_hw_set_key(DES3_SUB_KEY(keys, 0), 2);
-+      des_hw_cipher(out, in);
-+
-+      hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
-+      des_hw_set_key(DES3_SUB_KEY(keys, 1), 2);
-+      des_hw_cipher(out, out);
-+
-+      hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
-+      des_hw_set_key(DES3_SUB_KEY(keys, 2), 2);
-+      des_hw_cipher(out, out);
-+}
-+
-+static void inline des3_hw_eee_decrypt(u8 *keys, u8 *out, const u8 *in)
-+{
-+      hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
-+      des_hw_set_key(DES3_SUB_KEY(keys, 2), 2);
-+      des_hw_cipher(out, in);
-+
-+      hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
-+      des_hw_set_key(DES3_SUB_KEY(keys, 1), 2);
-+      des_hw_cipher(out, out);
-+
-+      hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
-+      des_hw_set_key(DES3_SUB_KEY(keys, 0), 2);
-+      des_hw_cipher(out, out);
-+}
++#endif /* CONFIG_UBICOM32 */
+ #endif
+       }
+ #ifdef CONFIG_USB_MUSB_HDRC_HCD
+-      if (!musb->bulk_ep) {
++      if ((!musb->bulk_ep_in) || (!musb->bulk_ep_out)) {
+               pr_debug("%s: missing bulk\n", musb_driver_name);
+               return -EINVAL;
+       }
+@@ -1393,12 +1454,16 @@ static int __init musb_core_init(u16 mus
+       musb->epmask = 1;
+       if (reg & MUSB_CONFIGDATA_DYNFIFO) {
++#ifndef CONFIG_UBICOM32
+               if (musb->config->dyn_fifo)
+                       status = ep_config_from_table(musb);
+-              else {
++              else
 +#endif
++              {
+                       ERR("reconfigure software for Dynamic FIFOs\n");
+                       status = -ENODEV;
+               }
 +
-+static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
-+                    unsigned int keylen)
-+{
-+      struct ubicom32_des_ctx *dctx = crypto_tfm_ctx(tfm);
-+      u32 *flags = &tfm->crt_flags;
-+      int ret;
-+
-+      /* test if key is valid (not a weak key) */
-+      ret = crypto_des_check_key(key, keylen, flags);
-+      if (ret == 0) {
-+              memcpy(dctx->key, key, keylen);
-+              dctx->key_len = keylen;
-+              //dctx->ctrl = (keylen == DES_KEY_SIZE) ? SEC_ALG_DES : SEC_ALG_3DES
-+              /* 2DES and 3DES are both implemented with DES hw function */
-+              dctx->ctrl = SEC_ALG_DES;
-+      }
-+      return ret;
-+}
-+
-+static inline void des_cipher_1b(struct crypto_tfm *tfm, u8 *out, const u8 *in, u32 extra_flags)
-+{
-+      const struct ubicom32_des_ctx *uctx = crypto_tfm_ctx(tfm);
-+
-+      hw_crypto_lock();
-+      hw_crypto_check();
-+      hw_crypto_set_ctrl(uctx->ctrl | extra_flags);
-+
-+      des_hw_set_key(uctx->key, uctx->key_len);
-+      des_hw_cipher(out, in);
-+
-+      hw_crypto_unlock();
-+}
-+
-+static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
-+{
-+      des_cipher_1b(tfm, out, in, SEC_DIR_ENCRYPT);
-+}
-+
-+static void des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
-+{
-+      des_cipher_1b(tfm, out, in, SEC_DIR_DECRYPT);
-+}
-+
-+static struct crypto_alg des_alg = {
-+      .cra_name               =       "des",
-+      .cra_driver_name        =       "des-ubicom32",
-+      .cra_priority           =       CRYPTO_UBICOM32_PRIORITY,
-+      .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
-+      .cra_blocksize          =       DES_BLOCK_SIZE,
-+      .cra_ctxsize            =       sizeof(struct ubicom32_des_ctx),
-+      .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
-+      .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
-+      .cra_module             =       THIS_MODULE,
-+      .cra_list               =       LIST_HEAD_INIT(des_alg.cra_list),
-+      .cra_u                  = {
-+              .cipher = {
-+                      .cia_min_keysize        =       DES_KEY_SIZE,
-+                      .cia_max_keysize        =       DES_KEY_SIZE,
-+                      .cia_setkey             =       des_setkey,
-+                      .cia_encrypt            =       des_encrypt,
-+                      .cia_decrypt            =       des_decrypt,
-+              }
-+      }
-+};
-+
-+static void ecb_des_ciper_loop(u8 *out, u8 *in, unsigned int n)
-+{
-+      while (likely(n)) {
-+              des_hw_cipher(out, in);
-+              out += DES_BLOCK_SIZE;
-+              in += DES_BLOCK_SIZE;
-+              n -= DES_BLOCK_SIZE;
-+      }
-+}
-+
-+static void ecb_des3_ede_encrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n)
-+{
-+      while (likely(n)) {
-+              des3_hw_ede_encrypt(keys, out, in);
-+
-+              out += DES_BLOCK_SIZE;
-+              in += DES_BLOCK_SIZE;
-+              n -= DES_BLOCK_SIZE;
-+      }
-+}
-+
-+static void ecb_des3_ede_decrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n)
-+{
-+      while (likely(n)) {
-+              des3_hw_ede_decrypt(keys, out, in);
-+
-+              out += DES_BLOCK_SIZE;
-+              in += DES_BLOCK_SIZE;
-+              n -= DES_BLOCK_SIZE;
-+      }
-+}
-+
-+#ifdef DES3_EEE
-+static void ecb_des3_eee_encrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n)
-+{
-+      while (likely(n)) {
-+              des3_hw_eee_encrypt(keys, out, in);
-+
-+              out += DES_BLOCK_SIZE;
-+              in += DES_BLOCK_SIZE;
-+              n -= DES_BLOCK_SIZE;
-+      }
-+}
-+
-+static void ecb_des3_eee_decrypt_loop(u8 *keys, u8 *out, u8 *in, unsigned int n)
-+{
-+      while (likely(n)) {
-+              des3_hw_eee_decrypt(keys, out, in);
-+
-+              out += DES_BLOCK_SIZE;
-+              in += DES_BLOCK_SIZE;
-+              n -= DES_BLOCK_SIZE;
-+      }
-+}
+       } else {
+               if (!musb->config->dyn_fifo)
+                       status = ep_config_from_hw(musb);
+@@ -1462,8 +1527,8 @@ static int __init musb_core_init(u16 mus
+ /*-------------------------------------------------------------------------*/
+-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
+-
++#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_UBICOM32)
++static u32_t musb_int_count = 0;
+ static irqreturn_t generic_interrupt(int irq, void *__hci)
+ {
+       unsigned long   flags;
+@@ -1472,10 +1537,17 @@ static irqreturn_t generic_interrupt(int
+       spin_lock_irqsave(&musb->lock, flags);
++#ifndef CONFIG_UBICOM32
+       musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
+       musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
+       musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
++#else
++      musb_read_int_status(&musb->int_usb, &musb->int_tx, &musb->int_rx);
++      //ubi32_usb_int_clr();
++      musb_int_count++;
 +#endif
-+
-+static inline void ecb_des_cipher_n(struct ubicom32_des_ctx *uctx, enum des_ops op, u8 *out, u8 *in, unsigned int n)
-+{
-+      switch (op) {
-+      case DES_ENCRYPT:
-+      case DES_DECRYPT:
-+              /* set the right algo, direction and key once */
-+              hw_crypto_set_ctrl(SEC_ALG_DES | (op == DES_ENCRYPT ? SEC_DIR_ENCRYPT : 0));
-+              des_hw_set_key(uctx->key, uctx->key_len);
-+              ecb_des_ciper_loop(out, in, n);
-+              break;
-+
-+      case DES3_EDE_ENCRYPT:
-+              ecb_des3_ede_encrypt_loop(uctx->key, out, in, n);
-+              break;
-+
-+      case DES3_EDE_DECRYPT:
-+              ecb_des3_ede_decrypt_loop(uctx->key, out, in, n);
-+              break;
-+
-+#ifdef DES3_EEE
-+      case DES3_EEE_ENCRYPT:
-+              ecb_des3_eee_encrypt_loop(uctx->key, out, in, n);
-+              break;
-+
-+      case DES3_EEE_DECRYPT:
-+              ecb_des3_eee_decrypt_loop(uctx->key, out, in, n);
-+              break;
++      DBG(4, "usb %x, tx %x, rx %x", musb->int_usb, musb->int_tx, musb->int_rx);
+       if (musb->int_usb || musb->int_tx || musb->int_rx)
+               retval = musb_interrupt(musb);
+@@ -2210,6 +2282,10 @@ static struct platform_driver musb_drive
+ static int __init musb_init(void)
+ {
++#ifdef CONFIG_UBICOM32
++      ubi32_usb_init();
 +#endif
-+      }
-+}
-+
-+static inline void des_xor_2w(u32 *data, u32 *iv)
-+{
-+      data[0] ^= iv[0];
-+      data[1] ^= iv[1];
-+}
-+
-+static void cbc_des_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
-+{
-+      while (likely(n)) {
-+              des_xor_2w((u32 *)in, (u32 *)iv);
-+              des_hw_cipher(out, in);
-+              SEC_COPY_2W(iv, out);
-+              out += DES_BLOCK_SIZE;
-+              in += DES_BLOCK_SIZE;
-+              n -= DES_BLOCK_SIZE;
-+      }
-+}
 +
-+static void cbc_des_decrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
-+{
-+      u8 next_iv[DES_BLOCK_SIZE];
-+      while (likely(n)) {
-+              SEC_COPY_2W(next_iv, in);
-+              des_hw_cipher(out, in);
-+              des_xor_2w((u32 *)out, (u32 *)iv);
-+              SEC_COPY_2W(iv, next_iv);
-+
-+              out += DES_BLOCK_SIZE;
-+              in += DES_BLOCK_SIZE;
-+              n -= DES_BLOCK_SIZE;
-+      }
-+}
-+
-+static void cbc_des3_ede_encrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n)
-+{
-+      while (likely(n)) {
-+              des_xor_2w((u32 *)in, (u32 *)iv);
-+              des3_hw_ede_encrypt(keys, out, in);
-+              SEC_COPY_2W(iv, out);
-+
-+              out += DES_BLOCK_SIZE;
-+              in += DES_BLOCK_SIZE;
-+              n -= DES_BLOCK_SIZE;
-+      }
-+}
-+
-+static void cbc_des3_ede_decrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n)
-+{
-+      u8 next_iv[DES_BLOCK_SIZE];
-+      while (likely(n)) {
-+              SEC_COPY_2W(next_iv, in);
-+              des3_hw_ede_decrypt(keys, out, in);
-+              des_xor_2w((u32 *)out, (u32 *)iv);
-+              SEC_COPY_2W(iv, next_iv);
-+
-+              out += DES_BLOCK_SIZE;
-+              in += DES_BLOCK_SIZE;
-+              n -= DES_BLOCK_SIZE;
-+      }
-+}
-+
-+#ifdef DES3_EEE
-+static void cbc_des3_eee_encrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n)
-+{
-+      while (likely(n)) {
-+              des_xor_2w((u32 *)in, (u32 *)iv);
-+              des3_hw_eee_encrypt(keys, out, in);
-+              SEC_COPY_2W(iv, out);
-+
-+              out += DES_BLOCK_SIZE;
-+              in += DES_BLOCK_SIZE;
-+              n -= DES_BLOCK_SIZE;
-+      }
-+}
-+
-+static void cbc_des3_eee_decrypt_loop(u8 *keys, u8 *out, u8 *in, u8 *iv, unsigned int n)
-+{
-+      u8 next_iv[DES_BLOCK_SIZE];
-+      while (likely(n)) {
-+              SEC_COPY_2W(next_iv, in);
-+              des3_hw_eee_decrypt(keys, out, in);
-+              des_xor_2w((u32 *)out, (u32 *)iv);
-+              SEC_COPY_2W(iv, next_iv);
-+
-+              out += DES_BLOCK_SIZE;
-+              in += DES_BLOCK_SIZE;
-+              n -= DES_BLOCK_SIZE;
-+      }
-+}
+ #ifdef CONFIG_USB_MUSB_HDRC_HCD
+       if (usb_disabled())
+               return 0;
+--- a/drivers/usb/musb/musb_core.h
++++ b/drivers/usb/musb/musb_core.h
+@@ -326,7 +326,12 @@ struct musb {
+        * queue until it completes or NAKs too much; then we try the next
+        * endpoint.
+        */
++#ifdef CONFIG_UBICOM32
++      struct musb_hw_ep       *bulk_ep_in;
++      struct musb_hw_ep       *bulk_ep_out;
++#else
+       struct musb_hw_ep       *bulk_ep;
 +#endif
+       struct list_head        control;        /* of musb_qh */
+       struct list_head        in_bulk;        /* of musb_qh */
+--- a/drivers/usb/musb/musb_gadget.c
++++ b/drivers/usb/musb/musb_gadget.c
+@@ -432,7 +432,7 @@ void musb_g_tx(struct musb *musb, u8 epn
+                * probably rates reporting as a host error
+                */
+               if (csr & MUSB_TXCSR_P_SENTSTALL) {
+-                      csr |= MUSB_TXCSR_P_WZC_BITS;
++                      csr &= ~(MUSB_TXCSR_P_WZC_BITS);
+                       csr &= ~MUSB_TXCSR_P_SENTSTALL;
+                       musb_writew(epio, MUSB_TXCSR, csr);
+                       if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+@@ -448,7 +448,7 @@ void musb_g_tx(struct musb *musb, u8 epn
+               if (csr & MUSB_TXCSR_P_UNDERRUN) {
+                       /* we NAKed, no big deal ... little reason to care */
+-                      csr |= MUSB_TXCSR_P_WZC_BITS;
++                      csr &= ~(MUSB_TXCSR_P_WZC_BITS);
+                       csr &= ~(MUSB_TXCSR_P_UNDERRUN
+                                       | MUSB_TXCSR_TXPKTRDY);
+                       musb_writew(epio, MUSB_TXCSR, csr);
+@@ -584,10 +584,16 @@ static void rxstate(struct musb *musb, s
+       u16                     csr = 0;
+       const u8                epnum = req->epnum;
+       struct usb_request      *request = &req->request;
+-      struct musb_ep          *musb_ep = &musb->endpoints[epnum].ep_out;
++      struct musb_ep          *musb_ep = NULL;
+       void __iomem            *epio = musb->endpoints[epnum].regs;
+-      unsigned                fifo_count = 0;
+-      u16                     len = musb_ep->packet_sz;
++      u16                     fifo_count = 0;
++      u16                     len = 0;
 +
-+static inline void cbc_des_cipher_n(struct ubicom32_des_ctx *uctx, enum des_ops op, u8 *out, u8 *in, u8 *iv, unsigned int n)
-+{
-+      switch (op) {
-+      case DES_ENCRYPT:
-+              hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_ENCRYPT);
-+              des_hw_set_key(uctx->key, uctx->key_len);
-+              cbc_des_encrypt_loop(out, in, iv, n);
-+              break;
-+
-+      case DES_DECRYPT:
-+              /* set the right algo, direction and key once */
-+              hw_crypto_set_ctrl(SEC_ALG_DES | SEC_DIR_DECRYPT);
-+              des_hw_set_key(uctx->key, uctx->key_len);
-+              cbc_des_decrypt_loop(out, in, iv, n);
-+              break;
-+
-+      case DES3_EDE_ENCRYPT:
-+              cbc_des3_ede_encrypt_loop(uctx->key, out, in, iv, n);
-+              break;
-+
-+      case DES3_EDE_DECRYPT:
-+              cbc_des3_ede_decrypt_loop(uctx->key, out, in, iv, n);
-+              break;
-+
-+#ifdef DES3_EEE
-+      case DES3_EEE_ENCRYPT:
-+              cbc_des3_eee_encrypt_loop(uctx->key, out, in, iv, n);
-+              break;
++      if (musb->endpoints[epnum].is_shared_fifo)
++              musb_ep = &musb->endpoints[epnum].ep_in;
++      else
++              musb_ep = &musb->endpoints[epnum].ep_out;
++      len =  musb_ep->packet_sz;
+       csr = musb_readw(epio, MUSB_RXCSR);
+@@ -726,7 +732,7 @@ static void rxstate(struct musb *musb, s
+                        */
+                       /* ack the read! */
+-                      csr |= MUSB_RXCSR_P_WZC_BITS;
++                      csr &= ~MUSB_RXCSR_P_WZC_BITS;
+                       csr &= ~MUSB_RXCSR_RXPKTRDY;
+                       musb_writew(epio, MUSB_RXCSR, csr);
+               }
+@@ -745,10 +751,15 @@ void musb_g_rx(struct musb *musb, u8 epn
+       u16                     csr;
+       struct usb_request      *request;
+       void __iomem            *mbase = musb->mregs;
+-      struct musb_ep          *musb_ep = &musb->endpoints[epnum].ep_out;
++      struct musb_ep          *musb_ep = NULL;
+       void __iomem            *epio = musb->endpoints[epnum].regs;
+       struct dma_channel      *dma;
++      if (musb->endpoints[epnum].is_shared_fifo)
++              musb_ep = &musb->endpoints[epnum].ep_in;
++      else
++              musb_ep = &musb->endpoints[epnum].ep_out;
 +
-+      case DES3_EEE_DECRYPT:
-+              cbc_des3_eee_decrypt_loop(uctx->key, out, in, iv, n);
-+              break;
+       musb_ep_select(mbase, epnum);
+       request = next_request(musb_ep);
+@@ -1769,7 +1780,9 @@ int usb_gadget_register_driver(struct us
+                       }
+               }
+       }
+-
++#ifndef CONFIG_USB_MUSB_OTG
++      musb_pullup(musb, 1);
 +#endif
-+      }
-+}
-+
-+static int des_cipher(struct blkcipher_desc *desc, struct scatterlist *dst,
-+                    struct scatterlist *src, unsigned int nbytes, u32 extra_flags, enum des_ops op)
-+{
-+      struct ubicom32_des_ctx *uctx = crypto_blkcipher_ctx(desc->tfm);
-+      int ret;
-+
-+      struct blkcipher_walk walk;
-+      blkcipher_walk_init(&walk, dst, src, nbytes);
-+      ret = blkcipher_walk_virt(desc, &walk);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      hw_crypto_lock();
-+      hw_crypto_check();
-+
-+      while ((nbytes = walk.nbytes)) {
-+              /* only use complete blocks */
-+              unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1);
-+              u8 *out = walk.dst.virt.addr;
-+              u8 *in = walk.src.virt.addr;
-+
-+              /* finish n/16 blocks */
-+              if (extra_flags & SEC_CBC_SET) {
-+                      cbc_des_cipher_n(uctx, op, out, in, walk.iv, n);
-+              } else {
-+                      ecb_des_cipher_n(uctx, op, out, in, n);
-+              }
-+
-+              nbytes &= DES_BLOCK_SIZE - 1;
-+              ret = blkcipher_walk_done(desc, &walk, nbytes);
-+      }
-+
-+      hw_crypto_unlock();
-+      return ret;
-+}
-+
-+static int ecb_des_encrypt(struct blkcipher_desc *desc,
-+                         struct scatterlist *dst, struct scatterlist *src,
-+                         unsigned int nbytes)
-+{
-+      return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES_ENCRYPT);
-+}
-+
-+static int ecb_des_decrypt(struct blkcipher_desc *desc,
-+                         struct scatterlist *dst, struct scatterlist *src,
-+                         unsigned int nbytes)
-+{
-+      return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES_DECRYPT);
-+}
-+
-+static struct crypto_alg ecb_des_alg = {
-+      .cra_name               =       "ecb(des)",
-+      .cra_driver_name        =       "ecb-des-ubicom32",
-+      .cra_priority           =       CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
-+      .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
-+      .cra_blocksize          =       DES_BLOCK_SIZE,
-+      .cra_ctxsize            =       sizeof(struct ubicom32_des_ctx),
-+      .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
-+      .cra_type               =       &crypto_blkcipher_type,
-+      .cra_module             =       THIS_MODULE,
-+      .cra_list               =       LIST_HEAD_INIT(ecb_des_alg.cra_list),
-+      .cra_u                  = {
-+              .blkcipher = {
-+                      .min_keysize            =       DES_KEY_SIZE,
-+                      .max_keysize            =       DES_KEY_SIZE,
-+                      .setkey                 =       des_setkey,
-+                      .encrypt                =       ecb_des_encrypt,
-+                      .decrypt                =       ecb_des_decrypt,
-+              }
-+      }
-+};
-+
-+static int cbc_des_encrypt(struct blkcipher_desc *desc,
-+                         struct scatterlist *dst, struct scatterlist *src,
-+                         unsigned int nbytes)
-+{
-+      return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES_ENCRYPT);
-+}
-+
-+static int cbc_des_decrypt(struct blkcipher_desc *desc,
-+                         struct scatterlist *dst, struct scatterlist *src,
-+                         unsigned int nbytes)
-+{
-+      return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES_DECRYPT);
-+}
-+
-+static struct crypto_alg cbc_des_alg = {
-+      .cra_name               =       "cbc(des)",
-+      .cra_driver_name        =       "cbc-des-ubicom32",
-+      .cra_priority           =       CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
-+      .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
-+      .cra_blocksize          =       DES_BLOCK_SIZE,
-+      .cra_ctxsize            =       sizeof(struct ubicom32_des_ctx),
-+      .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
-+      .cra_type               =       &crypto_blkcipher_type,
-+      .cra_module             =       THIS_MODULE,
-+      .cra_list               =       LIST_HEAD_INIT(cbc_des_alg.cra_list),
-+      .cra_u                  = {
-+              .blkcipher = {
-+                      .min_keysize            =       DES_KEY_SIZE,
-+                      .max_keysize            =       DES_KEY_SIZE,
-+                      .ivsize                 =       DES_BLOCK_SIZE,
-+                      .setkey                 =       des_setkey,
-+                      .encrypt                =       cbc_des_encrypt,
-+                      .decrypt                =       cbc_des_decrypt,
-+              }
-+      }
-+};
-+
-+/*
-+ * RFC2451:
-+ *
-+ *   For DES-EDE3, there is no known need to reject weak or
-+ *   complementation keys.  Any weakness is obviated by the use of
-+ *   multiple keys.
-+ *
-+ *   However, if the first two or last two independent 64-bit keys are
-+ *   equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the
-+ *   same as DES.  Implementers MUST reject keys that exhibit this
-+ *   property.
-+ *
-+ */
-+static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
-+                         unsigned int keylen)
-+{
-+      int i, ret;
-+      struct ubicom32_des_ctx *dctx = crypto_tfm_ctx(tfm);
-+      const u8 *temp_key = key;
-+      u32 *flags = &tfm->crt_flags;
-+
-+      if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
-+          memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2],
-+                 DES_KEY_SIZE))) {
-+
-+              *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
-+              return -EINVAL;
-+      }
-+      for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) {
-+              ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
-+              if (ret < 0)
-+                      return ret;
-+      }
-+      memcpy(dctx->key, key, keylen);
-+      dctx->ctrl = SEC_ALG_DES;       //hw 3DES not working yet
-+      dctx->key_len = keylen;
-+      return 0;
-+}
-+
-+static void des3_192_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-+{
-+      struct ubicom32_des_ctx *uctx = crypto_tfm_ctx(tfm);
-+
-+      hw_crypto_lock();
-+      hw_crypto_check();
-+
-+      des3_hw_ede_encrypt(uctx->key, dst, src);
-+
-+      hw_crypto_unlock();
-+}
-+
-+static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-+{
-+      struct ubicom32_des_ctx *uctx = crypto_tfm_ctx(tfm);
-+
-+      hw_crypto_lock();
-+      hw_crypto_check();
-+
-+      des3_hw_ede_decrypt(uctx->key, dst, src);
-+
-+      hw_crypto_unlock();
-+}
-+
-+static struct crypto_alg des3_192_alg = {
-+      .cra_name               =       "des3_ede",
-+      .cra_driver_name        =       "des3_ede-ubicom32",
-+      .cra_priority           =       CRYPTO_UBICOM32_PRIORITY,
-+      .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
-+      .cra_blocksize          =       DES3_192_BLOCK_SIZE,
-+      .cra_ctxsize            =       sizeof(struct ubicom32_des_ctx),
-+      .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
-+      .cra_module             =       THIS_MODULE,
-+      .cra_list               =       LIST_HEAD_INIT(des3_192_alg.cra_list),
-+      .cra_u                  = {
-+              .cipher = {
-+                      .cia_min_keysize        =       DES3_192_KEY_SIZE,
-+                      .cia_max_keysize        =       DES3_192_KEY_SIZE,
-+                      .cia_setkey             =       des3_192_setkey,
-+                      .cia_encrypt            =       des3_192_encrypt,
-+                      .cia_decrypt            =       des3_192_decrypt,
-+              }
-+      }
-+};
-+
-+static int ecb_des3_192_encrypt(struct blkcipher_desc *desc,
-+                              struct scatterlist *dst,
-+                              struct scatterlist *src, unsigned int nbytes)
-+{
-+      return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES3_EDE_ENCRYPT);
-+}
-+
-+static int ecb_des3_192_decrypt(struct blkcipher_desc *desc,
-+                              struct scatterlist *dst,
-+                              struct scatterlist *src, unsigned int nbytes)
-+{
-+      return des_cipher(desc, dst, src, nbytes, SEC_CBC_NONE, DES3_EDE_DECRYPT);
-+}
-+
-+static struct crypto_alg ecb_des3_192_alg = {
-+      .cra_name               =       "ecb(des3_ede)",
-+      .cra_driver_name        =       "ecb-des3_ede-ubicom32",
-+      .cra_priority           =       CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
-+      .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
-+      .cra_blocksize          =       DES3_192_BLOCK_SIZE,
-+      .cra_ctxsize            =       sizeof(struct ubicom32_des_ctx),
-+      .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
-+      .cra_type               =       &crypto_blkcipher_type,
-+      .cra_module             =       THIS_MODULE,
-+      .cra_list               =       LIST_HEAD_INIT(
-+                                              ecb_des3_192_alg.cra_list),
-+      .cra_u                  = {
-+              .blkcipher = {
-+                      .min_keysize            =       DES3_192_KEY_SIZE,
-+                      .max_keysize            =       DES3_192_KEY_SIZE,
-+                      .setkey                 =       des3_192_setkey,
-+                      .encrypt                =       ecb_des3_192_encrypt,
-+                      .decrypt                =       ecb_des3_192_decrypt,
-+              }
-+      }
-+};
-+
-+static int cbc_des3_192_encrypt(struct blkcipher_desc *desc,
-+                              struct scatterlist *dst,
-+                              struct scatterlist *src, unsigned int nbytes)
-+{
-+      return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES3_EDE_ENCRYPT);
-+}
-+
-+static int cbc_des3_192_decrypt(struct blkcipher_desc *desc,
-+                              struct scatterlist *dst,
-+                              struct scatterlist *src, unsigned int nbytes)
-+{
-+      return des_cipher(desc, dst, src, nbytes, SEC_CBC_SET, DES3_EDE_DECRYPT);
-+}
-+
-+static struct crypto_alg cbc_des3_192_alg = {
-+      .cra_name               =       "cbc(des3_ede)",
-+      .cra_driver_name        =       "cbc-des3_ede-ubicom32",
-+      .cra_priority           =       CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
-+      .cra_flags              =       CRYPTO_ALG_TYPE_BLKCIPHER,
-+      .cra_blocksize          =       DES3_192_BLOCK_SIZE,
-+      .cra_ctxsize            =       sizeof(struct ubicom32_des_ctx),
-+      .cra_alignmask          =       CRYPTO_UBICOM32_ALIGNMENT - 1,
-+      .cra_type               =       &crypto_blkcipher_type,
-+      .cra_module             =       THIS_MODULE,
-+      .cra_list               =       LIST_HEAD_INIT(
-+                                              cbc_des3_192_alg.cra_list),
-+      .cra_u                  = {
-+              .blkcipher = {
-+                      .min_keysize            =       DES3_192_KEY_SIZE,
-+                      .max_keysize            =       DES3_192_KEY_SIZE,
-+                      .ivsize                 =       DES3_192_BLOCK_SIZE,
-+                      .setkey                 =       des3_192_setkey,
-+                      .encrypt                =       cbc_des3_192_encrypt,
-+                      .decrypt                =       cbc_des3_192_decrypt,
-+              }
-+      }
-+};
-+
-+static int init(void)
-+{
-+      int ret = 0;
-+
-+      hw_crypto_init();
-+
-+      ret = crypto_register_alg(&des_alg);
-+      if (ret)
-+              goto des_err;
-+      ret = crypto_register_alg(&ecb_des_alg);
-+      if (ret)
-+              goto ecb_des_err;
-+      ret = crypto_register_alg(&cbc_des_alg);
-+      if (ret)
-+              goto cbc_des_err;
-+
-+      ret = crypto_register_alg(&des3_192_alg);
-+      if (ret)
-+              goto des3_192_err;
-+      ret = crypto_register_alg(&ecb_des3_192_alg);
-+      if (ret)
-+              goto ecb_des3_192_err;
-+      ret = crypto_register_alg(&cbc_des3_192_alg);
-+      if (ret)
-+              goto cbc_des3_192_err;
-+
-+out:
-+      return ret;
-+
-+cbc_des3_192_err:
-+      crypto_unregister_alg(&ecb_des3_192_alg);
-+ecb_des3_192_err:
-+      crypto_unregister_alg(&des3_192_alg);
-+des3_192_err:
-+      crypto_unregister_alg(&cbc_des_alg);
-+cbc_des_err:
-+      crypto_unregister_alg(&ecb_des_alg);
-+ecb_des_err:
-+      crypto_unregister_alg(&des_alg);
-+des_err:
-+      goto out;
-+}
-+
-+static void __exit fini(void)
-+{
-+      crypto_unregister_alg(&cbc_des3_192_alg);
-+      crypto_unregister_alg(&ecb_des3_192_alg);
-+      crypto_unregister_alg(&des3_192_alg);
-+      crypto_unregister_alg(&cbc_des_alg);
-+      crypto_unregister_alg(&ecb_des_alg);
-+      crypto_unregister_alg(&des_alg);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+
-+MODULE_ALIAS("des");
-+MODULE_ALIAS("des3_ede");
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms");
---- /dev/null
-+++ b/arch/ubicom32/crypto/Makefile
-@@ -0,0 +1,36 @@
-+#
-+# arch/ubicom32/crypto/Makefile
-+#     <TODO: Replace with short file description>
-+#
-+# (C) Copyright 2009, Ubicom, Inc.
-+#
-+# This file is part of the Ubicom32 Linux Kernel Port.
-+#
-+# The Ubicom32 Linux Kernel Port 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.
-+#
-+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+# see <http://www.gnu.org/licenses/>.
-+#
-+# Ubicom32 implementation derived from (with many thanks):
-+#   arch/m68knommu
-+#   arch/blackfin
-+#   arch/parisc
-+#
-+obj-$(CONFIG_CRYPTO_UBICOM32) += crypto_ubicom32.o
-+obj-$(CONFIG_CRYPTO_AES_UBICOM32) += aes_ubicom32.o
-+obj-$(CONFIG_CRYPTO_DES_UBICOM32) += des.o
-+obj-$(CONFIG_CRYPTO_MD5_UBICOM32) += md5.o
-+obj-$(CONFIG_CRYPTO_SHA1_UBICOM32) += sha1.o
-+
-+des-y := des_ubicom32.o des_check_key.o
-+md5-y := md5_ubicom32.o md5_ubicom32_asm.o
-+sha1-y := sha1_ubicom32.o
---- /dev/null
-+++ b/arch/ubicom32/crypto/md5_ubicom32_asm.S
-@@ -0,0 +1,234 @@
-+/*
-+ * arch/ubicom32/crypto/md5_ubicom32_asm.S
-+ *    MD5 (Message Digest 5) support for Ubicom32 v3 architecture
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#define __ASM__
-+#include <asm/ip5000.h>
-+
-+#ifndef RP
-+#define RP A5
-+#endif
-+
-+;*****************************************************************************************
-+; The function prototypes
-+;*****************************************************************************************
-+; void md5_ip5k_init(void)
-+; void md5_ip5k_transform(u32_t *data_input)
-+; void md5_get_digest(u32_t *digest)
-+
-+;*****************************************************************************************
-+; Inputs
-+;*****************************************************************************************;
-+; data_input is the pointer to the block of data over which the digest will be calculated.
-+;     It should be word aligned.
-+;
-+; digest is the pointer to the block of data into which the digest (the output) will be written.
-+;     It should be word aligned.
-+;
-+
-+;*****************************************************************************************
-+; Outputs
-+;*****************************************************************************************
-+; None
-+
-+;*****************************************************************************************
-+; An: Address Registers
-+;*****************************************************************************************
-+#define an_digest A3
-+#define an_data_input A3
-+#define an_security_block A4
-+
-+;*****************************************************************************************
-+; Hash Constants
-+;*****************************************************************************************
-+#define HASH_MD5_IN0 0x01234567
-+#define HASH_MD5_IN1 0x89abcdef
-+#define HASH_MD5_IN2 0xfedcba98
-+#define HASH_MD5_IN3 0x76543210
-+
-+#define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2
-+#define HASH_SECURITY_BLOCK_CONTROL_INIT_MD5 ((1 << 4) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION)
-+
-+;*****************************************************************************************
-+; Hash related defines
-+;*****************************************************************************************
-+#define hash_control 0x00(an_security_block)
-+#define hash_control_low 0x02(an_security_block)
-+#define hash_status 0x04(an_security_block)
-+
-+#define hash_input_0 0x30(an_security_block)
-+#define hash_input_1 0x34(an_security_block)
-+#define hash_input_2 0x38(an_security_block)
-+#define hash_input_3 0x3c(an_security_block)
-+#define hash_input_4 0x40(an_security_block)
-+
-+#define hash_output_0 0x70(an_security_block)
-+#define hash_output_0_low 0x72(an_security_block)
-+#define hash_output_1 0x74(an_security_block)
-+#define hash_output_1_low 0x76(an_security_block)
-+#define hash_output_2 0x78(an_security_block)
-+#define hash_output_2_low 0x7a(an_security_block)
-+#define hash_output_3 0x7c(an_security_block)
-+#define hash_output_3_low 0x7e(an_security_block)
-+
-+;*****************************************************************************************
-+; Assembly macros
-+;*****************************************************************************************
-+      ; C compiler reserves RP (A5) for return address during subroutine call.
-+      ; Use RP to return to caller
-+.macro        call_return_macro
-+      calli   RP, 0(RP)
-+.endm
-+
-+#if 0
-+;*****************************************************************************************
-+;     void md5_ip5k_init(void)
-+;             initialize the output registers of the hash module
-+;
-+      ;.section .text.md5_ip5k_init,"ax",@progbits
-+      .section .text
-+      .global _md5_ip5k_init
-+      .func md5_ip5k_init, _md5_ip5k_init
-+
-+_md5_ip5k_init:
-+      moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
-+
-+      movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5)
-+      movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5)
-+
-+      movei hash_output_0, #%hi(HASH_MD5_IN0)
-+      movei hash_output_0_low, #%lo(HASH_MD5_IN0)
-+
-+      movei hash_output_1, #%hi(HASH_MD5_IN1)
-+      movei hash_output_1_low, #%lo(HASH_MD5_IN1)
-+
-+      movei hash_output_2, #%hi(HASH_MD5_IN2)
-+      movei hash_output_2_low, #%lo(HASH_MD5_IN2)
-+
-+      movei hash_output_3, #%hi(HASH_MD5_IN3)
-+      movei hash_output_3_low, #%lo(HASH_MD5_IN3)
-+
-+      call_return_macro
-+      .endfunc
-+#endif
-+
-+;*****************************************************************************************
-+;     void md5_ip5k_init_digest(u32_t *hash_input)
-+;             initialize the output registers of the hash module
-+
-+      ;.section .text.md5_ip5k_init_digest,"ax",@progbits
-+      .section .text
-+      .global _md5_ip5k_init_digest
-+      .func md5_ip5k_init_digest, _md5_ip5k_init_digest
-+
-+_md5_ip5k_init_digest:
-+      movea an_data_input, D0
-+
-+      moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
-+
-+      movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5)
-+      movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_MD5)
-+
-+      move.4 hash_output_0, (an_data_input)4++
-+      move.4 hash_output_1, (an_data_input)4++
-+      move.4 hash_output_2, (an_data_input)4++
-+      move.4 hash_output_3, (an_data_input)4++
-+
-+      call_return_macro
-+      .endfunc
-+
-+;*****************************************************************************************
-+;     void md5_ip5k_transform(u32_t *data_input)
-+;             performs intermediate transformation step for the hash calculation
-+;
-+      ;.sect .text.md5_ip5k_transform,"ax",@progbits
-+      .section .text
-+      .global _md5_ip5k_transform
-+      .func md5_ip5k_transform, _md5_ip5k_transform
-+
-+_md5_ip5k_transform:
-+      movea an_data_input, D0
-+
-+      moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
-+
-+      ; Write the first 128bits (16 bytes)
-+      move.4 hash_input_0, (an_data_input)4++
-+      move.4 hash_input_1, (an_data_input)4++
-+      move.4 hash_input_2, (an_data_input)4++
-+      move.4 hash_input_3, (an_data_input)4++
-+      move.4 hash_input_4, D0
-+
-+      move.4 hash_input_0, (an_data_input)4++
-+      move.4 hash_input_1, (an_data_input)4++
-+      move.4 hash_input_2, (an_data_input)4++
-+      move.4 hash_input_3, (an_data_input)4++
-+      move.4 hash_input_4, D0
-+
-+      move.4 hash_input_0, (an_data_input)4++
-+      move.4 hash_input_1, (an_data_input)4++
-+      move.4 hash_input_2, (an_data_input)4++
-+      move.4 hash_input_3, (an_data_input)4++
-+      move.4 hash_input_4, D0
-+
-+      move.4 hash_input_0, (an_data_input)4++
-+      move.4 hash_input_1, (an_data_input)4++
-+      move.4 hash_input_2, (an_data_input)4++
-+      move.4 hash_input_3, (an_data_input)4++
-+      move.4 hash_input_4, D0
-+
-+      pipe_flush 0
-+
-+md5_ip5k_transform_wait:
-+      ; wait for the module to calculate the output hash
-+      btst hash_status, #0
-+      jmpne.f md5_ip5k_transform_wait
-+
-+      call_return_macro
-+      .endfunc
-+
-+;*****************************************************************************************
-+;     void md5_ip5k_get_digest(u32_t *digest)
-+;             Return the hash of the input data
-+;
-+      ;.sect .text.md5_get_digest,"ax",@progbits
-+      .section .text
-+      .global _md5_ip5k_get_digest
-+      .func md5_ip5k_get_digest, _md5_ip5k_get_digest
-+
-+_md5_ip5k_get_digest:
-+      movea an_digest, D0
-+
-+      moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
-+
-+      ; we have finished
-+      move.4 0(an_digest), hash_output_0
-+      move.4 4(an_digest), hash_output_1
-+      move.4 8(an_digest), hash_output_2
-+      move.4 12(an_digest), hash_output_3
-+
-+      call_return_macro
-+      .endfunc
---- /dev/null
-+++ b/arch/ubicom32/crypto/md5_ubicom32.c
-@@ -0,0 +1,200 @@
-+/*
-+ * arch/ubicom32/crypto/md5_ubicom32.c
-+ *   Ubicom32 implementation of the MD5 Secure Hash Algorithm
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/crypto.h>
-+
-+#include "crypto_ubicom32.h"
-+
-+#define MD5_DIGEST_SIZE       16
-+#define MD5_BLOCK_SIZE        64
-+#define MD5_HASH_WORDS        4
-+
-+extern void _md5_ip5k_init_digest(u32_t *digest);
-+extern void _md5_ip5k_transform(u32_t *data_input);
-+extern void _md5_ip5k_get_digest(u32_t *digest);
-+
-+struct ubicom32_md5_ctx {
-+      u64 count;              /* message length */
-+      u32 state[MD5_HASH_WORDS];
-+      u8 buf[2 * MD5_BLOCK_SIZE];
-+};
-+
-+static void md5_init(struct crypto_tfm *tfm)
-+{
-+      struct ubicom32_md5_ctx *mctx = crypto_tfm_ctx(tfm);
-+      mctx->state[0] = 0x01234567;
-+      mctx->state[1] = 0x89abcdef;
-+      mctx->state[2] = 0xfedcba98;
-+      mctx->state[3] = 0x76543210;
-+
-+      mctx->count = 0;
-+}
-+
-+static inline void _md5_process(u32 *digest, const u8 *data)
-+{
-+      _md5_ip5k_transform((u32 *)data);
-+}
-+
-+static void md5_update(struct crypto_tfm *tfm, const u8 *data,
-+                      unsigned int len)
-+{
-+      struct ubicom32_md5_ctx *mctx = crypto_tfm_ctx(tfm);
-+      int index, clen;
-+
-+      /* how much is already in the buffer? */
-+      index = mctx->count & 0x3f;
-+
-+      mctx->count += len;
-+
-+      if (index + len < MD5_BLOCK_SIZE) {
-+              goto store_only;
-+      }
-+
-+      hw_crypto_lock();
-+      hw_crypto_check();
-+
-+      /* init digest set ctrl register too */
-+      _md5_ip5k_init_digest(mctx->state);
-+
-+      if (unlikely(index == 0 && SEC_ALIGNED(data))) {
-+fast_process:
-+              while (len >= MD5_BLOCK_SIZE) {
-+                      _md5_process(mctx->state, data);
-+                      data += MD5_BLOCK_SIZE;
-+                      len -= MD5_BLOCK_SIZE;
-+              }
-+              goto store;
-+      }
-+
-+      /* process one stored block */
-+      if (index) {
-+              clen = MD5_BLOCK_SIZE - index;
-+              memcpy(mctx->buf + index, data, clen);
-+              _md5_process(mctx->state, mctx->buf);
-+              data += clen;
-+              len -= clen;
-+              index = 0;
-+      }
-+
-+      if (likely(SEC_ALIGNED(data))) {
-+              goto fast_process;
-+      }
-+
-+      /* process as many blocks as possible */
-+      while (len >= MD5_BLOCK_SIZE) {
-+              memcpy(mctx->buf, data, MD5_BLOCK_SIZE);
-+              _md5_process(mctx->state, mctx->buf);
-+              data += MD5_BLOCK_SIZE;
-+              len -= MD5_BLOCK_SIZE;
-+      }
-+
-+store:
-+      _md5_ip5k_get_digest(mctx->state);
-+      hw_crypto_unlock();
-+
-+store_only:
-+      /* anything left? */
-+      if (len)
-+              memcpy(mctx->buf + index , data, len);
-+}
-+
-+/* Add padding and return the message digest. */
-+static void md5_final(struct crypto_tfm *tfm, u8 *out)
-+{
-+      struct ubicom32_md5_ctx *mctx = crypto_tfm_ctx(tfm);
-+      u32 bits[2];
-+      unsigned int index, end;
-+
-+      /* must perform manual padding */
-+      index = mctx->count & 0x3f;
-+      end =  (index < 56) ? MD5_BLOCK_SIZE : (2 * MD5_BLOCK_SIZE);
-+
-+      /* start pad with 1 */
-+      mctx->buf[index] = 0x80;
-+
-+      /* pad with zeros */
-+      index++;
-+      memset(mctx->buf + index, 0x00, end - index - 8);
-+
-+      /* append message length */
-+      bits[0] = mctx->count << 3;
-+      bits[1] = mctx->count >> 29;
-+      __cpu_to_le32s(bits);
-+      __cpu_to_le32s(bits + 1);
-+
-+      memcpy(mctx->buf + end - 8, &bits, sizeof(bits));
-+
-+      /* force to use the mctx->buf and ignore the partial buf */
-+      mctx->count = mctx->count & ~0x3f;
-+      md5_update(tfm, mctx->buf, end);
-+
-+      /* copy digest to out */
-+      memcpy(out, mctx->state, MD5_DIGEST_SIZE);
-+
-+      /* wipe context */
-+      memset(mctx, 0, sizeof *mctx);
-+}
-+
-+static struct crypto_alg alg = {
-+      .cra_name       =       "md5",
-+      .cra_driver_name=       "md5-ubicom32",
-+      .cra_priority   =       CRYPTO_UBICOM32_PRIORITY,
-+      .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
-+      .cra_blocksize  =       MD5_BLOCK_SIZE,
-+      .cra_ctxsize    =       sizeof(struct ubicom32_md5_ctx),
-+      .cra_module     =       THIS_MODULE,
-+      .cra_list       =       LIST_HEAD_INIT(alg.cra_list),
-+      .cra_u = {
-+              .digest = {
-+                      .dia_digestsize =       MD5_DIGEST_SIZE,
-+                      .dia_init       =       md5_init,
-+                      .dia_update     =       md5_update,
-+                      .dia_final      =       md5_final,
-+              }
-+      }
-+};
-+
-+static int __init init(void)
-+{
-+      hw_crypto_init();
-+      return crypto_register_alg(&alg);
-+}
-+
-+static void __exit fini(void)
-+{
-+      crypto_unregister_alg(&alg);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+
-+MODULE_ALIAS("md5");
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("MD5 Secure Hash Algorithm");
---- /dev/null
-+++ b/arch/ubicom32/crypto/sha1_ubicom32_asm.S
-@@ -0,0 +1,244 @@
-+/*
-+ * arch/ubicom32/crypto/sha1_ubicom32_asm.S
-+ *    SHA1 hash support for Ubicom32 architecture V3.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#define __ASM__
-+#include <asm/ip5000.h>
-+
-+#ifndef RP
-+#define RP A5
+       return retval;
+ }
+ EXPORT_SYMBOL(usb_gadget_register_driver);
+--- a/drivers/usb/musb/musb_gadget_ep0.c
++++ b/drivers/usb/musb/musb_gadget_ep0.c
+@@ -240,14 +240,14 @@ __acquires(musb->lock)
+               case USB_REQ_SET_ADDRESS:
+                       /* change it after the status stage */
+                       musb->set_address = true;
+-                      musb->address = (u8) (ctrlrequest->wValue & 0x7f);
++                      musb->address = (u8) (le16_to_cpu(ctrlrequest->wValue) & 0x7f);
+                       handled = 1;
+                       break;
+               case USB_REQ_CLEAR_FEATURE:
+                       switch (recip) {
+                       case USB_RECIP_DEVICE:
+-                              if (ctrlrequest->wValue
++                              if (le16_to_cpu(ctrlrequest->wValue)
+                                               != USB_DEVICE_REMOTE_WAKEUP)
+                                       break;
+                               musb->may_wakeup = 0;
+@@ -261,8 +261,8 @@ __acquires(musb->lock)
+                               if (num == 0
+                                               || num >= MUSB_C_NUM_EPS
+-                                              || ctrlrequest->wValue
+-                                                      != USB_ENDPOINT_HALT)
++                                              || le16_to_cpu(ctrlrequest->wValue
++                                                      != USB_ENDPOINT_HALT))
+                                       break;
+                               if (ctrlrequest->wIndex & USB_DIR_IN)
+@@ -292,7 +292,7 @@ __acquires(musb->lock)
+                       switch (recip) {
+                       case USB_RECIP_DEVICE:
+                               handled = 1;
+-                              switch (ctrlrequest->wValue) {
++                              switch (le16_to_cpu(ctrlrequest->wValue)) {
+                               case USB_DEVICE_REMOTE_WAKEUP:
+                                       musb->may_wakeup = 1;
+                                       break;
+@@ -374,8 +374,8 @@ stall:
+                               if (epnum == 0
+                                               || epnum >= MUSB_C_NUM_EPS
+-                                              || ctrlrequest->wValue
+-                                                      != USB_ENDPOINT_HALT)
++                                              || le16_to_cpu(ctrlrequest->wValue
++                                                      != USB_ENDPOINT_HALT))
+                                       break;
+                               ep = musb->endpoints + epnum;
+--- a/drivers/usb/musb/musb_host.c
++++ b/drivers/usb/musb/musb_host.c
+@@ -160,7 +160,11 @@ static inline void musb_h_tx_start(struc
+       /* NOTE: no locks here; caller should lock and select EP */
+       if (ep->epnum) {
+               txcsr = musb_readw(ep->regs, MUSB_TXCSR);
++#ifndef CONFIG_UBICOM32
+               txcsr |= MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_H_WZC_BITS;
++#else
++              txcsr |= (MUSB_TXCSR_TXPKTRDY & (~MUSB_TXCSR_H_WZC_BITS));
 +#endif
-+
-+;*****************************************************************************************
-+; The function prototype
-+;*****************************************************************************************
-+; void sha1_ip5k_init(void)
-+; void sha1_ip5k_transform(u32_t *data_input)
-+; void sha1_ip5k_output(u32_t *digest)
-+
-+;*****************************************************************************************
-+; Inputs
-+;*****************************************************************************************
-+; data_input is the pointer to the block of data over which the digest will be calculated.
-+;     It should be word aligned.
-+;
-+; digest is the pointer to the block of data into which the digest (the output) will be written.
-+;     It should be word aligned.
-+;
-+
-+;*****************************************************************************************
-+; Outputs
-+;*****************************************************************************************
-+; None
-+
-+;*****************************************************************************************
-+; Hash Constants
-+;*****************************************************************************************
-+#define HASH_SHA1_IN0 0x67452301
-+#define HASH_SHA1_IN1 0xefcdab89
-+#define HASH_SHA1_IN2 0x98badcfe
-+#define HASH_SHA1_IN3 0x10325476
-+#define HASH_SHA1_IN4 0xc3d2e1f0
-+
-+#define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2
-+#define HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1 ((1 << 5) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION)
-+
-+;*****************************************************************************************
-+; An: Address Registers
-+;*****************************************************************************************
-+#define an_digest a4
-+#define an_data_input a4
-+#define an_security_block a3
-+
-+;*****************************************************************************************
-+; Hash related defines
-+;*****************************************************************************************
-+#define hash_control 0x00(an_security_block)
-+#define hash_control_low 0x02(an_security_block)
-+#define hash_status 0x04(an_security_block)
-+
-+#define hash_input_0 0x30(an_security_block)
-+#define hash_input_1 0x34(an_security_block)
-+#define hash_input_2 0x38(an_security_block)
-+#define hash_input_3 0x3c(an_security_block)
-+#define hash_input_4 0x40(an_security_block)
-+
-+#define hash_output_0 0x70(an_security_block)
-+#define hash_output_0_low 0x72(an_security_block)
-+#define hash_output_1 0x74(an_security_block)
-+#define hash_output_1_low 0x76(an_security_block)
-+#define hash_output_2 0x78(an_security_block)
-+#define hash_output_2_low 0x7a(an_security_block)
-+#define hash_output_3 0x7c(an_security_block)
-+#define hash_output_3_low 0x7e(an_security_block)
-+#define hash_output_4 0x80(an_security_block)
-+#define hash_output_4_low 0x82(an_security_block)
-+
-+;*****************************************************************************************
-+; Assembly macros
-+;*****************************************************************************************
-+      ; C compiler reserves RP (A5) for return address during subroutine call.
-+      ; Use RP to return to caller
-+.macro        call_return_macro
-+      calli   RP, 0(RP)
-+.endm
-+
-+;*****************************************************************************************
-+;     void sha1_ip5k_init(void)
-+;             initialize the output registers of the hash module
-+
-+      ;.section .text.sha1_ip5k_init,"ax",@progbits
-+      .section .ocm_text,"ax",@progbits
-+      .global _sha1_ip5k_init
-+      .func sha1_ip5k_init, _sha1_ip5k_init
-+
-+_sha1_ip5k_init:
-+      moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
-+
-+      movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1)
-+      movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1)
-+
-+      movei hash_output_0, #%hi(HASH_SHA1_IN0)
-+      movei hash_output_0_low, #%lo(HASH_SHA1_IN0)
-+
-+      movei hash_output_1, #%hi(HASH_SHA1_IN1)
-+      movei hash_output_1_low, #%lo(HASH_SHA1_IN1)
-+
-+      movei hash_output_2, #%hi(HASH_SHA1_IN2)
-+      movei hash_output_2_low, #%lo(HASH_SHA1_IN2)
-+
-+      movei hash_output_3, #%hi(HASH_SHA1_IN3)
-+      movei hash_output_3_low, #%lo(HASH_SHA1_IN3)
-+
-+      movei hash_output_4, #%hi(HASH_SHA1_IN4)
-+      movei hash_output_4_low, #%lo(HASH_SHA1_IN4)
-+
-+      call_return_macro
-+      .endfunc
-+
-+;*****************************************************************************************
-+;     void sha1_ip5k_init_digest(u32_t *hash_input)
-+;             initialize the output registers of the hash module
-+
-+      ;.section .text.sha1_ip5k_init_digest,"ax",@progbits
-+      .section .ocm_text,"ax",@progbits
-+      .global _sha1_ip5k_init_digest
-+      .func sha1_ip5k_init_digest, _sha1_ip5k_init_digest
-+
-+_sha1_ip5k_init_digest:
-+      movea an_data_input, D0
-+
-+      moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
-+
-+      movei hash_control, #%hi(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1)
-+      movei hash_control_low, #%lo(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1)
-+
-+      move.4 hash_output_0, (an_data_input)4++
-+      move.4 hash_output_1, (an_data_input)4++
-+      move.4 hash_output_2, (an_data_input)4++
-+      move.4 hash_output_3, (an_data_input)4++
-+      move.4 hash_output_4, (an_data_input)4++
-+
-+      call_return_macro
-+      .endfunc
-+
-+;*****************************************************************************************
-+;     void sha1_ip5k_transform(u32_t *data_input)
-+;             performs intermediate transformation step for the hash calculation
-+
-+      ;.section .text.sha1_ip5k_transform,"ax",@progbits
-+      .section .ocm_text,"ax",@progbits
-+      .global _sha1_ip5k_transform
-+      .func sha1_ip5k_transform, _sha1_ip5k_transform
-+
-+_sha1_ip5k_transform:
-+      movea an_data_input, D0
-+
-+      moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
-+
-+      ; Write the first 128bits (16 bytes)
-+      move.4 hash_input_0, (an_data_input)4++
-+      move.4 hash_input_1, (an_data_input)4++
-+      move.4 hash_input_2, (an_data_input)4++
-+      move.4 hash_input_3, (an_data_input)4++
-+      move.4 hash_input_4, D0
-+
-+      move.4 hash_input_0, (an_data_input)4++
-+      move.4 hash_input_1, (an_data_input)4++
-+      move.4 hash_input_2, (an_data_input)4++
-+      move.4 hash_input_3, (an_data_input)4++
-+      move.4 hash_input_4, D0
-+
-+      move.4 hash_input_0, (an_data_input)4++
-+      move.4 hash_input_1, (an_data_input)4++
-+      move.4 hash_input_2, (an_data_input)4++
-+      move.4 hash_input_3, (an_data_input)4++
-+      move.4 hash_input_4, D0
-+
-+      move.4 hash_input_0, (an_data_input)4++
-+      move.4 hash_input_1, (an_data_input)4++
-+      move.4 hash_input_2, (an_data_input)4++
-+      move.4 hash_input_3, (an_data_input)4++
-+      move.4 hash_input_4, D0
-+
-+      pipe_flush 0
-+
-+sha1_ip5k_transform_wait:
-+      ; wait for the module to calculate the output hash
-+      btst hash_status, #0
-+      jmpne.f sha1_ip5k_transform_wait
-+
-+      call_return_macro
-+      .endfunc
-+
-+;*****************************************************************************************
-+;     void sha1_ip5k_output(u32_t *digest)
-+;             Return the hash of the input data
-+
-+      ;.section .text.sha1_ip5k_output,"ax",@progbits
-+      .section .ocm_text,"ax",@progbits
-+      .global _sha1_ip5k_output
-+      .func sha1_ip5k_output, _sha1_ip5k_output
-+
-+_sha1_ip5k_output:
-+      movea an_digest, D0
-+
-+      moveai an_security_block, #SECURITY_BASE_EFFECTIVE_ADDRESS
-+
-+      ; we have finished
-+      move.4 0(an_digest), hash_output_0
-+      move.4 4(an_digest), hash_output_1
-+      move.4 8(an_digest), hash_output_2
-+      move.4 12(an_digest), hash_output_3
-+      move.4 16(an_digest), hash_output_4
-+
-+      call_return_macro
-+      .endfunc
-+
-+;*****************************************************************************************
-+;END                  ;End of program code
-+;*****************************************************************************************
---- /dev/null
-+++ b/arch/ubicom32/crypto/sha1_ubicom32.c
-@@ -0,0 +1,354 @@
-+/*
-+ * arch/ubicom32/crypto/sha1_ubicom32.c
-+ *   Ubicom32 implementation of the SHA1 Secure Hash Algorithm.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/crypto.h>
-+#include <crypto/sha.h>
-+#include <asm/linkage.h>
-+
-+#include "crypto_ubicom32.h"
-+#define HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION 2
-+#define HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1 ((1 << 5) | HASH_SECURITY_BLOCK_CONTROL_INIT_NO_ENCYPTION)
-+
-+struct ubicom32_sha1_ctx {
-+      u64 count;              /* message length */
-+      u32 state[5];
-+      u8 buf[2 * SHA1_BLOCK_SIZE];
-+};
-+
-+static inline void sha1_clear_2ws(u8 *buf, int wc)
-+{
-+      asm volatile (
-+      "1:     move.4  (%0)4++, #0             \n\t"
-+      "       move.4  (%0)4++, #0             \n\t"
-+      "       sub.4   %1, #2, %1              \n\t"
-+      "       jmple.f 1b                      \n\t"
-+              :
-+              : "a" (buf), "d" (wc)
-+              : "cc"
-+      );
-+}
-+
-+/* only wipe out count, state, and 1st half of buf - 9 bytes at most */
-+#define sha1_wipe_out(sctx) sha1_clear_2ws((u8 *)sctx, 2 + 5 + 16 - 2)
-+
-+static inline void sha1_init_digest(u32 *digest)
-+{
-+      hw_crypto_set_ctrl(HASH_SECURITY_BLOCK_CONTROL_INIT_SHA1);
-+      asm volatile (
-+      "       ; move digests to hash_output regs      \n\t"
-+      "       move.4  0x70(%0), 0x0(%1)               \n\t"
-+      "       move.4  0x74(%0), 0x4(%1)               \n\t"
-+      "       move.4  0x78(%0), 0x8(%1)               \n\t"
-+      "       move.4  0x7c(%0), 0xc(%1)               \n\t"
-+      "       move.4  0x80(%0), 0x10(%1)              \n\t"
-+              :
-+              : "a" (SEC_BASE), "a" (digest)
-+      );
-+}
-+
-+static inline void sha1_transform_feed(const u8 *in)
-+{
-+      asm volatile (
-+      "       ; write the 1st 16 bytes        \n\t"
-+      "       move.4  0x30(%0), 0x0(%1)       \n\t"
-+      "       move.4  0x34(%0), 0x4(%1)       \n\t"
-+      "       move.4  0x38(%0), 0x8(%1)       \n\t"
-+      "       move.4  0x3c(%0), 0xc(%1)       \n\t"
-+      "       move.4  0x40(%0), %1            \n\t"
-+      "       ; write the 2nd 16 bytes        \n\t"
-+      "       move.4  0x30(%0), 0x10(%1)      \n\t"
-+      "       move.4  0x34(%0), 0x14(%1)      \n\t"
-+      "       move.4  0x38(%0), 0x18(%1)      \n\t"
-+      "       move.4  0x3c(%0), 0x1c(%1)      \n\t"
-+      "       move.4  0x40(%0), %1            \n\t"
-+      "       ; write the 3rd 16 bytes        \n\t"
-+      "       move.4  0x30(%0), 0x20(%1)      \n\t"
-+      "       move.4  0x34(%0), 0x24(%1)      \n\t"
-+      "       move.4  0x38(%0), 0x28(%1)      \n\t"
-+      "       move.4  0x3c(%0), 0x2c(%1)      \n\t"
-+      "       move.4  0x40(%0), %1            \n\t"
-+      "       ; write the 4th 16 bytes        \n\t"
-+      "       move.4  0x30(%0), 0x30(%1)      \n\t"
-+      "       move.4  0x34(%0), 0x34(%1)      \n\t"
-+      "       move.4  0x38(%0), 0x38(%1)      \n\t"
-+      "       move.4  0x3c(%0), 0x3c(%1)      \n\t"
-+      "       move.4  0x40(%0), %1            \n\t"
-+      "       pipe_flush 0                    \n\t"
-+              :
-+              : "a"(SEC_BASE), "a"(in)
-+      );
-+}
-+
-+static inline void sha1_transform_wait(void)
-+{
-+      asm volatile (
-+      "       btst    0x04(%0), #0            \n\t"
-+      "       jmpne.f -4                      \n\t"
-+              :
-+              : "a"(SEC_BASE)
-+              : "cc"
-+      );
-+}
-+
-+static inline void sha1_output_digest(u32 *digest)
-+{
-+      asm volatile (
-+      "       move.4  0x0(%1), 0x70(%0)               \n\t"
-+      "       move.4  0x4(%1), 0x74(%0)               \n\t"
-+      "       move.4  0x8(%1), 0x78(%0)               \n\t"
-+      "       move.4  0xc(%1), 0x7c(%0)               \n\t"
-+      "       move.4  0x10(%1), 0x80(%0)              \n\t"
-+              :
-+              : "a" (SEC_BASE), "a" (digest)
-+      );
-+}
-+
-+static __ocm_text void sha1_init(struct crypto_tfm *tfm)
-+{
-+      struct ubicom32_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
-+
-+      sctx->state[0] = SHA1_H0;
-+      sctx->state[1] = SHA1_H1;
-+      sctx->state[2] = SHA1_H2;
-+      sctx->state[3] = SHA1_H3;
-+      sctx->state[4] = SHA1_H4;
-+      sctx->count = 0;
-+}
-+
-+static void __ocm_text sha1_update(struct crypto_tfm *tfm, const u8 *data,
-+                      unsigned int len)
-+{
-+      struct ubicom32_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
-+      int index, clen;
-+
-+      /* how much is already in the buffer? */
-+      index = sctx->count & 0x3f;
-+
-+      sctx->count += len;
-+
-+      if (index + len < SHA1_BLOCK_SIZE) {
-+              goto store_only;
-+      }
-+
-+      hw_crypto_lock();
-+      hw_crypto_check();
-+
-+      /* init digest set ctrl register too */
-+      sha1_init_digest(sctx->state);
-+
-+      if (unlikely(index == 0 && SEC_ALIGNED(data))) {
-+fast_process:
-+#if CRYPTO_UBICOM32_LOOP_ASM
-+              if (likely(len >= SHA1_BLOCK_SIZE)) {
-+                      register unsigned int cnt = len >> 6;   // loop = len / 64;
-+                      sha1_transform_feed(data);
-+                      data += SHA1_BLOCK_SIZE;
-+
-+                      /* cnt is pre-decremented in the loop */
-+                      asm volatile (
-+                      "; while (--loop):  work on 2nd block   \n\t"
-+                      "1:     add.4   %2, #-1, %2             \n\t"
-+                      "       jmpeq.f 5f                      \n\t"
-+                      "                                       \n\t"
-+                      "       ; write the 1st 16 bytes        \n\t"
-+                      "       move.4  0x30(%1), (%0)4++       \n\t"
-+                      "       move.4  0x34(%1), (%0)4++       \n\t"
-+                      "       move.4  0x38(%1), (%0)4++       \n\t"
-+                      "       move.4  0x3c(%1), (%0)4++       \n\t"
-+                      "       ; can not kick off hw before it \n\t"
-+                      "       ; is done with the prev block   \n\t"
-+                      "                                       \n\t"
-+                      "       btst    0x04(%1), #0            \n\t"
-+                      "       jmpne.f -4                      \n\t"
-+                      "                                       \n\t"
-+                      "       ; tell hw to load 1st 16 bytes  \n\t"
-+                      "       move.4  0x40(%1), %2            \n\t"
-+                      "                                       \n\t"
-+                      "       ; write the 2nd 16 bytes        \n\t"
-+                      "       move.4  0x30(%1), (%0)4++       \n\t"
-+                      "       move.4  0x34(%1), (%0)4++       \n\t"
-+                      "       move.4  0x38(%1), (%0)4++       \n\t"
-+                      "       move.4  0x3c(%1), (%0)4++       \n\t"
-+                      "       move.4  0x40(%1), %2            \n\t"
-+                      "                                       \n\t"
-+                      "       ; write the 3rd 16 bytes        \n\t"
-+                      "       move.4  0x30(%1), (%0)4++       \n\t"
-+                      "       move.4  0x34(%1), (%0)4++       \n\t"
-+                      "       move.4  0x38(%1), (%0)4++       \n\t"
-+                      "       move.4  0x3c(%1), (%0)4++       \n\t"
-+                      "       move.4  0x40(%1), %2            \n\t"
-+                      "                                       \n\t"
-+                      "       ; write the 4th 16 bytes        \n\t"
-+                      "       move.4  0x30(%1), (%0)4++       \n\t"
-+                      "       move.4  0x34(%1), (%0)4++       \n\t"
-+                      "       move.4  0x38(%1), (%0)4++       \n\t"
-+                      "       move.4  0x3c(%1), (%0)4++       \n\t"
-+                      "       move.4  0x40(%1), %2            \n\t"
-+                      "                                       \n\t"
-+                      "; no need flush, enough insts          \n\t"
-+                      "; before next hw wait                  \n\t"
-+                      "                                       \n\t"
-+                      "; go back to loop                      \n\t"
-+                      "       jmpt 1b                         \n\t"
-+                      "                                       \n\t"
-+                      "; wait hw for last block               \n\t"
-+                      "5:     btst 0x04(%1), #0               \n\t"
-+                      "       jmpne.f -4                      \n\t"
-+                      "                                       \n\t"
-+                              : "+a" (data)
-+                              : "a"( SEC_BASE), "d" (cnt)
-+                              : "cc"
-+                      );
-+
-+                      len = len & (64 - 1);
-+              }
-+#else
-+              while (likely(len >= SHA1_BLOCK_SIZE)) {
-+                      sha1_transform_feed(data);
-+                      data += SHA1_BLOCK_SIZE;
-+                      len -= SHA1_BLOCK_SIZE;
-+                      sha1_transform_wait();
-+              }
-+#endif
-+              goto store;
-+      }
-+
-+      /* process one stored block */
-+      if (index) {
-+              clen = SHA1_BLOCK_SIZE - index;
-+              memcpy(sctx->buf + index, data, clen);
-+              sha1_transform_feed(sctx->buf);
-+              data += clen;
-+              len -= clen;
-+              index = 0;
-+              sha1_transform_wait();
-+      }
-+
-+      if (likely(SEC_ALIGNED(data))) {
-+              goto fast_process;
-+      }
-+
-+      /* process as many blocks as possible */
-+      if (likely(len >= SHA1_BLOCK_SIZE)) {
-+              memcpy(sctx->buf, data, SHA1_BLOCK_SIZE);
-+              do {
-+                      sha1_transform_feed(sctx->buf);
-+                      data += SHA1_BLOCK_SIZE;
-+                      len -= SHA1_BLOCK_SIZE;
-+                      if (likely(len >= SHA1_BLOCK_SIZE)) {
-+                              memcpy(sctx->buf, data, SHA1_BLOCK_SIZE);
-+                              sha1_transform_wait();
-+                              continue;
-+                      }
-+                      /* it is the last block */
-+                      sha1_transform_wait();
-+                      break;
-+              } while (1);
-+      }
-+
-+store:
-+      sha1_output_digest(sctx->state);
-+      hw_crypto_unlock();
-+
-+store_only:
-+      /* anything left? */
-+      if (len)
-+              memcpy(sctx->buf + index , data, len);
-+}
-+
-+/* Add padding and return the message digest. */
-+static void __ocm_text sha1_final(struct crypto_tfm *tfm, u8 *out)
-+{
-+      struct ubicom32_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
-+      u64 bits;
-+      unsigned int index, end;
-+
-+      /* must perform manual padding */
-+      index = sctx->count & 0x3f;
-+      end =  (index < 56) ? SHA1_BLOCK_SIZE : (2 * SHA1_BLOCK_SIZE);
-+
-+      /* start pad with 1 */
-+      sctx->buf[index] = 0x80;
-+
-+      /* pad with zeros */
-+      index++;
-+      memset(sctx->buf + index, 0x00, end - index - 8);
-+
-+      /* append message length */
-+      bits = sctx->count << 3 ;
-+      SEC_COPY_2W(sctx->buf + end - 8, &bits);
-+
-+      /* force to use the sctx->buf and ignore the partial buf */
-+      sctx->count = sctx->count & ~0x3f;
-+      sha1_update(tfm, sctx->buf, end);
-+
-+      /* copy digest to out */
-+      SEC_COPY_5W(out, sctx->state);
-+
-+      /* wipe context */
-+      sha1_wipe_out(sctx);
-+}
-+
-+static struct crypto_alg alg = {
-+      .cra_name       =       "sha1",
-+      .cra_driver_name=       "sha1-ubicom32",
-+      .cra_priority   =       CRYPTO_UBICOM32_PRIORITY,
-+      .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
-+      .cra_blocksize  =       SHA1_BLOCK_SIZE,
-+      .cra_ctxsize    =       sizeof(struct ubicom32_sha1_ctx),
-+      .cra_module     =       THIS_MODULE,
-+      .cra_list       =       LIST_HEAD_INIT(alg.cra_list),
-+      .cra_u    = {
-+              .digest = {
-+                      .dia_digestsize =       SHA1_DIGEST_SIZE,
-+                      .dia_init       =       sha1_init,
-+                      .dia_update     =       sha1_update,
-+                      .dia_final      =       sha1_final,
-+              }
-+      }
-+};
-+
-+static int __init init(void)
-+{
-+      hw_crypto_init();
-+      return crypto_register_alg(&alg);
-+}
-+
-+static void __exit fini(void)
-+{
-+      crypto_unregister_alg(&alg);
-+}
-+
-+module_init(init);
-+module_exit(fini);
-+
-+MODULE_ALIAS("sha1");
-+
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm");
---- /dev/null
-+++ b/arch/ubicom32/include/asm/a.out.h
-@@ -0,0 +1,47 @@
-+/*
-+ * arch/ubicom32/include/asm/a.out.h
-+ *   Definitions for Ubicom32 a.out executable format.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_A_OUT_H
-+#define _ASM_UBICOM32_A_OUT_H
-+
-+struct exec
-+{
-+  unsigned long a_info;               /* Use macros N_MAGIC, etc for access */
-+  unsigned a_text;            /* length of text, in bytes */
-+  unsigned a_data;            /* length of data, in bytes */
-+  unsigned a_bss;             /* length of uninitialized data area for file, in bytes */
-+  unsigned a_syms;            /* length of symbol table data in file, in bytes */
-+  unsigned a_entry;           /* start address */
-+  unsigned a_trsize;          /* length of relocation info for text, in bytes */
-+  unsigned a_drsize;          /* length of relocation info for data, in bytes */
-+};
-+
-+#define N_TRSIZE(a)   ((a).a_trsize)
-+#define N_DRSIZE(a)   ((a).a_drsize)
-+#define N_SYMSIZE(a)  ((a).a_syms)
-+
-+#endif /* _ASM_UBICOM32_A_OUT_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/atomic.h
-@@ -0,0 +1,348 @@
-+/*
-+ * arch/ubicom32/include/asm/atomic.h
-+ *   Atomic operations definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_ATOMIC_H
-+#define _ASM_UBICOM32_ATOMIC_H
-+
-+#include <asm/system.h>
-+#include <asm/ubicom32-common.h>
-+#include <asm/types.h>
-+
-+/*
-+ * Most instructions on the Ubicom32 processor are atomic in that they
-+ * execute in one clock cycle.  However, Linux has several operations
-+ * (e.g. compare and swap) which will require more than a single instruction
-+ * to perform.   To achieve this, the Ubicom32 processor uses a single
-+ * global bit in a scratchpad register as a critical section lock. All
-+ * atomic operations acquire this lock.
-+ *
-+ * NOTE: To AVOID DEADLOCK(s), the atomic lock must only be used for atomic
-+ * operations or by the ldsr to avoid disabling a thread performing an atomic
-+ * operation.
-+ *
-+ * Do not attempt to disable interrupts while holding the atomic operations
-+ * lock or you will DEADLOCK the system.
-+ */
-+
-+#define ATOMIC_INIT(i)        { (i) }
-+
-+/*
-+ * __atomic_add()
-+ *    Add i to v and return the result.
-+ */
-+static inline void __atomic_add(int i, atomic_t *v)
-+{
-+      atomic_t *vt = v;
-+
-+      __atomic_lock_acquire();
-+      vt->counter += i;
-+      __atomic_lock_release();
-+}
-+
-+/*
-+ * __atomic_sub()
-+ *    Subtract i from v and return the result.
-+ */
-+static inline void __atomic_sub(int i, atomic_t *v)
-+{
-+      atomic_t *vt = v;
-+
-+      __atomic_lock_acquire();
-+      vt->counter -= i;
-+      __atomic_lock_release();
-+}
-+
-+/*
-+ * __atomic_add_return()
-+ *    Add i to v and return the result.
-+ *
-+ * The implementation here looks rather odd because we appear to be doing
-+ * the addition twice.  In fact that's exactly what we're doing but with
-+ * the ubicom32 instruction set we can do the inner load and add with two
-+ * instructions whereas generating both the atomic result and the "ret"
-+ * result requires three instructions.  The second add is generally only as
-+ * costly as a move instruction and in cases where we compare the result
-+ * with a constant the compiler can fold two constant values and do a
-+ * single instruction, thus saving an instruction overall!
-+ *
-+ * At the worst we save one instruction inside the atomic lock.
-+ */
-+static inline int __atomic_add_return(int i, atomic_t *v)
-+{
-+      int ret;
-+      atomic_t *vt = v;
-+
-+      __atomic_lock_acquire();
-+      ret = vt->counter;
-+      vt->counter = ret + i;
-+      __atomic_lock_release();
-+
-+      return ret + i;
-+}
-+
-+/*
-+ * __atomic_sub_return()
-+ *    Subtract i from v and return the result.
-+ *
-+ * The implementation here looks rather odd because we appear to be doing
-+ * the subtraction twice.  In fact that's exactly what we're doing but with
-+ * the ubicom32 instruction set we can do the inner load and sub with two
-+ * instructions whereas generating both the atomic result and the "ret"
-+ * result requires three instructions.  The second sub is generally only as
-+ * costly as a move instruction and in cases where we compare the result
-+ * with a constant the compiler can fold two constant values and do a
-+ * single instruction, thus saving an instruction overall!
-+ *
-+ * At the worst we save one instruction inside the atomic lock.
-+ */
-+static inline int __atomic_sub_return(int i, atomic_t *v)
-+{
-+      int ret;
-+      atomic_t *vt = v;
-+
-+      __atomic_lock_acquire();
-+      ret = vt->counter;
-+      vt->counter = ret - i;
-+      __atomic_lock_release();
-+
-+      return ret - i;
-+}
-+
-+/*
-+ * PUBLIC API FOR ATOMIC!
-+ */
-+#define atomic_add(i,v)       (__atomic_add( ((int)i),(v)))
-+#define atomic_sub(i,v)       (__atomic_sub( ((int)i),(v)))
-+#define atomic_inc(v) (__atomic_add(   1,(v)))
-+#define atomic_dec(v) (__atomic_sub(   1,(v)))
-+#define atomic_add_return(i,v)        (__atomic_add_return( ((int)i),(v)))
-+#define atomic_sub_return(i,v)        (__atomic_sub_return( ((int)i),(v)))
-+#define atomic_inc_return(v)  (__atomic_add_return(   1,(v)))
-+#define atomic_dec_return(v)  (__atomic_sub_return(   1,(v)))
-+#define atomic_inc_and_test(v)        (atomic_inc_return(v) == 0)
-+#define atomic_dec_and_test(v)        (atomic_dec_return(v) == 0)
-+#define atomic_add_negative(a, v)     (atomic_add_return((a), (v)) < 0)
-+#define atomic_sub_and_test(i,v)      (atomic_sub_return((i),(v)) == 0)
-+
-+/*
-+ * atomic_read()
-+ *    Acquire the atomic lock and read the variable.
-+ */
-+static inline int atomic_read(const atomic_t *v)
-+{
-+      int ret;
-+      const atomic_t *vt = v;
-+
-+      __atomic_lock_acquire();
-+      ret = vt->counter;
-+      __atomic_lock_release();
-+
-+      return ret;
-+}
-+
-+/*
-+ * atomic_set()
-+ *    Acquire the atomic lock and set the variable.
-+ */
-+static inline void atomic_set(atomic_t *v, int i)
-+{
-+      atomic_t *vt = v;
-+
-+      __atomic_lock_acquire();
-+      vt->counter = i;
-+      __atomic_lock_release();
-+}
-+
-+/*
-+ * atomic_cmpxchg
-+ *    Acquire the atomic lock and exchange if current == old.
-+ */
-+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
-+{
-+      int prev;
-+      atomic_t *vt = v;
-+
-+      __atomic_lock_acquire();
-+      prev = vt->counter;
-+      if (prev == old) {
-+              vt->counter = new;
-+      }
-+      __atomic_lock_release();
-+
-+      return prev;
-+}
-+
-+/*
-+ * atomic_xchg()
-+ *    Acquire the atomic lock and exchange values.
-+ */
-+static inline int atomic_xchg(atomic_t *v, int new)
-+{
-+      int prev;
-+      atomic_t *vt = v;
-+
-+      __atomic_lock_acquire();
-+      prev = vt->counter;
-+      vt->counter = new;
-+      __atomic_lock_release();
-+
-+      return prev;
-+}
-+
-+/*
-+ * atomic_add_unless()
-+ *    Acquire the atomic lock and add a unless the value is u.
-+ */
-+static inline int atomic_add_unless(atomic_t *v, int a, int u)
-+{
-+      int prev;
-+      atomic_t *vt = v;
-+
-+      __atomic_lock_acquire();
-+      prev = vt->counter;
-+      if (prev != u) {
-+              vt->counter += a;
-+              __atomic_lock_release();
-+              return 1;
-+      }
-+
-+      __atomic_lock_release();
-+      return 0;
-+}
-+
-+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
-+
-+#include <asm-generic/atomic.h>
-+
-+/*
-+ * The following is not a real function.  The compiler should remove the function
-+ * call as long as the user does not pass in a size that __xchg and __cmpxchg
-+ * are not prepared for.  If the user does pass in an unknown size, the user
-+ * will get a link time error.
-+ *
-+ * The no return is to prevent a compiler error that can occur when dealing with
-+ * uninitialized variables. Given that the function doesn't exist there is no
-+ * net effect (and if it did it would not return).
-+ */
-+extern void __xchg_called_with_bad_pointer(void) __attribute__((noreturn));
-+
-+/*
-+ * __xchg()
-+ *    Xchange *ptr for x atomically.
-+ *
-+ * Must be both locally atomic and atomic on SMP. Ubicom32 does not have an
-+ * atomic exchange instruction so we use the global atomic_lock.
-+ */
-+static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
-+{
-+      unsigned long ret;
-+
-+      __atomic_lock_acquire();
-+
-+      switch (size) {
-+      case 1:
-+              ret = *(volatile unsigned char *)ptr;
-+              *(volatile unsigned char *)ptr = x;
-+              break;
-+
-+      case 2:
-+              ret = *(volatile unsigned short *)ptr;
-+              *(volatile unsigned short *)ptr = x;
-+              break;
-+
-+      case 4:
-+              ret = *(volatile unsigned int *)ptr;
-+              *(volatile unsigned int *)ptr = x;
-+              break;
-+
-+      default:
-+              __xchg_called_with_bad_pointer();
-+              break;
-+      }
-+      __atomic_lock_release();
-+      return ret;
-+}
-+
-+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-+
-+/*
-+ * __cmpxchg()
-+ *    Compare and Xchange *ptr for x atomically.
-+ *
-+ * Must be both locally atomic and atomic on SMP. Ubicom32 does not have an
-+ * atomic exchange instruction so we use the global atomic_lock.
-+ */
-+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long next, int size)
-+{
-+      unsigned long prev;
-+
-+      __atomic_lock_acquire();
-+      switch (size) {
-+      case 1:
-+              prev = *(u8 *)ptr;
-+              if (prev == old) {
-+                      *(u8 *)ptr = (u8)next;
-+              }
-+              break;
-+
-+      case 2:
-+              prev = *(u16 *)ptr;
-+              if (prev == old) {
-+                      *(u16 *)ptr = (u16)next;
-+              }
-+              break;
-+
-+      case 4:
-+              prev = *(u32 *)ptr;
-+              if (prev == old) {
-+                      *(u32 *)ptr = (u32)next;
-+              }
-+              break;
-+
-+      default:
-+              __xchg_called_with_bad_pointer();
-+              break;
-+      }
-+      __atomic_lock_release();
-+      return prev;
-+}
-+
-+/*
-+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
-+ * them available.
-+ */
-+#define cmpxchg_local(ptr, o, n) \
-+      ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), (unsigned long)(n), sizeof(*(ptr))))
-+
-+#define cmpxchg(ptr, o, n) __cmpxchg((ptr), (o), (n), sizeof(*(ptr)))
-+
-+#define smp_mb__before_atomic_inc() asm volatile ("" : : : "memory")
-+#define smp_mb__after_atomic_inc() asm volatile ("" : : : "memory")
-+#define smp_mb__before_atomic_dec() asm volatile ("" : : : "memory")
-+#define smp_mb__after_atomic_dec() asm volatile ("" : : : "memory")
-+
-+#endif /* _ASM_UBICOM32_ATOMIC_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/audio.h
-@@ -0,0 +1,40 @@
-+/*
-+ * arch/ubicom32/include/asm/audio.h
-+ *    Audio include file
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#ifndef _AUDIO_H
-+#define _AUDIO_H
-+
-+#include <asm/devtree.h>
-+#include <asm/audionode.h>
-+
-+/*
-+ * Resource indices used to access IRQs via platform_get_resource
-+ */
-+#define AUDIO_MEM_RESOURCE    0
-+#define AUDIO_TX_IRQ_RESOURCE 0
-+#define AUDIO_RX_IRQ_RESOURCE 1
-+
-+extern struct platform_device * __init audio_device_alloc(const char *driver_name, const char *node_name, const char *inst_name, int priv_size);
-+
-+#define audio_device_priv(pdev) (((struct ubi32pcm_platform_data *)(((struct platform_device *)(pdev))->dev.platform_data))->priv_data)
-+#endif
---- /dev/null
-+++ b/arch/ubicom32/include/asm/audionode.h
-@@ -0,0 +1,152 @@
-+/*
-+ * audionode.h
-+ *    audionode and DMA descriptors
-+ *
-+ * Copyright \81© 2009 Ubicom Inc. <www.ubicom.com>.  All rights reserved.
-+ *
-+ * This file contains confidential information of Ubicom, Inc. and your use of
-+ * this file is subject to the Ubicom Software License Agreement distributed with
-+ * this file. If you are uncertain whether you are an authorized user or to report
-+ * any unauthorized use, please contact Ubicom, Inc. at +1-408-789-2200.
-+ * Unauthorized reproduction or distribution of this file is subject to civil and
-+ * criminal penalties.
-+ *
-+ */
-+#ifndef _AUDIONODE_H_
-+#define _AUDIONODE_H_
-+
-+#define AUDIO_INT_FLAG_MORE_SAMPLES 0x00000001
-+#define AUDIO_INT_FLAG_COMMAND      0x00000002
-+
-+/*
-+ * Commands the Primary OS sends to the audio device
-+ */
-+enum audio_command {
-+      AUDIO_CMD_NONE,
-+      AUDIO_CMD_START,
-+      AUDIO_CMD_STOP,
-+      AUDIO_CMD_PAUSE,
-+      AUDIO_CMD_RESUME,
-+      AUDIO_CMD_MUTE,
-+      AUDIO_CMD_UNMUTE,
-+      AUDIO_CMD_SETUP,
-+      AUDIO_CMD_ENABLE,
-+      AUDIO_CMD_DISABLE,
-+};
-+
-+/*
-+ * Flag bits passed in the registers
-+ */
-+#define CMD_START_FLAG_LE             (1 << 0)        /* Use Little Endian Mode */
-+
-+/*
-+ * Status bits that audio device can set to indicate reason
-+ * for interrupting the Primary OS
-+ */
-+#define AUDIO_STATUS_PLAY_DMA0_REQUEST (1 << 0) /* Audio device needs samples in DMA0 for playback */
-+#define AUDIO_STATUS_PLAY_DMA1_REQUEST (1 << 1) /* Audio device needs samples in DMA1 for playback */
-+
-+struct audio_dma {
-+      /*
-+       * NOTE: The active flag shall only be SET by the producer and CLEARED
-+       * by the consumer, NEVER the other way around.  For playback, the
-+       * Primary OS sets this flag and ipAudio clears it.
-+       *
-+       * The producer shall not modify the ptr or ctr fields when the transfer
-+       * is marked as active, as these are used by the consumer to do the
-+       * transfer.
-+       */
-+      volatile u32_t active;          /* Nonzero if data in ptr/ctr ready to be transferred */
-+      volatile void *ptr;             /* Pointer to data to be transferred */
-+      volatile u32_t ctr;             /* Counter: number of data units to transfer */
-+};
-+
-+#define AUDIONODE_CAP_BE      (1 << 0)
-+#define AUDIONODE_CAP_LE      (1 << 1)
-+
-+#define AUDIONODE_VERSION     7
-+struct audio_node {
-+      struct devtree_node dn;
-+
-+      /*
-+       * Version of this node
-+       */
-+      u32_t                   version;
-+
-+      /*
-+       * Pointer to the registers
-+       */
-+      struct audio_regs       *regs;
-+};
-+
-+/*
-+ * [OCM] Audio registers
-+ *    Registers exposed as part of our MMIO area
-+ */
-+#define AUDIO_REGS_VERSION    7
-+struct audio_regs {
-+      /*
-+       * Version of this register set
-+       */
-+      u32_t version;
-+
-+      /*
-+       * Interrupt status
-+       */
-+      volatile u32_t int_status;
-+
-+      /*
-+       * Interrupt request
-+       */
-+      volatile u32_t int_req;
-+
-+      /*
-+       * Current IRQ being serviced
-+       */
-+      u32_t cur_irq;
-+
-+      /*
-+       * Maximum number of devices supported
-+       */
-+      u32_t max_devs;
-+
-+      /*
-+       * [DDR] Device registers for each of the devices
-+       */
-+      struct audio_dev_regs *adr;
-+};
-+
-+#define AUDIO_DEV_REGS_VERSION 2
-+struct audio_dev_regs {
-+      u32_t version;                                  /* Version of this register set */
-+
-+      u8_t name[32];                                  /* Name of this driver */
-+      u32_t caps;                                     /* Capabilities of this driver */
-+      const u32_t *sample_rates;                      /* Sample Rates supported by this driver */
-+      u32_t n_sample_rates;                           /* Number of sample rates supported by this driver */
-+      u32_t channel_mask;                             /* A bit set in a particular position means we support this channel configuration */
-+      volatile u32_t int_flags;                       /* Reason for interrupting audio device */
-+      volatile enum audio_command command;    /* Command from Primary OS */
-+      volatile u32_t flags;                           /* Flag bits for this command */
-+      volatile u32_t channels;                        /* Number of channels */
-+      volatile u32_t sample_rate;                     /* Sample rate */
-+      volatile u32_t status;                          /* Status bits sent from ipAudio to Primary OS */
-+      void *primary_os_buffer_ptr;                    /*
-+                                                       * Playback: Pointer to next sample to be removed from
-+                                                       *           Primary OS sample buffer
-+                                                       * Capture: Pointer to where next sample will be inserted
-+                                                       *          into Primary OS sample buffer
-+                                                       */
-+
-+      /*
-+       * These are the transfer requests.  They are used in alternating
-+       * order so that when ipAudio is processing one request, the
-+       * Primary OS can fill in the other one.
-+       *
-+       * NOTE: The active bit shall always be SET by the producer and
-+       * CLEARED by the consumer, NEVER the other way around.
-+       */
-+      struct audio_dma dma_xfer_requests[2];
-+};
-+
-+#endif
---- /dev/null
-+++ b/arch/ubicom32/include/asm/auxvec.h
-@@ -0,0 +1,32 @@
-+/*
-+ * arch/ubicom32/include/asm/auxvec.h
-+ *   Symbolic values for the entries in the auxiliary table
-+ *   put on the initial stack.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_AUXVEC_H
-+#define _ASM_UBICOM32_AUXVEC_H
-+
-+#endif /* _ASM_UBICOM32_AUXVEC_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/bitops.h
-@@ -0,0 +1,172 @@
-+/*
-+ * arch/ubicom32/include/asm/bitops.h
-+ *   Bit manipulation definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_BITOPS_H
-+#define _ASM_UBICOM32_BITOPS_H
-+
-+/*
-+ * Copyright 1992, Linus Torvalds.
-+ */
-+
-+#include <linux/compiler.h>
-+#include <asm/byteorder.h>    /* swab32 */
-+
-+#ifdef __KERNEL__
-+
-+#ifndef _LINUX_BITOPS_H
-+#error only <linux/bitops.h> can be included directly
-+#endif
-+
-+#include <asm-generic/bitops/ffs.h>
-+#include <asm-generic/bitops/__ffs.h>
-+
-+#include <asm-generic/bitops/sched.h>
-+#include <asm-generic/bitops/ffz.h>
-+
-+#include <asm/ubicom32-common.h>
-+
-+static inline void set_bit(int bit, volatile unsigned long *p)
-+{
-+      unsigned long mask = 1UL << (bit & 31);
-+
-+      p += bit >> 5;
-+
-+      __atomic_lock_acquire();
-+      *p |= mask;
-+      __atomic_lock_release();
-+}
-+
-+static inline void clear_bit(int bit, volatile unsigned long *p)
-+{
-+      unsigned long mask = 1UL << (bit & 31);
-+
-+      p += bit >> 5;
-+
-+      __atomic_lock_acquire();
-+      *p &= ~mask;
-+      __atomic_lock_release();
-+}
-+
-+/*
-+ * clear_bit() doesn't provide any barrier for the compiler.
-+ */
-+#define smp_mb__before_clear_bit()    barrier()
-+#define smp_mb__after_clear_bit()     barrier()
-+
-+static inline void change_bit(int bit, volatile unsigned long *p)
-+{
-+      unsigned long mask = 1UL << (bit & 31);
-+
-+      p += bit >> 5;
-+
-+      __atomic_lock_acquire();
-+      *p ^= mask;
-+      __atomic_lock_release();
-+}
-+
-+static inline int test_and_set_bit(int bit, volatile unsigned long *p)
-+{
-+      unsigned int res;
-+      unsigned long mask = 1UL << (bit & 31);
-+
-+      p += bit >> 5;
-+
-+      __atomic_lock_acquire();
-+      res = *p;
-+      *p = res | mask;
-+      __atomic_lock_release();
-+
-+      return res & mask;
-+}
-+
-+static inline int test_and_clear_bit(int bit, volatile unsigned long *p)
-+{
-+      unsigned int res;
-+      unsigned long mask = 1UL << (bit & 31);
-+
-+      p += bit >> 5;
-+
-+      __atomic_lock_acquire();
-+      res = *p;
-+      *p = res & ~mask;
-+      __atomic_lock_release();
-+
-+      return res & mask;
-+}
-+
-+static inline int test_and_change_bit(int bit, volatile unsigned long *p)
-+{
-+      unsigned int res;
-+      unsigned long mask = 1UL << (bit & 31);
-+
-+      p += bit >> 5;
-+
-+      __atomic_lock_acquire();
-+      res = *p;
-+      *p = res ^ mask;
-+      __atomic_lock_release();
-+
-+      return res & mask;
-+}
-+
-+#include <asm-generic/bitops/non-atomic.h>
-+
-+/*
-+ * This routine doesn't need to be atomic.
-+ */
-+static inline int __constant_test_bit(int nr, const volatile unsigned long *addr)
-+{
-+      return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
-+}
-+
-+static inline int __test_bit(int nr, const volatile unsigned long *addr)
-+{
-+      int     * a = (int *) addr;
-+      int     mask;
-+
-+      a += nr >> 5;
-+      mask = 1 << (nr & 0x1f);
-+      return ((mask & *a) != 0);
-+}
-+
-+#define test_bit(nr,addr) (__builtin_constant_p(nr) ?  __constant_test_bit((nr),(addr)) :  __test_bit((nr),(addr)))
-+
-+#include <asm-generic/bitops/find.h>
-+#include <asm-generic/bitops/hweight.h>
-+#include <asm-generic/bitops/lock.h>
-+
-+#include <asm-generic/bitops/ext2-non-atomic.h>
-+#include <asm-generic/bitops/ext2-atomic.h>
-+#include <asm-generic/bitops/minix.h>
-+
-+#endif /* __KERNEL__ */
-+
-+#include <asm-generic/bitops/fls.h>
-+#include <asm-generic/bitops/__fls.h>
-+#include <asm-generic/bitops/fls64.h>
-+
-+#endif /* _ASM_UBICOM32_BITOPS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/board.h
-@@ -0,0 +1,34 @@
-+/*
-+ * arch/ubicom32/include/asm/board.h
-+ *   Board init and revision definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_BOARD_H
-+#define _ASM_UBICOM32_BOARD_H
-+
-+extern const char *board_get_revision(void);
-+extern void __init board_init(void);
-+
-+#endif /* _ASM_UBICOM32_BOARD_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/bootargs.h
-@@ -0,0 +1,34 @@
-+/*
-+ * arch/ubicom32/include/asm/bootargs.h
-+ *   Kernel command line via the devtree API.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_BOOTARGS_H
-+#define _ASM_UBICOM32_BOOTARGS_H
-+
-+extern const char *bootargs_get_cmdline(void);
-+extern void __init bootargs_init(void);
-+
-+#endif /* _ASM_UBICOM32_BOOTARGS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/bootinfo.h
-@@ -0,0 +1,34 @@
-+/*
-+ * arch/ubicom32/include/asm/bootinfo.h
-+ *   Definitions of firmware boot parameters passed to the kernel.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_BOOTINFO_H
-+#define _ASM_UBICOM32_BOOTINFO_H
-+
-+/* Nothing for ubicom32 */
-+
-+#endif /* _ASM_UBICOM32_BOOTINFO_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/bug.h
-@@ -0,0 +1,95 @@
-+/*
-+ * arch/ubicom32/include/asm/bug.h
-+ *   Generic bug.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_BUG_H
-+#define _ASM_UBICOM32_BUG_H
-+
-+#include <linux/kernel.h>
-+#include <asm/thread.h>
-+
-+#if defined(CONFIG_BUG) && defined(CONFIG_STOP_ON_BUG)
-+
-+/*
-+ * BUG()
-+ *    Ubicom specific version of the BUG() macro.
-+ *
-+ * This implementation performs a THREAD_STALL stopping all threads before
-+ * calling panic.  This enables a developer to see the "real" state of the
-+ * machine (since panic alters the system state).  We do the printf first
-+ * because while it is slow, it does not alter system state (like
-+ * interrupts).
-+ *
-+ * TODO: Implement the trap sequence used by other architectures.
-+ */
-+#define BUG() do { \
-+      printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
-+      THREAD_STALL; \
-+      panic("BUG!"); \
-+} while (0)
-+
-+
-+/*
-+ * __WARN()
-+ *    WARN() using printk() for now.
-+ *
-+ * TODO: Implement the trap sequence used by other architectures.
-+ */
-+#define __WARN()                                                      \
-+      do {                                                            \
-+              printk("WARN: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
-+      } while(0)
-+
-+/*
-+ * WARN_ON()
-+ *    Ubicom specific version of the WARN_ON macro.
-+ *
-+ * This implementation performs a printk for the WARN_ON() instead
-+ * of faulting into the kernel and using report_bug().
-+ *
-+ * TODO: Implement the trap sequence used by other architectures.
-+ */
-+#define WARN_ON(x) ({                                         \
-+      int __ret_warn_on = !!(x);                              \
-+      if (__builtin_constant_p(__ret_warn_on)) {              \
-+              if (__ret_warn_on)                              \
-+                      __WARN();                               \
-+      } else {                                                \
-+              if (unlikely(__ret_warn_on))                    \
-+                      __WARN();                               \
-+      }                                                       \
-+      unlikely(__ret_warn_on);                                \
-+})
-+
-+
-+#define HAVE_ARCH_BUG
-+#define HAVE_ARCH_WARN_ON
-+
-+#endif
-+
-+#include <asm-generic/bug.h>
-+
-+#endif /* _ASM_UBICOM32_BUG_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/bugs.h
-@@ -0,0 +1,44 @@
-+/*
-+ * arch/ubicom32/include/asm/bugs.h
-+ *   Definition of check_bugs() for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 1994  Linus Torvalds
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+/*
-+ * This is included by init/main.c to check for architecture-dependent bugs.
-+ *
-+ * Needs:
-+ *    void check_bugs(void);
-+ */
-+
-+#ifndef _ASM_UBICOM32_BUGS_H
-+#define _ASM_UBICOM32_BUGS_H
-+
-+static void check_bugs(void)
-+{
-+}
-+
-+#endif /* _ASM_UBICOM32_BUGS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/byteorder.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/byteorder.h
-+ *   Byte order swapping utility routines.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_BYTEORDER_H
-+#define _ASM_UBICOM32_BYTEORDER_H
-+
-+#include <linux/byteorder/big_endian.h>
-+
-+#endif /* _ASM_UBICOM32_BYTEORDER_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/cachectl.h
-@@ -0,0 +1,39 @@
-+/*
-+ * arch/ubicom32/include/asm/cachectl.h
-+ *   Ubicom32 cache control definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_CACHECTL_H
-+#define _ASM_UBICOM32_CACHECTL_H
-+
-+#include <asm/ip5000.h>
-+
-+/*
-+ * mem_cache_control()
-+ *    Special cache control operation
-+ */
-+extern void mem_cache_control(unsigned long cc, unsigned long begin_addr, unsigned long end_addr, unsigned long op);
-+
-+#endif /* _ASM_UBICOM32_CACHECTL_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/cacheflush.h
-@@ -0,0 +1,111 @@
-+/*
-+ * arch/ubicom32/include/asm/cacheflush.h
-+ *   Cache flushing definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_CACHEFLUSH_H
-+#define _ASM_UBICOM32_CACHEFLUSH_H
-+
-+/*
-+ * (C) Copyright 2000-2004, Greg Ungerer <gerg@snapgear.com>
-+ */
-+#include <linux/mm.h>
-+#include <asm/cachectl.h>
-+#include <asm/ip5000.h>
-+
-+#define flush_cache_all()                     __flush_cache_all()
-+#define flush_cache_mm(mm)                    do { } while (0)
-+#define flush_cache_dup_mm(mm)                        do { } while (0)
-+#define flush_cache_range(vma, start, end)    __flush_cache_all()
-+#define flush_cache_page(vma, vmaddr)         do { } while (0)
-+#define flush_dcache_page(page)                       do { } while (0)
-+#define flush_dcache_mmap_lock(mapping)               do { } while (0)
-+#define flush_dcache_mmap_unlock(mapping)     do { } while (0)
-+
-+#define flush_dcache_range(start, end)                                        \
-+do {                                                                  \
-+      /* Flush the data cache and invalidate the I cache. */          \
-+      mem_cache_control(DCCR_BASE, start, end, CCR_CTRL_FLUSH_ADDR);  \
-+      mem_cache_control(ICCR_BASE, start, end, CCR_CTRL_INV_ADDR);    \
-+} while (0)
-+
-+#define flush_icache_range(start, end)                                        \
-+do {                                                                  \
-+      /* Flush the data cache and invalidate the I cache. */          \
-+      mem_cache_control(DCCR_BASE, start, end, CCR_CTRL_FLUSH_ADDR);  \
-+      mem_cache_control(ICCR_BASE, start, end, CCR_CTRL_INV_ADDR);    \
-+} while (0)
-+
-+#define flush_icache_page(vma,pg)             do { } while (0)
-+#define flush_icache_user_range(vma,pg,adr,len)       do { } while (0)
-+#define flush_cache_vmap(start, end)          do { } while (0)
-+#define flush_cache_vunmap(start, end)                do { } while (0)
-+
-+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
-+      memcpy(dst, src, len)
-+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-+      memcpy(dst, src, len)
-+
-+/*
-+ * Cache handling for IP5000
-+ */
-+extern inline void mem_cache_invalidate_all(unsigned long cc)
-+{
-+      if (cc == DCCR_BASE)
-+              UBICOM32_LOCK(DCCR_LOCK_BIT);
-+      else
-+              UBICOM32_LOCK(ICCR_LOCK_BIT);
-+
-+      asm volatile (
-+      "       bset    "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_RESET)"      \n\t"
-+      "       nop                                                                     \n\t"
-+      "       bclr    "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_RESET)"      \n\t"
-+      "       pipe_flush 0                                                            \n\t"
-+              :
-+              : "a"(cc)
-+              : "cc"
-+      );
-+
-+      if (cc == DCCR_BASE)
-+              UBICOM32_UNLOCK(DCCR_LOCK_BIT);
-+      else
-+              UBICOM32_UNLOCK(ICCR_LOCK_BIT);
-+
-+}
-+
-+static inline void __flush_cache_all(void)
-+{
-+      /*
-+       * Flush Icache
-+       */
-+      mem_cache_invalidate_all(ICCR_BASE);
-+
-+      /*
-+       * Flush Dcache
-+       */
-+      mem_cache_invalidate_all(DCCR_BASE);
-+}
-+
-+#endif /* _ASM_UBICOM32_CACHEFLUSH_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/cache.h
-@@ -0,0 +1,40 @@
-+/*
-+ * arch/ubicom32/include/asm/cache.h
-+ *   Cache line definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_CACHE_H
-+#define _ASM_UBICOM32_CACHE_H
-+
-+/*
-+ * bytes per L1 cache line
-+ */
-+#define L1_CACHE_SHIFT  5
-+#define L1_CACHE_BYTES  (1 << L1_CACHE_SHIFT)
-+
-+#define __cacheline_aligned
-+#define ____cacheline_aligned
-+
-+#endif /* _ASM_UBICOM32_CACHE_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/checksum.h
-@@ -0,0 +1,149 @@
-+/*
-+ * arch/ubicom32/include/asm/checksum.h
-+ *   Checksum utilities for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_CHECKSUM_H
-+#define _ASM_UBICOM32_CHECKSUM_H
-+
-+#include <linux/in6.h>
-+
-+/*
-+ * computes the checksum of a memory block at buff, length len,
-+ * and adds in "sum" (32-bit)
-+ *
-+ * returns a 32-bit number suitable for feeding into itself
-+ * or csum_tcpudp_magic
-+ *
-+ * this function must be called with even lengths, except
-+ * for the last fragment, which may be odd
-+ *
-+ * it's best to have buff aligned on a 32-bit boundary
-+ */
-+__wsum csum_partial(const void *buff, int len, __wsum sum);
-+
-+/*
-+ * the same as csum_partial, but copies from src while it
-+ * checksums
-+ *
-+ * here even more important to align src and dst on a 32-bit (or even
-+ * better 64-bit) boundary
-+ */
-+
-+__wsum csum_partial_copy_nocheck(const void *src, void *dst,
-+      int len, __wsum sum);
-+
-+
-+/*
-+ * the same as csum_partial_copy, but copies from user space.
-+ *
-+ * here even more important to align src and dst on a 32-bit (or even
-+ * better 64-bit) boundary
-+ */
-+
-+extern __wsum csum_partial_copy_from_user(const void __user *src,
-+      void *dst, int len, __wsum sum, int *csum_err);
-+
-+__sum16 ip_fast_csum(const void *iph, unsigned int ihl);
-+
-+/*
-+ *    Fold a partial checksum
-+ */
-+
-+static inline __sum16 csum_fold(__wsum sum)
-+{
-+      asm volatile (
-+      "       lsr.4   d15, %0, #16    \n\t"
-+      "       bfextu  %0, %0, #16     \n\t"
-+      "       add.4   %0, d15, %0     \n\t"
-+      "       lsr.4   d15, %0, #16    \n\t"
-+      "       bfextu  %0, %0, #16     \n\t"
-+      "       add.4   %0, d15, %0     \n\t"
-+              : "=&d" (sum)
-+              : "0"(sum)
-+              : "d15"
-+      );
-+      return (__force __sum16)~sum;
-+}
-+
-+
-+/*
-+ * computes the checksum of the TCP/UDP pseudo-header
-+ * returns a 16-bit checksum, already complemented
-+ */
-+
-+static inline __wsum
-+csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
-+                unsigned short proto, __wsum sum)
-+{
-+      asm volatile (
-+      "       add.4   %0, %2, %0      \n\t"
-+      "       addc    %0, %3, %0      \n\t"
-+      "       addc    %0, %4, %0      \n\t"
-+      "       addc    %0, %5, %0      \n\t"
-+      "       addc    %0, #0, %0      \n\t"
-+              : "=&d" (sum)
-+              : "0"(sum), "r" (saddr), "r" (daddr), "r" (len), "r"(proto)
-+      );
-+      return sum;
-+}
-+
-+static inline __sum16
-+csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len,
-+                unsigned short proto, __wsum 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
-+ */
-+extern __sum16 ip_compute_csum(const void *buff, int len);
-+
-+#define _HAVE_ARCH_IPV6_CSUM
-+
-+static __inline__ __sum16
-+csum_ipv6_magic(const struct in6_addr *saddr, const struct in6_addr *daddr,
-+              __u32 len, unsigned short proto, __wsum sum)
-+{
-+      asm volatile (
-+      "       add.4   %0, 0(%2), %0   \n\t"
-+      "       addc    %0, 4(%2), %0   \n\t"
-+      "       addc    %0, 8(%2), %0   \n\t"
-+      "       addc    %0, 12(%2), %0  \n\t"
-+      "       addc    %0, 0(%3), %0   \n\t"
-+      "       addc    %0, 4(%3), %0   \n\t"
-+      "       addc    %0, 8(%3), %0   \n\t"
-+      "       addc    %0, 12(%3), %0  \n\t"
-+      "       addc    %0, %4, %0      \n\t"
-+      "       addc    %0, #0, %0      \n\t"
-+              : "=&d" (sum)
-+              : "0" (sum), "a" (saddr), "a" (daddr), "d" (len + proto)
-+      );
-+      return csum_fold(sum);
-+}
-+
-+#endif /* _ASM_UBICOM32_CHECKSUM_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/cpu.h
-@@ -0,0 +1,45 @@
-+/*
-+ * arch/ubicom32/include/asm/cpu.h
-+ *   CPU definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 2004-2005 ARM Ltd.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_CPU_H
-+#define _ASM_UBICOM32_CPU_H
-+
-+#include <linux/percpu.h>
-+
-+struct cpuinfo_ubicom32 {
-+      unsigned long tid;                      /* Hardware thread number */
-+
-+#ifdef CONFIG_SMP
-+      volatile unsigned long ipi_pending;     /* Bit map of operations to execute */
-+      unsigned long ipi_count;                /* Number of IPI(s) taken on this cpu */
-+#endif
-+};
-+
-+DECLARE_PER_CPU(struct cpuinfo_ubicom32, cpu_data);
-+
-+#endif /* _ASM_UBICOM32_CPU_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/cputime.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/cputime.h
-+ *   Generic cputime.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_CPUTIME_H
-+#define _ASM_UBICOM32_CPUTIME_H
-+
-+#include <asm-generic/cputime.h>
-+
-+#endif /* _ASM_UBICOM32_CPUTIME_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/current.h
-@@ -0,0 +1,44 @@
-+/*
-+ * arch/ubicom32/include/asm/current.h
-+ *   Definition of get_current() for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * (C) Copyright 2000, Lineo, David McCullough <davidm@uclinux.org>
-+ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_CURRENT_H
-+#define _ASM_UBICOM32_CURRENT_H
-+
-+#include <linux/thread_info.h>
-+
-+struct task_struct;
-+
-+static inline struct task_struct *get_current(void)
-+{
-+      return(current_thread_info()->task);
-+}
-+
-+#define       current get_current()
-+
-+#endif /* _ASM_UBICOM32_CURRENT_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/delay.h
-@@ -0,0 +1,75 @@
-+/*
-+ * arch/ubicom32/include/asm/delay.h
-+ *   Definition of delay routines for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_DELAY_H
-+#define _ASM_UBICOM32_DELAY_H
-+
-+#include <asm/param.h>
-+#include <asm/ip5000.h>
-+
-+static inline void __delay(unsigned long loops)
-+{
-+      if (loops == 0) {
-+              return;
-+      }
-+
-+      asm volatile (
-+      "1:     add.4   %0, #-1, %0             \n\t"
-+      "       jmpne.t 1b                      \n\t"
-+      : "+d" (loops)
-+      );
-+}
-+
-+/*
-+ *    Ubicom32 processor uses fixed 12MHz external OSC.
-+ *    So we use that as reference to count 12 cycles/us
-+ */
-+
-+extern unsigned long loops_per_jiffy;
-+
-+static inline void _udelay(unsigned long usecs)
-+{
-+#if defined(CONFIG_UBICOM32_V4) || defined(CONFIG_UBICOM32_V3)
-+      asm volatile (
-+              "       add.4           d15, 0(%0), %1                  \n\t"
-+              "       sub.4           #0, 0(%0), d15                  \n\t"
-+              "       jmpmi.w.f       .-4                             \n\t"
-+              :
-+              : "a"(TIMER_BASE + TIMER_MPTVAL), "d"(usecs * (12000000/1000000))
-+              : "d15"
-+      );
-+#else
-+      BUG();
-+#endif
-+}
-+
-+/*
-+ *    Moved the udelay() function into library code, no longer inlined.
-+ */
-+extern void udelay(unsigned long usecs);
-+
-+#endif /* _ASM_UBICOM32_DELAY_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/device.h
-@@ -0,0 +1,35 @@
-+/*
-+ * arch/ubicom32/include/asm/device.h
-+ *   Generic device.h for Ubicom32 architecture.
-+ *
-+ *   Used for arch specific extensions to struct device
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_DEVICE_H
-+#define _ASM_UBICOM32_DEVICE_H
-+
-+#include <asm-generic/device.h>
-+
-+#endif /* _ASM_UBICOM32_DEVICE_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/devtree.h
-@@ -0,0 +1,52 @@
-+/*
-+ * arch/ubicom32/include/asm/devtree.h
-+ *   Device Tree Header File (Shared between ultra and the Host OS)
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_DEVTREE_H
-+#define _ASM_UBICOM32_DEVTREE_H
-+
-+#define DEVTREE_MAX_NAME 32
-+#define DEVTREE_IRQ_NONE 0xff
-+#define DEVTREE_IRQ_DONTCARE 0xff
-+#define DEVTREE_NODE_MAGIC 0x10203040
-+
-+struct devtree_node {
-+      struct devtree_node *next;
-+      unsigned char sendirq;
-+      unsigned char recvirq;
-+      char name[DEVTREE_MAX_NAME];
-+      unsigned int magic;
-+};
-+
-+extern struct devtree_node *devtree;
-+extern struct devtree_node *devtree_find_by_irq(uint8_t sendirq, uint8_t recvirq);
-+extern struct devtree_node *devtree_find_node(const char *str);
-+extern struct devtree_node *devtree_find_next(struct devtree_node **cur);
-+extern int devtree_irq(struct devtree_node *dn, unsigned char *sendirq, unsigned char *recvirq);
-+extern void devtree_print(void);
-+
-+#endif /* _ASM_UBICOM32_DEVTREE_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/div64.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/div64.h
-+ *   Generic div64.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_DIV64_H
-+#define _ASM_UBICOM32_DIV64_H
-+
-+#include <asm-generic/div64.h>
-+
-+#endif /* _ASM_UBICOM32_DIV64_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/dma.h
-@@ -0,0 +1,34 @@
-+/*
-+ * arch/ubicom32/include/asm/dma.h
-+ *   DMA definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_DMA_H
-+#define _ASM_UBICOM32_DMA_H
-+
-+/* Nothing so far */
-+#define MAX_DMA_ADDRESS 0x00  /* This is quite suspicious */
-+
-+#endif /* _ASM_UBICOM32_DMA_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/dma-mapping.h
-@@ -0,0 +1,328 @@
-+/*
-+ * arch/ubicom32/include/asm/dma-mapping.h
-+ *   Generic dma-mapping.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_DMA_MAPPING_H
-+#define _ASM_UBICOM32_DMA_MAPPING_H
-+
-+#include <linux/scatterlist.h>
-+#ifdef CONFIG_PCI
-+
-+/* we implement the API below in terms of the existing PCI one,
-+ * so include it */
-+#include <linux/pci.h>
-+/* need struct page definitions */
-+#include <linux/mm.h>
-+
-+static inline int
-+dma_supported(struct device *dev, u64 mask)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      return pci_dma_supported(to_pci_dev(dev), mask);
-+}
-+
-+static inline int
-+dma_set_mask(struct device *dev, u64 dma_mask)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
-+}
-+
-+static inline void *
-+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-+                 gfp_t flag)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
-+}
-+
-+static inline void
-+dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-+                  dma_addr_t dma_handle)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle);
-+}
-+
-+static inline dma_addr_t
-+dma_map_single(struct device *dev, void *cpu_addr, size_t size,
-+             enum dma_data_direction direction)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction);
-+}
-+
-+static inline void
-+dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-+               enum dma_data_direction direction)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction);
-+}
-+
-+static inline dma_addr_t
-+dma_map_page(struct device *dev, struct page *page,
-+           unsigned long offset, size_t size,
-+           enum dma_data_direction direction)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction);
-+}
-+
-+static inline void
-+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-+             enum dma_data_direction direction)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction);
-+}
-+
-+static inline int
-+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-+         enum dma_data_direction direction)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
-+}
-+
-+static inline void
-+dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-+           enum dma_data_direction direction)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction);
-+}
-+
-+static inline void
-+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-+                      enum dma_data_direction direction)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
-+                                  size, (int)direction);
-+}
-+
-+static inline void
-+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
-+                         enum dma_data_direction direction)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
-+                                     size, (int)direction);
-+}
-+
-+static inline void
-+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-+                  enum dma_data_direction direction)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction);
-+}
-+
-+static inline void
-+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-+                     enum dma_data_direction direction)
-+{
-+      BUG_ON(dev->bus != &pci_bus_type);
-+
-+      pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction);
-+}
-+
-+static inline int
-+dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-+{
-+      return pci_dma_mapping_error(to_pci_dev(dev), dma_addr);
-+}
-+
-+
-+#else
-+
-+static inline int
-+dma_supported(struct device *dev, u64 mask)
-+{
-+      return 0;
-+}
-+
-+static inline int
-+dma_set_mask(struct device *dev, u64 dma_mask)
-+{
-+      BUG();
-+      return 0;
-+}
-+
-+static inline void *
-+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
-+                 gfp_t flag)
-+{
-+      BUG();
-+      return NULL;
-+}
-+
-+static inline void
-+dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-+                  dma_addr_t dma_handle)
-+{
-+      BUG();
-+}
-+
-+static inline dma_addr_t
-+dma_map_single(struct device *dev, void *cpu_addr, size_t size,
-+             enum dma_data_direction direction)
-+{
-+      BUG();
-+      return 0;
-+}
-+
-+static inline void
-+dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-+               enum dma_data_direction direction)
-+{
-+      BUG();
-+}
-+
-+static inline dma_addr_t
-+dma_map_page(struct device *dev, struct page *page,
-+           unsigned long offset, size_t size,
-+           enum dma_data_direction direction)
-+{
-+      BUG();
-+      return 0;
-+}
-+
-+static inline void
-+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
-+             enum dma_data_direction direction)
-+{
-+      BUG();
-+}
-+
-+static inline int
-+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
-+         enum dma_data_direction direction)
-+{
-+      BUG();
-+      return 0;
-+}
-+
-+static inline void
-+dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
-+           enum dma_data_direction direction)
-+{
-+      BUG();
-+}
-+
-+static inline void
-+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
-+                      enum dma_data_direction direction)
-+{
-+      BUG();
-+}
-+
-+static inline void
-+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
-+                         enum dma_data_direction direction)
-+{
-+      BUG();
-+}
-+
-+static inline void
-+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
-+                  enum dma_data_direction direction)
-+{
-+      BUG();
-+}
-+
-+static inline void
-+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
-+                     enum dma_data_direction direction)
-+{
-+      BUG();
-+}
-+
-+static inline int
-+dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-+{
-+      return 0;
-+}
-+
-+#endif
-+
-+/* Now for the API extensions over the pci_ one */
-+
-+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-+#define dma_is_consistent(d, h)       (1)
-+
-+static inline int
-+dma_get_cache_alignment(void)
-+{
-+      /* no easy way to get cache size on all processors, so return
-+       * the maximum possible, to be safe */
-+      return (1 << INTERNODE_CACHE_SHIFT);
-+}
-+
-+static inline void
-+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
-+                            unsigned long offset, size_t size,
-+                            enum dma_data_direction direction)
-+{
-+      /* just sync everything, that's all the pci API can do */
-+      dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction);
-+}
-+
-+static inline void
-+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-+                               unsigned long offset, size_t size,
-+                               enum dma_data_direction direction)
-+{
-+      /* just sync everything, that's all the pci API can do */
-+      dma_sync_single_for_device(dev, dma_handle, offset+size, direction);
-+}
-+
-+static inline void
-+dma_cache_sync(struct device *dev, void *vaddr, size_t size,
-+             enum dma_data_direction direction)
-+{
-+      /* could define this in terms of the dma_cache ... operations,
-+       * but if you get this on a platform, you should convert the platform
-+       * to using the generic device DMA API */
-+      BUG();
-+}
-+
-+#endif /* _ASM_UBICOM32_DMA_MAPPING_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/elf.h
-@@ -0,0 +1,173 @@
-+/*
-+ * arch/ubicom32/include/asm/elf.h
-+ *   Definitions for elf executable format for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_ELF_H
-+#define _ASM_UBICOM32_ELF_H
-+
-+/*
-+ * ELF register definitions..
-+ */
-+
-+#include <asm/ptrace.h>
-+#include <asm/user.h>
-+
-+/*
-+ * Processor specific flags for the ELF header e_flags field.
-+ */
-+#define EF_UBICOM32_V3                0x00000001      /* -fmarch=ubicom32v3 */
-+#define EF_UBICOM32_V4                0x00000002      /* -fmarch=ubicom32v4 */
-+#define EF_UBICOM32_PIC               0x80000000      /* -fpic */
-+#define EF_UBICOM32_FDPIC     0x40000000      /* -mfdpic */
-+
-+/*
-+ * Ubicom32 ELF relocation types
-+ */
-+#define R_UBICOM32_NONE                       0
-+#define R_UBICOM32_16                 1
-+#define R_UBICOM32_32                 2
-+#define R_UBICOM32_LO16                       3
-+#define R_UBICOM32_HI16                       4
-+#define R_UBICOM32_21_PCREL           5
-+#define R_UBICOM32_24_PCREL           6
-+#define R_UBICOM32_HI24                       7
-+#define R_UBICOM32_LO7_S              8
-+#define R_UBICOM32_LO7_2_S            9
-+#define R_UBICOM32_LO7_4_S            10
-+#define R_UBICOM32_LO7_D              11
-+#define R_UBICOM32_LO7_2_D            12
-+#define R_UBICOM32_LO7_4_D            13
-+#define R_UBICOM32_32_HARVARD         14
-+#define R_UBICOM32_LO7_CALLI          15
-+#define R_UBICOM32_LO16_CALLI         16
-+#define R_UBICOM32_GOT_HI24           17
-+#define R_UBICOM32_GOT_LO7_S          18
-+#define R_UBICOM32_GOT_LO7_2_S                19
-+#define R_UBICOM32_GOT_LO7_4_S                20
-+#define R_UBICOM32_GOT_LO7_D          21
-+#define R_UBICOM32_GOT_LO7_2_D                22
-+#define R_UBICOM32_GOT_LO7_4_D                23
-+#define R_UBICOM32_FUNCDESC_GOT_HI24    24
-+#define R_UBICOM32_FUNCDESC_GOT_LO7_S   25
-+#define R_UBICOM32_FUNCDESC_GOT_LO7_2_S 26
-+#define R_UBICOM32_FUNCDESC_GOT_LO7_4_S 27
-+#define R_UBICOM32_FUNCDESC_GOT_LO7_D   28
-+#define R_UBICOM32_FUNCDESC_GOT_LO7_2_D 29
-+#define R_UBICOM32_FUNCDESC_GOT_LO7_4_D 30
-+#define R_UBICOM32_GOT_LO7_CALLI        31
-+#define R_UBICOM32_FUNCDESC_GOT_LO7_CALLI 32
-+#define R_UBICOM32_FUNCDESC_VALUE       33
-+#define R_UBICOM32_FUNCDESC             34
-+#define R_UBICOM32_GOTOFFSET_LO         35
-+#define R_UBICOM32_GOTOFFSET_HI         36
-+#define R_UBICOM32_FUNCDESC_GOTOFFSET_LO 37
-+#define R_UBICOM32_FUNCDESC_GOTOFFSET_HI 38
-+#define R_UBICOM32_GNU_VTINHERIT        200
-+#define R_UBICOM32_GNU_VTENTRY          201
-+
-+typedef unsigned long elf_greg_t;
-+
-+#define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t))
-+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-+
-+typedef struct user_ubicom32fp_struct elf_fpregset_t;
-+
-+/*
-+ * This is used to ensure we don't load something for the wrong architecture.
-+ */
-+#define elf_check_arch(x) ((x)->e_machine == EM_UBICOM32)
-+
-+#define elf_check_fdpic(x) ((x)->e_flags & EF_UBICOM32_FDPIC)
-+
-+#define elf_check_const_displacement(x) ((x)->e_flags & EF_UBICOM32_PIC)
-+
-+/*
-+ * These are used to set parameters in the core dumps.
-+ */
-+#define ELF_CLASS     ELFCLASS32
-+#define ELF_DATA      ELFDATA2MSB
-+#define ELF_ARCH      EM_UBICOM32
-+
-+/* For SVR4/m68k the function pointer to be registered with `atexit' is
-+   passed in %a1.  Although my copy of the ABI has no such statement, it
-+   is actually used on ASV.  */
-+#define ELF_PLAT_INIT(_r, load_addr)  _r->a1 = 0
-+
-+#define ELF_FDPIC_PLAT_INIT(_regs, _exec_map_addr, _interp_map_addr,  \
-+                          _dynamic_addr)                              \
-+      do {                                                            \
-+              _regs->dn[1]    = _exec_map_addr;                       \
-+              _regs->dn[2]    = _interp_map_addr;                     \
-+              _regs->dn[3]    = _dynamic_addr;                        \
-+              _regs->an[1]    = 0; /* dl_fini will be set by ldso */  \
-+      } while (0)
-+
-+#define USE_ELF_CORE_DUMP
-+#define ELF_EXEC_PAGESIZE     4096
-+
-+#ifdef __KERNEL__
-+#ifdef CONFIG_UBICOM32_V4
-+#define ELF_FDPIC_CORE_EFLAGS (EF_UBICOM32_FDPIC | EF_UBICOM32_V4)
-+#elif defined CONFIG_UBICOM32_V3
-+#define ELF_FDPIC_CORE_EFLAGS (EF_UBICOM32_FDPIC | EF_UBICOM32_V3)
-+#else
-+#error Unknown/Unsupported ubicom32 architecture.
-+#endif
-+#endif
-+
-+/* 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         0xD0000000UL
-+
-+/*
-+ * For Ubicom32, the elf_gregset_t and struct pt_regs are the same size
-+ * data structure so a copy is performed instead of providing the
-+ * ELF_CORE_COPY_REGS macro.
-+ */
-+
-+/*
-+ * ELF_CORE_COPY_TASK_REGS is needed to dump register state from multi threaded user projects.
-+ */
-+extern int dump_task_regs(struct task_struct *, elf_gregset_t *);
-+#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
-+
-+/* This yields a mask that user programs can use to figure out what
-+   instruction set this cpu supports.  */
-+
-+#define ELF_HWCAP     (0)
-+
-+/* 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.  */
-+
-+#define ELF_PLATFORM  (NULL)
-+
-+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
-+
-+#endif /* _ASM_UBICOM32_ELF_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/emergency-restart.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/emergency-restart.h
-+ *   Generic emergency-restart.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_EMERGENCY_RESTART_H
-+#define _ASM_UBICOM32_EMERGENCY_RESTART_H
-+
-+#include <asm-generic/emergency-restart.h>
-+
-+#endif /* _ASM_UBICOM32_EMERGENCY_RESTART_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/entry.h
-@@ -0,0 +1,34 @@
-+/*
-+ * arch/ubicom32/include/asm/entry.h
-+ *   Entry register/stack definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_ENTRY_H
-+#define _ASM_UBICOM32_ENTRY_H
-+
-+#include <asm/setup.h>
-+#include <asm/page.h>
-+
-+#endif /* _ASM_UBICOM32_ENTRY_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/errno.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/errno.h
-+ *   Generic errno.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_ERRNO_H
-+#define _ASM_UBICOM32_ERRNO_H
-+
-+#include <asm-generic/errno.h>
-+
-+#endif /* _ASM_UBICOM32_ERRNO_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/fb.h
-@@ -0,0 +1,39 @@
-+/*
-+ * arch/ubicom32/include/asm/fb.h
-+ *   Definition of fb_is_primary_device() for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_FB_H
-+#define _ASM_UBICOM32_FB_H
-+#include <linux/fb.h>
-+
-+#define fb_pgprotect(...) do {} while (0)
-+
-+static inline int fb_is_primary_device(struct fb_info *info)
-+{
-+      return 0;
-+}
-+
-+#endif /* _ASM_UBICOM32_FB_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/fcntl.h
-@@ -0,0 +1,38 @@
-+/*
-+ * arch/ubicom32/include/asm/fcntl.h
-+ *   File control bit definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_FCNTL_H
-+#define _ASM_UBICOM32_FCNTL_H
-+
-+#define O_DIRECTORY   040000  /* must be a directory */
-+#define O_NOFOLLOW    0100000 /* don't follow links */
-+#define O_DIRECT      0200000 /* direct disk access hint - currently ignored */
-+#define O_LARGEFILE   0400000
-+
-+#include <asm-generic/fcntl.h>
-+
-+#endif /* _ASM_UBICOM32_FCNTL_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/flat.h
-@@ -0,0 +1,73 @@
-+/*
-+ * arch/ubicom32/include/asm/flat.h
-+ *   Definitions to support flat-format executables.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_FLAT_H
-+#define _ASM_UBICOM32_FLAT_H
-+
-+#define ARCH_FLAT_ALIGN 0x80
-+#define ARCH_FLAT_ALIGN_TEXT 1
-+
-+#define  R_UBICOM32_32                2
-+#define  R_UBICOM32_HI24      7
-+#define  R_UBICOM32_LO7_S     8
-+#define  R_UBICOM32_LO7_2_S   9
-+#define  R_UBICOM32_LO7_4_S   10
-+#define  R_UBICOM32_LO7_D     11
-+#define  R_UBICOM32_LO7_2_D   12
-+#define  R_UBICOM32_LO7_4_D   13
-+#define  R_UBICOM32_LO7_CALLI 15
-+#define  R_UBICOM32_LO16_CALLI        16
-+
-+extern void ubicom32_flat_put_addr_at_rp(unsigned long *rp, u32_t val, u32_t rval, unsigned long  *p);
-+extern unsigned long ubicom32_flat_get_addr_from_rp(unsigned long *rp, u32_t relval, u32_t flags, unsigned long *p);
-+
-+#define       flat_stack_align(sp)                    /* nothing needed */
-+#define       flat_argvp_envp_on_stack()              1
-+#define       flat_old_ram_flag(flags)                (flags)
-+#define       flat_reloc_valid(reloc, size)           ((reloc) <= (size))
-+#define       flat_get_addr_from_rp(rp, relval, flags, p)     (ubicom32_flat_get_addr_from_rp(rp, relval,flags, p))
-+#define       flat_put_addr_at_rp(rp, val, relval)    do {ubicom32_flat_put_addr_at_rp(rp, val, relval, &persistent);} while(0)
-+#define       flat_get_relocate_addr(rel)             ((persistent) ? (persistent & 0x07ffffff) : (rel & 0x07ffffff))
-+
-+static inline int flat_set_persistent(unsigned int relval, unsigned long *p)
-+{
-+      if (*p) {
-+              return 0;
-+      } else {
-+              if ((relval >> 27) != R_UBICOM32_32) {
-+                      /*
-+                       * Something other than UBICOM32_32. The next entry has the relocation.
-+                       */
-+                      *p = relval;
-+                      return 1;
-+              }
-+      }
-+      return 0;
-+}
-+
-+#endif /* _ASM_UBICOM32_FLAT_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/fpu.h
-@@ -0,0 +1,37 @@
-+/*
-+ * arch/ubicom32/include/asm/fpu.h
-+ *   Floating point state definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_FPU_H
-+#define _ASM_UBICOM32_FPU_H
-+
-+/*
-+ * MAX floating point unit state size (FSAVE/FRESTORE)
-+ */
-+/* No FP unit present then... */
-+#define FPSTATESIZE (2) /* dummy size */
-+
-+#endif /* _ASM_UBICOM32_FPU_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ftrace.h
-@@ -0,0 +1 @@
-+/* empty */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/futex.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/futex.h
-+ *   Generic futex.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_FUTEX_H
-+#define _ASM_UBICOM32_FUTEX_H
-+
-+#include <asm-generic/futex.h>
-+
-+#endif /* _ASM_UBICOM32_FUTEX_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/.gitignore
-@@ -0,0 +1 @@
-+/ocm_size.h
---- /dev/null
-+++ b/arch/ubicom32/include/asm/gpio.h
-@@ -0,0 +1,453 @@
-+/*
-+ * arch/ubicom32/include/asm/gpio.h
-+ *   Definitions for GPIO operations on Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_GPIO_H
-+#define _ASM_UBICOM32_GPIO_H
-+
-+#include <linux/compiler.h>
-+#include <asm/irq.h>
-+
-+#include <asm/ip5000.h>
-+
-+#define ARCH_NR_GPIOS          512
-+#define MAX_UBICOM_ONCHIP_GPIO   (9 * 32)
-+
-+/*
-+ * Macros for manipulating GPIO numbers
-+ */
-+#define gpio_bit(gn)                  (1 << (gn & 0x1f))
-+#define gpio_bank(gn)                 (gn >> 5)
-+
-+#define gpio_pin_index(gn)            (gn & 0x1f)
-+#define gpio_port_index(gn)           (gn >> 5)
-+
-+#define GPIO_RA_0    ((32 * 0) + 0)
-+#define GPIO_RA_1    ((32 * 0) + 1)
-+#define GPIO_RA_2    ((32 * 0) + 2)
-+#define GPIO_RA_3    ((32 * 0) + 3)
-+#define GPIO_RA_4    ((32 * 0) + 4)
-+#define GPIO_RA_5    ((32 * 0) + 5)
-+#define GPIO_RA_6    ((32 * 0) + 6)
-+#define GPIO_RA_7    ((32 * 0) + 7)
-+
-+#define GPIO_RB_0    ((32 * 1) + 0)
-+#define GPIO_RB_1    ((32 * 1) + 1)
-+#define GPIO_RB_2    ((32 * 1) + 2)
-+#define GPIO_RB_3    ((32 * 1) + 3)
-+#define GPIO_RB_4    ((32 * 1) + 4)
-+#define GPIO_RB_5    ((32 * 1) + 5)
-+#define GPIO_RB_6    ((32 * 1) + 6)
-+#define GPIO_RB_7    ((32 * 1) + 7)
-+#define GPIO_RB_8    ((32 * 1) + 8)
-+#define GPIO_RB_9    ((32 * 1) + 9)
-+#define GPIO_RB_10   ((32 * 1) + 10)
-+#define GPIO_RB_11   ((32 * 1) + 11)
-+#define GPIO_RB_12   ((32 * 1) + 12)
-+#define GPIO_RB_13   ((32 * 1) + 13)
-+#define GPIO_RB_14   ((32 * 1) + 14)
-+#define GPIO_RB_15   ((32 * 1) + 15)
-+#define GPIO_RB_16   ((32 * 1) + 16)
-+#define GPIO_RB_17   ((32 * 1) + 17)
-+#define GPIO_RB_18   ((32 * 1) + 18)
-+#define GPIO_RB_19   ((32 * 1) + 19)
-+
-+#define GPIO_RC_0    ((32 * 2) + 0)
-+#define GPIO_RC_1    ((32 * 2) + 1)
-+#define GPIO_RC_2    ((32 * 2) + 2)
-+#define GPIO_RC_3    ((32 * 2) + 3)
-+#define GPIO_RC_4    ((32 * 2) + 4)
-+#define GPIO_RC_5    ((32 * 2) + 5)
-+#define GPIO_RC_6    ((32 * 2) + 6)
-+#define GPIO_RC_7    ((32 * 2) + 7)
-+#define GPIO_RC_8    ((32 * 2) + 8)
-+#define GPIO_RC_9    ((32 * 2) + 9)
-+#define GPIO_RC_10   ((32 * 2) + 10)
-+#define GPIO_RC_11   ((32 * 2) + 11)
-+#define GPIO_RC_12   ((32 * 2) + 12)
-+#define GPIO_RC_13   ((32 * 2) + 13)
-+#define GPIO_RC_14   ((32 * 2) + 14)
-+#define GPIO_RC_15   ((32 * 2) + 15)
-+#define GPIO_RC_16   ((32 * 2) + 16)
-+#define GPIO_RC_17   ((32 * 2) + 17)
-+#define GPIO_RC_18   ((32 * 2) + 18)
-+#define GPIO_RC_19   ((32 * 2) + 19)
-+#define GPIO_RC_20   ((32 * 2) + 20)
-+#define GPIO_RC_21   ((32 * 2) + 21)
-+#define GPIO_RC_22   ((32 * 2) + 22)
-+#define GPIO_RC_23   ((32 * 2) + 23)
-+#define GPIO_RC_24   ((32 * 2) + 24)
-+#define GPIO_RC_25   ((32 * 2) + 25)
-+#define GPIO_RC_26   ((32 * 2) + 26)
-+#define GPIO_RC_27   ((32 * 2) + 27)
-+#define GPIO_RC_28   ((32 * 2) + 28)
-+#define GPIO_RC_29   ((32 * 2) + 29)
-+#define GPIO_RC_30   ((32 * 2) + 30)
-+#define GPIO_RC_31   ((32 * 2) + 31)
-+
-+#define GPIO_RD_0    ((32 * 3) + 0)
-+#define GPIO_RD_1    ((32 * 3) + 1)
-+#define GPIO_RD_2    ((32 * 3) + 2)
-+#define GPIO_RD_3    ((32 * 3) + 3)
-+#define GPIO_RD_4    ((32 * 3) + 4)
-+#define GPIO_RD_5    ((32 * 3) + 5)
-+#define GPIO_RD_6    ((32 * 3) + 6)
-+#define GPIO_RD_7    ((32 * 3) + 7)
-+#define GPIO_RD_8    ((32 * 3) + 8)
-+#define GPIO_RD_9    ((32 * 3) + 9)
-+#define GPIO_RD_10   ((32 * 3) + 10)
-+#define GPIO_RD_11   ((32 * 3) + 11)
-+
-+#define GPIO_RE_0    ((32 * 4) + 0)
-+#define GPIO_RE_1    ((32 * 4) + 1)
-+#define GPIO_RE_2    ((32 * 4) + 2)
-+#define GPIO_RE_3    ((32 * 4) + 3)
-+#define GPIO_RE_4    ((32 * 4) + 4)
-+#define GPIO_RE_5    ((32 * 4) + 5)
-+#define GPIO_RE_6    ((32 * 4) + 6)
-+#define GPIO_RE_7    ((32 * 4) + 7)
-+
-+#define GPIO_RF_0    ((32 * 5) + 0)
-+#define GPIO_RF_1    ((32 * 5) + 1)
-+#define GPIO_RF_2    ((32 * 5) + 2)
-+#define GPIO_RF_3    ((32 * 5) + 3)
-+#define GPIO_RF_4    ((32 * 5) + 4)
-+#define GPIO_RF_5    ((32 * 5) + 5)
-+#define GPIO_RF_6    ((32 * 5) + 6)
-+#define GPIO_RF_7    ((32 * 5) + 7)
-+#define GPIO_RF_8    ((32 * 5) + 8)
-+#define GPIO_RF_9    ((32 * 5) + 9)
-+#define GPIO_RF_10   ((32 * 5) + 10)
-+#define GPIO_RF_11   ((32 * 5) + 11)
-+#define GPIO_RF_12   ((32 * 5) + 12)
-+#define GPIO_RF_13   ((32 * 5) + 13)
-+#define GPIO_RF_14   ((32 * 5) + 14)
-+#define GPIO_RF_15   ((32 * 5) + 15)
-+
-+#define GPIO_RG_0    ((32 * 6) + 0)
-+#define GPIO_RG_1    ((32 * 6) + 1)
-+#define GPIO_RG_2    ((32 * 6) + 2)
-+#define GPIO_RG_3    ((32 * 6) + 3)
-+#define GPIO_RG_4    ((32 * 6) + 4)
-+#define GPIO_RG_5    ((32 * 6) + 5)
-+#define GPIO_RG_6    ((32 * 6) + 6)
-+#define GPIO_RG_7    ((32 * 6) + 7)
-+#define GPIO_RG_8    ((32 * 6) + 8)
-+#define GPIO_RG_9    ((32 * 6) + 9)
-+#define GPIO_RG_10   ((32 * 6) + 10)
-+#define GPIO_RG_11   ((32 * 6) + 11)
-+#define GPIO_RG_12   ((32 * 6) + 12)
-+#define GPIO_RG_13   ((32 * 6) + 13)
-+#define GPIO_RG_14   ((32 * 6) + 14)
-+#define GPIO_RG_15   ((32 * 6) + 15)
-+#define GPIO_RG_16   ((32 * 6) + 16)
-+#define GPIO_RG_17   ((32 * 6) + 17)
-+#define GPIO_RG_18   ((32 * 6) + 18)
-+#define GPIO_RG_19   ((32 * 6) + 19)
-+#define GPIO_RG_20   ((32 * 6) + 20)
-+#define GPIO_RG_21   ((32 * 6) + 21)
-+#define GPIO_RG_22   ((32 * 6) + 22)
-+#define GPIO_RG_23   ((32 * 6) + 23)
-+#define GPIO_RG_24   ((32 * 6) + 24)
-+#define GPIO_RG_25   ((32 * 6) + 25)
-+#define GPIO_RG_26   ((32 * 6) + 26)
-+#define GPIO_RG_27   ((32 * 6) + 27)
-+#define GPIO_RG_28   ((32 * 6) + 28)
-+#define GPIO_RG_29   ((32 * 6) + 29)
-+#define GPIO_RG_30   ((32 * 6) + 30)
-+#define GPIO_RG_31   ((32 * 6) + 31)
-+
-+#define GPIO_RH_0    ((32 * 7) + 0)
-+#define GPIO_RH_1    ((32 * 7) + 1)
-+#define GPIO_RH_2    ((32 * 7) + 2)
-+#define GPIO_RH_3    ((32 * 7) + 3)
-+#define GPIO_RH_4    ((32 * 7) + 4)
-+#define GPIO_RH_5    ((32 * 7) + 5)
-+#define GPIO_RH_6    ((32 * 7) + 6)
-+#define GPIO_RH_7    ((32 * 7) + 7)
-+#define GPIO_RH_8    ((32 * 7) + 8)
-+#define GPIO_RH_9    ((32 * 7) + 9)
-+
-+#define GPIO_RI_0    ((32 * 8) + 0)
-+#define GPIO_RI_1    ((32 * 8) + 1)
-+#define GPIO_RI_2    ((32 * 8) + 2)
-+#define GPIO_RI_3    ((32 * 8) + 3)
-+#define GPIO_RI_4    ((32 * 8) + 4)
-+#define GPIO_RI_5    ((32 * 8) + 5)
-+#define GPIO_RI_6    ((32 * 8) + 6)
-+#define GPIO_RI_7    ((32 * 8) + 7)
-+#define GPIO_RI_8    ((32 * 8) + 8)
-+#define GPIO_RI_9    ((32 * 8) + 9)
-+#define GPIO_RI_10   ((32 * 8) + 10)
-+#define GPIO_RI_11   ((32 * 8) + 11)
-+#define GPIO_RI_12   ((32 * 8) + 12)
-+#define GPIO_RI_13   ((32 * 8) + 13)
-+#define GPIO_RI_14   ((32 * 8) + 14)
-+#define GPIO_RI_15   ((32 * 8) + 15)
-+
-+/*
-+ * The following section defines extra GPIO available to some boards.
-+ * These GPIO are generally external to the processor (i.e. SPI/I2C
-+ * expander chips).
-+ *
-+ * Note that these defines show all possible GPIO available, however,
-+ * depending on the actual board configuration, some GPIO are not
-+ * available for use.
-+ */
-+#ifdef CONFIG_IP7500MEDIA
-+/*
-+ * U15
-+ */
-+#define IP7500MEDIA_U15_BASE  (32 * 10)
-+#define IP7500MEDIA_IO0               (IP7500MEDIA_U15_BASE + 0)
-+#define IP7500MEDIA_IO1               (IP7500MEDIA_U15_BASE + 1)
-+#define IP7500MEDIA_IO2               (IP7500MEDIA_U15_BASE + 2)
-+#define IP7500MEDIA_IO3               (IP7500MEDIA_U15_BASE + 3)
-+#define IP7500MEDIA_IO4               (IP7500MEDIA_U15_BASE + 4)
-+#define IP7500MEDIA_IO5               (IP7500MEDIA_U15_BASE + 5)
-+#define IP7500MEDIA_IO6               (IP7500MEDIA_U15_BASE + 6)
-+#define IP7500MEDIA_IO7               (IP7500MEDIA_U15_BASE + 7)
-+
-+/*
-+ * U16
-+ */
-+#define IP7500MEDIA_U16_BASE  (32 * 11)
-+#define IP7500MEDIA_IO8               (IP7500MEDIA_U16_BASE + 0)
-+#define IP7500MEDIA_IO9               (IP7500MEDIA_U16_BASE + 1)
-+#define IP7500MEDIA_IO10      (IP7500MEDIA_U16_BASE + 2)
-+#define IP7500MEDIA_IO11      (IP7500MEDIA_U16_BASE + 3)
-+#define IP7500MEDIA_IO12      (IP7500MEDIA_U16_BASE + 4)
-+#define IP7500MEDIA_IO13      (IP7500MEDIA_U16_BASE + 5)
-+#define IP7500MEDIA_IO14      (IP7500MEDIA_U16_BASE + 6)
-+#define IP7500MEDIA_IO15      (IP7500MEDIA_U16_BASE + 7)
-+
-+/*
-+ * U17
-+ */
-+#define IP7500MEDIA_U17_BASE  (32 * 12)
-+#define IP7500MEDIA_IO16      (IP7500MEDIA_U17_BASE + 0)
-+#define IP7500MEDIA_IO17      (IP7500MEDIA_U17_BASE + 1)
-+#define IP7500MEDIA_IO18      (IP7500MEDIA_U17_BASE + 2)
-+#define IP7500MEDIA_IO19      (IP7500MEDIA_U17_BASE + 3)
-+#define IP7500MEDIA_IO20      (IP7500MEDIA_U17_BASE + 4)
-+#define IP7500MEDIA_IO21      (IP7500MEDIA_U17_BASE + 5)
-+#define IP7500MEDIA_IO22      (IP7500MEDIA_U17_BASE + 6)
-+#define IP7500MEDIA_IO23      (IP7500MEDIA_U17_BASE + 7)
-+
-+/*
-+ * U18
-+ */
-+#define IP7500MEDIA_U18_BASE  (32 * 13)
-+#define IP7500MEDIA_IO24      (IP7500MEDIA_U18_BASE + 0)
-+#define IP7500MEDIA_IO25      (IP7500MEDIA_U18_BASE + 1)
-+#define IP7500MEDIA_IO26      (IP7500MEDIA_U18_BASE + 2)
-+#define IP7500MEDIA_IO27      (IP7500MEDIA_U18_BASE + 3)
-+#define IP7500MEDIA_IO28      (IP7500MEDIA_U18_BASE + 4)
-+#define IP7500MEDIA_IO29      (IP7500MEDIA_U18_BASE + 5)
-+#define IP7500MEDIA_IO30      (IP7500MEDIA_U18_BASE + 6)
-+#define IP7500MEDIA_IO31      (IP7500MEDIA_U18_BASE + 7)
-+#endif
-+
-+#ifdef CONFIG_IP7145DPF
-+/*
-+ * U48
-+ */
-+#define IP7145DPF_U48_BASE    (32 * 10)
-+#define IP7145DPF_IO0         (IP7145DPF_U48_BASE + 0)
-+#define IP7145DPF_IO1         (IP7145DPF_U48_BASE + 1)
-+#define IP7145DPF_IO2         (IP7145DPF_U48_BASE + 2)
-+#define IP7145DPF_IO3         (IP7145DPF_U48_BASE + 3)
-+#define IP7145DPF_IO4         (IP7145DPF_U48_BASE + 4)
-+#define IP7145DPF_IO5         (IP7145DPF_U48_BASE + 5)
-+#define IP7145DPF_IO6         (IP7145DPF_U48_BASE + 6)
-+#define IP7145DPF_IO7         (IP7145DPF_U48_BASE + 7)
-+
-+/*
-+ * U72
-+ */
-+#define IP7145DPF_U72_BASE    (32 * 11)
-+#define IP7145DPF_IOB0                (IP7145DPF_U72_BASE + 0)
-+#define IP7145DPF_IOB1                (IP7145DPF_U72_BASE + 1)
-+#define IP7145DPF_IOB2                (IP7145DPF_U72_BASE + 2)
-+#define IP7145DPF_IOB3                (IP7145DPF_U72_BASE + 3)
-+#define IP7145DPF_IOB4                (IP7145DPF_U72_BASE + 4)
-+#define IP7145DPF_IOB5                (IP7145DPF_U72_BASE + 5)
-+#define IP7145DPF_IOB6                (IP7145DPF_U72_BASE + 6)
-+#define IP7145DPF_IOB7                (IP7145DPF_U72_BASE + 7)
-+#endif
-+
-+#include <asm-generic/gpio.h>
-+
-+/*
-+ * The following macros bypass gpiolib to generate direct references
-+ * to the port registers.  These assume, minimally, that either
-+ * gpio_direction_input() or gpio_direction_output() have already been
-+ * called to setup the pin direction and to enable the pin function to
-+ * be gpio.  These macros generate the hardware port address based on
-+ * the assumption that all ports are 32 bits wide (even though we know
-+ * they are not).  This is so we can efficiently turn pin numbers into
-+ * port addresses without a lookup.
-+ *
-+ * These operations must be done in one instruction to prevent clobbering
-+ * other thread's accesses to the same port.
-+ */
-+#define UBICOM32_GPIO_ENABLE(pin)                             \
-+      do {                                                    \
-+              asm volatile ("or.4 (%[port]), (%[port]), %[mask]\n\t"                                          \
-+                              :                                                                               \
-+                              : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_mask),  \
-+                                [mask] "d" (gpio_bit(pin))                                                    \
-+                              : "cc", "memory"                                                                \
-+              );                                                                                              \
-+      } while (0);
-+
-+#define UBICOM32_GPIO_DISABLE(pin)                            \
-+      do {                                                    \
-+              asm volatile ("and.4 (%[port]), (%[port]), %[mask]\n\t"                                         \
-+                              :                                                                               \
-+                              : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_mask),  \
-+                                [mask] "d" (~gpio_bit(pin))                                                   \
-+                              : "cc", "memory"                                                                \
-+              );                                                                                              \
-+      } while (0);
-+
-+#define UBICOM32_GPIO_SET_PIN_INPUT(pin)                      \
-+      do {                                                    \
-+              asm volatile ("and.4 (%[port]), (%[port]), %[mask]\n\t"                                         \
-+                              :                                                                               \
-+                              : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_ctl),   \
-+                                [mask] "d" (~gpio_bit(pin))                                                   \
-+                              : "cc", "memory"                                                                \
-+              );                                                                                              \
-+      } while (0);
-+
-+#define UBICOM32_GPIO_SET_PIN_OUTPUT(pin)                     \
-+      do {                                                    \
-+              asm volatile ("or.4 (%[port]), (%[port]), %[mask]\n\t"                                          \
-+                              :                                                                               \
-+                              : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_ctl),   \
-+                                [mask] "d" (gpio_bit(pin))                                                    \
-+                              : "cc", "memory"                                                                \
-+              );                                                                                              \
-+      } while (0);
-+
-+#define UBICOM32_GPIO_SET_PIN_TOGGLE(pin)                     \
-+      do {                                                    \
-+              asm volatile ("xor.4 (%[port]), (%[port]), %[mask]\n\t"                                         \
-+                              :                                                                               \
-+                              : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_out),   \
-+                                [mask] "d" (gpio_bit(pin))                                                    \
-+                              : "cc", "memory"                                                                \
-+              );                                                                                              \
-+      } while (0);
-+
-+#define UBICOM32_GPIO_SET_PIN_HIGH(pin)                               \
-+      do {                                                    \
-+              asm volatile ("or.4 (%[port]), (%[port]), %[mask]\n\t"                                          \
-+                              :                                                                               \
-+                              : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_out),   \
-+                                [mask] "d" (gpio_bit(pin))                                                    \
-+                              : "cc", "memory"                                                                \
-+              );                                                                                              \
-+      } while (0);
-+
-+#define UBICOM32_GPIO_SET_PIN_LOW(pin)                                \
-+      do {                                                    \
-+              asm volatile ("and.4 (%[port]), (%[port]), %[mask]\n\t"                                         \
-+                              :                                                                               \
-+                              : [port] "a" (&UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_out),   \
-+                                [mask] "d" (~gpio_bit(pin))                                                   \
-+                              : "cc", "memory"                                                                \
-+              );                                                                                              \
-+      } while (0);
-+
-+#define UBICOM32_GPIO_SET_PIN(pin, val) \
-+  if ( val ) {                          \
-+    UBICOM32_GPIO_SET_PIN_HIGH(pin);    \
-+  } else {                              \
-+    UBICOM32_GPIO_SET_PIN_LOW(pin);   \
-+  }
-+
-+#define UBICOM32_GPIO_GET_PIN(pin)                                    \
-+  (0 != (UBICOM32_IO_PORT(IO_BASE + (gpio_bank(pin) << 12))->gpio_in  \
-+       & gpio_bit(pin)))
-+
-+
-+static inline int gpio_get_value(unsigned gpio)
-+{
-+  if (gpio <= MAX_UBICOM_ONCHIP_GPIO)
-+    return UBICOM32_GPIO_GET_PIN(gpio);
-+  else
-+    return __gpio_get_value(gpio);
-+}
-+
-+static inline void gpio_set_value(unsigned gpio, int value)
-+{
-+  if (gpio <= MAX_UBICOM_ONCHIP_GPIO)
-+    {
-+      UBICOM32_GPIO_SET_PIN(gpio, value);
-+    }
-+  else
-+    {
-+      __gpio_set_value(gpio, value);
-+    }
-+}
-+
-+static inline int gpio_cansleep(unsigned gpio)
-+{
-+  return __gpio_cansleep(gpio);
-+}
-+
-+static inline int gpio_to_irq(unsigned gpio)
-+{
-+#if defined(IP5000) || defined(IP5000_REV2)
-+  if ((gpio >= GPIO_RA_4) && (gpio <= GPIO_RA_6))
-+    return 25;
-+  else
-+    return -ENXIO;
-+
-+#elif defined(IP7000) || defined(IP7000_REV2)
-+  if ((gpio >= GPIO_RA_4) && (gpio <= GPIO_RA_6))
-+    return 44 + (gpio - GPIO_RA_4);
-+  else
-+    return -ENXIO;
-+
-+#else
-+    return -ENXIO;
-+
-+#endif
-+}
-+
-+static inline int irq_to_gpio(unsigned gpio)
-+{
-+      return -ENXIO;
-+}
-+
-+extern struct ubicom32_io_port *ubi_gpio_get_port(unsigned gpio);
-+
-+extern int __init ubi_gpio_init(void);
-+
-+#endif /* _ASM_UBICOM32_GPIO_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/hardirq.h
-@@ -0,0 +1,55 @@
-+/*
-+ * arch/ubicom32/include/asm/hardirq.h
-+ *   Definition of ack_bad_irq() for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 1997, 98, 99, 2000, 01, 05 Ralf Baechle (ralf@linux-mips.org)
-+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
-+ * Copyright (C) 2001 MIPS Technologies, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_HARDIRQ_H
-+#define _ASM_UBICOM32_HARDIRQ_H
-+
-+#include <linux/threads.h>
-+#include <linux/irq.h>
-+
-+/*
-+ * The hardirq mask has to be large enough to have space
-+ * for potentially all IRQ sources in the system nesting
-+ * on a single CPU.  For Ubicom32, we have 64 IRQ sources.
-+ */
-+#define HARDIRQ_BITS  6
-+#if (1 << HARDIRQ_BITS) < NR_IRQS
-+# error HARDIRQ_BITS is too low!
-+#endif
-+
-+typedef struct {
-+      unsigned int __softirq_pending;
-+} ____cacheline_aligned irq_cpustat_t;
-+
-+#include <linux/irq_cpustat.h>        /* Standard mappings for irq_cpustat_t above */
-+
-+extern void ack_bad_irq(unsigned int irq);
-+
-+#endif /* _ASM_UBICOM32_HARDIRQ_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/hw_irq.h
-@@ -0,0 +1,31 @@
-+/*
-+ * arch/ubicom32/include/asm/hw_irq.h
-+ *   Ubicom32 architecture APIC support.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_HW_IRQ_H
-+#define _ASM_UBICOM32_HW_IRQ_H
-+
-+#endif /* _ASM_UBICOM32_HW_IRQ_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ioctl.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/ioctl.h
-+ *   Generic ioctl.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_IOCTL_H
-+#define _ASM_UBICOM32_IOCTL_H
-+
-+#include <asm-generic/ioctl.h>
-+
-+#endif /* _ASM_UBICOM32_IOCTL_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ioctls.h
-@@ -0,0 +1,111 @@
-+/*
-+ * arch/ubicom32/include/asm/ioctls.h
-+ *   Definitions of ioctls for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_IOCTLS_H
-+#define _ASM_UBICOM32_IOCTLS_H
-+
-+#include <asm/ioctl.h>
-+
-+/* 0x54 is just a magic number to make these relatively unique ('T') */
-+
-+#define TCGETS                0x5401
-+#define TCSETS                0x5402
-+#define TCSETSW               0x5403
-+#define TCSETSF               0x5404
-+#define TCGETA                0x5405
-+#define TCSETA                0x5406
-+#define TCSETAW               0x5407
-+#define TCSETAF               0x5408
-+#define TCSBRK                0x5409
-+#define TCXONC                0x540A
-+#define TCFLSH                0x540B
-+#define TIOCEXCL      0x540C
-+#define TIOCNXCL      0x540D
-+#define TIOCSCTTY     0x540E
-+#define TIOCGPGRP     0x540F
-+#define TIOCSPGRP     0x5410
-+#define TIOCOUTQ      0x5411
-+#define TIOCSTI               0x5412
-+#define TIOCGWINSZ    0x5413
-+#define TIOCSWINSZ    0x5414
-+#define TIOCMGET      0x5415
-+#define TIOCMBIS      0x5416
-+#define TIOCMBIC      0x5417
-+#define TIOCMSET      0x5418
-+#define TIOCGSOFTCAR  0x5419
-+#define TIOCSSOFTCAR  0x541A
-+#define FIONREAD      0x541B
-+#define TIOCINQ               FIONREAD
-+#define TIOCLINUX     0x541C
-+#define TIOCCONS      0x541D
-+#define TIOCGSERIAL   0x541E
-+#define TIOCSSERIAL   0x541F
-+#define TIOCPKT               0x5420
-+#define FIONBIO               0x5421
-+#define TIOCNOTTY     0x5422
-+#define TIOCSETD      0x5423
-+#define TIOCGETD      0x5424
-+#define TCSBRKP               0x5425  /* Needed for POSIX tcsendbreak() */
-+#define TIOCSBRK      0x5427  /* BSD compatibility */
-+#define TIOCCBRK      0x5428  /* BSD compatibility */
-+#define TIOCGSID      0x5429  /* Return the session ID of FD */
-+#define TCGETS2               _IOR('T',0x2A, struct termios2)
-+#define TCSETS2               _IOW('T',0x2B, struct termios2)
-+#define TCSETSW2      _IOW('T',0x2C, struct termios2)
-+#define TCSETSF2      _IOW('T',0x2D, struct termios2)
-+#define TIOCGPTN      _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
-+#define TIOCSPTLCK    _IOW('T',0x31, int)  /* Lock/unlock Pty */
-+
-+#define FIONCLEX      0x5450  /* these numbers need to be adjusted. */
-+#define FIOCLEX               0x5451
-+#define FIOASYNC      0x5452
-+#define TIOCSERCONFIG 0x5453
-+#define TIOCSERGWILD  0x5454
-+#define TIOCSERSWILD  0x5455
-+#define TIOCGLCKTRMIOS        0x5456
-+#define TIOCSLCKTRMIOS        0x5457
-+#define TIOCSERGSTRUCT        0x5458 /* For debugging only */
-+#define TIOCSERGETLSR   0x5459 /* Get line status register */
-+#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
-+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
-+
-+#define TIOCMIWAIT    0x545C  /* wait for a change on serial input line(s) */
-+#define TIOCGICOUNT   0x545D  /* read serial port inline interrupt counts */
-+#define FIOQSIZE      0x545E
-+
-+/* Used for packet mode */
-+#define TIOCPKT_DATA           0
-+#define TIOCPKT_FLUSHREAD      1
-+#define TIOCPKT_FLUSHWRITE     2
-+#define TIOCPKT_STOP           4
-+#define TIOCPKT_START          8
-+#define TIOCPKT_NOSTOP                16
-+#define TIOCPKT_DOSTOP                32
-+
-+#define TIOCSER_TEMT    0x01  /* Transmitter physically empty */
-+
-+#endif /* _ASM_UBICOM32_IOCTLS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/io.h
-@@ -0,0 +1,313 @@
-+/*
-+ * arch/ubicom32/include/asm/io.h
-+ *   I/O memory accessor functions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_IO_H
-+#define _ASM_UBICOM32_IO_H
-+
-+#ifdef __KERNEL__
-+#include <linux/string.h>
-+#include <linux/compiler.h>
-+
-+static inline unsigned short _swapw(volatile unsigned short v)
-+{
-+    return ((v << 8) | (v >> 8));
-+}
-+
-+static inline unsigned int _swapl(volatile unsigned long v)
-+{
-+    return ((v << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24));
-+}
-+
-+#ifndef CONFIG_PCI
-+#define readb(addr) \
-+    ({ unsigned char __v = (*(volatile unsigned char *) (addr)); __v; })
-+#define readw(addr) \
-+    ({ unsigned short __v = (*(volatile unsigned short *) (addr)); __v; })
-+#define readl(addr) \
-+    ({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
-+
-+#define writeb(b,addr) (void)((*(volatile unsigned char *) (addr)) = (b))
-+#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b))
-+#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b))
-+#else /*CONFIG_PCI */
-+
-+#define PCI_CPU_REG_BASE (0x00000000UL)   /* taking lower 2GB space */
-+#define PCI_DEV_REG_BASE (0x80000000UL)
-+
-+#if PCI_CPU_REG_BASE > PCI_DEV_REG_BASE
-+#define IS_PCI_ADDRESS(x) (((unsigned int)(x)&(PCI_CPU_REG_BASE)) == 0)
-+#else
-+#define IS_PCI_ADDRESS(x) ((unsigned int)(x)&(PCI_DEV_REG_BASE))
-+#endif
-+
-+extern unsigned int ubi32_pci_read_u32(const volatile void __iomem *addr);
-+extern unsigned short ubi32_pci_read_u16(const volatile void __iomem *addr);
-+extern unsigned char ubi32_pci_read_u8(const volatile void __iomem *addr);
-+extern  void ubi32_pci_write_u32(unsigned int val, const volatile void __iomem *addr);
-+extern  void ubi32_pci_write_u16(unsigned short val, const volatile void __iomem *addr);
-+extern  void ubi32_pci_write_u8(unsigned char val, const volatile void __iomem *addr);
-+
-+static  inline unsigned char readb(const volatile void __iomem *addr)
-+{
-+      if (IS_PCI_ADDRESS(addr))
-+              return ubi32_pci_read_u8(addr);
-+      else
-+              return (unsigned char)(*(volatile unsigned char *)addr);
-+}
-+static inline unsigned short readw(const volatile void __iomem *addr)
-+{
-+      if (IS_PCI_ADDRESS(addr))
-+              return ubi32_pci_read_u16(addr);
-+      else
-+              return (unsigned short)(*(volatile unsigned short *)addr);
-+}
-+
-+static  inline unsigned int  readl(const volatile void __iomem *addr)
-+{
-+      if (IS_PCI_ADDRESS(addr))
-+              return ubi32_pci_read_u32(addr);
-+      else
-+              return (unsigned int)(*(volatile unsigned int *)addr);
-+}
-+
-+static inline void writel(unsigned int val, volatile void __iomem *addr)
-+{
-+      if (IS_PCI_ADDRESS(addr))
-+                ubi32_pci_write_u32(val, addr);
-+        else
-+              *(volatile unsigned int *)addr = val;
-+}
-+
-+static inline void writew(unsigned short val, volatile void __iomem *addr)
-+{
-+      if (IS_PCI_ADDRESS(addr))
-+                ubi32_pci_write_u16(val, addr);
-+        else
-+              *(volatile unsigned short *)addr = val;
-+}
-+
-+static inline void writeb(unsigned char val, volatile void __iomem *addr)
-+{
-+      if (IS_PCI_ADDRESS(addr))
-+                ubi32_pci_write_u8(val, addr);
-+        else
-+              *(volatile unsigned char *)addr = val;
-+}
-+#endif
-+
-+#define readb_relaxed(addr) readb(addr)
-+#define readw_relaxed(addr) readw(addr)
-+#define readl_relaxed(addr) readl(addr)
-+
-+
-+#define __raw_readb readb
-+#define __raw_readw readw
-+#define __raw_readl readl
-+#define __raw_writeb writeb
-+#define __raw_writew writew
-+#define __raw_writel writel
-+
-+static inline void io_outsb(unsigned int addr, const void *buf, int len)
-+{
-+      volatile unsigned char *ap = (volatile unsigned char *) addr;
-+      unsigned char *bp = (unsigned char *) buf;
-+      while (len--)
-+              *ap = *bp++;
-+}
-+
-+static inline void io_outsw(unsigned int addr, const void *buf, int len)
-+{
-+      volatile unsigned short *ap = (volatile unsigned short *) addr;
-+      unsigned short *bp = (unsigned short *) buf;
-+      while (len--)
-+              *ap = _swapw(*bp++);
-+}
-+
-+static inline void io_outsl(unsigned int addr, const void *buf, int len)
-+{
-+      volatile unsigned int *ap = (volatile unsigned int *) addr;
-+      unsigned int *bp = (unsigned int *) buf;
-+      while (len--)
-+              *ap = _swapl(*bp++);
-+}
-+
-+static inline void io_insb(unsigned int addr, void *buf, int len)
-+{
-+      volatile unsigned char *ap = (volatile unsigned char *) addr;
-+      unsigned char *bp = (unsigned char *) buf;
-+      while (len--)
-+              *bp++ = *ap;
-+}
-+
-+static inline void io_insw(unsigned int addr, void *buf, int len)
-+{
-+      volatile unsigned short *ap = (volatile unsigned short *) addr;
-+      unsigned short *bp = (unsigned short *) buf;
-+      while (len--)
-+              *bp++ = _swapw(*ap);
-+}
-+
-+static inline void io_insl(unsigned int addr, void *buf, int len)
-+{
-+      volatile unsigned int *ap = (volatile unsigned int *) addr;
-+      unsigned int *bp = (unsigned int *) buf;
-+      while (len--)
-+              *bp++ = _swapl(*ap);
-+}
-+
-+#define mmiowb()
-+
-+/*
-+ *    make the short names macros so specific devices
-+ *    can override them as required
-+ */
-+#ifndef CONFIG_PCI
-+#define memset_io(a,b,c)      memset((void *)(a),(b),(c))
-+#define memcpy_fromio(a,b,c)  memcpy((a),(void *)(b),(c))
-+#define memcpy_toio(a,b,c)    memcpy((void *)(a),(b),(c))
-+#else
-+extern void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned len);
-+extern void memcpy_toio(volatile void __iomem *to, const void *from, unsigned len);
-+extern void memset_io(volatile void __iomem *addr, int val, size_t count);
-+#endif
-+
-+#define inb(addr)    readb(addr)
-+#define inw(addr)    readw(addr)
-+#define inl(addr)    readl(addr)
-+#define outb(x,addr) ((void) writeb(x,addr))
-+#define outw(x,addr) ((void) writew(x,addr))
-+#define outl(x,addr) ((void) writel(x,addr))
-+
-+#define inb_p(addr)    inb(addr)
-+#define inw_p(addr)    inw(addr)
-+#define inl_p(addr)    inl(addr)
-+#define outb_p(x,addr) outb(x,addr)
-+#define outw_p(x,addr) outw(x,addr)
-+#define outl_p(x,addr) outl(x,addr)
-+
-+#define outsb(a,b,l) io_outsb(a,b,l)
-+#define outsw(a,b,l) io_outsw(a,b,l)
-+#define outsl(a,b,l) io_outsl(a,b,l)
-+
-+#define insb(a,b,l) io_insb(a,b,l)
-+#define insw(a,b,l) io_insw(a,b,l)
-+#define insl(a,b,l) io_insl(a,b,l)
-+
-+#ifndef CONFIG_PCI
-+#define ioread8_rep(a,d,c)    insb(a,d,c)
-+#define ioread16_rep(a,d,c)   insw(a,d,c)
-+#define ioread32_rep(a,d,c)   insl(a,d,c)
-+#define iowrite8_rep(a,s,c)   outsb(a,s,c)
-+#define iowrite16_rep(a,s,c)  outsw(a,s,c)
-+#define iowrite32_rep(a,s,c)  outsl(a,s,c)
-+#else
-+extern void  ioread8_rep(void __iomem *port, void *buf, unsigned long count);
-+extern void  ioread16_rep(void __iomem *port, void *buf, unsigned long count);
-+extern void  ioread32_rep(void __iomem *port, void *buf, unsigned long count);
-+extern void  iowrite8_rep(void __iomem *port, const void *buf, unsigned long count);
-+extern void  iowrite16_rep(void __iomem *port, const void *buf, unsigned long count);
-+extern void  iowrite32_rep(void __iomem *port, const void *buf, unsigned long count);
-+#endif
-+
-+
-+#ifndef CONFIG_PCI
-+#define ioread8(X)                    readb(X)
-+#define ioread16(X)                   readw(X)
-+#define ioread32(X)                   readl(X)
-+#define iowrite8(val,X)                       writeb(val,X)
-+#define iowrite16(val,X)              writew(val,X)
-+#define iowrite32(val,X)              writel(val,X)
-+#else /*CONFIG_PCI */
-+extern  unsigned char  ioread8(void __iomem *addr);
-+extern  unsigned short ioread16(void __iomem *addr);
-+extern  unsigned int  ioread32(void __iomem *addr);
-+extern  void iowrite8(unsigned char val, void __iomem *addr);
-+extern  void iowrite16(unsigned short val, void __iomem *addr);
-+extern  void iowrite32(unsigned int val, void __iomem *addr);
-+#endif /* CONFIG_PCI */
-+
-+#define IO_SPACE_LIMIT 0xffff
-+
-+/* Values for nocacheflag and cmode */
-+#define IOMAP_FULL_CACHING            0
-+#define IOMAP_NOCACHE_SER             1
-+#define IOMAP_NOCACHE_NONSER          2
-+#define IOMAP_WRITETHROUGH            3
-+
-+extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag);
-+extern void __iounmap(void *addr, unsigned long size);
-+
-+static inline void *ioremap(unsigned long physaddr, unsigned long size)
-+{
-+      return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
-+}
-+static inline void *ioremap_nocache(unsigned long physaddr, unsigned long size)
-+{
-+      return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
-+}
-+static inline void *ioremap_writethrough(unsigned long physaddr, unsigned long size)
-+{
-+      return __ioremap(physaddr, size, IOMAP_WRITETHROUGH);
-+}
-+static inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size)
-+{
-+      return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
-+}
-+
-+extern void iounmap(void *addr);
-+
-+#define ioport_map(port, nr)            ((void __iomem*)(port))
-+#define ioport_unmap(addr)
-+
-+
-+/* Pages to physical address... */
-+#define page_to_phys(page)      ((page - mem_map) << PAGE_SHIFT)
-+#define page_to_bus(page)       ((page - mem_map) << PAGE_SHIFT)
-+
-+/*
-+ * Macros used for converting between virtual and physical mappings.
-+ */
-+#define phys_to_virt(vaddr)   ((void *) (vaddr))
-+#define virt_to_phys(vaddr)   ((unsigned long) (vaddr))
-+
-+#define virt_to_bus virt_to_phys
-+#define bus_to_virt phys_to_virt
-+
-+/*
-+ * 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
-+
-+#endif /* __KERNEL__ */
-+
-+#endif /* _ASM_UBICOM32_IO_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ip5000-asm.h
-@@ -0,0 +1,156 @@
-+/*
-+ * arch/ubicom32/include/asm/ip5000-asm.h
-+ *    Instruction macros for the IP5000.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_IP5000_ASM_H
-+#define _ASM_UBICOM32_IP5000_ASM_H
-+
-+#if !defined(__LINKER__)
-+
-+#if defined(__ASSEMBLY__)
-+.macro        cycles  quant
-+.if   (\quant) == 1
-+      nop
-+.else
-+.if   (((\quant) + 3) / 8) > 0
-+.rept (((\quant) + 3) / 8)
-+      jmpt.f          .+4
-+.endr
-+.endif
-+.if   ((((\quant) + 3) % 8) / 4) > 0
-+      jmpt.t          .+4
-+.endif
-+.endif
-+.endm
-+#else
-+/*
-+ * Same macro as above just in C inline asm
-+ */
-+asm ("                                        \n\
-+.macro        cycles  quant                   \n\
-+.if   (\\quant) == 1                  \n\
-+      nop                             \n\
-+.else                                 \n\
-+.if   (((\\quant) + 3) / 8) > 0       \n\
-+.rept (((\\quant) + 3) / 8)           \n\
-+      jmpt.f          .+4             \n\
-+.endr                                 \n\
-+.endif                                        \n\
-+.if   ((((\\quant) + 3) % 8) / 4) > 0 \n\
-+      jmpt.t          .+4             \n\
-+.endif                                        \n\
-+.endif                                        \n\
-+.endm                                 \n\
-+");
-+#endif
-+
-+
-+#if defined(__ASSEMBLY__)
-+.macro        pipe_flush      cyc
-+      cycles          11 - (\cyc)
-+.endm
-+#else
-+/*
-+ * Same macro as above just in C inline asm
-+ */
-+asm ("                                        \n\
-+.macro        pipe_flush      cyc             \n\
-+      cycles          11 - (\\cyc)    \n\
-+.endm                                 \n\
-+");
-+
-+#endif
-+
-+#if defined(__ASSEMBLY__)
-+.macro        setcsr_flush    cyc
-+      cycles          5 - (\cyc)
-+.endm
-+#else
-+/*
-+ * Same macro as above just in C inline asm
-+ */
-+asm ("                                        \n\
-+.macro        setcsr_flush    cyc             \n\
-+      cycles          5 - (\\cyc)     \n\
-+.endm                                 \n\
-+");
-+#endif
-+
-+/*
-+ * Macros for prefetch (using miss-aligned memory write)
-+ */
-+#if defined(__ASSEMBLY__)
-+
-+.macro        pre_fetch_macro thread_num, Ascratch, Aaddress length
-+      bclr            MT_TRAP_EN, MT_TRAP_EN, #(\thread_num)
-+      bset            \Ascratch, \Aaddress, #0        ; force a miss-aligned address
-+      jmpt.t          .+4                             ; delay for both address setup and trap disable
-+      move.4          (\Ascratch), #0
-+      .if             (\length > 32)
-+      move.4          32(\Ascratch), #0
-+      .endif
-+      .if             (\length > 64)
-+      move.4          64(\Ascratch), #0
-+      .endif
-+      .if             (\length > 96)
-+      move.4          96(\Ascratch), #0
-+      .endif
-+      .if             (\length > 128)
-+      invalid_instruction                             ; maximum pre-fetch size is 4 cache lines
-+      .endif
-+      bset            MT_TRAP_EN, MT_TRAP_EN, #(\thread_num)
-+.endm
-+
-+#else
-+/*
-+ * Same macro as above just in C inline asm
-+ */
-+asm ("                                                                \n\
-+.macro        pre_fetch_macro thread_num, Ascratch, Aaddress length   \n\
-+      bclr            MT_TRAP_EN, MT_TRAP_EN, #(\thread_num)  \n\
-+      bset            \\Ascratch, \\Aaddress, #0      ; force a miss-aligned address \n\
-+      jmpt.t          .+4                             ; delay for both address setup and trap disable \n\
-+      move.4          (\\Ascratch), #0                        \n\
-+      .if             (\\length > 32)                         \n\
-+      move.4          32(\\Ascratch), #0                      \n\
-+      .endif                                                  \n\
-+      .if             (\\length > 64)                         \n\
-+      move.4          64(\\Ascratch), #0                      \n\
-+      .endif                                                  \n\
-+      .if             (\\length > 96)                         \n\
-+      move.4          96(\\Ascratch), #0                      \n\
-+      .endif                                                  \n\
-+      .if             (\\length > 128)                        \n\
-+      invalid_instruction                             ; maximum pre-fetch size is 4 cache lines \n\
-+      .endif                                                  \n\
-+      bset            MT_TRAP_EN, MT_TRAP_EN, #(\\thread_num) \n\
-+.endm                                                         \n\
-+");
-+#endif
-+
-+#endif /* !defined(__LINKER__) */
-+#endif /* defined _ASM_UBICOM32_IP5000_ASM_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ip5000.h
-@@ -0,0 +1,845 @@
-+/*
-+ * arch/ubicom32/include/asm/ip5000.h
-+ *   Specific details for the Ubicom IP5000 processor.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_IP5000_H
-+#define _ASM_UBICOM32_IP5000_H
-+
-+#include <asm/memory_map.h>
-+
-+/*
-+ * Inline assembly define
-+ */
-+#define S(arg) #arg
-+#define D(arg) S(arg)
-+
-+/*
-+ * Assembler include file
-+ */
-+#include <asm/ip5000-asm.h>
-+
-+/*
-+ * Timing
-+ */
-+#define JMPT_PENALTY 3
-+#define JMPF_PENALTY 7
-+#define RET_PENALTY 7
-+
-+/*
-+ * Threads
-+ */
-+#if defined(IP5000) || defined(IP5000_REV2)
-+#define THREAD_COUNT 10
-+#elif defined(IP7000) || defined(IP7000_REV2)
-+#define THREAD_COUNT 12
-+#else
-+#error "Unknown IP5K silicon"
-+#endif
-+
-+/*
-+ * Arch
-+ */
-+#if defined(IP5000) || defined(IP5000_REV2)
-+#define UBICOM32_ARCH_VERSION 3
-+#elif defined(IP7000) || defined(IP7000_REV2)
-+#define UBICOM32_ARCH_VERSION 4
-+#else
-+#error "Unknown IP5K silicon"
-+#endif
-+
-+
-+/*
-+ * Registers
-+ */
-+#define ROSR_INT (1 << 0)
-+
-+/* Interrupts */
-+#define INT_CHIP(reg, bit) (((reg) << 5) | (bit))
-+#define INT_REG(interrupt) (((interrupt) >> 5) * 4)
-+#define INT_SET(interrupt) 0x0114 + INT_REG(interrupt)
-+#define INT_CLR(interrupt) 0x0124 + INT_REG(interrupt)
-+#define INT_STAT(interrupt) 0x0104 + INT_REG(interrupt)
-+#define INT_MASK(interrupt) 0x00C0 + INT_REG(interrupt)
-+#define INT_BIT(interrupt) ((interrupt) & 0x1F)
-+#define INT_BIT_MASK(interrupt) (1 << INT_BIT(interrupt))
-+
-+/*
-+ * The LOCK_INT and THREAD_INT are used to wake up corresponding thread. They are sharing
-+ * the same set of SW interrupt resource.
-+ *
-+ * LOCK_INT(n): One SW INT per NRT thread that can participate lock operation.
-+ *    The threads that can participate lock are application threads and DSR thread.
-+ *    (Lock locks - numbers are hard-coded in lock.h)
-+ * THREAD_INT(n):   One SW INT per HRT thread for wake up trigger.
-+ */
-+#define LOCK_INT(thread)      INT_CHIP(0, (thread))
-+#define THREAD_INT(thread)    INT_CHIP(0, (thread))
-+
-+/*
-+ * The SYSTEM_INT and DSR_INT are sharing the same set of SW interrupt resource.
-+ *
-+ * SYSTEM_INT(n): One SW INT per NRT threads (application threads) as system queue interrupt,
-+ *    and for DSR as self-trigger interrupt.
-+ *    (The application threads include at least thread 0)
-+ * DSR_INT(n):    One SW INT per HRT thread to request DSR service.
-+ */
-+#define SYSTEM_INT(thread)    INT_CHIP(0, THREAD_COUNT + (thread))
-+#define DSR_INT(thread)               INT_CHIP(0, THREAD_COUNT + (thread))
-+
-+/* GLOBAL_CTRL */
-+#define GLOBAL_CTRL_TRAP_RST_EN (1 << 9)
-+#define GLOBAL_CTRL_AERROR_RST_EN (1 << 8)
-+#define GLOBAL_CTRL_MT_MIN_DELAY(x) ((x) << 3)
-+#define GLOBAL_CTRL_HRT_BANK_SELECT (1 << 2)
-+#define GLOBAL_CTRL_INT_EN (1 << 0)
-+
-+/*
-+ * HRT Tables
-+ */
-+#define HRT_TABLE0_BASE 0x0800
-+#define HRT_TABLE1_BASE 0x0900
-+#define HRT_TABLE_SIZE 64
-+
-+/*
-+ * Break Point Trap Register
-+ */
-+#define ASYNCERROR_INT INT_CHIP(0, 31)
-+#define BREAKPOINT_INT INT_CHIP(1, 31)
-+
-+/*
-+ * Port interrupts
-+ *    The non-existing FIFO INTs are mapped to INT2 for the ports.
-+ */
-+#define IO_PORT_PTR_TO_NUM(port) (((port) & 0x0000ffff) >> 12)
-+#define RX_FIFO_INT(port) \
-+      ((IO_PORT_PTR_TO_NUM(port) == 0) ? INT_CHIP(0, 25) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 1) ? INT_CHIP(0, 26) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 2) ? INT_CHIP(0, 29) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 3) ? INT_CHIP(1, 24) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 4) ? INT_CHIP(1, 27) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 5) ? INT_CHIP(1, 16) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 6) ? INT_CHIP(1, 19) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 7) ? INT_CHIP(1, 20) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 8) ? INT_CHIP(1, 21) : \
-+      INT_CHIP(1, 15))))))))))
-+#define TX_FIFO_INT(port) \
-+      ((IO_PORT_PTR_TO_NUM(port) == 0) ? INT_CHIP(0, 24) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 1) ? INT_CHIP(0, 27) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 2) ? INT_CHIP(0, 29) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 3) ? INT_CHIP(1, 25) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 4) ? INT_CHIP(1, 28) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 5) ? INT_CHIP(1, 17) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 6) ? INT_CHIP(1, 19) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 7) ? INT_CHIP(1, 20) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 8) ? INT_CHIP(1, 22) : \
-+      INT_CHIP(1, 15))))))))))
-+#define PORT_OTHER_INT(port) \
-+      ((IO_PORT_PTR_TO_NUM(port) == 0) ? INT_CHIP(0, 25) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 1) ? INT_CHIP(0, 28) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 2) ? INT_CHIP(0, 29) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 3) ? INT_CHIP(1, 26) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 4) ? INT_CHIP(1, 29) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 5) ? INT_CHIP(1, 18) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 6) ? INT_CHIP(1, 19) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 7) ? INT_CHIP(1, 20) : \
-+      ((IO_PORT_PTR_TO_NUM(port) == 8) ? INT_CHIP(1, 23) : \
-+      INT_CHIP(1, 15))))))))))
-+
-+/*
-+ * On Chip Peripherals Base.
-+ */
-+#define OCP_BASE      0x01000000
-+#define OCP_GENERAL   0x000
-+#define OCP_TIMERS    0x100
-+#define OCP_TRNG      0x200   /* True Random Number Generator Control Reigsters */
-+#define OCP_DEBUG     0x300
-+#define OCP_SECURITY  0x400
-+#define OCP_ICCR      0x500   /* I-Cache Control Registers */
-+#define OCP_DCCR      0x600   /* D-Cache Control Registers */
-+#define OCP_OCMC      0x700   /* On Chip Memory Control Registers */
-+#define OCP_STATISTICS        0x800   /* Statistics Counters */
-+#define OCP_MTEST     0x900   /* Memory Test Registers */
-+#define OCP_MCFG      0xa00   /* Memory Configuration Registers -- IP7000 only */
-+#define OCP_DEBUG_INST        0x000   /* Up to 16M */
-+
-+/*
-+ * General Configuration Registers (PLL)
-+ */
-+#define GENERAL_CFG_BASE (OCP_BASE + OCP_GENERAL)
-+#define GEN_CLK_CORE_CFG 0x00
-+#define GEN_CLK_IO_CFG 0x04
-+#define GEN_CLK_DDR_CFG 0x08
-+#define GEN_CLK_DDRDS_CFG 0x0c
-+#define GEN_CLK_SLIP_CLR 0x10
-+#define GEN_CLK_SLIP_START 0x14
-+#define GEN_CLK_SERDES_SEL 0x18       /* IP7000 only */
-+#define GEN_CLK_DDR_CFG2 0x1c /* IP7000 only */
-+#define GEN_DDR_CAL_CTRL 0x30 /* IP5000 only */
-+#define GEN_DDR_CAL_STAT 0x34 /* IP5000 only */
-+#define GEN_USB_DFT_CTRL 0x38 /* IP5000 only */
-+#define GEN_USB_DFT_STAT 0x3c /* IP5000 only */
-+#define GEN_USB_PHY_CFG 0x40  /* IP7000 only */
-+#define GEN_USB_PHY_TEST 0x44 /* IP7000 only */
-+#define GEN_USB_PHY_STAT 0x48 /* IP7000 only */
-+#define GEN_SW_RESET 0x80
-+#define GEN_RESET_REASON 0x84
-+#define GEN_BOND_CFG 0x88
-+#define GEN_IO_PU_CFG 0x8c
-+#define GEN_MEM_RM_CFG 0x90
-+#define GEN_IO_CONFIG 0x94
-+
-+#define GEN_CLK_PLL_SECURITY_BIT_NO 31
-+#define GEN_CLK_PLL_SECURITY (1 << GEN_CLK_PLL_SECURITY_BIT_NO)
-+#define GEN_CLK_PLL_ENSAT (1 << 30)
-+#define GEN_CLK_PLL_FASTEN (1 << 29)
-+#define GEN_CLK_PLL_NR(v) (((v) - 1) << 23)
-+#define GEN_CLK_PLL_NF(v) (((v) - 1) << 11)
-+#define GEN_CLK_PLL_OD(v) (((v) - 1) << 8)
-+#define GEN_CLK_PLL_RESET (1 << 7)
-+#define GEN_CLK_PLL_BYPASS (1 << 6)
-+#define GEN_CLK_PLL_POWERDOWN (1 << 5)
-+#define GEN_CLK_PLL_SELECT (1 << 4)
-+
-+#define GEN_GET_CLK_PLL_NR(v) ((((v) >> 23) & 0x003f) + 1)
-+#define GEN_GET_CLK_PLL_NF(v) ((((v) >> 11) & 0x0fff) + 1)
-+#define GEN_GET_CLK_PLL_OD(v) ((((v) >> 8) & 0x7) + 1)
-+
-+
-+#define RESET_FLAG_DST_MEM_ERROR (1 << 18)
-+#define RESET_FLAG_SRC1_MEM_ERROR (1 << 17)
-+#define RESET_FLAG_WRITE_ADDR (1 << 16)
-+#define RESET_FLAG_DST_SYNC_ERROR (1 << 15)
-+#define RESET_FLAG_SRC1_SYNC_ERROR (1 << 14)
-+#define RESET_FLAG_DST_ALGN_ERROR (1 << 13)
-+#define RESET_FLAG_SRC1_ALGN_ERROR (1 << 12)
-+#define RESET_FLAG_DST_ADDR_ERROR (1 << 11)
-+#define RESET_FLAG_SRC1_ADDR_ERROR (1 << 10)
-+#define RESET_FLAG_ILLEGAL_INST (1 << 9)
-+#define RESET_FLAG_INST_SYNC_ERROR (1 << 8)
-+#define RESET_FLAG_INST_ADDR_ERROR (1 << 7)
-+#define RESET_FLAG_DATA_PORT_ERROR (1 << 6)
-+#define RESET_FLAG_INST_PORT_ERROR (1 << 5)
-+#define RESET_FLAG_SW_RESET (1 << 4)
-+#define RESET_FLAG_DEBUG (1 << 3)
-+#define RESET_FLAG_WATCHDOG (1 << 2)
-+#define RESET_FLAG_POWER_ON (1 << 1)
-+#define RESET_FLAG_EXTERNAL (1 << 0)
-+
-+/*
-+ * Timer block
-+ */
-+#define TIMER_BASE (OCP_BASE + OCP_TIMERS)
-+#define TIMER_MPTVAL 0x00
-+#define TIMER_RTCOM 0x04
-+#define TIMER_TKEY 0x08
-+#define TIMER_WDCOM 0x0c
-+#define TIMER_WDCFG 0x10
-+#define TIMER_SYSVAL 0x14
-+#define TIMER_SYSCOM(tmr) (0x18 + (tmr) * 4)
-+#define TIMER_TRN_CFG 0x100
-+#define TIMER_TRN 0x104
-+
-+#define TIMER_COUNT 10
-+#define TIMER_INT(tmr) INT_CHIP(1, (tmr))
-+#define TIMER_TKEYVAL 0xa1b2c3d4
-+#define TIMER_WATCHDOG_DISABLE 0x4d3c2b1a
-+#define TIMER_TRN_CFG_ENABLE_OSC 0x00000007
-+
-+#ifndef __ASSEMBLY__
-+/*
-+ * ubicom32_io_timer
-+ */
-+struct ubicom32_io_timer {
-+      volatile u32_t mptval;
-+      volatile u32_t rtcom;
-+      volatile u32_t tkey;
-+      volatile u32_t wdcom;
-+      volatile u32_t wdcfg;
-+      volatile u32_t sysval;
-+      volatile u32_t syscom[TIMER_COUNT];
-+      volatile u32_t reserved[64 - 6 - TIMER_COUNT];  // skip all the way to OCP-TRNG section
-+      volatile u32_t rsgcfg;
-+      volatile u32_t trn;
-+};
-+
-+#define UBICOM32_IO_TIMER ((struct ubicom32_io_timer *)TIMER_BASE)
-+#endif
-+
-+#define UBICOM32_VECTOR_TO_TIMER_INDEX(vector) (vector - TIMER_INT(0))
-+
-+/*
-+ * OCP-Debug Module (Mailbox)
-+ */
-+#define ISD_MAILBOX_BASE (OCP_BASE + OCP_DEBUG)
-+#define ISD_MAILBOX_IN 0x00
-+#define ISD_MAILBOX_OUT 0x04
-+#define ISD_MAILBOX_STATUS 0x08
-+
-+#define ISD_MAILBOX_INT INT_CHIP(1, 30)
-+
-+#define ISD_MAILBOX_STATUS_IN_FULL (1 << 31)
-+#define ISD_MAILBOX_STATUS_IN_EMPTY (1 << 30)
-+#define ISD_MAILBOX_STATUS_OUT_FULL (1 << 29)
-+#define ISD_MAILBOX_STATUS_OUT_EMPTY (1 << 28)
-+
-+/*
-+ * OCP-Security
-+ */
-+#define SECURITY_BASE (OCP_BASE + OCP_SECURITY)
-+#define SECURITY_BASE_EFFECTIVE_ADDRESS (SECURITY_BASE >> 7) // To load the base address in a single instruction
-+#define SECURITY_CTRL 0x00
-+#define SECURITY_CTRL_BYTE_OFFSET(x) ((x) << 16)
-+#define SECURITY_CTRL_KEY_SIZE(x) ((x) << 8)
-+#define SECURITY_CTRL_HASH_ALG_NONE (0 << 4)
-+#define SECURITY_CTRL_HASH_ALG_MD5 (1 << 4)
-+#define SECURITY_CTRL_HASH_ALG_SHA1 (2 << 4)
-+#define SECURITY_CTRL_CBC (1 << 3)
-+#define SECURITY_CTRL_CIPHER_ALG_AES (0 << 1)
-+#define SECURITY_CTRL_CIPHER_ALG_NONE (1 << 1)
-+#define SECURITY_CTRL_CIPHER_ALG_DES (2 << 1)
-+#define SECURITY_CTRL_CIPHER_ALG_3DES (3 << 1)
-+#define SECURITY_CTRL_ENCIPHER (1 << 0)
-+#define SECURITY_CTRL_DECIPHER (0 << 0)
-+#define SECURITY_STAT 0x04
-+#define SECURITY_STAT_BUSY (1 << 0)
-+#define SECURITY_KEY_VALUE(x) (0x10 + (x) * 4)
-+#define SECURITY_KEY_IN(x) (0x30 + (x) * 4)
-+#define SECURITY_KEY_OUT(x) (0x50 + (x) * 4)
-+#define SECURITY_KEY_HASH(x) (0x70 + (x) * 4)
-+
-+/*
-+ * OCP-ICCR
-+ */
-+#define ICCR_BASE (OCP_BASE + OCP_ICCR)
-+#define ICACHE_TOTAL_SIZE 16384                       /* in bytes */
-+
-+/*
-+ * OCP-DCCR
-+ */
-+#define DCCR_BASE (OCP_BASE + OCP_DCCR)
-+#if defined(IP5000) || defined(IP5000_REV2)
-+#define DCACHE_TOTAL_SIZE 8192                        /* in bytes */
-+#elif defined(IP7000) || defined(IP7000_REV2)
-+#define DCACHE_TOTAL_SIZE 16384                       /* in bytes */
-+#endif
-+
-+#if defined(IP5000) || defined(IP5000_REV2) || defined(IP7000) || defined(IP7000_REV2)
-+#define DCACHE_WRITE_QUEUE_LENGTH 6
-+#else
-+#error "Unknown IP5K silicon"
-+#endif
-+
-+#define CACHE_LINE_SIZE 32                    /* in bytes */
-+
-+#define CCR_ADDR 0x00
-+#define CCR_RDD 0x04
-+#define CCR_WRD 0x08
-+#define CCR_STAT 0x0c
-+#define CCR_CTRL 0x10
-+
-+#define CCR_STAT_MCBE 0
-+#define CCR_STAT_WIDEL 1                      /* D-cache only */
-+
-+#define CCR_CTRL_DONE 0
-+#define CCR_CTRL_RESET 2
-+#define CCR_CTRL_VALID 3
-+#define CCR_CTRL_RD_DATA (1 << 4)
-+#define CCR_CTRL_RD_TAG (2 << 4)
-+#define CCR_CTRL_WR_DATA (3 << 4)
-+#define CCR_CTRL_WR_TAG (4 << 4)
-+#define CCR_CTRL_INV_INDEX (5 << 4)
-+#define CCR_CTRL_INV_ADDR (6 << 4)
-+#define CCR_CTRL_FLUSH_INDEX (7 << 4)         /* D-cache only */
-+#define CCR_CTRL_FLUSH_INV_INDEX (8 << 4)     /* D-cache only */
-+#define CCR_CTRL_FLUSH_ADDR (9 << 4)          /* D-cache only */
-+#define CCR_CTRL_FLUSH_INV_ADDR (10 << 4)     /* D-cache only */
-+
-+/*
-+ * OCP-OCMC
-+ */
-+#define OCMC_BASE (OCP_BASE + OCP_OCMC)
-+#define OCMC_BANK_MASK 0x00
-+#define OCMC_BIST_CNTL 0x04   /* IP5000 only */
-+#define OCMC_BIST_STAT 0x08   /* IP5000 only */
-+
-+#define OCMC_BANK_PROG(n) ((1<<(n))-1)
-+
-+#define OCMC_BIST_WRCK (1 << 7)
-+#define OCMC_BIST_RESET (1 << 5)
-+#define OCMC_BIST_SMART (1 << 4)
-+#define OCMC_BIST_RUN (1 << 3)
-+#define OCMC_BIST_REPAIR (1 << 2)
-+
-+#define OCMC_BIST_READY (1 << 3)
-+#define OCMC_BIST_FAIL (1 << 2)
-+
-+/*
-+ * OCP-STATISTICS
-+ */
-+#define STATISTICS_BASE (OCP_BASE + OCP_STATISTICS)
-+#define STAT_COUNTER_CTRL(n) ((n)*8)
-+#define STAT_COUNTER(n) ((n)*8 + 4)
-+
-+#define STAT_EVENT_MP_INST 0
-+#define STAT_EVENT_OCM_ACCESS 4
-+#define STAT_EVENT_OCM_REQ 5
-+#define STAT_EVENT_IC_REQ_INVAL 13
-+#define STAT_EVENT_IC_MISS_INVAL 14
-+#define STAT_EVENT_IC_REQ_INVAL_NACK 15
-+#define STAT_EVENT_IC_REQ_VAL 16
-+#define STAT_EVENT_IC_MISS_VAL 17
-+#define STAT_EVENT_IC_REQ_VAL_NACK 18
-+#define STAT_EVENT_IC_MISS_Q 19
-+#define STAT_EVENT_DC_RD_REQ 20
-+#define STAT_EVENT_DC_RD_MISS 21
-+#define STAT_EVENT_DC_WR_REQ 22
-+#define STAT_EVENT_DC_WR_MISS 23
-+#define STAT_EVENT_DC_MISS_Q 24
-+#define STAT_EVENT_DC_WB_FULL 25
-+#define STAT_EVENT_DC_REQ_NACK 26
-+#define STAT_EVENT_DC_CORE_REQ 27
-+#define STAT_EVENT_DC_MISS 28
-+#define STAT_EVENT_DC_EVICT 29
-+#define STAT_EVENT_TRUE 30
-+#define STAT_EVENT_FALSE 31
-+
-+/*
-+ * OCP_MTEST
-+ */
-+#define MTEST_BASE (OCP_BASE + OCP_MTEST)
-+#define MTEST_ADDR 0x00
-+#define MTEST_WR 0x04
-+#define MTEST_RD 0x08
-+#define MTEST_CTRL 0x0c
-+
-+/*
-+ * OCP_MCFG (IP7000 only)
-+ */
-+#define MCFG_BASE (OCP_BASE + OCP_MCFG)
-+#define MCFG_CTRL 0x00
-+#define MCFG_WCFG 0x04
-+#define MCFG_RCFG 0x08
-+
-+/*
-+ * Port registers
-+ */
-+#define IO_BASE 0x02000000
-+#define RA (IO_BASE + 0x00000000)
-+#define RB (IO_BASE + 0x00001000)
-+#define RC (IO_BASE + 0x00002000)
-+#define RD (IO_BASE + 0x00003000)
-+#define RE (IO_BASE + 0x00004000)
-+#define RF (IO_BASE + 0x00005000)
-+#define RG (IO_BASE + 0x00006000)
-+#define RH (IO_BASE + 0x00007000)
-+#define RI (IO_BASE + 0x00008000)
-+#define RJ (IO_BASE + 0x00009000)
-+#define RLATCH (IO_BASE + 0x00ff0000) // For latched output only
-+#define IO_PORT_BR_OFFSET 0x00000800
-+
-+/*
-+ * General I/O Register Map (per port)
-+ */
-+#define IO_FUNC 0x00
-+#define IO_GPIO_CTL 0x04
-+#define IO_GPIO_OUT 0x08
-+#define IO_GPIO_IN 0x0C
-+#define IO_INT_STATUS 0x10
-+#define IO_INT_MASK 0x14
-+#define IO_INT_SET 0x18
-+#define IO_INT_CLR 0x1C
-+#define IO_TX_FIFO 0x20
-+#define IO_TX_FIFO_HI 0x24
-+#define IO_RX_FIFO 0x28
-+#define IO_RX_FIFO_HI 0x2c
-+#define IO_CTL0 0x30
-+#define IO_CTL1 0x34
-+#define IO_CTL2 0x38
-+#define IO_STATUS0 0x3c
-+#define IO_STATUS1 0x40
-+#define IO_STATUS2 0x44
-+#define IO_FIFO_WATER 0x48
-+#define IO_FIFO_LEVEL 0x4c
-+#define IO_GPIO_MASK 0x50
-+
-+#define IO_FUNC_FUNCTION_RESET(func) ((1 << ((func) - 1)) << 4)       /* Function 0 doesn't need reset */
-+#define IO_FUNC_RX_FIFO (1 << 3)
-+#define IO_FUNC_SELECT(func) ((func) << 0)
-+
-+/*
-+ * External interrupt pins.
-+ */
-+#define EXT_INT_IO_BIT(pin) ((pin) + 5)       // Interrupt pin number -> I/O INT bit
-+#define EXT_INT_RISING_EDGE(pin) (0x2 << (2*(pin) + 7))
-+#define EXT_INT_FALLING_EDGE(pin) (0x1 << (2*(pin) + 7))
-+
-+/*
-+ * Flash
-+ */
-+#define IO_XFL_BASE RA
-+
-+#define IO_XFL_INT_START (1 << 16)
-+#define IO_XFL_INT_ERR (1 << 8)
-+#define IO_XFL_INT_DONE (1 << 0)
-+
-+#define IO_XFL_CTL0_MASK (0xffe07fff)
-+#define IO_XFL_CTL0_RD_CMD(cmd) (((cmd) & 0xff) << 24)
-+#define IO_XFL_CTL0_RD_DUMMY(n) (((n) & 0x7) << 21)
-+#define IO_XFL_CTL0_CLK_WIDTH(core_cycles) ((((core_cycles) + 1) & 0x7e) << 8)        /* must be even number */
-+#define IO_XFL_CTL0_CE_WAIT(spi_cycles) (((spi_cycles) & 0x3f) << 2)
-+#define IO_XFL_CTL0_MCB_LOCK (1 << 1)
-+#define IO_XFL_CTL0_ENABLE (1 << 0)
-+#define IO_XFL_CTL0_FAST_VALUE(div, wait) (IO_XFL_CTL0_RD_CMD(0xb) | IO_XFL_CTL0_RD_DUMMY(1) | IO_XFL_CTL0_CLK_WIDTH(div) | IO_XFL_CTL0_CE_WAIT(wait) | IO_XFL_CTL0_ENABLE)
-+#define IO_XFL_CTL0_VALUE(div, wait) (IO_XFL_CTL0_RD_CMD(3) | IO_XFL_CTL0_CLK_WIDTH(div) | IO_XFL_CTL0_CE_WAIT(wait) | IO_XFL_CTL0_ENABLE)
-+
-+#define IO_XFL_CTL1_MASK (0xc0003fff)
-+#define IO_XFL_CTL1_FC_INST(inst) (((inst) & 0x3) << 30)
-+#define IO_XFL_CTL1_FC_DATA(n) (((n) & 0x3ff) << 4)
-+#define IO_XFL_CTL1_FC_DUMMY(n) (((n) & 0x7) << 1)
-+#define IO_XFL_CTL1_FC_ADDR (1 << 0)
-+
-+#define IO_XFL_CTL2_FC_CMD(cmd) (((cmd) & 0xff) << 24)
-+#define IO_XFL_CTL2_FC_ADDR(addr) ((addr) & 0x00ffffff)       /* Only up to 24 bits */
-+
-+#define IO_XFL_STATUS0_MCB_ACTIVE (1 << 0)
-+#define IO_XFL_STATUS0_IOPCS_ACTIVE (1 << 1)
-+
-+/*
-+ * SDRAM
-+ */
-+#define IO_SDRAM_DATA_BASE RG
-+#define IO_SDRAM_CNTL_BASE RH
-+
-+#define IO_SDRAM_CTRL0_EN_REF (1 << 0)
-+
-+/*
-+ * Port function code (common fucntion codes for all I/O ports)
-+ */
-+#define IO_PORTX_FUNC_GPIO 0x00
-+#define IO_PORTX_FUNC_XFL 0x01
-+#define IO_PORTX_FUNC_PCI 0x01
-+#define IO_PORTX_FUNC_SERDES 0x01
-+#define IO_PORTX_FUNC_GMII 0x01
-+#define IO_PORTX_FUNC_DDR 0x01
-+#define IO_PORTX_FUNC_PCIX 0x01
-+#define IO_PORTX_FUNC_USB2_0 0x01
-+#define IO_PORTX_FUNC_GPIO_INT_CLK 0x02
-+#define IO_PORTX_FUNC_PLIO 0x02
-+#define IO_PORTX_FUNC_GPIO_INT 0x03
-+#define IO_PORTX_FUNC_MII 0x03
-+
-+/*
-+ * Port 0
-+ */
-+#define IO_PORT0_FUNC_GPIO IO_PORTX_FUNC_GPIO
-+#define IO_PORT0_FUNC_XFL_INT_CLK IO_PORTX_FUNC_XFL   // Default mode after reset
-+#define IO_PORT0_FUNC_GPIO_INT_CLK IO_PORTX_FUNC_GPIO_INT_CLK
-+#define IO_PORT0_FUNC_GPIO_INT IO_PORTX_FUNC_GPIO_INT
-+
-+/*
-+ * Port 1
-+ */
-+#define IO_PORT1_FUNC_GPIO IO_PORTX_FUNC_GPIO
-+#define IO_PORT1_FUNC_PCI IO_PORTX_FUNC_PCI           // PCI control
-+#define IO_PORT1_FUNC_MII IO_PORTX_FUNC_MII           // port 4 MII extension
-+
-+/*
-+ * Port 2
-+ */
-+#define IO_PORT2_FUNC_GPIO IO_PORTX_FUNC_GPIO
-+#define IO_PORT2_FUNC_PCI IO_PORTX_FUNC_PCI           // PCI data I/O
-+#define IO_PORT2_FUNC_PLIO IO_PORTX_FUNC_PLIO         // Extended LM
-+
-+/*
-+ * Port 3
-+ */
-+#define IO_PORT3_FUNC_GPIO IO_PORTX_FUNC_GPIO
-+#define IO_PORT3_FUNC_SERDES IO_PORTX_FUNC_SERDES
-+#define IO_PORT3_FUNC_PLIO IO_PORTX_FUNC_PLIO
-+
-+/*
-+ * Port 4
-+ */
-+#define IO_PORT4_FUNC_GPIO IO_PORTX_FUNC_GPIO
-+#define IO_PORT4_FUNC_SERDES IO_PORTX_FUNC_SERDES
-+#define IO_PORT4_FUNC_PLIO IO_PORTX_FUNC_PLIO         // Extended LM
-+#define IO_PORT4_FUNC_MII IO_PORTX_FUNC_MII
-+
-+/*
-+ * Port 5
-+ */
-+#define IO_PORT5_FUNC_GPIO IO_PORTX_FUNC_GPIO
-+#define IO_PORT5_FUNC_GMII IO_PORTX_FUNC_GMII
-+
-+/*
-+ * Port 6
-+ */
-+#define IO_PORT6_FUNC_GPIO IO_PORTX_FUNC_GPIO
-+#define IO_PORT6_FUNC_DDR IO_PORTX_FUNC_DDR
-+
-+/*
-+ * Port 7
-+ */
-+#define IO_PORT7_FUNC_GPIO IO_PORTX_FUNC_GPIO
-+#define IO_PORT7_FUNC_DDR IO_PORTX_FUNC_DDR
-+
-+/*
-+ * Port 8
-+ */
-+#define IO_PORT8_FUNC_GPIO IO_PORTX_FUNC_GPIO
-+#define IO_PORT8_FUNC_PCIX IO_PORTX_FUNC_PCIX
-+#define IO_PORT8_FUNC_PLIO IO_PORTX_FUNC_PLIO         // Extended LM
-+#define IO_PORT8_FUNC_MII IO_PORTX_FUNC_MII           // port 4 MII extension
-+
-+/*
-+ * Port 9
-+ */
-+#define IO_PORT9_FUNC_USB2_0 IO_PORTX_FUNC_USB2_0
-+
-+/*
-+ * FIFO
-+ */
-+#define IO_PORTX_INT_FIFO_TX_RESET (1 << 31)
-+#define IO_PORTX_INT_FIFO_RX_RESET (1 << 30)
-+#define IO_PORTX_INT_FIFO_TX_UF (1 << 15)
-+#define IO_PORTX_INT_FIFO_TX_WM (1 << 14)
-+#define IO_PORTX_INT_FIFO_RX_OF (1 << 13)
-+#define IO_PORTX_INT_FIFO_RX_WM (1 << 12)
-+
-+#define IO_PORTX_FUNC_FIFO_TX_WM(n) ((n) << 16)
-+#define IO_PORTX_FUNC_FIFO_RX_WM(n) ((n) << 0)
-+
-+/*
-+ * MII
-+ */
-+#define IO_PORTX_INT_MII_TX_ERR_SEND (1 << 18)
-+#define IO_PORTX_INT_MII_TX_HALT (1 << 17)
-+#define IO_PORTX_INT_MII_TX_START (1 << 16)
-+#define IO_PORTX_INT_MII_THRESHOLD (1 << 8)
-+#define IO_PORTX_INT_MII_RX_EOP (1 << 7)
-+#define IO_PORTX_INT_MII_RX_SFD (1 << 6)
-+#define IO_PORTX_INT_MII_RX_ERR (1 << 5)
-+#define IO_PORTX_INT_MII_TX_EOP (1 << 4)
-+#define IO_PORTX_INT_MII_COL (1 << 3)
-+#define IO_PORTX_INT_MII_CRS (1 << 2)
-+#define IO_PORTX_INT_MII_ODD_NIB_ERR (1 << 1)
-+#define IO_PORTX_INT_MII_FALSE_CARRIER (1 << 0)
-+
-+/*
-+ * SerDes
-+ */
-+#define IO_PORTX_INT_SERDES_TXBUF_VALID (1 << 16)
-+#define IO_PORTX_INT_SERDES_RXERR (1 << 7)
-+#define IO_PORTX_INT_SERDES_RXEOP (1 << 6)
-+#define IO_PORTX_INT_SERDES_SYND (1 << 5)
-+#define IO_PORTX_INT_SERDES_TXBE (1 << 4)
-+#define IO_PORTX_INT_SERDES_TXEOP (1 << 3)
-+#define IO_PORTX_INT_SERDES_SXLP (1 << 2)
-+#define IO_PORTX_INT_SERDES_RXBF (1 << 1)
-+#define IO_PORTX_INT_SERDES_RXCRS (1 << 0)
-+
-+#ifndef __ASSEMBLY__
-+struct ubicom32_io_port {
-+      volatile u32_t function;
-+      volatile u32_t gpio_ctl;
-+      volatile u32_t gpio_out;
-+      volatile u32_t gpio_in;
-+      volatile u32_t int_status;
-+      volatile u32_t int_mask;
-+      volatile u32_t int_set;
-+      volatile u32_t int_clr;
-+      volatile u32_t tx_fifo;
-+      volatile u32_t tx_fifo_hi;
-+      volatile u32_t rx_fifo;
-+      volatile u32_t rx_fifo_hi;
-+      volatile u32_t ctl0;
-+      volatile u32_t ctl1;
-+      volatile u32_t ctl2;
-+      volatile u32_t status0;
-+      volatile u32_t status1;
-+      volatile u32_t status2;
-+      volatile u32_t fifo_watermark;
-+      volatile u32_t fifo_level;
-+      volatile u32_t gpio_mask;
-+};
-+
-+#define UBICOM32_IO_PORT(port) ((struct ubicom32_io_port *)((port)))
-+#endif
-+
-+#ifndef __ASSEMBLY__
-+/*
-+ * ubicom32_set_interrupt()
-+ */
-+extern inline void ubicom32_set_interrupt(u8_t interrupt)
-+{
-+      u32_t ibit = INT_BIT_MASK(interrupt);
-+
-+      if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) {
-+              asm volatile (
-+                      "move.4         "D(INT_SET(INT_CHIP(0, 0)))", %0\n\t"
-+                      :
-+                      : "r" (ibit)
-+              );
-+
-+              return;
-+      }
-+
-+      asm volatile (
-+              "move.4         "D(INT_SET(INT_CHIP(1, 0)))", %0\n\t"
-+              :
-+              : "r" (ibit)
-+      );
-+}
-+
-+/*
-+ * ubicom32_clear_interrupt()
-+ */
-+extern inline void ubicom32_clear_interrupt(u8_t interrupt)
-+{
-+      u32_t ibit = INT_BIT_MASK(interrupt);
-+
-+      if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) {
-+              asm volatile (
-+                      "move.4         "D(INT_CLR(INT_CHIP(0, 0)))", %0\n\t"
-+                      :
-+                      : "r" (ibit)
-+              );
-+
-+              return;
-+      }
-+
-+      asm volatile (
-+              "move.4         "D(INT_CLR(INT_CHIP(1, 0)))", %0\n\t"
-+              :
-+              : "r" (ibit)
-+      );
-+}
-+
-+/*
-+ * ubicom32_enable_interrupt()
-+ */
-+extern inline void ubicom32_enable_interrupt(u8_t interrupt)
-+{
-+      u32_t ibit = INT_BIT_MASK(interrupt);
-+
-+      if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) {
-+              asm volatile (
-+                      "or.4           "D(INT_MASK(INT_CHIP(0, 0)))", "D(INT_MASK(INT_CHIP(0, 0)))", %0\n\t"
-+                      :
-+                      : "d" (ibit)
-+              );
-+
-+              return;
-+      }
-+
-+      asm volatile (
-+              "or.4           "D(INT_MASK(INT_CHIP(1, 0)))", "D(INT_MASK(INT_CHIP(1, 0)))", %0\n\t"
-+              :
-+              : "d" (ibit)
-+      );
-+}
-+
-+/*
-+ * ubicom32_disable_interrupt()
-+ */
-+extern inline void ubicom32_disable_interrupt(u8_t interrupt)
-+{
-+      u32_t ibit = ~INT_BIT_MASK(interrupt);
-+
-+      if (INT_REG(interrupt) == INT_REG(INT_CHIP(0, 0))) {
-+              asm volatile (
-+                      "and.4          "D(INT_MASK(INT_CHIP(0, 0)))", "D(INT_MASK(INT_CHIP(0, 0)))", %0\n\t"
-+                      :
-+                      : "d" (ibit)
-+              );
-+
-+              return;
-+      }
-+
-+      asm volatile (
-+              "and.4          "D(INT_MASK(INT_CHIP(1, 0)))", "D(INT_MASK(INT_CHIP(1, 0)))", %0\n\t"
-+              :
-+              : "d" (ibit)
-+      );
-+}
-+
-+/*
-+ * ubicom32_enable_global_interrupts()
-+ */
-+extern inline void ubicom32_enable_global_interrupts(void)
-+{
-+      asm volatile(
-+              "bset           GLOBAL_CTRL, GLOBAL_CTRL, #%bit("D(GLOBAL_CTRL_INT_EN)")"
-+      );
-+}
-+
-+/*
-+ * ubicom32_disable_global_interrupts()
-+ */
-+extern inline void ubicom32_disable_global_interrupts(void)
-+{
-+      asm volatile(
-+              "bclr           GLOBAL_CTRL, GLOBAL_CTRL, #%bit("D(GLOBAL_CTRL_INT_EN)")"
-+      );
-+}
-+
-+/*
-+ * ubicom32_get_reset_reason()
-+ */
-+extern inline u32_t ubicom32_get_reset_reason(void)
-+{
-+      return *(u32_t *)(GENERAL_CFG_BASE + GEN_RESET_REASON);
-+}
-+
-+/*
-+ * ubicom32_read_reg()
-+ */
-+extern inline u32_t ubicom32_read_reg(volatile void *reg)
-+{
-+      u32_t v;
-+      asm volatile (
-+              "move.4         %[dest], %[src] \n\t"
-+              : [dest] "=r" (v)
-+              : [src] "m" (*(u32_t *)reg)
-+      );
-+      return v;
-+}
-+
-+/*
-+ * ubicom32_write_reg()
-+ */
-+extern inline void ubicom32_write_reg(volatile void *reg, u32_t v)
-+{
-+      asm volatile (
-+              "move.4         %[dest], %[src] \n\t"
-+              :
-+              : [src] "r" (v), [dest] "m" (*(u32_t *)reg)
-+      );
-+}
-+
-+#endif /* __ASSEMBLY__ */
-+#endif /* _ASM_UBICOM32_IP5000_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ipcbuf.h
-@@ -0,0 +1,55 @@
-+/*
-+ * arch/ubicom32/include/asm/ipcbuf.h
-+ *   Definition of ipc64_perm struct for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_IPCBUF_H
-+#define _ASM_UBICOM32_IPCBUF_H
-+
-+/*
-+ * The user_ipc_perm structure for m68k 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 /* _ASM_UBICOM32_IPCBUF_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/irqflags.h
-@@ -0,0 +1,96 @@
-+/*
-+ * arch/ubicom32/include/asm/irqflags.h
-+ *   Raw implementation of local IRQ functions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_IRQFLAGS_H
-+#define _ASM_UBICOM32_IRQFLAGS_H
-+
-+#include <linux/thread_info.h>
-+#include <asm/ubicom32-common.h>
-+#if defined(CONFIG_SMP)
-+#include <asm/smp.h>
-+#endif
-+#include <asm/ldsr.h>
-+
-+#if defined(CONFIG_PREEMPT)
-+#error Not supported by Ubicom32 irq handling, yet!
-+#endif
-+
-+/*
-+ * raw_local_irq_enable()
-+ *    Enable interrupts for this thread.
-+ */
-+static inline void raw_local_irq_enable(void)
-+{
-+      ldsr_local_irq_enable();
-+}
-+
-+/*
-+ * raw_local_irq_disable()
-+ *    Disable interrupts for this thread.
-+ */
-+static inline void raw_local_irq_disable(void)
-+{
-+      ldsr_local_irq_disable();
-+}
-+
-+/*
-+ * raw_local_save_flags()
-+ *    Get the current IRQ state.
-+ */
-+#define raw_local_save_flags(flags)           \
-+do {                                          \
-+      (flags) = ldsr_local_irq_is_disabled(); \
-+} while (0)
-+
-+/*
-+ * raw_local_irq_save()
-+ *    Save the current interrupt state and disable interrupts.
-+ */
-+#define raw_local_irq_save(flags)             \
-+do {                                          \
-+      (flags) = ldsr_local_irq_save();        \
-+} while (0)
-+
-+/*
-+ * raw_local_irq_restore()
-+ *    Restore the IRQ state back to flags.
-+ */
-+static inline void raw_local_irq_restore(unsigned long flags)
-+{
-+      ldsr_local_irq_restore(flags);
-+}
-+
-+/*
-+ * raw_irqs_disabled_flags()
-+ *    Return true if the flags indicate that IRQ(s) are disabled.
-+ */
-+static inline int raw_irqs_disabled_flags(unsigned long flags)
-+{
-+      return (flags);
-+}
-+
-+#endif /* _ASM_UBICOM32_IRQFLAGS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/irq.h
-@@ -0,0 +1,45 @@
-+/*
-+ * arch/ubicom32/include/asm/irq.h
-+ *   IRQ definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_IRQ_H
-+#define _ASM_UBICOM32_IRQ_H
-+
-+#include <asm/irqflags.h>
-+
-+/*
-+ * We setup the IRQS to cover the full range of interrupt registers in
-+ * processor.
-+ */
-+#define NR_IRQS               64
-+
-+#define irq_canonicalize(irq) (irq)
-+
-+extern int irq_soft_alloc(unsigned int *soft);
-+extern void ack_bad_irq(unsigned int irq);
-+extern void do_IRQ(int irq, struct pt_regs *fp);
-+
-+#endif /* _ASM_UBICOM32_IRQ_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/irq_regs.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/irq_regs.h
-+ *   Generic irq_regs.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_IRQ_REGS_H
-+#define _ASM_UBICOM32_IRQ_REGS_H
-+
-+#include <asm-generic/irq_regs.h>
-+
-+#endif /* _ASM_UBICOM32_IRQ_REGS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/Kbuild
-@@ -0,0 +1 @@
-+include include/asm-generic/Kbuild.asm
---- /dev/null
-+++ b/arch/ubicom32/include/asm/kdebug.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/kdebug.h
-+ *   Generic kdebug.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_KDEBUG_H
-+#define _ASM_UBICOM32_KDEBUG_H
-+
-+#include <asm-generic/kdebug.h>
-+
-+#endif /* _ASM_UBICOM32_KDEBUG_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/kmap_types.h
-@@ -0,0 +1,48 @@
-+/*
-+ * arch/ubicom32/include/asm/kmap_types.h
-+ *   Definition of km_type's for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_KMAP_TYPES_H
-+#define _ASM_UBICOM32_KMAP_TYPES_H
-+
-+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 /* _ASM_UBICOM32_KMAP_TYPES_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ldsr.h
-@@ -0,0 +1,186 @@
-+/*
-+ * arch/ubicom32/include/asm/ldsr.h
-+ *   Ubicom32 LDSR interface definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_LDSR_H
-+#define _ASM_UBICOM32_LDSR_H
-+
-+#include <asm/ubicom32-common.h>
-+#include <asm/types.h>
-+#include <asm/thread.h>
-+
-+extern unsigned int ldsr_soft_irq_mask;
-+
-+/*
-+ * ldsr_local_irq_is_disabled()
-+ *    Test if interrupts are disabled for this thread?
-+ */
-+static inline int ldsr_local_irq_is_disabled(void)
-+{
-+      int ret;
-+      thread_t self = thread_get_self();
-+      unsigned int mask = (1 << self);
-+
-+      asm volatile (
-+      "       and.4   %0, scratchpad1, %1     \n\t"
-+              : "=r" (ret)
-+              : "d" (mask)
-+              : "cc"
-+      );
-+
-+      /*
-+       *  We return a simple 1 == disabled, 0 == enabled
-+       *  losing which tid this is for, because Linux
-+       *  can restore interrupts on a different thread.
-+       */
-+      return ret >> self;
-+}
-+
-+/*
-+ * ldsr_local_irq_save()
-+ *    Get the current interrupt state and disable interrupts.
-+ */
-+static inline unsigned int ldsr_local_irq_save(void)
-+{
-+      int ret;
-+      thread_t self = thread_get_self();
-+      unsigned int mask = (1 << self);
-+
-+      /*
-+       * Ensure the compiler can not optimize out the code
-+       * (volatile) and that it does not "cache" values around
-+       * the interrupt state change (memory).  This ensures
-+       * that interrupt changes are treated as a critical
-+       * section.
-+       */
-+      asm volatile (
-+      "       and.4   %0, scratchpad1, %1             \n\t"
-+      "       or.4    scratchpad1, scratchpad1, %1    \n\t"
-+              : "=&r" (ret)
-+              : "d" (mask)
-+              : "cc", "memory"
-+      );
-+
-+      /*
-+       *  We return a simple 1 == disabled, 0 == enabled
-+       *  losing which tid this is for, because Linux
-+       *  can restore interrupts on a different thread.
-+       */
-+      return ret >> self;
-+}
-+
-+/*
-+ * ldsr_local_irq_restore()
-+ *    Restore this cpu's interrupt enable/disable state.
-+ *
-+ * Note: flags is either 0 or 1.
-+ */
-+static inline void ldsr_local_irq_restore(unsigned int flags)
-+{
-+      unsigned int temp;
-+      thread_t self = thread_get_self();
-+      unsigned int mask = (1 << self);
-+      flags = (flags << self);
-+
-+      /*
-+       * Ensure the compiler can not optimize out the code
-+       * (volatile) and that it does not "cache" values around
-+       * the interrupt state change (memory).  This ensures
-+       * that interrupt changes are treated as a critical
-+       * section.
-+       *
-+       * Atomic change to our bit in scratchpad1 without
-+       * causing any temporary glitch in the value and
-+       * without effecting other values.  Also this uses
-+       * no branches so no penalties.
-+       */
-+      asm volatile (
-+      "       xor.4   %0, scratchpad1, %1             \n\t"
-+      "       and.4   %0, %2, %0                      \n\t"
-+      "       xor.4   scratchpad1, scratchpad1, %0    \n\t"
-+      "       move.4  int_set0, %3                    \n\t"
-+              : "=&d"(temp)
-+              : "d"(flags), "r"(mask), "r"(ldsr_soft_irq_mask)
-+              : "cc", "memory"
-+      );
-+}
-+
-+/*
-+ * ldsr_local_irq_disable_interrupt()
-+ *    Disable ints for this thread.
-+ */
-+static inline void ldsr_local_irq_disable(void)
-+{
-+      unsigned int mask = (1 << thread_get_self());
-+
-+      /*
-+       * Ensure the compiler can not optimize out the code
-+       * (volatile) and that it does not "cache" values around
-+       * the interrupt state change (memory).  This ensures
-+       * that interrupt changes are treated as a critical
-+       * section.
-+       */
-+      asm  volatile (
-+      "       or.4    scratchpad1, scratchpad1, %0    \n\t"
-+              :
-+              : "d" (mask)
-+              : "cc", "memory"
-+      );
-+}
-+
-+/*
-+ * ldsr_local_irq_enable_interrupt
-+ *    Enable ints for this thread.
-+ */
-+static inline void ldsr_local_irq_enable(void)
-+{
-+      unsigned int mask = (1 << thread_get_self());
-+
-+      /*
-+       * Ensure the compiler can not optimize out the code
-+       * (volatile) and that it does not "cache" values around
-+       * the interrupt state change (memory).  This ensures
-+       * that interrupt changes are treated as a critical
-+       * section.
-+       */
-+      asm volatile (
-+      "       and.4   scratchpad1, scratchpad1, %0    \n\t"
-+      "       move.4  int_set0, %1                    \n\t"
-+              :
-+              : "d" (~mask), "r" (ldsr_soft_irq_mask)
-+              : "cc", "memory"
-+      );
-+}
-+
-+extern void ldsr_init(void);
-+extern void ldsr_set_trap_irq(unsigned int irq);
-+extern void ldsr_mask_vector(unsigned int vector);
-+extern void ldsr_unmask_vector(unsigned int vector);
-+extern void ldsr_enable_vector(unsigned int vector);
-+extern void ldsr_disable_vector(unsigned int vector);
-+extern thread_t ldsr_get_threadid(void);
-+
-+#endif /* _ASM_UBICOM32_LDSR_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/linkage.h
-@@ -0,0 +1,34 @@
-+/*
-+ * arch/ubicom32/include/asm/linkage.h
-+ *   Definition of Ubicom32 architecture specific linkage types.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_LINKAGE_H
-+#define _ASM_UBICOM32_LINKAGE_H
-+
-+#define __ocm_text __section(.ocm_text)
-+#define __ocm_data __section(.ocm_data)
-+
-+#endif        /* _ASM_UBICOM32_LINKAGE_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/local.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/local.h
-+ *   Generic local.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_LOCAL_H
-+#define _ASM_UBICOM32_LOCAL_H
-+
-+#include <asm-generic/local.h>
-+
-+#endif /* _ASM_UBICOM32_LOCAL_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/machdep.h
-@@ -0,0 +1,43 @@
-+/*
-+ * arch/ubicom32/include/asm/machdep.h
-+ *   Machine dependent utility routines.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_MACHDEP_H
-+#define _ASM_UBICOM32_MACHDEP_H
-+
-+#include <linux/interrupt.h>
-+
-+/* Hardware clock functions */
-+extern unsigned long hw_timer_offset(void);
-+
-+/* machine dependent power off functions */
-+extern void (*mach_reset)(void);
-+extern void (*mach_halt)(void);
-+extern void (*mach_power_off)(void);
-+
-+extern void config_BSP(char *command, int len);
-+
-+#endif /* _ASM_UBICOM32_MACHDEP_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/mc146818rtc.h
-@@ -0,0 +1,36 @@
-+/*
-+ * arch/ubicom32/include/asm/mc146818rtc.h
-+ *   Generic mc146818rtc.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+/*
-+ * Machine dependent access functions for RTC registers.
-+ */
-+#ifndef _ASM_UBICOM32_MC146818RTC_H
-+#define _ASM_UBICOM32_MC146818RTC_H
-+
-+/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */
-+
-+#endif /* _ASM_UBICOM32_MC146818RTC_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/memory_map.h
-@@ -0,0 +1,66 @@
-+/*
-+ * arch/ubicom32/include/asm/memory_map.h
-+ *   Machine memory maps/
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_MEMORY_MAP_H
-+#define _ASM_UBICOM32_MEMORY_MAP_H
-+
-+/*
-+ * Memory Size
-+ */
-+#define OCM_SECTOR_SIZE       0x00008000              /* 32K */
-+
-+#if defined(CONFIG_UBICOM32_V3)
-+#define OCMSIZE       0x00030000      /* 192K on-chip RAM for both program and data */
-+#elif defined(CONFIG_UBICOM32_V4)
-+#define OCMSIZE       0x0003C000      /* 240K on-chip RAM for both program and data */
-+#else
-+#error "Unknown IP5K silicon"
-+#endif
-+
-+#define OCMSTART      0x3ffc0000 /* alias from 0x03000000 for easy
-+                                  * jump to/from SDRAM */
-+#define OCMEND                (OCMSTART + OCMSIZE)
-+
-+#define SDRAMSTART    0x40000000
-+
-+#define KERNELSTART   (SDRAMSTART + 0x00400000)
-+
-+#define FLASHSTART    0x60000000
-+
-+/*
-+ * CODELOADER / OS_SYSCALL OCM Reservations
-+ * Don't change these unless you know what you are doing.
-+ */
-+#define CODELOADER_SIZE  0x30
-+#define CODELOADER_BEGIN OCMSTART /* Must be OCM start for gdb to work. */
-+#define CODELOADER_END         (CODELOADER_BEGIN + CODELOADER_SIZE)
-+
-+#define OS_SYSCALL_BEGIN CODELOADER_END       /* system_call at this address */
-+#define OS_SYSCALL_SIZE  (512 - CODELOADER_SIZE)
-+#define OS_SYSCALL_END         (OS_SYSCALL_BEGIN + OS_SYSCALL_SIZE)
-+
-+#endif /* _ASM_UBICOM32_MEMORY_MAP_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/mman.h
-@@ -0,0 +1,44 @@
-+/*
-+ * arch/ubicom32/include/asm/mman.h
-+ *   Memory mapping definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_MMAN_H
-+#define _ASM_UBICOM32_MMAN_H
-+
-+#include <asm-generic/mman.h>
-+
-+#define MAP_GROWSDOWN 0x0100          /* stack-like segment */
-+#define MAP_DENYWRITE 0x0800          /* ETXTBSY */
-+#define MAP_EXECUTABLE        0x1000          /* mark it as an executable */
-+#define MAP_LOCKED    0x2000          /* pages are locked */
-+#define MAP_NORESERVE 0x4000          /* don't check for reservations */
-+#define MAP_POPULATE  0x8000          /* populate (prefault) pagetables */
-+#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 /* _ASM_UBICOM32_MMAN_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/mmu_context.h
-@@ -0,0 +1,60 @@
-+/*
-+ * arch/ubicom32/include/asm/mmu_context.h
-+ *   MMU context definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 2004, Microtronix Datacom Ltd., All rights reserved.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_MMU_CONTEXT_H
-+#define _ASM_UBICOM32_MMU_CONTEXT_H
-+
-+#include <asm/setup.h>
-+#include <asm/page.h>
-+#include <asm/pgalloc.h>
-+
-+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
-+{
-+}
-+
-+extern inline int
-+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
-+{
-+      // mm->context = virt_to_phys(mm->pgd);
-+      return(0);
-+}
-+
-+#define destroy_context(mm)           do { } while(0)
-+
-+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
-+{
-+}
-+
-+#define deactivate_mm(tsk,mm) do { } while (0)
-+
-+extern inline void activate_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm)
-+{
-+}
-+
-+#endif /* _ASM_UBICOM32_MMU_CONTEXT_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/mmu.h
-@@ -0,0 +1,41 @@
-+/*
-+ * arch/ubicom32/include/asm/mmu.h
-+ *   Definition of mm_context_t struct for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 2002, David McCullough <davidm@snapgear.com>
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_MMU_H
-+#define _ASM_UBICOM32_MMU_H
-+
-+typedef struct {
-+      struct vm_list_struct   *vmlist;
-+      unsigned long           end_brk;
-+#ifdef CONFIG_BINFMT_ELF_FDPIC
-+      unsigned long   exec_fdpic_loadmap;
-+      unsigned long   interp_fdpic_loadmap;
-+#endif
-+} mm_context_t;
-+
-+#endif /* _ASM_UBICOM32_MMU_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/module.h
-@@ -0,0 +1,48 @@
-+/*
-+ * arch/ubicom32/include/asm/module.h
-+ *   Ubicom32 architecture specific module definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_MODULE_H
-+#define _ASM_UBICOM32_MODULE_H
-+
-+struct mod_arch_specific {
-+      void *ocm_inst;
-+      int ocm_inst_size;
-+};
-+
-+#define Elf_Shdr Elf32_Shdr
-+#define Elf_Sym Elf32_Sym
-+#define Elf_Ehdr Elf32_Ehdr
-+
-+#define ARCH_PROC_MODULES_EXTRA(m,mod) \
-+      seq_printf(m, " OCM(%d bytes @ 0x%p)", \
-+                 (mod)->arch.ocm_inst_size, (mod)->arch.ocm_inst)
-+
-+#define ARCH_OOPS_MODULE_EXTRA(mod) \
-+      printk(KERN_INFO "%p %u OCM(%p %u)\n", \
-+              (mod)->module_core, (mod)->core_size, \
-+              (mod)->arch.ocm_inst, (mod)->arch.ocm_inst_size)
-+#endif /* _ASM_UBICOM32_MODULE_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/msgbuf.h
-@@ -0,0 +1,58 @@
-+/*
-+ * arch/ubicom32/include/asm/msgbuf.h
-+ *   Definition of msqid64_ds struct for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_MSGBUF_H
-+#define _ASM_UBICOM32_MSGBUF_H
-+
-+/*
-+ * The msqid64_ds structure for ubicom32 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 /* _ASM_UBICOM32_MSGBUF_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/mutex.h
-@@ -0,0 +1,41 @@
-+/*
-+ * arch/ubicom32/include/asm/mutex.h
-+ *   Generic mutex.h for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+/*
-+ * Pull in the generic implementation for the mutex fastpath.
-+ *
-+ * TODO: implement optimized primitives instead, or leave the generic
-+ * implementation in place, or pick the atomic_xchg() based generic
-+ * implementation. (see asm-generic/mutex-xchg.h for details)
-+ */
-+
-+#ifndef _ASM_UBICOM32_MUTEX_H
-+#define _ASM_UBICOM32_MUTEX_H
-+
-+#include <asm-generic/mutex-dec.h>
-+
-+#endif /* _ASM_UBICOM32_MUTEX_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/namei.h
-@@ -0,0 +1,38 @@
-+/*
-+ * arch/ubicom32/include/asm/namei.h
-+ *   Definition of __emul_prefix() for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_NAMEI_H
-+#define _ASM_UBICOM32_NAMEI_H
-+
-+/* This dummy routine maybe changed to something useful
-+ * for /usr/gnemul/ emulation stuff.
-+ * Look at asm-sparc/namei.h for details.
-+ */
-+
-+#define __emul_prefix() NULL
-+
-+#endif /* _ASM_UBICOM32_NAMEI_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ocm-alloc.h
-@@ -0,0 +1,36 @@
-+/*
-+ * arch/ubicom32/include/asm/ocm-alloc.h
-+ *   Ubicom32 architecture specific ocm definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_OCM_ALLOC_H
-+#define _ASM_UBICOM32_OCM_ALLOC_H
-+
-+
-+extern void *ocm_inst_alloc(size_t size, pid_t pid);
-+extern int ocm_free(const void *ptr);
-+extern int ocm_inst_free(const void *ptr);
-+
-+#endif /* _ASM_UBICOM32_OCM_ALLOC_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ocm_size.h
-@@ -0,0 +1,3 @@
-+#define APP_OCM_CODE_SIZE (0x3ffc2e00-0x3ffc0000)
-+#define APP_OCM_DATA_SIZE (0x3ffd3500-0x3ffc8000)
-+
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ocm_text.lds.inc
-@@ -0,0 +1,175 @@
-+/*
-+ * arch/ubicom32/include/asm/ocm_text.lds.inc
-+ *    <TODO: Replace with short file description>
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+*(.text.do_csum)
-+*(.text.tcp_packet)
-+*(.text.ipt_do_table)
-+*(.text.nf_conntrack_in)
-+*(.text.ip_forward)
-+*(.text.dev_queue_xmit)
-+*(.text.netif_receive_skb)
-+*(.text.ip_route_input)
-+*(.text.ip_finish_output)
-+*(.text.nf_iterate)
-+*(.text.__hash_conntrack)
-+*(.text.memset)
-+*(.text.memcpy)
-+*(.text.ip_rcv)
-+*(.text.__nf_conntrack_find)
-+*(.text.dev_hard_start_xmit)
-+*(.text.vlan_dev_hard_start_xmit)
-+*(.text.vlan_dev_hard_header)
-+*(.text.__nf_ct_refresh_acct)
-+*(.text.tcp_error)
-+*(.text.pfifo_fast_enqueue)
-+*(.text.ipv4_confirm)
-+*(.text.ip_output)
-+*(.text.neigh_connected_output)
-+*(.text.nf_hook_slow)
-+*(.text.nf_nat_packet)
-+*(.text.local_bh_enable)
-+*(.text.pfifo_fast_dequeue)
-+*(.text.ubi32_eth_receive)
-+*(.text.nf_nat_fn)
-+*(.text.skb_checksum)
-+*(.text.memmove)
-+*(.text.ubi32_eth_tx_done)
-+*(.text.eth_header)
-+*(.text.skb_release_data)
-+*(.text.nf_conntrack_find_get)
-+*(.text.process_backlog)
-+*(.text.vlan_skb_recv)
-+*(.text.ip_rcv_finish)
-+*(.text.__qdisc_run)
-+*(.text.skb_push)
-+*(.text.eth_type_trans)
-+*(.text.__alloc_skb)
-+*(.text.netif_rx)
-+*(.text.nf_ip_checksum)
-+*(.text.__skb_checksum_complete_head)
-+*(.text.ipv4_conntrack_defrag)
-+*(.text.tcp_pkt_to_tuple)
-+*(.text.kfree)
-+*(.text.tcp_manip_pkt)
-+*(.text.skb_put)
-+*(.text.nf_ct_get_tuple)
-+*(.text.__kmalloc)
-+*(.text.ubi32_eth_start_xmit)
-+*(.text.free_block)
-+*(.text.ipt_hook)
-+*(.text.kmem_cache_free)
-+*(.text.skb_pull_rcsum)
-+*(.text.cache_alloc_refill)
-+*(.text.skb_release_head_state)
-+*(.text.manip_pkt)
-+*(.text.ip_sabotage_in)
-+*(.text.ip_forward_finish)
-+*(.text.kmem_cache_alloc)
-+*(.text.local_bh_disable)
-+*(.text.ipv4_pkt_to_tuple)
-+*(.text.inet_proto_csum_replace4)
-+*(.text.__nf_ct_l4proto_find)
-+*(.text.csum_partial)
-+*(.text.neigh_resolve_output)
-+*(.text.__kfree_skb)
-+*(.text.kfree_skb)
-+*(.text.__find_vlan_dev)
-+*(.text.ldsr_ctxsw_thread)
-+*(.text.__do_IRQ)
-+*(.text.skb_pull)
-+*(.text.ipv4_invert_tuple)
-+*(.text.nf_ct_invert_tuplepr)
-+*(.text.skb_make_writable)
-+*(.text.ipv4_get_l4proto)
-+*(.text.handle_IRQ_event)
-+*(.text.net_rx_action)
-+*(.text.__do_softirq)
-+*(.text.nf_nat_in)
-+*(.text.note_interrupt)
-+*(.text.ipv4_conntrack_in)
-+*(.text.dst_release)
-+*(.text.tasklet_action)
-+*(.text.nf_nat_out)
-+*(.text.nf_ct_invert_tuple)
-+*(.text.do_IRQ)
-+*(.text.__tasklet_schedule)
-+*(.text.__skb_checksum_complete)
-+*(.text.ubi32_eth_interrupt)
-+*(.text.dev_kfree_skb_any)
-+*(.text.ret_from_interrupt_to_kernel)
-+*(.text.preemptive_context_save)
-+*(.text.irq_ack_vector)
-+*(.text.update_wall_time)
-+*(.text.ldsr_thread)
-+*(.text.irq_exit)
-+*(.text.ubi32_eth_do_tasklet)
-+*(.text.__napi_schedule)
-+*(.text.idle_cpu)
-+*(.text.run_timer_softirq)
-+*(.text.ldsr_mask_vector)
-+*(.text.irq_enter)
-+*(.text.ldsr_get_lsb)
-+*(.text.ldsr_unmask_vector)
-+*(.text.ip_fast_csum)
-+*(.text.hrtimer_run_queues)
-+*(.text.tcp_invert_tuple)
-+*(.text.T___705)
-+*(.text.run_posix_cpu_timers)
-+*(.text.free_hot_cold_page)
-+*(.text.lock_timer_base)
-+*(.text.calc_delta_mine)
-+*(.text.slab_destroy)
-+*(.text.rcu_pending)
-+*(.text.scheduler_tick)
-+*(.text.hrtimer_run_pending)
-+*(.text.do_softirq)
-+*(.text.del_timer)
-+*(.text.irq_end_vector)
-+*(.text.pci_read_u32)
-+*(.text.udivmodsi4)
-+*(.text.memcmp)
-+*(.text.memset)
-+*(.text.__slab_alloc)
-+*(.text.br_handle_frame)
-+*(.text.br_fdb_update)
-+*(.text.__br_fdb_get)
-+*(.text.br_forward)
-+*(.text.br_handle_frame_finish)
-+*(.text.pci_write_u32)
-+*(.text.kmem_freepages)
-+*(.text.br_dev_queue_push_xmit)
-+*(.text.ioread32)
-+*(.text.next_zones_zonelist)
-+*(.text.ubi32_pci_read_u32)
-+*(.text.zone_watermark_ok)
-+*(.text.__rmqueue_smallest)
-+*(.text.ubi32_eth_napi_poll)
-+*(.text.ubi32_pci_write_u32)
-+*(.text.ubi32_pci_read_u32)
-+*(.text._local_bh_enable)
-+*(.text._local_bh_disable)
-+*(.text.get_slab)
---- /dev/null
-+++ b/arch/ubicom32/include/asm/page.h
-@@ -0,0 +1,106 @@
-+/*
-+ * arch/ubicom32/include/asm/page.h
-+ *   Memory page related operations and definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_PAGE_H
-+#define _ASM_UBICOM32_PAGE_H
-+
-+/* PAGE_SHIFT determines the page size */
-+
-+#define PAGE_SHIFT    12
-+#define PAGE_SIZE     (1 << PAGE_SHIFT)
-+#define PAGE_MASK     (~(PAGE_SIZE-1))
-+
-+#include <asm/setup.h>
-+
-+#ifndef __ASSEMBLY__
-+
-+#define get_user_page(vaddr)          __get_free_page(GFP_KERNEL)
-+#define free_user_page(page, addr)    free_page(addr)
-+
-+#define clear_page(page)      memset((page), 0, PAGE_SIZE)
-+#define copy_page(to,from)    memcpy((to), (from), PAGE_SIZE)
-+
-+#define clear_user_page(page, vaddr, pg)      clear_page(page)
-+#define copy_user_page(to, from, vaddr, pg)   copy_page(to, from)
-+
-+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
-+      alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
-+#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
-+
-+/*
-+ * These are used to make use of C type-checking..
-+ */
-+typedef struct { unsigned long pte; } pte_t;
-+typedef struct { unsigned long pmd[16]; } pmd_t;
-+typedef struct { unsigned long pgd; } pgd_t;
-+typedef struct { unsigned long pgprot; } pgprot_t;
-+typedef struct page *pgtable_t;
-+
-+#define pte_val(x)    ((x).pte)
-+#define pmd_val(x)    ((&x)->pmd[0])
-+#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) } )
-+
-+extern unsigned long memory_start;
-+extern unsigned long memory_end;
-+
-+#endif /* !__ASSEMBLY__ */
-+
-+#include <asm/page_offset.h>
-+
-+#define PAGE_OFFSET           (PAGE_OFFSET_RAW)
-+
-+#ifndef __ASSEMBLY__
-+
-+#define __pa(vaddr)           virt_to_phys((void *)(vaddr))
-+#define __va(paddr)           phys_to_virt((unsigned long)(paddr))
-+
-+#define virt_to_pfn(kaddr)    (__pa(kaddr) >> PAGE_SHIFT)
-+#define pfn_to_virt(pfn)      __va((pfn) << PAGE_SHIFT)
-+
-+#define virt_to_page(addr)    (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT))
-+#define page_to_virt(page)    ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
-+
-+#define pfn_to_page(pfn)      virt_to_page(pfn_to_virt(pfn))
-+#define page_to_pfn(page)     virt_to_pfn(page_to_virt(page))
-+#define pfn_valid(pfn)                ((pfn) < max_mapnr)
-+
-+#define       virt_addr_valid(kaddr)  (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
-+                              ((void *)(kaddr) < (void *)memory_end))
-+
-+#endif /* __ASSEMBLY__ */
-+
-+#ifdef __KERNEL__
-+#include <asm-generic/page.h>
-+#endif
-+
-+#endif /* _ASM_UBICOM32_PAGE_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/page_offset.h
-@@ -0,0 +1,35 @@
-+/*
-+ * arch/ubicom32/include/asm/page_offset.h
-+ *   Definition of PAGE_OFFSET_RAW for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_PAGE_OFFSET_H
-+#define _ASM_UBICOM32_PAGE_OFFSET_H
-+
-+/* This handles the memory map.. */
-+#define       PAGE_OFFSET_RAW         0x3ffc0000
-+
-+#endif /* _ASM_UBICOM32_PAGE_OFFSET_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/param.h
-@@ -0,0 +1,49 @@
-+/*
-+ * arch/ubicom32/include/asm/param.h
-+ *   Definition of miscellaneous constants, including HZ.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_PARAM_H
-+#define _ASM_UBICOM32_PARAM_H
-+
-+#ifdef __KERNEL__
-+#define HZ CONFIG_HZ
-+#define       USER_HZ         HZ
-+#define       CLOCKS_PER_SEC  (USER_HZ)
-+#endif
-+
-+#ifndef HZ
-+#define HZ    100
-+#endif
-+
-+#define EXEC_PAGESIZE 4096
-+
-+#ifndef NOGROUP
-+#define NOGROUP               (-1)
-+#endif
-+
-+#define MAXHOSTNAMELEN        64      /* max length of hostname */
-+
-+#endif /* _ASM_UBICOM32_PARAM_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/pci.h
-@@ -0,0 +1,210 @@
-+/*
-+ * arch/ubicom32/include/asm/pci.h
-+ *   Definitions of PCI operations for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_PCI_H
-+#define _ASM_UBICOM32_PCI_H
-+
-+#include <asm/io.h>
-+
-+/* 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   (1)
-+
-+
-+
-+/*
-+ * Perform a master read/write to the PCI bus.
-+ * These functions return a PCI_RESP_xxx code.
-+ */
-+extern u8 pci_read_u32(u8 pci_cmd, u32 address, u32 *data);
-+extern u8 pci_write_u32(u8 pci_cmd, u32 address, u32 data);
-+extern u8 pci_read_u16(u8 pci_cmd, u32 address, u16 *data);
-+extern u8 pci_write_u16(u8 pci_cmd, u32 address, u16 data);
-+extern u8 pci_read_u8(u8 pci_cmd, u32 address, u8 *data);
-+extern u8 pci_write_u8(u8 pci_cmd, u32 address, u8 data);
-+
-+
-+#define PCIBIOS_MIN_IO          0x100
-+#define PCIBIOS_MIN_MEM         0x10000000
-+
-+#define pcibios_assign_all_busses()   0
-+#define pcibios_scan_all_fns(a, b)    0
-+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);
-+
-+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                   */
-+        u64             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;
-+};
-+
-+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;
-+}
-+
-+static inline void pcibios_set_master(struct pci_dev *dev)
-+{
-+        /* No special bus mastering setup handling */
-+}
-+#define HAVE_ARCH_PCI_SET_DMA_MAX_SEGMENT_SIZE 1
-+#define HAVE_ARCH_PCI_SET_DMA_SEGMENT_BOUNDARY 1
-+
-+#ifdef CONFIG_PCI
-+static inline void * pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-+                     dma_addr_t *dma_handle)
-+{
-+    void *vaddr = kmalloc(size, GFP_KERNEL);
-+    if(vaddr != NULL) {
-+        *dma_handle = virt_to_phys(vaddr);
-+    }
-+    return vaddr;
-+}
-+
-+static  inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
-+{
-+      return 1;
-+}
-+
-+static  inline void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-+      void *cpu_addr, dma_addr_t dma_handle)
-+{
-+      kfree(cpu_addr);
-+      return;
-+}
-+
-+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
-+      size_t size, int direction)
-+{
-+       return virt_to_phys(ptr);
-+}
-+
-+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-+      size_t size, int direction)
-+{
-+       return;
-+}
-+
-+static inline dma_addr_t
-+pci_map_page(struct pci_dev *hwdev, struct page *page,
-+             unsigned long offset, size_t size, int direction)
-+{
-+       return pci_map_single(hwdev, page_address(page) + offset, size, (int)direction);
-+}
-+
-+static inline void
-+pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address,
-+               size_t size, int direction)
-+{
-+      pci_unmap_single(hwdev, dma_address, size, direction);
-+}
-+
-+static inline int
-+pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-+           int nents, int direction)
-+{
-+        return nents;
-+}
-+
-+static inline void
-+pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-+             int nents, int direction)
-+{
-+}
-+
-+static inline void
-+pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg,
-+                int nelems, int direction)
-+{
-+}
-+
-+static inline void
-+pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg,
-+                int nelems, int direction)
-+{
-+}
-+
-+static inline void
-+pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle,
-+                    size_t size, int direction)
-+{
-+}
-+
-+static inline void
-+pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle,
-+                    size_t size, int direction)
-+{
-+}
-+
-+static inline int
-+pci_dma_mapping_error(struct pci_dev *hwdev, dma_addr_t dma_addr)
-+{
-+        return dma_addr == 0;
-+}
-+extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
-+extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
-+#endif
-+
-+#endif /* _ASM_UBICOM32_PCI_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/pcm_tio.h
-@@ -0,0 +1,84 @@
-+/*
-+ * arch/ubicom32/include/asm/pcm_tio.h
-+ *   Ubicom32 architecture PCM TIO definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+#ifndef _ASM_UBICOM32_PCM_TIO_H
-+#define _ASM_UBICOM32_PCM_TIO_H
-+
-+#include <asm/devtree.h>
-+
-+#define PCM_TIO_REGS_VERSION  2
-+struct pcm_tio_regs {
-+      /*
-+       * set this value to 1 to reload the parameters and restart the HRT
-+       */
-+      u32_t           reload;
-+
-+      /*
-+       * Pointers to the input and output buffers
-+       */
-+      void            *input_buf;
-+      void            *output_buf;
-+
-+      /*
-+       * Buffer size (see pcm_hrt.S for constraints)
-+       */
-+      u32_t           buffer_size;
-+
-+      /*
-+       * Current cycle.  This variable increases every time half the buffer
-+       * is consumed.
-+       */
-+      u32_t           cycle;
-+
-+      /*
-+       * Fields below this line are not accessed by the HRT.  They are purely
-+       * informational for the user of this TIO.
-+       */
-+
-+      /*
-+       * Version of this structure
-+       */
-+      u32_t           version;
-+
-+      /*
-+       * Number of channels supported
-+       */
-+      u32_t           channels;
-+
-+      /*
-+       * Maximum buffer size
-+       */
-+      u32_t           max_buffer_size;
-+};
-+
-+/*
-+ * Our device node
-+ */
-+#define PCM_TIO_NODE_VERSION  1
-+struct pcm_tio_node {
-+      struct devtree_node     dn;
-+      u32_t                   version;
-+      struct pcm_tio_regs     *regs;
-+};
-+
-+#endif
-+
---- /dev/null
-+++ b/arch/ubicom32/include/asm/percpu.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/percpu.h
-+ *   Generic percpu.h for the Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_PERCPU_H
-+#define _ASM_UBICOM32_PERCPU_H
-+
-+#include <asm-generic/percpu.h>
-+
-+#endif /* _ASM_UBICOM32_PERCPU_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/pgalloc.h
-@@ -0,0 +1,36 @@
-+/*
-+ * arch/ubicom32/include/asm/pgalloc.h
-+ *   Page table allocation definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_PGALLOC_H
-+#define _ASM_UBICOM32_PGALLOC_H
-+
-+#include <linux/mm.h>
-+#include <asm/setup.h>
-+
-+#define check_pgt_cache()     do { } while (0)
-+
-+#endif /* _ASM_UBICOM32_PGALLOC_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/pgtable.h
-@@ -0,0 +1,124 @@
-+/*
-+ * arch/ubicom32/include/asm/pgtable.h
-+ *   Ubicom32 pseudo page table definitions and operations.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 2004   Microtronix Datacom Ltd
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *   and various works, Alpha, ix86, M68K, Sparc, ...et al
-+ */
-+#ifndef _ASM_UBICOM32_PGTABLE_H
-+#define _ASM_UBICOM32_PGTABLE_H
-+
-+#include <asm-generic/4level-fixup.h>
-+
-+//vic - this bit copied from m68knommu version
-+#include <asm/setup.h>
-+#include <asm/io.h>
-+#include <linux/sched.h>
-+
-+typedef pte_t *pte_addr_t;
-+
-+#define pgd_present(pgd)      (1)       /* pages are always present on NO_MM */
-+#define pgd_none(pgd)         (0)
-+#define pgd_bad(pgd)          (0)
-+#define pgd_clear(pgdp)
-+#define kern_addr_valid(addr)         (1)
-+#define       pmd_offset(a, b)        ((void *)0)
-+
-+#define PAGE_NONE             __pgprot(0)    /* these mean nothing to NO_MM */
-+#define PAGE_SHARED           __pgprot(0)    /* these mean nothing to NO_MM */
-+#define PAGE_COPY             __pgprot(0)    /* these mean nothing to NO_MM */
-+#define PAGE_READONLY         __pgprot(0)    /* these mean nothing to NO_MM */
-+#define PAGE_KERNEL           __pgprot(0)    /* these mean nothing to NO_MM */
-+//vic - this bit copied from m68knommu version
-+
-+extern void paging_init(void);
-+#define swapper_pg_dir ((pgd_t *) 0)
-+
-+#define __swp_type(x)         (0)
-+#define __swp_offset(x)               (0)
-+#define __swp_entry(typ,off)  ((swp_entry_t) { ((typ) | ((off) << 7)) })
-+#define __pte_to_swp_entry(pte)       ((swp_entry_t) { pte_val(pte) })
-+#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
-+
-+/*
-+ * pgprot_noncached() is only for infiniband pci support, and a real
-+ * implementation for RAM would be more complicated.
-+ */
-+#define pgprot_noncached(prot)        (prot)
-+
-+static inline int pte_file(pte_t pte) { return 0; }
-+
-+/*
-+ * ZERO_PAGE is a global shared page that is always zero: used
-+ * for zero-mapped memory areas etc..
-+ */
-+#define ZERO_PAGE(vaddr)      (virt_to_page(0))
-+
-+extern unsigned int kobjsize(const void *objp);
-+extern int is_in_rom(unsigned long);
-+
-+/*
-+ * No page table caches to initialise
-+ */
-+#define pgtable_cache_init()   do { } while (0)
-+
-+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)               \
-+              remap_pfn_range(vma, vaddr, pfn, size, prot)
-+
-+extern inline void flush_cache_mm(struct mm_struct *mm)
-+{
-+}
-+
-+extern inline void flush_cache_range(struct mm_struct *mm,
-+                                   unsigned long start,
-+                                   unsigned long end)
-+{
-+}
-+
-+/* Push the page at kernel virtual address and clear the icache */
-+extern inline void flush_page_to_ram (unsigned long address)
-+{
-+}
-+
-+/* Push n pages at kernel virtual address and clear the icache */
-+extern inline void flush_pages_to_ram (unsigned long address, int n)
-+{
-+}
-+
-+/*
-+ * All 32bit addresses are effectively valid for vmalloc...
-+ * Sort of meaningless for non-VM targets.
-+ */
-+#define       VMALLOC_START   0
-+#define       VMALLOC_END     0xffffffff
-+
-+#define arch_enter_lazy_mmu_mode()    do {} while (0)
-+#define arch_leave_lazy_mmu_mode()    do {} while (0)
-+#define arch_flush_lazy_mmu_mode()    do {} while (0)
-+#define arch_enter_lazy_cpu_mode()    do {} while (0)
-+#define arch_leave_lazy_cpu_mode()    do {} while (0)
-+#define arch_flush_lazy_cpu_mode()    do {} while (0)
-+
-+#endif /* _ASM_UBICOM32_PGTABLE_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/plio.h
-@@ -0,0 +1,313 @@
-+/*
-+ * plio.h
-+ *    PLIO defines.
-+ *
-+ * Copyright Â© 2009 Ubicom Inc. <www.ubicom.com>.  All Rights Reserved.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ * This file contains confidential information of Ubicom, Inc. and your use of
-+ * this file is subject to the Ubicom Software License Agreement distributed with
-+ * this file. If you are uncertain whether you are an authorized user or to report
-+ * any unauthorized use, please contact Ubicom, Inc. at +1-408-789-2200.
-+ * Unauthorized reproduction or distribution of this file is subject to civil and
-+ * criminal penalties.
-+ */
-+
-+#ifndef __PLIO__H__
-+#define __PLIO__H__
-+
-+#include <asm/ip5000.h>
-+#include <asm/thread.h>
-+
-+#define PLIO_PORT             RD
-+#define PLIO_EXT_PORT         RI
-+
-+#define TRANSMIT_FIFO_WATERMARK 8
-+
-+/*
-+ * PLIO non-blocking register definitions
-+ */
-+#define PLIO_FN               2
-+
-+typedef struct {
-+      unsigned        : 10;
-+      unsigned        rxfifo_thread_enable: 1;   /* allowed rxfifo thread enable */
-+      unsigned        : 1;
-+      unsigned        rxfifo_thread: 4;          /* allowed rxfifo thread access */
-+      unsigned        : 4;
-+      unsigned        br_thread: 4;              /* allowed blocking region thread access */
-+      unsigned        fn_reset: 4;               /* function reset bit vector */
-+      unsigned        rxfifo_sel: 1;             /* select between RXFIFO 0 and 1 */
-+      unsigned        fn_sel: 3;                 /* select port function */
-+} plio_io_function_t;
-+
-+typedef struct {
-+      unsigned        : 24;
-+      unsigned        pin:8;
-+} plio_gpio_t;
-+
-+typedef struct {
-+      unsigned        : 16;
-+      unsigned        txfifo_uf: 1;              /* TXFIFO underflow */
-+      unsigned        txfifo_wm: 1;              /* TXFIFO watermark */
-+      unsigned        rxfifo_of: 1;              /* RXFIFO overflow */
-+      unsigned        rxfifo_wm: 1;              /* RXFIFO watermark */
-+      unsigned        : 5;
-+      unsigned        lreg_int_addr_rd: 1;       /* read from specified LREG address */
-+      unsigned        lreg_int_addr_wr: 1;       /* write to specified LREG address */
-+      unsigned        extctl_int: 4;             /* synchronized external interrupts */
-+      unsigned        pfsm_int: 1;               /* state machine */
-+} plio_intstat_t;
-+
-+typedef struct {
-+      unsigned        txfifo_reset: 1;           /* TXFIFO reset for int_set only */
-+      unsigned        rxfifo_reset: 1;           /* RXFIFO reset for int_set only */
-+      unsigned        : 11;
-+      unsigned        idif_txfifo_flush: 1;      /* flush TXFIFO and idif_txfifo */
-+      unsigned        idif_rxfifo_flush: 1;      /* flush RXFIFO and idif_rxfifo */
-+      unsigned        pfsm_start: 1;             /* input to fsm */
-+      unsigned        txfifo_uf: 1;              /* TXFIFO underflow */
-+      unsigned        txfifo_wm: 1;              /* TXFIFO watermark */
-+      unsigned        rxfifo_of: 1;              /* RXFIFO overflow */
-+      unsigned        rxfifo_wm: 1;              /* RXFIFO watermark */
-+      unsigned        : 5;
-+      unsigned        lreg_int_addr_rd: 1;       /* read from specified LREG address */
-+      unsigned        lreg_int_addr_wr: 1;       /* write to specified LREG address */
-+      unsigned        extctl_int: 4;             /* synchronized external interrupts */
-+      unsigned        pfsm_int: 1;               /* state machine */
-+} plio_intset_t;
-+
-+typedef enum {
-+      PLIO_PORT_MODE_D,
-+      PLIO_PORT_MODE_DE,
-+      PLIO_PORT_MODE_DI,
-+      PLIO_PORT_MODE_DEI,
-+      PLIO_PORT_MODE_DC,
-+} plio_port_mode_t;
-+
-+typedef enum {
-+      PLIO_CLK_CORE,  /* CORE CLK */
-+      PLIO_CLK_IO,    /* IO CLK */
-+      PLIO_CLK_EXT,   /* EXT CLK */
-+} plio_clk_src_t;
-+typedef struct {
-+      unsigned                : 4;
-+      unsigned                edif_iaena_sel: 1;         /* Input Address Enable Select */
-+      unsigned                edif_iaclk_sel: 1;         /* Input Address Clock Select */
-+      unsigned                edif_iald_inv: 1;          /* Input Address Strobe Invert */
-+      unsigned                edif_idclk_sel: 1;         /* Input Data Clock Select */
-+      unsigned                edif_idld_inv: 1;          /* Input Data Strobe Invert */
-+      unsigned                edif_ds: 3;                /* specify IDR and ODR data shift */
-+      unsigned                edif_cmp_mode: 1;          /* configure IDR comparator output */
-+      unsigned                edif_idena_sel: 1;         /* Input Data Enable Select */
-+      unsigned                ecif_extclk_ena: 1;        /* plio_extctl output select */
-+      unsigned                idif_tx_fifo_cmd_sel: 1;   /* select pfsm_cmd data word position */
-+      unsigned                ptif_porti_cfg: 2;         /* select port I pin configuration */
-+      unsigned                ptif_portd_cfg: 3;         /* select port D pin configuration */
-+      plio_port_mode_t        ptif_port_mode: 3;      /* select other plio ports  */
-+      unsigned                icif_clk_plio_ext_inv: 1;  /* invert external plio clock when set */
-+      unsigned                icif_rst_plio: 1;          /* reset plio function and io fifos */
-+      plio_clk_src_t          icif_clk_src_sel: 2;      /* select plio clock source */
-+      unsigned                pfsm_prog: 1;              /* enable pfsm programming */
-+      unsigned                pfsm_cmd: 3;               /* software input to pfsm */
-+} plio_fctl0_t;
-+
-+typedef struct {
-+      unsigned        : 2;
-+      unsigned        idif_byteswap_tx: 3;       /* swap TXFIFO byte order */
-+      unsigned        idif_byteswap_rx: 3;       /* swap RXFIFO byte order */
-+      unsigned        : 1;
-+      unsigned        lreg_ena: 1;               /* enable local register map */
-+      unsigned        lreg_addr_fifo_cmp_ena: 1; /* enable a specific LREG address from/to TX/RX fifos */
-+      unsigned        lreg_addr_fifo_cmp: 5;     /* LREG address routed from/to TX/RX fifos */
-+      unsigned        : 1;
-+      unsigned        dcod_iald_idld_sel: 2;     /* select address/data strobes */
-+      unsigned        dcod_rw_src_sel: 1;        /* select LREG strobe source */
-+      unsigned        dcod_rd_sel: 5;            /* select read strobe source */
-+      unsigned        dcod_wr_sel: 5;            /* select write strobe source */
-+      unsigned        dcod_rd_lvl: 1;            /* select active level of read strobe */
-+      unsigned        dcod_wr_lvl: 1;            /* select active level of read strobe */
-+} plio_fctl1_t;
-+
-+typedef struct {
-+      unsigned        icif_eclk_div: 16;         /* external plio clock divider */
-+      unsigned        icif_iclk_div: 16;         /* internal plio clock divider */
-+} plio_fctl2_t;
-+
-+typedef struct {
-+      unsigned        : 27;
-+      unsigned        pfsm_state: 5;             /* current pfsm state */
-+} plio_stat_0_t;
-+
-+typedef struct {
-+      unsigned        : 3;
-+      unsigned        lreg_r_int_addr: 5;
-+      unsigned        : 11;
-+      unsigned        lreg_w_int_addr: 5;
-+      unsigned        lreg_w_int_data: 8;
-+} plio_stat_1_t;
-+
-+typedef struct {
-+      unsigned        : 32;
-+} plio_stat_2_t;
-+
-+typedef struct {
-+      unsigned        tx: 16;
-+      unsigned        rx: 16;
-+} plio_io_fifo_wm_t, plio_io_fifo_lvl_t;
-+
-+
-+/* plio blocking region register definitions
-+ */
-+typedef struct {
-+      unsigned         ns1: 5;
-+      unsigned         ic1: 7;
-+      unsigned         ec1: 4;
-+      unsigned         ns0: 5;
-+      unsigned         ic0: 7;
-+      unsigned         ec0: 4;
-+} plio_sram_t;
-+
-+typedef struct {
-+      unsigned         : 2;
-+      unsigned         s9: 3;
-+      unsigned         s8: 3;
-+      unsigned         s7: 3;
-+      unsigned         s6: 3;
-+      unsigned         s5: 3;
-+      unsigned         s4: 3;
-+      unsigned         s3: 3;
-+      unsigned         s2: 3;
-+      unsigned         s1: 3;
-+      unsigned         s0: 3;
-+} plio_grpsel_t;
-+
-+typedef struct {
-+      unsigned        s7: 4;
-+      unsigned        s6: 4;
-+      unsigned        s5: 4;
-+      unsigned        s4: 4;
-+      unsigned        s3: 4;
-+      unsigned        s2: 4;
-+      unsigned        s1: 4;
-+      unsigned        s0: 4;
-+} plio_cs_lut_t;
-+
-+typedef struct {
-+      unsigned        lut3: 8;
-+      unsigned        lut2: 8;
-+      unsigned        lut1: 8;
-+      unsigned        lut0: 8;
-+} plio_extctl_t;
-+
-+typedef struct {
-+      plio_grpsel_t   grpsel[4];
-+      u16_t           cv[16];
-+      plio_cs_lut_t   cs_lut[4];
-+      plio_extctl_t   extctl_o_lut[8];
-+} plio_pfsm_t;
-+
-+typedef struct {
-+      u32_t           odr_oe_sel;
-+      u32_t           odr_oe;
-+      u32_t           cmp;
-+      u32_t           ncmp;
-+      u32_t           cmp_mask;
-+} plio_edif_t;
-+
-+typedef enum {
-+      PLIO_ECIF_CLK_OUT       = 9,
-+      PLIO_ECIF_IALD          = 9,
-+      PLIO_ECIF_CLK_IN        = 8,
-+      PLIO_ECIF_IDLD          = 8,
-+      PLIO_ECIF_INT           = 2,
-+} plio_ecif_output_t;
-+
-+typedef struct {
-+      u32_t           bypass_sync;
-+      u32_t           ift;
-+      u32_t           output_type;
-+      u32_t           output_ena;
-+      u32_t           output_lvl;
-+} plio_ecif_t;
-+
-+typedef struct {
-+      u32_t           idr_addr_pos_mask;
-+      u32_t           reserved;
-+      u32_t           lreg_bar;
-+} plio_dcod_t;
-+
-+typedef struct {
-+      u32_t           addr_rd_ena;
-+      u32_t           addr_wr_ena;
-+      u32_t           addr_rd_int_ena;
-+      u32_t           addr_wr_int_ena;
-+} plio_lcfg_t;
-+
-+
-+/*
-+ * PLIO configuration
-+ */
-+typedef struct {
-+      plio_fctl0_t    fctl0;
-+      plio_fctl1_t    fctl1;
-+      plio_fctl2_t    fctl2;
-+} plio_fctl_t;
-+
-+typedef struct {
-+      plio_pfsm_t     pfsm;
-+      plio_edif_t     edif;
-+      plio_ecif_t     ecif;
-+      plio_dcod_t     dcod;
-+      plio_lcfg_t     lcfg;
-+} plio_config_t;
-+
-+typedef struct {
-+      plio_io_function_t      function;
-+      plio_gpio_t             gpio_ctl;
-+      plio_gpio_t             gpio_out;
-+      plio_gpio_t             gpio_in;
-+      plio_intstat_t          intstat;
-+      plio_intstat_t          intmask;
-+      plio_intset_t           intset;
-+      plio_intstat_t          intclr;
-+      unsigned                tx_lo;
-+      unsigned                tx_hi;
-+      unsigned                rx_lo;
-+      unsigned                rx_hi;
-+      plio_fctl0_t            fctl0;
-+      plio_fctl1_t            fctl1;
-+      plio_fctl2_t            fctl2;
-+      plio_stat_0_t           stat0;
-+      plio_stat_1_t           stat1;
-+      plio_stat_2_t           stat2;
-+      plio_io_fifo_wm_t       fifo_wm;
-+      plio_io_fifo_lvl_t      fifo_lvl;
-+} plio_nbr_t;
-+
-+typedef struct {
-+      u32_t                   pfsm_sram[256];
-+      plio_config_t           config;
-+} plio_br_t;
-+
-+#define PLIO_NBR      ((plio_nbr_t *)(PLIO_PORT))
-+#define PLIO_BR               ((plio_br_t *)((PLIO_PORT + IO_PORT_BR_OFFSET)))
-+#define PEXT_NBR      ((plio_nbr_t *)(PLIO_EXT_PORT))
-+
-+extern void plio_init(const plio_fctl_t *plio_fctl, const plio_config_t *plio_config, const plio_sram_t plio_sram_cfg[], int sram_cfg_size);
-+
-+#endif // __PLIO__H__
---- /dev/null
-+++ b/arch/ubicom32/include/asm/poll.h
-@@ -0,0 +1,36 @@
-+/*
-+ * arch/ubicom32/include/asm/poll.h
-+ *   Ubicom32 specific poll() related flags definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_POLL_H
-+#define _ASM_UBICOM32_POLL_H
-+
-+#define POLLWRNORM    POLLOUT
-+#define POLLWRBAND    0x0100
-+
-+#include <asm-generic/poll.h>
-+
-+#endif /* _ASM_UBICOM32_POLL_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/posix_types.h
-@@ -0,0 +1,93 @@
-+/*
-+ * arch/ubicom32/include/asm/posix_types.h
-+ *   Ubicom32 architecture posix types.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 2004   Microtronix Datacom Ltd
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef __ARCH_UBICOM32_POSIX_TYPES_H
-+#define __ARCH_UBICOM32_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 long __kernel_ino_t;
-+typedef unsigned short        __kernel_mode_t;
-+typedef unsigned short        __kernel_nlink_t;
-+typedef long          __kernel_off_t;
-+typedef int           __kernel_pid_t;
-+typedef unsigned short        __kernel_ipc_pid_t;
-+typedef unsigned short        __kernel_uid_t;
-+typedef unsigned short        __kernel_gid_t;
-+typedef unsigned int  __kernel_size_t;
-+typedef int           __kernel_ssize_t;
-+typedef int           __kernel_ptrdiff_t;
-+typedef long          __kernel_time_t;
-+typedef long          __kernel_suseconds_t;
-+typedef long          __kernel_clock_t;
-+typedef int           __kernel_timer_t;
-+typedef int           __kernel_clockid_t;
-+typedef int           __kernel_daddr_t;
-+typedef char *                __kernel_caddr_t;
-+typedef unsigned short        __kernel_uid16_t;
-+typedef unsigned short        __kernel_gid16_t;
-+typedef unsigned int  __kernel_uid32_t;
-+typedef unsigned int  __kernel_gid32_t;
-+
-+typedef unsigned short        __kernel_old_uid_t;
-+typedef unsigned short        __kernel_old_gid_t;
-+typedef unsigned short        __kernel_old_dev_t;
-+
-+#ifdef __GNUC__
-+typedef long long     __kernel_loff_t;
-+#endif
-+
-+typedef struct {
-+#if defined(__KERNEL__) || defined(__USE_ALL)
-+      int     val[2];
-+#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
-+      int     __val[2];
-+#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
-+} __kernel_fsid_t;
-+
-+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
-+
-+#undef        __FD_SET
-+#define       __FD_SET(d, set)        ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
-+
-+#undef        __FD_CLR
-+#define       __FD_CLR(d, set)        ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
-+
-+#undef        __FD_ISSET
-+#define       __FD_ISSET(d, set)      ((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
-+
-+#undef        __FD_ZERO
-+#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
-+
-+#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
-+
-+#endif
---- /dev/null
-+++ b/arch/ubicom32/include/asm/processor.h
-@@ -0,0 +1,163 @@
-+/*
-+ * arch/ubicom32/include/asm/processor.h
-+ *   Thread related definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 1995 Hamish Macdonald
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_PROCESSOR_H
-+#define _ASM_UBICOM32_PROCESSOR_H
-+
-+/*
-+ * Default implementation of macro that returns current
-+ * instruction pointer ("program counter").
-+ */
-+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
-+
-+#include <linux/compiler.h>
-+#include <linux/threads.h>
-+#include <asm/types.h>
-+#include <asm/segment.h>
-+#include <asm/fpu.h>
-+#include <asm/ptrace.h>
-+#include <asm/current.h>
-+#include <asm/thread_info.h>
-+
-+#if defined(CONFIG_UBICOM32_V3)
-+      #define CPU "IP5K"
-+#endif
-+#if defined(CONFIG_UBICOM32_V4)
-+      #define CPU "IP7K"
-+#endif
-+#ifndef CPU
-+      #define CPU "UNKNOWN"
-+#endif
-+
-+/*
-+ * User space process size: 1st byte beyond user address space.
-+ */
-+extern unsigned long memory_end;
-+#define TASK_SIZE     (memory_end)
-+
-+/*
-+ * This decides where the kernel will search for a free chunk of vm
-+ * space during mmap's. We won't be using it
-+ */
-+#define TASK_UNMAPPED_BASE    0
-+
-+/*
-+ * This is the structure where we are going to save callee-saved registers.
-+ * A5 is the return address, A7 is the stack pointer, A6 is the frame
-+ * pointer.  This is the frame that is created because of switch_to. This
-+ * is not the frame due to interrupt preemption or because of syscall entry.
-+ */
-+
-+struct thread_struct {
-+      unsigned long  d10;             /* D10  */
-+      unsigned long  d11;             /* D11  */
-+      unsigned long  d12;             /* D12  */
-+      unsigned long  d13;             /* D13  */
-+      unsigned long  a1;              /* A1  */
-+      unsigned long  a2;              /* A2  */
-+      unsigned long  a5;              /* A5 return address. */
-+      unsigned long  a6;              /* A6 */
-+      unsigned long  sp;              /* A7 kernel stack pointer. */
-+};
-+
-+#define INIT_THREAD  { \
-+      0, 0, 0, 0, 0, 0, 0, 0, \
-+      sizeof(init_stack) + (unsigned long) init_stack - 8, \
-+}
-+
-+/*
-+ * Do necessary setup to start up a newly executed thread.
-+ *
-+ * pass the data segment into user programs if it exists,
-+ * it can't hurt anything as far as I can tell
-+ */
-+/*
-+ * Do necessary setup to start up a newly executed thread.
-+ */
-+#define start_thread(regs, new_pc, new_sp)     \
-+      do {                                     \
-+              regs->pc = new_pc & ~3;          \
-+              regs->an[5] = new_pc & ~3;       \
-+              regs->an[7] = new_sp;            \
-+              regs->nesting_level = -1;        \
-+              regs->frame_type = UBICOM32_FRAME_TYPE_NEW_THREAD; \
-+              regs->thread_type = NORMAL_THREAD; \
-+      } while(0)
-+
-+/* Forward declaration, a strange C thing */
-+struct task_struct;
-+
-+/* Free all resources held by a thread. */
-+static inline void release_thread(struct task_struct *dead_task)
-+{
-+}
-+
-+/* Prepare to copy thread state - unlazy all lazy status */
-+#define prepare_to_copy(tsk)  do { } while (0)
-+
-+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-+
-+/*
-+ * Free current thread data structures etc..
-+ */
-+static inline void exit_thread(void)
-+{
-+}
-+
-+unsigned long thread_saved_pc(struct task_struct *tsk);
-+unsigned long get_wchan(struct task_struct *p);
-+
-+#define       KSTK_EIP(tsk)   (tsk->thread.a5)
-+#define       KSTK_ESP(tsk)   (tsk->thread.sp)
-+
-+#define cpu_relax()    barrier()
-+
-+extern void processor_init(void);
-+extern unsigned int processor_timers(void);
-+extern unsigned int processor_threads(void);
-+extern unsigned int processor_frequency(void);
-+extern int processor_interrupts(unsigned int *int0, unsigned int *int1);
-+extern void processor_ocm(unsigned long *socm, unsigned long *eocm);
-+extern void processor_dram(unsigned long *sdram, unsigned long *edram);
-+
-+#define THREAD_SIZE_LONGS      (THREAD_SIZE/sizeof(unsigned long))
-+#define KSTK_TOP(info)                                                 \
-+({                                                                     \
-+       unsigned long *__ptr = (unsigned long *)(info);                 \
-+       (unsigned long)(&__ptr[THREAD_SIZE_LONGS]);                     \
-+})
-+
-+#define task_pt_regs(task)                                             \
-+({                                                                     \
-+       struct pt_regs *__regs__;                                       \
-+       __regs__ = (struct pt_regs *)(KSTK_TOP(task_stack_page(task))-8); \
-+       __regs__ - 1;                                                   \
-+})
-+
-+#endif        /* _ASM_UBICOM32_PROCESSOR_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/profilesample.h
-@@ -0,0 +1,44 @@
-+/*
-+ * arch/ubicom32/mach-common/profile.h
-+ *   Private data for the profile module
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+
-+#ifndef _PROFILESAMPLE_H_
-+#define _PROFILESAMPLE_H_
-+
-+/*
-+ * a sample taken by the ipProfile package for sending to the profilertool
-+ */
-+struct profile_sample {
-+      unsigned int pc;                        /* PC value */
-+      unsigned int a5;                        /* a5 contents for parent of leaf function */
-+      unsigned int parent;                    /* return address from stack, to find the caller */
-+      unsigned int latency;                   /* CPU clocks since the last message dispatch in this thread (thread 0 ony for now) */
-+      unsigned short active;                  /* which threads are active - for accurate counting */
-+      unsigned short d_blocked;               /* which threads are blocked due to D cache misses */
-+      unsigned short i_blocked;               /* which threads are blocked due to I cache misses */
-+      unsigned char cond_codes;               /* for branch prediction */
-+      unsigned char thread;                   /* I-blocked, D-blocked, 4-bit thread number */
-+};
-+
-+#endif
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ptrace.h
-@@ -0,0 +1,177 @@
-+/*
-+ * arch/ubicom32/include/asm/ptrace.h
-+ *   Ubicom32 architecture ptrace support.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_PTRACE_H
-+#define _ASM_UBICOM32_PTRACE_H
-+
-+#ifndef __ASSEMBLY__
-+
-+/*
-+ * We use hard coded constants because this is shared with user
-+ * space and the values are NOT allowed to change.  Only fields
-+ * that are intended to be exposed get values.
-+ */
-+#define PT_D0           0
-+#define PT_D1           4
-+#define PT_D2           8
-+#define PT_D3           12
-+#define PT_D4           16
-+#define PT_D5           20
-+#define PT_D6           24
-+#define PT_D7           28
-+#define PT_D8           32
-+#define PT_D9           36
-+#define PT_D10          40
-+#define PT_D11          44
-+#define PT_D12          48
-+#define PT_D13          52
-+#define PT_D14          56
-+#define PT_D15          60
-+#define PT_A0           64
-+#define PT_A1           68
-+#define PT_A2           72
-+#define PT_A3           76
-+#define PT_A4           80
-+#define PT_A5           84
-+#define PT_A6           88
-+#define PT_A7           92
-+#define PT_SP           92
-+#define PT_ACC0HI       96
-+#define PT_ACC0LO       100
-+#define PT_MAC_RC16     104
-+#define PT_ACC1HI       108
-+#define PT_ACC1LO       112
-+#define PT_SOURCE3      116
-+#define PT_INST_CNT     120
-+#define PT_CSR          124
-+#define PT_DUMMY_UNUSED 128
-+#define PT_INT_MASK0    132
-+#define PT_INT_MASK1    136
-+#define PT_TRAP_CAUSE   140
-+#define PT_PC           144
-+#define PT_ORIGINAL_D0  148
-+#define PT_FRAME_TYPE   152
-+
-+/*
-+ * The following 'registers' are not registers at all but are used
-+ * locate the relocated sections.
-+ */
-+#define PT_TEXT_ADDR          200
-+#define PT_TEXT_END_ADDR      204
-+#define PT_DATA_ADDR          208
-+#define PT_EXEC_FDPIC_LOADMAP 212
-+#define PT_INTERP_FDPIC_LOADMAP       216
-+
-+/*
-+ * This struct defines the way the registers are stored on the
-+ * stack during a system call.
-+ */
-+enum thread_type {
-+      NORMAL_THREAD,
-+      KERNEL_THREAD,
-+};
-+
-+#define UBICOM32_FRAME_TYPE_SYSCALL   -1 /* System call frame */
-+#define UBICOM32_FRAME_TYPE_INVALID   0 /* Invalid frame, no longer in use */
-+#define UBICOM32_FRAME_TYPE_INTERRUPT 1 /* Interrupt frame */
-+#define UBICOM32_FRAME_TYPE_TRAP      2 /* Trap frame */
-+#define UBICOM32_FRAME_TYPE_SIGTRAMP  3 /* Signal trampoline frame. */
-+#define UBICOM32_FRAME_TYPE_NEW_THREAD        4 /* New Thread. */
-+
-+struct pt_regs {
-+      /*
-+       * Data Registers
-+       */
-+      unsigned long dn[16];
-+
-+      /*
-+       * Address Registers
-+       */
-+      unsigned long an[8];
-+
-+      /*
-+       * Per thread misc registers.
-+       */
-+      unsigned long acc0[2];
-+      unsigned long mac_rc16;
-+      unsigned long acc1[2];
-+      unsigned long source3;
-+      unsigned long inst_cnt;
-+      unsigned long csr;
-+      unsigned long dummy_unused;
-+      unsigned long int_mask0;
-+      unsigned long int_mask1;
-+      unsigned long trap_cause;
-+      unsigned long pc;
-+      unsigned long original_dn_0;
-+
-+      /*
-+       * Frame type. Syscall frames are -1. For other types look above.
-+       */
-+      unsigned long frame_type;
-+
-+      /*
-+       * These fields are not exposed to ptrace.
-+       */
-+      unsigned long previous_pc;
-+      long nesting_level;             /* When the kernel in in user space this
-+                                       * will be -1. */
-+      unsigned long thread_type;      /* This indicates if this is a kernel
-+                                       * thread. */
-+};
-+
-+/*
-+ * This is the extended stack used by signal handlers and the context
-+ * switcher: it's pushed after the normal "struct pt_regs".
-+ */
-+struct switch_stack {
-+      unsigned long  dummy;
-+};
-+
-+#ifdef __KERNEL__
-+
-+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
-+#define PTRACE_GETREGS                12
-+#define PTRACE_SETREGS                13
-+
-+#ifndef PS_S
-+#define PS_S  (0x2000)
-+#define PS_M  (0x1000)
-+#endif
-+
-+extern  int __user_mode(unsigned long sp);
-+
-+#define user_mode(regs) (__user_mode((regs->an[7])))
-+#define user_stack(regs) ((regs)->an[7])
-+#define instruction_pointer(regs) ((regs)->pc)
-+#define profile_pc(regs) instruction_pointer(regs)
-+extern void show_regs(struct pt_regs *);
-+#endif /* __KERNEL__ */
-+
-+#endif /* __ASSEMBLY__ */
-+
-+#endif /* _ASM_UBICOM32_PTRACE_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/range-protect-asm.h
-@@ -0,0 +1,91 @@
-+/*
-+ * arch/ubicom32/include/asm/range-protect-asm.h
-+ *   Assembly macros for enabling memory protection.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_RANGE_PROTECT_ASM_H
-+#define _ASM_UBICOM32_RANGE_PROTECT_ASM_H
-+
-+#if defined(__ASSEMBLY__)
-+
-+#include <asm/thread-asm.h>
-+
-+/*
-+ * You should only use the enable/disable ranges when you have the atomic lock,
-+ * if you do not there will be problems.
-+ */
-+
-+/*
-+ * enable_kernel_ranges
-+ *    Enable the kernel ranges (disabling protection) for thread,
-+ *    where thread == (1 << thread number)
-+ */
-+.macro        enable_kernel_ranges thread
-+#ifdef CONFIG_PROTECT_KERNEL
-+      or.4    I_RANGE0_EN, I_RANGE0_EN, \thread        /* Enable Range Register */
-+      or.4    D_RANGE0_EN, D_RANGE0_EN, \thread
-+      or.4    D_RANGE1_EN, D_RANGE1_EN, \thread
-+#endif
-+.endm
-+
-+/*
-+ * enable_kernel_ranges_for_current
-+ *    Enable the kernel ranges (disabling protection) for this thread
-+ */
-+.macro        enable_kernel_ranges_for_current scratch_reg
-+#ifdef CONFIG_PROTECT_KERNEL
-+      thread_get_self_mask \scratch_reg
-+      enable_kernel_ranges \scratch_reg
-+#endif
-+.endm
-+
-+/*
-+ * disable_kernel_ranges
-+ *    Disables the kernel ranges (enabling protection) for thread
-+ *    where thread == (1 << thread number)
-+ */
-+.macro        disable_kernel_ranges thread
-+#ifdef CONFIG_PROTECT_KERNEL
-+      not.4   \thread, \thread
-+      and.4   I_RANGE0_EN, I_RANGE0_EN, \thread        /* Disable Range Register */
-+      and.4   D_RANGE0_EN, D_RANGE0_EN, \thread
-+      and.4   D_RANGE1_EN, D_RANGE1_EN, \thread
-+#endif
-+.endm
-+
-+/*
-+ * disable_kernel_ranges_for_current
-+ *    Disable kernel ranges (enabling protection) for this thread
-+ */
-+.macro        disable_kernel_ranges_for_current scratch_reg
-+#ifdef CONFIG_PROTECT_KERNEL
-+      thread_get_self_mask \scratch_reg
-+      disable_kernel_ranges \scratch_reg
-+#endif
-+.endm
-+#endif
-+
-+#endif  /* _ASM_UBICOM32_RANGE_PROTECT_ASM_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/range-protect.h
-@@ -0,0 +1,62 @@
-+/*
-+ * arch/ubicom32/include/asm/range-protect.h
-+ *   Assembly macros declared in C for enabling memory protection.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_RANGE_PROTECT_H
-+#define _ASM_UBICOM32_RANGE_PROTECT_H
-+
-+#if !defined(__ASSEMBLY__)
-+#include <asm/thread.h>
-+/*
-+ * The following macros should be the identical to the ones in
-+ * range-protect-asm.h
-+ *
-+ * You should only use the enable/disable ranges when you have the atomic lock,
-+ * if you do not there will be problems.
-+ */
-+
-+/*
-+ * enable_kernel_ranges
-+ *    Enable the kernel ranges (disabling protection) for thread,
-+ *    where thread == (1 << thread number)
-+ */
-+asm (
-+      ".macro enable_kernel_ranges thread                     \n\t"
-+#ifdef CONFIG_PROTECT_KERNEL
-+      "       or.4    I_RANGE0_EN, I_RANGE0_EN, \\thread      \n\t" /* Enable Range Register */
-+      "       or.4    D_RANGE0_EN, D_RANGE0_EN, \\thread      \n\t"
-+      "       or.4    D_RANGE1_EN, D_RANGE1_EN, \\thread      \n\t"
-+#endif
-+      ".endm                                                  \n\t"
-+);
-+
-+#else /* __ASSEMBLY__ */
-+
-+#include <asm/range-protect-asm.h>
-+
-+#endif
-+#endif  /* _ASM_UBICOM32_RANGE_PROTECT_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/resource.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/resource.h
-+ *   Generic definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_RESOURCE_H
-+#define _ASM_UBICOM32_RESOURCE_H
-+
-+#include <asm-generic/resource.h>
-+
-+#endif /* _ASM_UBICOM32_RESOURCE_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ring_tio.h
-@@ -0,0 +1,42 @@
-+/*
-+ * arch/ubicom32/include/asm/ring_tio.h
-+ *   Ubicom32 architecture Ring TIO definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+#ifndef _ASM_UBICOM32_RING_TIO_H
-+#define _ASM_UBICOM32_RING_TIO_H
-+
-+#include <asm/devtree.h>
-+
-+#define RING_TIO_NODE_VERSION 2
-+
-+/*
-+ * Devtree node for ring
-+ */
-+struct ring_tio_node {
-+      struct devtree_node     dn;
-+
-+      u32_t                   version;
-+      void                    *regs;
-+};
-+
-+extern void ring_tio_init(const char *node_name);
-+
-+#endif /* _ASM_UBICOM32_RING_TIO_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/scatterlist.h
-@@ -0,0 +1,49 @@
-+/*
-+ * arch/ubicom32/include/asm/scatterlist.h
-+ *   Definitions of struct scatterlist for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SCATTERLIST_H
-+#define _ASM_UBICOM32_SCATTERLIST_H
-+
-+#include <linux/mm.h>
-+#include <asm/types.h>
-+
-+struct scatterlist {
-+#ifdef CONFIG_DEBUG_SG
-+      unsigned long   sg_magic;
-+#endif
-+      unsigned long   page_link;
-+      unsigned int    offset;
-+      dma_addr_t      dma_address;
-+      unsigned int    length;
-+};
-+
-+#define sg_dma_address(sg)      ((sg)->dma_address)
-+#define sg_dma_len(sg)          ((sg)->length)
-+
-+#define ISA_DMA_THRESHOLD     (0xffffffff)
-+
-+#endif /* _ASM_UBICOM32_SCATTERLIST_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/sd_tio.h
-@@ -0,0 +1,36 @@
-+/*
-+ * arch/ubicom32/include/asm/sd_tio.h
-+ *   SD TIO definitions
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+#ifndef _ASM_UBICOM32_SD_TIO_H
-+#define _ASM_UBICOM32_SD_TIO_H
-+
-+#include <asm/devtree.h>
-+
-+/*
-+ * Devtree node for SD
-+ */
-+struct sd_tio_node {
-+      struct devtree_node     dn;
-+      void                    *regs;
-+};
-+
-+#endif /* _ASM_UBICOM32_SD_TIO_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/sections.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/sections.h
-+ *   Generic sections.h definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SECTIONS_H
-+#define _ASM_UBICOM32_SECTIONS_H
-+
-+#include <asm-generic/sections.h>
-+
-+#endif /* _ASM_UBICOM32_SECTIONS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/segment.h
-@@ -0,0 +1,78 @@
-+/*
-+ * arch/ubicom32/include/asm/segment.h
-+ *   Memory segment definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SEGMENT_H
-+#define _ASM_UBICOM32_SEGMENT_H
-+
-+/* define constants */
-+/* Address spaces (FC0-FC2) */
-+#define USER_DATA     (1)
-+#ifndef __USER_DS
-+#define __USER_DS     (USER_DATA)
-+#endif
-+#define USER_PROGRAM  (2)
-+#define SUPER_DATA    (5)
-+#ifndef __KERNEL_DS
-+#define __KERNEL_DS   (SUPER_DATA)
-+#endif
-+#define SUPER_PROGRAM (6)
-+#define CPU_SPACE     (7)
-+
-+#ifndef __ASSEMBLY__
-+
-+typedef struct {
-+      unsigned long seg;
-+} mm_segment_t;
-+
-+#define MAKE_MM_SEG(s)        ((mm_segment_t) { (s) })
-+#define USER_DS               MAKE_MM_SEG(__USER_DS)
-+#define KERNEL_DS     MAKE_MM_SEG(__KERNEL_DS)
-+
-+/*
-+ * Get/set the SFC/DFC registers for MOVES instructions
-+ */
-+
-+static inline mm_segment_t get_fs(void)
-+{
-+    return USER_DS;
-+}
-+
-+static inline mm_segment_t get_ds(void)
-+{
-+    /* return the supervisor data space code */
-+    return KERNEL_DS;
-+}
-+
-+static inline void set_fs(mm_segment_t val)
-+{
-+}
-+
-+#define segment_eq(a,b)       ((a).seg == (b).seg)
-+
-+#endif /* __ASSEMBLY__ */
-+
-+#endif /* _ASM_UBICOM32_SEGMENT_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/semaphore.h
-@@ -0,0 +1,140 @@
-+/*
-+ * arch/ubicom32/include/asm/semaphore.h
-+ *   Interrupt-safe semaphores for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * (C) Copyright 1996 Linus Torvalds
-+ * m68k version by Andreas Schwab
-+ * Copyright (C) 2004   Microtronix Datacom Ltd
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SEMAPHORE_H
-+#define _ASM_UBICOM32_SEMAPHORE_H
-+
-+#define RW_LOCK_BIAS           0x01000000
-+
-+#ifndef __ASSEMBLY__
-+
-+#include <linux/linkage.h>
-+#include <linux/wait.h>
-+#include <linux/spinlock.h>
-+#include <linux/rwsem.h>
-+
-+#include <asm/system.h>
-+#include <asm/atomic.h>
-+
-+struct semaphore {
-+      atomic_t count;
-+      atomic_t waking;
-+      wait_queue_head_t wait;
-+};
-+
-+#define __SEMAPHORE_INITIALIZER(name, n)                              \
-+{                                                                     \
-+      .count          = ATOMIC_INIT(n),                               \
-+      .waking         = ATOMIC_INIT(0),                               \
-+      .wait           = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait)    \
-+}
-+
-+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
-+      struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
-+
-+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
-+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
-+
-+static inline void sema_init (struct semaphore *sem, int val)
-+{
-+      *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val);
-+}
-+
-+static inline void init_MUTEX (struct semaphore *sem)
-+{
-+      sema_init(sem, 1);
-+}
-+
-+static inline void init_MUTEX_LOCKED (struct semaphore *sem)
-+{
-+      sema_init(sem, 0);
-+}
-+
-+asmlinkage void __down_failed(void /* special register calling convention */);
-+asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
-+asmlinkage int  __down_failed_trylock(void  /* params in registers */);
-+asmlinkage void __up_wakeup(void /* special register calling convention */);
-+
-+asmlinkage void __down(struct semaphore * sem);
-+asmlinkage int  __down_interruptible(struct semaphore * sem);
-+asmlinkage int  __down_trylock(struct semaphore * sem);
-+asmlinkage void __up(struct semaphore * sem);
-+
-+extern spinlock_t semaphore_wake_lock;
-+
-+/*
-+ * This is ugly, but we want the default case to fall through.
-+ * "down_failed" is a special asm handler that calls the C
-+ * routine that actually waits.
-+ */
-+static inline void down(struct semaphore * sem)
-+{
-+      might_sleep();
-+
-+      if (atomic_dec_return(&sem->count) < 0)
-+              __down(sem);
-+}
-+
-+static inline int down_interruptible(struct semaphore * sem)
-+{
-+      int ret = 0;
-+
-+
-+      might_sleep();
-+
-+      if(atomic_dec_return(&sem->count) < 0)
-+              ret = __down_interruptible(sem);
-+      return ret;
-+}
-+
-+static inline int down_trylock(struct semaphore * sem)
-+{
-+      int ret = 0;
-+
-+      if (atomic_dec_return (&sem->count) < 0)
-+              ret = __down_trylock(sem);
-+      return ret;
-+}
-+
-+/*
-+ * Note! This is subtle. We jump to wake people up only if
-+ * the semaphore was negative (== somebody was waiting on it).
-+ * The default case (no contention) will result in NO
-+ * jumps for both down() and up().
-+ */
-+static inline void up(struct semaphore * sem)
-+{
-+      if (atomic_inc_return(&sem->count) <= 0)
-+              __up(sem);
-+}
-+
-+#endif /* __ASSEMBLY__ */
-+
-+#endif /* _ASM_UBICOM32_SEMAPHORE_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/semaphore-helper.h
-@@ -0,0 +1,109 @@
-+/*
-+ * arch/ubicom32/include/asm/semaphore-helper.h
-+ *   Semaphore related definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SEMAPHORE_HELPER_H
-+#define _ASM_UBICOM32_SEMAPHORE_HELPER_H
-+
-+/*
-+ * SMP- and interrupt-safe semaphores helper functions.
-+ *
-+ * (C) Copyright 1996 Linus Torvalds
-+ *
-+ * m68k version by Andreas Schwab
-+ */
-+
-+
-+/*
-+ * These two _must_ execute atomically wrt each other.
-+ */
-+static inline void wake_one_more(struct semaphore * sem)
-+{
-+      atomic_inc(&sem->waking);
-+}
-+
-+static inline int waking_non_zero(struct semaphore *sem)
-+{
-+      int ret;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&semaphore_wake_lock, flags);
-+      ret = 0;
-+      if (atomic_read(&sem->waking) > 0) {
-+              atomic_dec(&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
-+ */
-+static inline int waking_non_zero_interruptible(struct semaphore *sem,
-+                                              struct task_struct *tsk)
-+{
-+      int ret;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&semaphore_wake_lock, flags);
-+      ret = 0;
-+      if (atomic_read(&sem->waking) > 0) {
-+              atomic_dec(&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_trylock:
-+ *    1       failed to lock
-+ *    0       got the lock
-+ */
-+static inline int waking_non_zero_trylock(struct semaphore *sem)
-+{
-+      int ret;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&semaphore_wake_lock, flags);
-+      ret = 1;
-+      if (atomic_read(&sem->waking) > 0) {
-+              atomic_dec(&sem->waking);
-+              ret = 0;
-+      } else
-+              atomic_inc(&sem->count);
-+      spin_unlock_irqrestore(&semaphore_wake_lock, flags);
-+      return ret;
-+}
-+
-+#endif /* _ASM_UBICOM32_SEMAPHORE_HELPER_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/sembuf.h
-@@ -0,0 +1,52 @@
-+/*
-+ * arch/ubicom32/include/asm/sembuf.h
-+ *   The semid64_ds structure for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SEMBUF_H
-+#define _ASM_UBICOM32_SEMBUF_H
-+
-+/*
-+ * The semid64_ds structure for ubicom32 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 /* _ASM_UBICOM32_SEMBUF_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/setup.h
-@@ -0,0 +1,35 @@
-+/*
-+ * arch/ubicom32/include/asm/setup.h
-+ *   Kernel command line length definition.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 2004, Microtronix Datacom Ltd., All rights reserved.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_SETUP_H
-+#define _ASM_UBICOM32_SETUP_H
-+
-+#define COMMAND_LINE_SIZE 512
-+
-+#endif /* _ASM_UBICOM32_SETUP_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/shmbuf.h
-@@ -0,0 +1,69 @@
-+/*
-+ * arch/ubicom32/include/asm/shmbuf.h
-+ *   The shmid64_ds structure for the Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SHMBUF_H
-+#define _ASM_UBICOM32_SHMBUF_H
-+
-+/*
-+ * The shmid64_ds structure for m68k 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 /* _ASM_UBICOM32_SHMBUF_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/shmparam.h
-@@ -0,0 +1,35 @@
-+/*
-+ * arch/ubicom32/include/asm/shmparam.h
-+ *   Shared memory definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 2004   Microtronix Datacom Ltd
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *   Alpha, ix86, M68K, Sparc, ...et al
-+ */
-+#ifndef _ASM_UBICOM32_SHMPARAM_H
-+#define _ASM_UBICOM32_SHMPARAM_H
-+
-+#define       SHMLBA          PAGE_SIZE       /* attach addr a multiple of this */
-+
-+#endif /* _ASM_UBICOM32_SHMPARAM_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/sigcontext.h
-@@ -0,0 +1,37 @@
-+/*
-+ * arch/ubicom32/include/asm/sigcontext.h
-+ *   Definition of sigcontext struct for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SIGCONTEXT_H
-+#define _ASM_UBICOM32_SIGCONTEXT_H
-+
-+#include <asm/ptrace.h>
-+
-+struct sigcontext {
-+      struct pt_regs sc_regs;
-+};
-+
-+#endif /* _ASM_UBICOM32_SIGCONTEXT_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/siginfo.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/siginfo.h
-+ *   Generic siginfo.h definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SIGINFO_H
-+#define _ASM_UBICOM32_SIGINFO_H
-+
-+#include <asm-generic/siginfo.h>
-+
-+#endif /* _ASM_UBICOM32_SIGINFO_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/signal.h
-@@ -0,0 +1,180 @@
-+/*
-+ * arch/ubicom32/include/asm/signal.h
-+ *   Signal related definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SIGNAL_H
-+#define _ASM_UBICOM32_SIGNAL_H
-+
-+#include <linux/types.h>
-+
-+/* Avoid too many header ordering problems.  */
-+struct siginfo;
-+
-+#ifdef __KERNEL__
-+/* Most things should be clean enough to redefine this at will, if care
-+   is taken to make libc match.  */
-+
-+#define _NSIG         64
-+#define _NSIG_BPW     32
-+#define _NSIG_WORDS   (_NSIG / _NSIG_BPW)
-+
-+typedef unsigned long old_sigset_t;           /* at least 32 bits */
-+
-+typedef struct {
-+      unsigned long sig[_NSIG_WORDS];
-+} sigset_t;
-+
-+#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
-+
-+/*
-+ * SA_FLAGS values:
-+ *
-+ * SA_ONSTACK indicates that a registered stack_t will be used.
-+ * SA_RESTART flag to get restarting signals (which were the default long ago)
-+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
-+ * SA_RESETHAND clears the handler when the signal is delivered.
-+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
-+ * SA_NODEFER prevents the current signal from being masked in the handler.
-+ *
-+ * 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_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
-+
-+#include <asm-generic/signal.h>
-+
-+#ifdef __KERNEL__
-+struct old_sigaction {
-+      __sighandler_t sa_handler;
-+      old_sigset_t sa_mask;
-+      unsigned long sa_flags;
-+      void (*sa_restorer)(void);
-+};
-+
-+struct sigaction {
-+      __sighandler_t sa_handler;
-+      unsigned long sa_flags;
-+      void (*sa_restorer)(void);
-+      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 *ss_sp;
-+      int ss_flags;
-+      size_t ss_size;
-+} stack_t;
-+
-+#ifdef __KERNEL__
-+
-+#include <asm/sigcontext.h>
-+#undef __HAVE_ARCH_SIG_BITOPS
-+
-+#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-+
-+#endif /* __KERNEL__ */
-+
-+#endif /* _ASM_UBICOM32_SIGNAL_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/smp.h
-@@ -0,0 +1,87 @@
-+/*
-+ * arch/ubicom32/include/asm/smp.h
-+ *   SMP definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SMP_H
-+#define _ASM_UBICOM32_SMP_H
-+
-+#ifndef CONFIG_SMP
-+#error you should not include smp.h if smp is off
-+#endif
-+
-+#ifndef ASSEMBLY
-+#include <linux/bitops.h>
-+#include <linux/threads.h>
-+#include <linux/cpumask.h>
-+#include <asm/ip5000.h>
-+
-+typedef unsigned long address_t;
-+extern unsigned int smp_ipi_irq;
-+
-+/*
-+ * This magic constant controls our willingness to transfer
-+ * a process across CPUs.
-+ *
-+ * Such a transfer incurs cache and tlb
-+ * misses. The current value is inherited from i386. Still needs
-+ * to be tuned for parisc.
-+ */
-+#define PROC_CHANGE_PENALTY   15              /* Schedule penalty */
-+#define NO_PROC_ID            0xFF            /* No processor magic marker */
-+#define ANY_PROC_ID           0xFF            /* Any processor magic marker */
-+
-+#ifdef CONFIG_SMP
-+#define raw_smp_processor_id()        (current_thread_info()->cpu)
-+#endif /* CONFIG_SMP */
-+
-+static inline int __cpu_disable (void)
-+{
-+  return 0;
-+}
-+
-+static inline void __cpu_die (unsigned int cpu)
-+{
-+      while(1) {
-+      };
-+}
-+
-+extern int __cpu_up(unsigned int cpu);
-+extern void smp_send_timer_all(void);
-+extern void smp_timer_broadcast(const struct cpumask *mask);
-+extern void smp_set_affinity(unsigned int irq, const struct cpumask *dest);
-+extern void arch_send_call_function_single_ipi(int cpu);
-+#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
-+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
-+
-+/*
-+ * TODO: Once these are fully tested, we should turn them into
-+ * inline macros for performance.
-+ */
-+extern unsigned long smp_get_affinity(unsigned int irq, int *all);
-+extern void smp_reset_ipi(unsigned long mask);
-+
-+#endif /* !ASSEMBLY */
-+#endif /*  _ASM_UBICOM32_SMP_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/socket.h
-@@ -0,0 +1,87 @@
-+/*
-+ * arch/ubicom32/include/asm/socket.h
-+ *   Socket options definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SOCKET_H
-+#define _ASM_UBICOM32_SOCKET_H
-+
-+#include <asm/sockios.h>
-+
-+/* For setsockopt(2) */
-+#define SOL_SOCKET    1
-+
-+#define SO_DEBUG      1
-+#define SO_REUSEADDR  2
-+#define SO_TYPE               3
-+#define SO_ERROR      4
-+#define SO_DONTROUTE  5
-+#define SO_BROADCAST  6
-+#define SO_SNDBUF     7
-+#define SO_RCVBUF     8
-+#define SO_SNDBUFFORCE        32
-+#define SO_RCVBUFFORCE        33
-+#define SO_KEEPALIVE  9
-+#define SO_OOBINLINE  10
-+#define SO_NO_CHECK   11
-+#define SO_PRIORITY   12
-+#define SO_LINGER     13
-+#define SO_BSDCOMPAT  14
-+/* To add :#define SO_REUSEPORT 15 */
-+#define SO_PASSCRED   16
-+#define SO_PEERCRED   17
-+#define SO_RCVLOWAT   18
-+#define SO_SNDLOWAT   19
-+#define SO_RCVTIMEO   20
-+#define SO_SNDTIMEO   21
-+
-+/* Security levels - as per NRL IPv6 - don't actually do anything */
-+#define SO_SECURITY_AUTHENTICATION            22
-+#define SO_SECURITY_ENCRYPTION_TRANSPORT      23
-+#define SO_SECURITY_ENCRYPTION_NETWORK                24
-+
-+#define SO_BINDTODEVICE       25
-+
-+/* Socket filtering */
-+#define SO_ATTACH_FILTER        26
-+#define SO_DETACH_FILTER        27
-+
-+#define SO_PEERNAME             28
-+#define SO_TIMESTAMP          29
-+#define SCM_TIMESTAMP         SO_TIMESTAMP
-+
-+#define SO_ACCEPTCONN         30
-+
-+#define SO_PEERSEC              31
-+#define SO_PASSSEC            34
-+#define SO_TIMESTAMPNS                35
-+#define SCM_TIMESTAMPNS               SO_TIMESTAMPNS
-+
-+#define SO_MARK                       36
-+
-+#define SO_TIMESTAMPING               37
-+#define SCM_TIMESTAMPING      SO_TIMESTAMPING
-+
-+#endif /* _ASM_UBICOM32_SOCKET_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/sockios.h
-@@ -0,0 +1,40 @@
-+/*
-+ * arch/ubicom32/include/asm/sockios.h
-+ *   Socket-level ioctl definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SOCKIOS_H
-+#define _ASM_UBICOM32_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 (timeval) */
-+#define SIOCGSTAMPNS  0x8907          /* Get stamp (timespec) */
-+
-+#endif /* _ASM_UBICOM32_SOCKIOS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/spinlock.h
-@@ -0,0 +1,296 @@
-+/*
-+ * arch/ubicom32/include/asm/spinlock.h
-+ *   Spinlock related definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SPINLOCK_H
-+#define _ASM_UBICOM32_SPINLOCK_H
-+
-+#include <asm/system.h>
-+#include <asm/processor.h>
-+#include <asm/spinlock_types.h>
-+
-+/*
-+ * __raw_spin_lock()
-+ *    Lock the lock.
-+ */
-+static inline void __raw_spin_lock(raw_spinlock_t *x)
-+{
-+      asm volatile (
-+      "1:     bset    %0, %0, #0      \n\t"
-+      "       jmpne.f 1b              \n\t"
-+              : "+U4" (x->lock)
-+              :
-+              : "memory", "cc"
-+      );
-+}
-+
-+/*
-+ * __raw_spin_unlock()
-+ *    Unlock the lock.
-+ */
-+static inline void __raw_spin_unlock(raw_spinlock_t *x)
-+{
-+      asm volatile (
-+      "       bclr    %0, %0, #0      \n\t"
-+              : "+U4" (x->lock)
-+              :
-+              : "memory", "cc"
-+      );
-+}
-+
-+/*
-+ * __raw_spin_is_locked()
-+ *    Test if the lock is locked.
-+ */
-+static inline int __raw_spin_is_locked(raw_spinlock_t *x)
-+{
-+      return x->lock;
-+}
-+
-+/*
-+ * __raw_spin_unlock_wait()
-+ *    Wait for the lock to be unlocked.
-+ *
-+ * Note: the caller has not guarantee that the lock will not
-+ * be acquired before they get to it.
-+ */
-+static inline void __raw_spin_unlock_wait(raw_spinlock_t *x)
-+{
-+      do {
-+              cpu_relax();
-+      } while (__raw_spin_is_locked(x));
-+}
-+
-+/*
-+ * __raw_spin_trylock()
-+ *    Try the lock, return 0 on failure, 1 on success.
-+ */
-+static inline int __raw_spin_trylock(raw_spinlock_t *x)
-+{
-+      int ret = 0;
-+
-+      asm volatile (
-+      "       bset    %1, %1, #0      \n\t"
-+      "       jmpne.f 1f              \n\t"
-+      "       move.4  %0, #1          \n\t"
-+      "1:                             \n\t"
-+              : "+r" (ret), "+U4" (x->lock)
-+              :
-+              : "memory", "cc"
-+      );
-+
-+      return ret;
-+}
-+
-+/*
-+ * __raw_spin_lock_flags()
-+ *    Spin waiting for the lock (enabling IRQ(s))
-+ */
-+static inline void __raw_spin_lock_flags(raw_spinlock_t *x, unsigned long flags)
-+{
-+      mb();
-+      while (!__raw_spin_trylock(x)) {
-+              /*
-+               * If the flags from the IRQ are set, interrupts are disabled and we
-+               * need to re-enable them.
-+               */
-+              if (!flags) {
-+                      cpu_relax();
-+              } else {
-+                      raw_local_irq_enable();
-+                      cpu_relax();
-+                      raw_local_irq_disable();
-+              }
-+      }
-+      mb();
-+}
-+
-+/*
-+ * Read-write spinlocks, allowing multiple readers but only one writer.
-+ * Linux rwlocks are unfair to writers; they can be starved for an indefinite
-+ * time by readers.  With care, they can also be taken in interrupt context.
-+ *
-+ * In Ubicom32 architecture implementation, we have a spinlock and a counter.
-+ * Readers use the lock to serialise their access to the counter (which
-+ * records how many readers currently hold the lock).
-+ * Writers hold the spinlock, preventing any readers or other writers from
-+ * grabbing the rwlock.
-+ */
-+
-+/*
-+ * __raw_read_lock()
-+ *    Increment the counter in the rwlock.
-+ *
-+ * Note that we have to ensure interrupts are disabled in case we're
-+ * interrupted by some other code that wants to grab the same read lock
-+ */
-+static inline void __raw_read_lock(raw_rwlock_t *rw)
-+{
-+      unsigned long flags;
-+      raw_local_irq_save(flags);
-+      __raw_spin_lock_flags(&rw->lock, flags);
-+      rw->counter++;
-+      __raw_spin_unlock(&rw->lock);
-+      raw_local_irq_restore(flags);
-+}
-+
-+/*
-+ * __raw_read_unlock()
-+ *    Decrement the counter.
-+ *
-+ * Note that we have to ensure interrupts are disabled in case we're
-+ * interrupted by some other code that wants to grab the same read lock
-+ */
-+static inline void __raw_read_unlock(raw_rwlock_t *rw)
-+{
-+      unsigned long flags;
-+      raw_local_irq_save(flags);
-+      __raw_spin_lock_flags(&rw->lock, flags);
-+      rw->counter--;
-+      __raw_spin_unlock(&rw->lock);
-+      raw_local_irq_restore(flags);
-+}
-+
-+/*
-+ * __raw_read_trylock()
-+ *    Increment the counter if we can.
-+ *
-+ * Note that we have to ensure interrupts are disabled in case we're
-+ * interrupted by some other code that wants to grab the same read lock
-+ */
-+static inline int __raw_read_trylock(raw_rwlock_t *rw)
-+{
-+      unsigned long flags;
-+ retry:
-+      raw_local_irq_save(flags);
-+      if (__raw_spin_trylock(&rw->lock)) {
-+              rw->counter++;
-+              __raw_spin_unlock(&rw->lock);
-+              raw_local_irq_restore(flags);
-+              return 1;
-+      }
-+
-+      raw_local_irq_restore(flags);
-+
-+      /*
-+       * If write-locked, we fail to acquire the lock
-+       */
-+      if (rw->counter < 0) {
-+              return 0;
-+      }
-+
-+      /*
-+       * Wait until we have a realistic chance at the lock
-+       */
-+      while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0) {
-+              cpu_relax();
-+      }
-+
-+      goto retry;
-+}
-+
-+/*
-+ * __raw_write_lock()
-+ *
-+ * Note that we have to ensure interrupts are disabled in case we're
-+ * interrupted by some other code that wants to read_trylock() this lock
-+ */
-+static inline void __raw_write_lock(raw_rwlock_t *rw)
-+{
-+      unsigned long flags;
-+retry:
-+      raw_local_irq_save(flags);
-+      __raw_spin_lock_flags(&rw->lock, flags);
-+
-+      if (rw->counter != 0) {
-+              __raw_spin_unlock(&rw->lock);
-+              raw_local_irq_restore(flags);
-+
-+              while (rw->counter != 0)
-+                      cpu_relax();
-+
-+              goto retry;
-+      }
-+
-+      rw->counter = -1; /* mark as write-locked */
-+      mb();
-+      raw_local_irq_restore(flags);
-+}
-+
-+static inline void __raw_write_unlock(raw_rwlock_t *rw)
-+{
-+      rw->counter = 0;
-+      __raw_spin_unlock(&rw->lock);
-+}
-+
-+/* Note that we have to ensure interrupts are disabled in case we're
-+ * interrupted by some other code that wants to read_trylock() this lock */
-+static inline int __raw_write_trylock(raw_rwlock_t *rw)
-+{
-+      unsigned long flags;
-+      int result = 0;
-+
-+      raw_local_irq_save(flags);
-+      if (__raw_spin_trylock(&rw->lock)) {
-+              if (rw->counter == 0) {
-+                      rw->counter = -1;
-+                      result = 1;
-+              } else {
-+                      /* Read-locked.  Oh well. */
-+                      __raw_spin_unlock(&rw->lock);
-+              }
-+      }
-+      raw_local_irq_restore(flags);
-+
-+      return result;
-+}
-+
-+/*
-+ * read_can_lock - would read_trylock() succeed?
-+ * @lock: the rwlock in question.
-+ */
-+static inline int __raw_read_can_lock(raw_rwlock_t *rw)
-+{
-+      return rw->counter >= 0;
-+}
-+
-+/*
-+ * write_can_lock - would write_trylock() succeed?
-+ * @lock: the rwlock in question.
-+ */
-+static inline int __raw_write_can_lock(raw_rwlock_t *rw)
-+{
-+      return !rw->counter;
-+}
-+
-+#define __raw_read_lock_flags(lock, flags) __raw_read_lock(lock)
-+#define __raw_write_lock_flags(lock, flags) __raw_write_lock(lock)
-+
-+#define _raw_spin_relax(lock) cpu_relax()
-+#define _raw_read_relax(lock) cpu_relax()
-+#define _raw_write_relax(lock)        cpu_relax()
-+
-+#endif /* _ASM_UBICOM32_SPINLOCK_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/spinlock_types.h
-@@ -0,0 +1,43 @@
-+/*
-+ * arch/ubicom32/include/asm/spinlock_types.h
-+ *   Spinlock related structure definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SPINLOCK_TYPES_H
-+#define _ASM_UBICOM32_SPINLOCK_TYPES_H
-+
-+typedef struct {
-+      volatile unsigned int lock;
-+} raw_spinlock_t;
-+
-+typedef struct {
-+      raw_spinlock_t lock;
-+      volatile int counter;
-+} raw_rwlock_t;
-+
-+#define __RAW_SPIN_LOCK_UNLOCKED      { 0 }
-+#define __RAW_RW_LOCK_UNLOCKED                { __RAW_SPIN_LOCK_UNLOCKED, 0 }
-+
-+#endif /* _ASM_UBICOM32_SPINLOCK_TYPES_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/stacktrace.h
-@@ -0,0 +1,72 @@
-+/*
-+ * arch/ubicom32/include/asm/stacktrace.h
-+ *   Stacktrace functions for the Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_STACKTRACE_H
-+#define _ASM_UBICOM32_STACKTRACE_H
-+
-+#define between(a, b, c)      (( \
-+                      ((unsigned long) a) >= ((unsigned long) b)) && \
-+                      (((unsigned long)a) <= ((unsigned long)c)))
-+
-+/*
-+ * These symbols are filled in by the linker.
-+ */
-+extern unsigned long _stext;
-+extern unsigned long _etext;
-+
-+/* OCM text goes from __ocm_text_run_begin to __data_begin */
-+extern unsigned long __ocm_text_run_begin;
-+extern unsigned long __data_begin;
-+
-+/* Account for OCM case - see stacktrace.c maybe combine(also trap.c) */
-+/*
-+ * ubicom32_is_kernel()
-+ *
-+ *    Check to see if the given address belongs to the kernel.
-+ * NOMMU does not permit any other means.
-+ */
-+static inline int ubicom32_is_kernel(unsigned long addr)
-+{
-+      int is_kernel = between(addr, &_stext, &_etext) || \
-+                      between(addr, &__ocm_text_run_begin, &__data_begin);
-+
-+#ifdef CONFIG_MODULES
-+      if (!is_kernel)
-+              is_kernel = is_module_address(addr);
-+#endif
-+      return is_kernel;
-+}
-+
-+extern unsigned long stacktrace_iterate(
-+                              unsigned long **trace,
-+                              unsigned long stext, unsigned long etext,
-+                              unsigned long ocm_stext, unsigned long ocm_etext,
-+                              unsigned long sstack, unsigned long estack);
-+#ifdef CONFIG_STACKTRACE
-+void stacktrace_save_entries(struct task_struct *tsk, struct stack_trace *trace, unsigned long sp);
-+#endif
-+#endif /* _ASM_UBICOM32_STACKTRACE_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/statfs.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/statfs.h
-+ *   Generic statfs.h definitions
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_STATFS_H
-+#define _ASM_UBICOM32_STATFS_H
-+
-+#include <asm-generic/statfs.h>
-+
-+#endif /* _ASM_UBICOM32_STATFS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/stat.h
-@@ -0,0 +1,104 @@
-+/*
-+ * arch/ubicom32/include/asm/stat.h
-+ *   File status definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_STAT_H
-+#define _ASM_UBICOM32_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;
-+};
-+
-+struct stat {
-+      unsigned short st_dev;
-+      unsigned short __pad1;
-+      unsigned long  st_ino;
-+      unsigned short st_mode;
-+      unsigned short st_nlink;
-+      unsigned short st_uid;
-+      unsigned short st_gid;
-+      unsigned short st_rdev;
-+      unsigned short __pad2;
-+      unsigned long  st_size;
-+      unsigned long  st_blksize;
-+      unsigned long  st_blocks;
-+      unsigned long  st_atime;
-+      unsigned long  __unused1;
-+      unsigned long  st_mtime;
-+      unsigned long  __unused2;
-+      unsigned long  st_ctime;
-+      unsigned long  __unused3;
-+      unsigned long  __unused4;
-+      unsigned long  __unused5;
-+};
-+
-+/* This matches struct stat64 in glibc2.1, hence the absolutely
-+ * insane amounts of padding around dev_t's.
-+ */
-+struct stat64 {
-+      unsigned long long      st_dev;
-+      unsigned char   __pad1[2];
-+
-+#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 char   __pad3[2];
-+
-+      long long       st_size;
-+      unsigned long   st_blksize;
-+
-+      unsigned long long      st_blocks;      /* Number 512-byte blocks allocated. */
-+
-+      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 /* _ASM_UBICOM32_STAT_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/string.h
-@@ -0,0 +1,40 @@
-+/*
-+ * arch/ubicom32/include/asm/string.h
-+ *   String operation definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_STRING_H
-+#define _ASM_UBICOM32_STRING_H
-+
-+#define __HAVE_ARCH_MEMSET
-+extern void *memset(void *b, int c, size_t len);
-+
-+#define __HAVE_ARCH_MEMCPY
-+extern void *memcpy(void *to, const void *from, size_t len);
-+
-+#define __HAVE_ARCH_MEMMOVE
-+extern void * memmove(void *to, const void *from, size_t len);
-+
-+#endif /* _ASM_UBICOM32_STRING_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/swab.h
-@@ -0,0 +1,45 @@
-+/*
-+ * arch/ubicom32/include/asm/byteorder.h
-+ *   Byte order swapping utility routines.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_BYTEORDER_H
-+#define _ASM_UBICOM32_BYTEORDER_H
-+
-+#include <linux/types.h>
-+
-+#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__)
-+#  define __BYTEORDER_HAS_U64__
-+#  define __SWAB_64_THRU_32__
-+#endif
-+
-+#if defined(IP7000) || defined(IP7000_REV2)
-+
-+#define __arch__swab16 __builtin_ubicom32_swapb_2
-+#define __arch__swab32 __builtin_ubicom32_swapb_4
-+
-+#endif /* IP7000 */
-+
-+#endif /* _ASM_UBICOM32_BYTEORDER_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/switch-dev.h
-@@ -0,0 +1,51 @@
-+/*
-+ * arch/ubicom32/include/asm/switch-dev.h
-+ *   generic Ethernet switch platform data definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SWITCH_DEV_H
-+#define _ASM_UBICOM32_SWITCH_DEV_H
-+
-+#define SWITCH_DEV_FLAG_HW_RESET      0x01
-+#define SWITCH_DEV_FLAG_SW_RESET      0x02
-+
-+struct switch_core_platform_data {
-+      /*
-+       * See flags above
-+       */
-+      u32_t           flags;
-+
-+      /*
-+       * GPIO to use for nReset
-+       */
-+      int             pin_reset;
-+
-+      /*
-+       * Name of this switch
-+       */
-+      const char      *name;
-+};
-+
-+#endif /* _ASM_UBICOM32_SWITCH_DEV_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/system.h
-@@ -0,0 +1,101 @@
-+/*
-+ * arch/ubicom32/include/asm/system.h
-+ *   Low level switching definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_SYSTEM_H
-+#define _ASM_UBICOM32_SYSTEM_H
-+
-+#include <linux/irqflags.h>
-+#include <linux/linkage.h>
-+#include <asm/segment.h>
-+#include <asm/entry.h>
-+#include <asm/ldsr.h>
-+#include <asm/irq.h>
-+#include <asm/percpu.h>
-+#include <asm/ubicom32-common.h>
-+#include <asm/processor.h>
-+
-+/*
-+ * switch_to(n) should switch tasks to task ptr, first checking that
-+ * ptr isn't the current task, in which case it does nothing.
-+ */
-+asmlinkage void resume(void);
-+extern void *__switch_to(struct task_struct *prev,
-+              struct thread_struct *prev_switch,
-+              struct thread_struct *next_switch);
-+
-+/*
-+ * We will need a per linux thread sw_ksp for the switch_to macro to
-+ * track the kernel stack pointer for the current thread on that linux thread.
-+ */
-+#define switch_to(prev,next,last)                                     \
-+({                                                                    \
-+      void *_last;                                                    \
-+      _last = (void *)                                                \
-+              __switch_to(prev, &prev->thread, &next->thread);        \
-+      (last) = _last;                                                 \
-+})
-+
-+/*
-+ * Force strict CPU ordering.
-+ * Not really required on ubicom32...
-+ */
-+#define nop()  asm volatile ("nop"::)
-+#define mb()   asm volatile (""   : : :"memory")
-+#define rmb()  asm volatile (""   : : :"memory")
-+#define wmb()  asm volatile (""   : : :"memory")
-+#define set_mb(var, value)    ({ (var) = (value); wmb(); })
-+
-+#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()      mb()
-+#define smp_rmb()     rmb()
-+#define smp_wmb()     wmb()
-+#define smp_read_barrier_depends()    do { } while(0)
-+#endif
-+
-+#define read_barrier_depends()  ((void)0)
-+
-+/*
-+ * The following defines change how the scheduler calls the switch_to()
-+ * macro.
-+ *
-+ * 1) The first causes the runqueue to be unlocked on entry to
-+ * switch_to().  Since our ctx code does not play with the runqueue
-+ * we do not need it unlocked.
-+ *
-+ * 2) The later turns interrupts on during a ctxsw to reduce the latency of
-+ * interrupts during ctx.  At this point in the port, we believe that this
-+ * latency is not a problem since we have very little code to perform a ctxsw.
-+ */
-+// #define __ARCH_WANT_UNLOCKED_CTXSW
-+// #define __ARCH_WANT_INTERRUPTS_ON_CTXSW
-+
-+#endif /* _ASM_UBICOM32_SYSTEM_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/termbits.h
-@@ -0,0 +1,227 @@
-+/*
-+ * arch/ubicom32/include/asm/termbits.h
-+ *   Terminal/serial port definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_TERMBITS_H
-+#define _ASM_UBICOM32_TERMBITS_H
-+
-+#include <linux/posix_types.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                      /* Shift from CBAUD to CIBAUD */
-+
-+/* 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
-+
-+
-+/* 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_UBICOM32_TERMBITS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/termios.h
-@@ -0,0 +1,119 @@
-+/*
-+ * arch/ubicom32/include/asm/termios.h
-+ *   Ubicom32 termio definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_TERMIOS_H
-+#define _ASM_UBICOM32_TERMIOS_H
-+
-+#include <asm/termbits.h>
-+#include <asm/ioctls.h>
-+
-+struct winsize {
-+      unsigned short ws_row;
-+      unsigned short ws_col;
-+      unsigned short ws_xpixel;
-+      unsigned short ws_ypixel;
-+};
-+
-+#define NCC 8
-+struct termio {
-+      unsigned short c_iflag;         /* input mode flags */
-+      unsigned short c_oflag;         /* output mode flags */
-+      unsigned short c_cflag;         /* control mode flags */
-+      unsigned short c_lflag;         /* local mode flags */
-+      unsigned char c_line;           /* line discipline */
-+      unsigned char c_cc[NCC];        /* control characters */
-+};
-+
-+#ifdef __KERNEL__
-+/*    intr=^C         quit=^|         erase=del       kill=^U
-+      eof=^D          vtime=\0        vmin=\1         sxtc=\0
-+      start=^Q        stop=^S         susp=^Z         eol=\0
-+      reprint=^R      discard=^U      werase=^W       lnext=^V
-+      eol2=\0
-+*/
-+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
-+#endif
-+
-+/* modem lines */
-+#define TIOCM_LE      0x001
-+#define TIOCM_DTR     0x002
-+#define TIOCM_RTS     0x004
-+#define TIOCM_ST      0x008
-+#define TIOCM_SR      0x010
-+#define TIOCM_CTS     0x020
-+#define TIOCM_CAR     0x040
-+#define TIOCM_RNG     0x080
-+#define TIOCM_DSR     0x100
-+#define TIOCM_CD      TIOCM_CAR
-+#define TIOCM_RI      TIOCM_RNG
-+#define TIOCM_OUT1    0x2000
-+#define TIOCM_OUT2    0x4000
-+#define TIOCM_LOOP    0x8000
-+
-+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-+
-+#ifdef __KERNEL__
-+
-+/*
-+ * Translate a "termio" structure into a "termios". Ugh.
-+ */
-+#define user_termio_to_kernel_termios(termios, termio) \
-+({ \
-+      unsigned short tmp; \
-+      get_user(tmp, &(termio)->c_iflag); \
-+      (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \
-+      get_user(tmp, &(termio)->c_oflag); \
-+      (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \
-+      get_user(tmp, &(termio)->c_cflag); \
-+      (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \
-+      get_user(tmp, &(termio)->c_lflag); \
-+      (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \
-+      get_user((termios)->c_line, &(termio)->c_line); \
-+      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 termios2))
-+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
-+#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_UBICOM32_TERMIOS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/thread-asm.h
-@@ -0,0 +1,51 @@
-+/*
-+ * arch/ubicom32/include/asm/thread-asm.h
-+ *   Ubicom32 architecture specific thread definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_THREAD_ASM_H
-+#define _ASM_UBICOM32_THREAD_ASM_H
-+
-+/*
-+ * thread_get_self
-+ *    Read and shift the current thread into reg
-+ *
-+ * Note that we don't need to mask the result as bits 6 through 31 of the
-+ * ROSR are zeroes.
-+ */
-+.macro        thread_get_self reg
-+      lsr.4   \reg, ROSR, #2
-+.endm
-+
-+/*
-+ * thread_get_self_mask
-+ *    Read and shift the current thread mask into reg
-+ */
-+.macro        thread_get_self_mask reg
-+      lsr.4   \reg, ROSR, #2
-+      lsl.4   \reg, #1, \reg   /* Thread bit */
-+.endm
-+
-+#endif /* _ASM_UBICOM32_THREAD_ASM_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/thread.h
-@@ -0,0 +1,320 @@
-+/*
-+ * arch/ubicom32/include/asm/thread.h
-+ *   Ubicom32 architecture specific thread definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_THREAD_H
-+#define _ASM_UBICOM32_THREAD_H
-+
-+#if !defined(__ASSEMBLY__)
-+
-+#include <asm/ptrace.h>
-+#include <asm/ubicom32-common.h>
-+
-+typedef int thread_t;
-+typedef unsigned char thread_type_t;
-+typedef void (*thread_exec_fn_t)(void *arg);
-+
-+#define THREAD_NULL 0x40
-+#define THREAD_TYPE_HRT (1 << 0)
-+#define THREAD_TYPE_SPECIAL 0
-+#define THREAD_TYPE_NORMAL 0
-+#define THREAD_TYPE_BACKGROUND (1 << 1)
-+
-+/*
-+ * This is the upper bound on the maximum hardware threads that one will find
-+ * on a Ubicom processor. It is used to size per hardware thread data structures.
-+ */
-+#define THREAD_ARCHITECTURAL_MAX 16
-+
-+/*
-+ * TODO: Rename this at some point to be thread_
-+ */
-+extern unsigned int sw_ksp[THREAD_ARCHITECTURAL_MAX];
-+
-+
-+/*
-+ * thread_get_self()
-+ */
-+static inline thread_t thread_get_self(void)
-+{
-+      thread_t result;
-+
-+      /*
-+       * Note that ROSR has zeroes in bits 6 through 31 and so we don't need
-+       * to do any additional bit masking here.
-+       */
-+      asm (
-+              "lsr.4  %0, ROSR, #2    \n\t"
-+              : "=d" (result)
-+              :
-+              : "cc"
-+      );
-+
-+      return result;
-+}
-+
-+/*
-+ * thread_suspend()
-+ */
-+static inline void thread_suspend(void)
-+{
-+      asm volatile (
-+              "suspend\n\t"
-+              :
-+              :
-+      );
-+}
-+
-+/*
-+ * thread_resume()
-+ */
-+static inline void thread_resume(thread_t thread)
-+{
-+      asm volatile (
-+              "move.4         MT_ACTIVE_SET, %0       \n\t"
-+              "pipe_flush     0                       \n\t"
-+              "pipe_flush     0                       \n\t"
-+              :
-+              : "d" (1 << thread)
-+      );
-+}
-+
-+
-+
-+/*
-+ * thread_enable_mask()
-+ *    Enable all threads in the mask.
-+ *
-+ * All writes to MT_EN must be protected by the MT_EN_LOCK bit
-+ */
-+static inline void thread_enable_mask(unsigned int mask)
-+{
-+      /*
-+       * must flush the pipeline twice.
-+       * first pipe_flush is to ensure write to MT_EN is completed
-+       * second one is to ensure any new instructions from
-+       * the targeted thread (the one being disabled), that
-+       * are issued while the write to MT_EN is being executed,
-+       * are completed.
-+       */
-+      UBICOM32_LOCK(MT_EN_LOCK_BIT);
-+      asm volatile (
-+              "or.4           MT_EN, MT_EN, %0        \n\t"
-+              "pipe_flush     0                       \n\t"
-+              "pipe_flush     0                       \n\t"
-+              :
-+              : "d" (mask)
-+              : "cc"
-+      );
-+      UBICOM32_UNLOCK(MT_EN_LOCK_BIT);
-+}
-+
-+/*
-+ * thread_enable()
-+ */
-+static inline void thread_enable(thread_t thread)
-+{
-+      thread_enable_mask(1 << thread);
-+}
-+
-+/*
-+ * thread_disable_mask()
-+ *    Disable all threads in the mask.
-+ *
-+ * All writes to MT_EN must be protected by the MT_EN_LOCK bit
-+ */
-+static inline void thread_disable_mask(unsigned int mask)
-+{
-+      /*
-+       * must flush the pipeline twice.
-+       * first pipe_flush is to ensure write to MT_EN is completed
-+       * second one is to ensure any new instructions from
-+       * the targeted thread (the one being disabled), that
-+       * are issued while the write to MT_EN is being executed,
-+       * are completed.
-+       */
-+      UBICOM32_LOCK(MT_EN_LOCK_BIT);
-+      asm volatile (
-+              "and.4          MT_EN, MT_EN, %0        \n\t"
-+              "pipe_flush     0                       \n\t"
-+              "pipe_flush     0                       \n\t"
-+              :
-+              : "d" (~mask)
-+              : "cc"
-+      );
-+      UBICOM32_UNLOCK(MT_EN_LOCK_BIT);
-+}
-+
-+/*
-+ * thread_disable()
-+ */
-+static inline void thread_disable(thread_t thread)
-+{
-+      thread_disable_mask(1 << thread);
-+}
-+
-+/*
-+ * thread_disable_others()
-+ *    Disable all other threads
-+ */
-+static inline void thread_disable_others(void)
-+{
-+      thread_t self = thread_get_self();
-+      thread_disable_mask(~(1 << self));
-+}
-+
-+/*
-+ * thread_is_trapped()
-+ *    Is the specified tid trapped?
-+ */
-+static inline int thread_is_trapped(thread_t tid)
-+{
-+      int thread_mask = (1 << tid);
-+      int trap_thread;
-+
-+      asm (
-+              "move.4         %0, MT_TRAP             \n\t"
-+              : "=d" (trap_thread)
-+              :
-+      );
-+      return (trap_thread & thread_mask);
-+}
-+
-+/*
-+ * thread_is_enabled()
-+ *    Is the specified tid enabled?
-+ */
-+static inline int thread_is_enabled(thread_t tid)
-+{
-+      int thread_mask = (1 << tid);
-+      int enabled_threads;
-+
-+      asm (
-+              "move.4         %0, MT_EN               \n\t"
-+              : "=d" (enabled_threads)
-+              :
-+      );
-+      return (enabled_threads & thread_mask);
-+}
-+
-+/*
-+ * thread_get_instruction_count()
-+ */
-+static inline unsigned int thread_get_instruction_count(void)
-+{
-+      unsigned int result;
-+      asm (
-+              "move.4         %0, INST_CNT            \n\t"
-+              : "=r" (result)
-+      );
-+      return result;
-+}
-+
-+/*
-+ * thread_get_pc()
-+ *    pc could point to a speculative and cancelled instruction unless thread is disabled
-+ */
-+static inline void *thread_get_pc(thread_t thread)
-+{
-+      void *result;
-+      asm (
-+              "move.4         csr, %1         \n\t"
-+              "setcsr_flush   0               \n\t"
-+              "move.4         %0, pc          \n\t"
-+              "move.4         csr, #0         \n\t"
-+              "setcsr_flush   0               \n\t"
-+              : "=r" (result)
-+              : "r" ((thread << 9) | (1 << 8))
-+      );
-+      return result;
-+}
-+
-+/*
-+ * thread_get_trap_cause()
-+ *    This should be called only when the thread is not running
-+ */
-+static inline unsigned int thread_get_trap_cause(thread_t thread)
-+{
-+      unsigned int result;
-+      asm (
-+              "move.4         csr, %1         \n\t"
-+              "setcsr_flush   0               \n\t"
-+              "move.4         %0, trap_cause  \n\t"
-+              "move.4         csr, #0         \n\t"
-+              "setcsr_flush   0               \n\t"
-+              : "=r" (result)
-+              : "r" ((thread << 9) | (1 << 8))
-+      );
-+      return result;
-+}
-+
-+/*
-+ * THREAD_STALL macro.
-+ */
-+#define THREAD_STALL \
-+              asm volatile ( \
-+                      "move.4 mt_dbg_active_clr, #-1  \n\t" \
-+                      "pipe_flush 0                   \n\t" \
-+                      : \
-+                      : \
-+              )
-+
-+extern unsigned int thread_get_mainline(void);
-+extern void thread_set_mainline(thread_t tid);
-+extern thread_t thread_alloc(void);
-+extern thread_t thread_start(thread_t thread, thread_exec_fn_t exec, void *arg, unsigned int *sp_high, thread_type_t type);
-+
-+/*
-+ * asm macros
-+ */
-+asm (
-+/*
-+ * thread_get_self
-+ *    Read and shift the current thread into reg
-+ *
-+ * Note that we don't need to mask the result as bits 6 through 31 of the
-+ * ROSR are zeroes.
-+ */
-+".macro       thread_get_self reg             \n\t"
-+"     lsr.4   \\reg, ROSR, #2         \n\t"
-+".endm                                        \n\t"
-+
-+/*
-+ * thread_get_self_mask
-+ *    Read and shift the current thread mask into reg
-+ */
-+".macro       thread_get_self_mask reg        \n\t"
-+"     lsr.4   \\reg, ROSR, #2         \n\t"
-+"     lsl.4   \\reg, #1, \\reg        \n\t"    /* Thread bit */
-+".endm                                        \n\t"
-+);
-+
-+#else /* __ASSEMBLY__ */
-+
-+#include <asm/thread-asm.h>
-+
-+#endif /* __ASSEMBLY__ */
-+#endif /* _ASM_UBICOM32_THREAD_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/thread_info.h
-@@ -0,0 +1,134 @@
-+/*
-+ * arch/ubicom32/include/asm/thread_info.h
-+ *   Ubicom32 architecture low-level thread information.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Adapted from the i386 and PPC versions by Greg Ungerer (gerg@snapgear.com)
-+ * Copyright (C) 2002  David Howells (dhowells@redhat.com)
-+ * - Incorporating suggestions made by Linus Torvalds and Dave Miller
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_THREAD_INFO_H
-+#define _ASM_UBICOM32_THREAD_INFO_H
-+
-+#include <asm/page.h>
-+
-+/*
-+ * Size of kernel stack for each process. This must be a power of 2...
-+ */
-+#ifdef CONFIG_4KSTACKS
-+#define THREAD_SIZE_ORDER (0)
-+#else
-+#define THREAD_SIZE_ORDER (1)
-+#endif
-+
-+/*
-+ * for asm files, THREAD_SIZE is now generated by asm-offsets.c
-+ */
-+#define THREAD_SIZE (PAGE_SIZE<<THREAD_SIZE_ORDER)
-+
-+#ifdef __KERNEL__
-+
-+#ifndef __ASSEMBLY__
-+
-+/*
-+ * low level task data.
-+ */
-+struct thread_info {
-+      struct task_struct *task;               /* main task structure */
-+      struct exec_domain *exec_domain;        /* execution domain */
-+      unsigned long      flags;               /* low level flags */
-+      int                cpu;                 /* cpu we're on */
-+      int                preempt_count;       /* 0 => preemptable, <0 => BUG */
-+      int                interrupt_nesting;   /* Interrupt nesting level. */
-+      struct restart_block restart_block;
-+};
-+
-+/*
-+ * macros/functions for gaining access to the thread information structure
-+ */
-+#define INIT_THREAD_INFO(tsk)                 \
-+{                                             \
-+      .task           = &tsk,                 \
-+      .exec_domain    = &default_exec_domain, \
-+      .flags          = 0,                    \
-+      .cpu            = 0,                    \
-+      .interrupt_nesting      = 0,            \
-+      .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)
-+{
-+      struct thread_info *ti;
-+
-+      asm (
-+              "and.4  %0, sp, %1\n\t"
-+              : "=&r" (ti)
-+              : "d" (~(THREAD_SIZE-1))
-+              : "cc"
-+      );
-+
-+      return ti;
-+}
-+
-+#define STACK_WARN (THREAD_SIZE / 8)
-+
-+#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR 1
-+
-+/* thread information allocation */
-+#define alloc_thread_info(tsk) ((struct thread_info *) \
-+                              __get_free_pages(GFP_KERNEL, THREAD_SIZE_ORDER))
-+#define free_thread_info(ti)  free_pages((unsigned long) (ti), THREAD_SIZE_ORDER)
-+#endif /* __ASSEMBLY__ */
-+
-+#define       PREEMPT_ACTIVE  0x4000000
-+
-+/*
-+ * thread information flag bit numbers
-+ */
-+#define TIF_SYSCALL_TRACE     0       /* syscall trace active */
-+#define TIF_SIGPENDING                1       /* signal pending */
-+#define TIF_NEED_RESCHED      2       /* rescheduling necessary */
-+#define TIF_POLLING_NRFLAG    3       /* true if poll_idle() is polling
-+                                         TIF_NEED_RESCHED */
-+#define TIF_MEMDIE            4
-+
-+/* as above, but as bit values */
-+#define _TIF_SYSCALL_TRACE    (1<<TIF_SYSCALL_TRACE)
-+#define _TIF_SIGPENDING               (1<<TIF_SIGPENDING)
-+#define _TIF_NEED_RESCHED     (1<<TIF_NEED_RESCHED)
-+#define _TIF_POLLING_NRFLAG   (1<<TIF_POLLING_NRFLAG)
-+
-+#define _TIF_WORK_MASK                0x0000FFFE      /* work to do on interrupt/exception return */
-+
-+#endif /* __KERNEL__ */
-+
-+#endif /* _ASM_UBICOM32_THREAD_INFO_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/timex.h
-@@ -0,0 +1,56 @@
-+/*
-+ * arch/ubicom32/include/asm/timex.h
-+ *   Ubicom32 architecture timex specifications.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_TIMEX_H
-+#define _ASM_UBICOM32_TIMEX_H
-+
-+#define CLOCK_TICK_RATE       266000000
-+
-+// #define ARCH_HAS_READ_CURRENT_TIMER
-+
-+typedef unsigned long cycles_t;
-+
-+static inline cycles_t get_cycles(void)
-+{
-+      return 0;
-+}
-+
-+extern int timer_alloc(void);
-+extern void timer_set(int timervector, unsigned int cycles);
-+extern int timer_reset(int timervector, unsigned int cycles);
-+extern void timer_tick_init(void);
-+extern void timer_device_init(void);
-+
-+#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
-+extern void local_timer_interrupt(void);
-+#endif
-+
-+#if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
-+extern int local_timer_setup(unsigned int cpu);
-+#endif
-+
-+#endif /* _ASM_UBICOM32_TIMEX_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/tlbflush.h
-@@ -0,0 +1,79 @@
-+/*
-+ * arch/ubicom32/include/asm/tlbflush.h
-+ *   TLB operations for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 2000 Lineo, David McCullough <davidm@uclinux.org>
-+ * Copyright (C) 2000-2002, Greg Ungerer <gerg@snapgear.com>
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_TLB_FLUSH_H
-+#define _ASM_UBICOM32_TLB_FLUSH_H
-+
-+#include <asm/setup.h>
-+
-+/*
-+ * flush all user-space atc entries.
-+ */
-+static inline void __flush_tlb(void)
-+{
-+      BUG();
-+}
-+
-+static inline void __flush_tlb_one(unsigned long addr)
-+{
-+      BUG();
-+}
-+
-+#define flush_tlb() __flush_tlb()
-+
-+/*
-+ * flush all atc entries (both kernel and user-space entries).
-+ */
-+static inline void flush_tlb_all(void)
-+{
-+      BUG();
-+}
-+
-+static inline void flush_tlb_mm(struct mm_struct *mm)
-+{
-+      BUG();
-+}
-+
-+static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
-+{
-+      BUG();
-+}
-+
-+static inline void flush_tlb_range(struct mm_struct *mm,
-+                                 unsigned long start, unsigned long end)
-+{
-+      BUG();
-+}
-+
-+static inline void flush_tlb_kernel_page(unsigned long addr)
-+{
-+      BUG();
-+}
-+
-+#endif /* _ASM_UBICOM32_TLB_FLUSH_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/tlb.h
-@@ -0,0 +1,47 @@
-+/*
-+ * arch/ubicom32/include/asm/tlb.h
-+ *   Ubicom32 architecture TLB operations.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_TLB_H
-+#define _ASM_UBICOM32_TLB_H
-+
-+/*
-+ * ubicom32 doesn't need any special per-pte or
-+ * per-vma handling..
-+ */
-+#define tlb_start_vma(tlb, vma)       do { } while (0)
-+#define tlb_end_vma(tlb, vma) do { } while (0)
-+#define __tlb_remove_tlb_entry(tlb, ptep, address)    do { } while (0)
-+
-+/*
-+ * .. because we flush the whole mm when it
-+ * fills up.
-+ */
-+#define tlb_flush(tlb)
-+
-+#include <asm-generic/tlb.h>
-+
-+#endif /* _ASM_UBICOM32_TLB_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/topology.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/topology.h
-+ *   Generic topology.h definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_TOPOLOGY_H
-+#define _ASM_UBICOM32_TOPOLOGY_H
-+
-+#include <asm-generic/topology.h>
-+
-+#endif /* _ASM_UBICOM32_TOPOLOGY_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/traps.h
-@@ -0,0 +1,55 @@
-+/*
-+ * arch/ubicom32/include/asm/traps.h
-+ *   Trap related definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_TRAPS_H
-+#define _ASM_UBICOM32_TRAPS_H
-+
-+/*
-+ * Trap causes passed from ultra to Host OS
-+ */
-+#define TRAP_CAUSE_TOTAL              13
-+#define TRAP_CAUSE_DST_RANGE_ERR      12
-+#define TRAP_CAUSE_SRC1_RANGE_ERR     11
-+#define TRAP_CAUSE_I_RANGE_ERR                10
-+#define TRAP_CAUSE_DCAPT              9
-+#define TRAP_CAUSE_DST_SERROR         8
-+#define TRAP_CAUSE_SRC1_SERROR                7
-+#define TRAP_CAUSE_DST_MISALIGNED     6
-+#define TRAP_CAUSE_SRC1_MISALIGNED    5
-+#define TRAP_CAUSE_DST_DECODE_ERR     4
-+#define TRAP_CAUSE_SRC1_DECODE_ERR    3
-+#define TRAP_CAUSE_ILLEGAL_INST               2
-+#define TRAP_CAUSE_I_SERROR           1
-+#define TRAP_CAUSE_I_DECODE_ERR               0
-+
-+extern void trap_handler(int irq, struct pt_regs *regs);
-+extern void trap_init_interrupt(void);
-+extern void unaligned_emulate(unsigned int thread);
-+extern int unaligned_only(unsigned int cause);
-+
-+#endif /* _ASM_UBICOM32_TRAPS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/types.h
-@@ -0,0 +1,75 @@
-+/*
-+ * arch/ubicom32/include/asm/types.h
-+ *   Date type definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_TYPES_H
-+#define _ASM_UBICOM32_TYPES_H
-+
-+/*
-+ * This file is never included by application software unless
-+ * explicitly requested (e.g., via linux/types.h) in which case the
-+ * application is Linux specific so (user-) name space pollution is
-+ * not a major issue.  However, for interoperability, libraries still
-+ * need to be careful to avoid a name clashes.
-+ */
-+
-+#include <asm-generic/int-ll64.h>
-+
-+#ifndef __ASSEMBLY__
-+
-+typedef unsigned short umode_t;
-+
-+#endif /* __ASSEMBLY__ */
-+
-+/*
-+ * These aren't exported outside the kernel to avoid name space clashes
-+ */
-+#ifdef __KERNEL__
-+
-+#define BITS_PER_LONG 32
-+
-+#ifndef __ASSEMBLY__
-+
-+/* DMA addresses are always 32-bits wide */
-+
-+typedef u32 dma_addr_t;
-+typedef u32 dma64_addr_t;
-+
-+/*
-+ * XXX These are "Ubicom style" typedefs. They should be removed in all files used by linux.
-+ */
-+typedef u32 u32_t;
-+typedef s32 s32_t;
-+typedef u16 u16_t;
-+typedef s16 s16_t;
-+typedef u8 u8_t;
-+typedef s8 s8_t;
-+
-+#endif /* __ASSEMBLY__ */
-+
-+#endif /* __KERNEL__ */
-+
-+#endif /* _ASM_UBICOM32_TYPES_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/uaccess.h
-@@ -0,0 +1,347 @@
-+/*
-+ * arch/ubicom32/include/asm/uaccess.h
-+ *   User space memory access functions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *   arch/alpha
-+ */
-+#ifndef _ASM_UBICOM32_UACCESS_H
-+#define _ASM_UBICOM32_UACCESS_H
-+
-+/*
-+ * User space memory access functions
-+ */
-+#include <linux/sched.h>
-+#include <linux/mm.h>
-+#include <linux/string.h>
-+
-+#include <asm/segment.h>
-+
-+#define VERIFY_READ   0
-+#define VERIFY_WRITE  1
-+
-+/*
-+ * The exception table consists of pairs of addresses: the first is the
-+ * address of an instruction that is allowed to fault, and the second is
-+ * the address at which the program should continue.  No registers are
-+ * modified, so it is entirely up to the continuation code to figure out
-+ * what to do.
-+ *
-+ * All the routines below use bits of fixup code that are out of line
-+ * with the main instruction path.  This means when everything is well,
-+ * we don't even have to jump over them.  Further, they do not intrude
-+ * on our cache or tlb entries.
-+ */
-+struct exception_table_entry
-+{
-+      unsigned long insn, fixup;
-+};
-+
-+/*
-+ * Ubicom32 does not currently support the exception table handling.
-+ */
-+extern unsigned long search_exception_table(unsigned long);
-+
-+
-+#if defined(CONFIG_ACCESS_OK_CHECKS_ENABLED)
-+extern int __access_ok(unsigned long addr, unsigned long size);
-+#else
-+static inline int __access_ok(unsigned long addr, unsigned long size)
-+{
-+      return 1;
-+}
-+#endif
-+#define access_ok(type, addr, size) \
-+      likely(__access_ok((unsigned long)(addr), (size)))
-+
-+/*
-+ * The following functions do not exist.  They keep callers
-+ * of put_user and get_user from passing unsupported argument
-+ * types.  They result in a link time error.
-+ */
-+extern int __put_user_bad(void);
-+extern int __get_user_bad(void);
-+
-+/*
-+ * __put_user_no_check()
-+ *    Put the requested data into the user space verifying the address
-+ *
-+ * Careful to not
-+ * (a) re-use the arguments for side effects (sizeof/typeof is ok)
-+ * (b) require any knowledge of processes at this stage
-+ */
-+#define __put_user_no_check(x, ptr, size)             \
-+({                                                    \
-+      int __pu_err = 0;                               \
-+      __typeof__(*(ptr)) __user *__pu_addr = (ptr);   \
-+      switch (size) {                                 \
-+      case 1:                                         \
-+      case 2:                                         \
-+      case 4:                                         \
-+      case 8:                                         \
-+              *__pu_addr = (__typeof__(*(ptr)))x;     \
-+              break;                                  \
-+      default:                                        \
-+              __pu_err = __put_user_bad();            \
-+              break;                                  \
-+      }                                               \
-+      __pu_err;                                       \
-+})
-+
-+/*
-+ * __put_user_check()
-+ *    Put the requested data into the user space verifying the address
-+ *
-+ * Careful to not
-+ * (a) re-use the arguments for side effects (sizeof/typeof is ok)
-+ * (b) require any knowledge of processes at this stage
-+ *
-+ * If requested, access_ok() will verify that ptr is a valid user
-+ * pointer.
-+ */
-+#define __put_user_check(x, ptr, size)                                \
-+({                                                            \
-+      int __pu_err = -EFAULT;                                 \
-+      __typeof__(*(ptr)) __user *__pu_addr = (ptr);           \
-+      if (access_ok(VERIFY_WRITE, __pu_addr, size)) {         \
-+              __pu_err = 0;                                   \
-+              switch (size) {                                 \
-+              case 1:                                         \
-+              case 2:                                         \
-+              case 4:                                         \
-+              case 8:                                         \
-+                      *__pu_addr = (__typeof__(*(ptr)))x;     \
-+                      break;                                  \
-+              default:                                        \
-+                      __pu_err = __put_user_bad();            \
-+                      break;                                  \
-+              }                                               \
-+      }                                                       \
-+      __pu_err;                                               \
-+})
-+
-+/*
-+ * __get_user_no_check()
-+ *    Read the value at ptr into x.
-+ *
-+ * If requested, access_ok() will verify that ptr is a valid user
-+ * pointer.  If the caller passes a modifying argument for ptr (e.g. x++)
-+ * this macro will not work.
-+ */
-+#define __get_user_no_check(x, ptr, size)                     \
-+({                                                            \
-+      int __gu_err = 0;                                       \
-+      __typeof__((x)) __gu_val = 0;                           \
-+      const __typeof__(*(ptr)) __user *__gu_addr = (ptr);     \
-+      switch (size) {                                         \
-+      case 1:                                                 \
-+      case 2:                                                 \
-+      case 4:                                                 \
-+      case 8:                                                 \
-+              __gu_val = (__typeof__((x)))*(__gu_addr);       \
-+              break;                                          \
-+      default:                                                \
-+              __gu_err = __get_user_bad();                    \
-+              (x) = 0;                                        \
-+              break;                                          \
-+      }                                                       \
-+      (x) = __gu_val;                                         \
-+      __gu_err;                                               \
-+})
-+
-+/*
-+ * __get_user_check()
-+ *    Read the value at ptr into x.
-+ *
-+ * If requested, access_ok() will verify that ptr is a valid user
-+ * pointer.
-+ */
-+#define __get_user_check(x, ptr, size)                                        \
-+({                                                                    \
-+      int __gu_err = -EFAULT;                                         \
-+      __typeof__(x) __gu_val = 0;                                     \
-+      const __typeof__(*(ptr)) __user *__gu_addr = (ptr);             \
-+      if (access_ok(VERIFY_READ, __gu_addr, size)) {                  \
-+              __gu_err = 0;                                           \
-+              switch (size) {                                         \
-+              case 1:                                                 \
-+              case 2:                                                 \
-+              case 4:                                                 \
-+              case 8:                                                 \
-+                      __gu_val = (__typeof__((x)))*(__gu_addr);       \
-+                      break;                                          \
-+              default:                                                \
-+                      __gu_err = __get_user_bad();                    \
-+                      (x) = 0;                                        \
-+                      break;                                          \
-+              }                                                       \
-+      }                                                               \
-+      (x) = __gu_val;                                                 \
-+      __gu_err;                                                       \
-+})
-+
-+/*
-+ * The "xxx" versions are allowed to perform some amount of address
-+ * space checking.  See access_ok().
-+ */
-+#define put_user(x,ptr) \
-+      __put_user_check((__typeof__(*(ptr)))(x),(ptr), sizeof(*(ptr)))
-+#define get_user(x,ptr) \
-+      __get_user_check((x), (ptr), sizeof(*(ptr)))
-+
-+/*
-+ * The "__xxx" versions do not do address space checking, useful when
-+ * doing multiple accesses to the same area (the programmer has to do the
-+ * checks by hand with "access_ok()")
-+ */
-+#define __put_user(x,ptr) \
-+      __put_user_no_check((__typeof__(*(ptr)))(x),(ptr), sizeof(*(ptr)))
-+#define __get_user(x,ptr) \
-+      __get_user_no_check((x), (ptr), sizeof(*(ptr)))
-+
-+/*
-+ * __copy_tofrom_user_no_check()
-+ *    Copy the data either to or from user space.
-+ *
-+ * Return the number of bytes NOT copied.
-+ */
-+static inline unsigned long
-+__copy_tofrom_user_no_check(void *to, const void *from, unsigned long n)
-+{
-+      memcpy(to, from, n);
-+      return 0;
-+}
-+
-+/*
-+ * copy_to_user()
-+ *    Copy the kernel data to user space.
-+ *
-+ * Return the number of bytes that were copied.
-+ */
-+static inline unsigned long
-+copy_to_user(void __user *to, const void *from, unsigned long n)
-+{
-+      if (!access_ok(VERIFY_WRITE, to, n)) {
-+              return n;
-+      }
-+      return __copy_tofrom_user_no_check((__force void *)to, from, n);
-+}
-+
-+/*
-+ * copy_from_user()
-+ *    Copy the user data to kernel space.
-+ *
-+ * Return the number of bytes that were copied.  On error, we zero
-+ * out the destination.
-+ */
-+static inline unsigned long
-+copy_from_user(void *to, const void __user *from, unsigned long n)
-+{
-+      if (!access_ok(VERIFY_READ, from, n)) {
-+              return n;
-+      }
-+      return __copy_tofrom_user_no_check(to, (__force void *)from, n);
-+}
-+
-+#define __copy_to_user(to, from, n) \
-+      __copy_tofrom_user_no_check((__force void *)to, from, n)
-+#define __copy_from_user(to, from, n) \
-+      __copy_tofrom_user_no_check(to, (__force void *)from, n)
-+#define __copy_to_user_inatomic(to, from, n) \
-+      __copy_tofrom_user_no_check((__force void *)to, from, n)
-+#define __copy_from_user_inatomic(to, from, n) \
-+      __copy_tofrom_user_no_check(to, (__force void *)from, n)
-+
-+#define copy_to_user_ret(to, from, n, retval) \
-+      ({ if (copy_to_user(to, from, n)) return retval; })
-+
-+#define copy_from_user_ret(to, from, n, retval) \
-+      ({ if (copy_from_user(to, from, n)) return retval; })
-+
-+/*
-+ * strncpy_from_user()
-+ *    Copy a null terminated string from userspace.
-+ *
-+ * dst - Destination in kernel space.  The buffer must be at least count.
-+ * src - Address of string in user space.
-+ * count - Maximum number of bytes to copy (including the trailing NULL).
-+ *
-+ * Returns the length of the string (not including the trailing NULL.  If
-+ * count is smaller than the length of the string, we copy count bytes
-+ * and return count.
-+ *
-+ */
-+static inline long strncpy_from_user(char *dst, const __user char *src, long count)
-+{
-+      char *tmp;
-+      if (!access_ok(VERIFY_READ, src, 1)) {
-+              return -EFAULT;
-+      }
-+
-+      strncpy(dst, src, count);
-+      for (tmp = dst; *tmp && count > 0; tmp++, count--) {
-+              ;
-+      }
-+      return(tmp - dst);
-+}
-+
-+/*
-+ * strnlen_user()
-+ *    Return the size of a string (including the ending 0)
-+ *
-+ * Return -EFAULT on exception, a value greater than <n> if too long
-+ */
-+static inline long strnlen_user(const __user char *src, long n)
-+{
-+      if (!access_ok(VERIFY_READ, src, 1)) {
-+              return -EFAULT;
-+      }
-+      return(strlen(src) + 1);
-+}
-+
-+#define strlen_user(str) strnlen_user(str, 32767)
-+
-+/*
-+ * __clear_user()
-+ *    Zero Userspace
-+ */
-+static inline unsigned long __clear_user(__user void *to, unsigned long n)
-+{
-+      memset(to, 0, n);
-+      return 0;
-+}
-+
-+/*
-+ * clear_user()
-+ *    Zero user space (check for valid addresses)
-+ */
-+static inline unsigned long clear_user(__user void *to, unsigned long n)
-+{
-+      if (!access_ok(VERIFY_WRITE, to, n)) {
-+              return -EFAULT;
-+      }
-+      return __clear_user(to, n);
-+}
-+
-+#endif /* _ASM_UBICOM32_UACCESS_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/uart_tio.h
-@@ -0,0 +1,126 @@
-+/*
-+ * arch/ubicom32/include/asm/uart_tio.h
-+ *   Ubicom32 architecture UART TIO definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+#ifndef _ASM_UBICOM32_UART_TIO_H
-+#define _ASM_UBICOM32_UART_TIO_H
-+
-+#include <asm/devtree.h>
-+
-+#define UARTTIO_RX_FIFO_SIZE          16
-+#define UARTTIO_TX_FIFO_SIZE          16
-+
-+/*
-+ * Interrupt flags
-+ */
-+#define UARTTIO_UART_INT_RX           0x00000001      // set when a character has been recevied (TODO: add watermark)
-+#define UARTTIO_UART_INT_RXOVF                0x00000002      // set when the receive buffer has overflowed
-+#define UARTTIO_UART_INT_RXFRAME      0x00000004      // set when there has been a framing error
-+
-+#define UARTTIO_UART_INT_TX           0x00000100      // set every time a character is transmitted
-+#define UARTTIO_UART_INT_TXBE         0x00000200      // set when the transmit buffer is empty (TODO: add watermark)
-+
-+#define UARTTIO_UART_FLAG_ENABLED     0x80000000
-+#define UARTTIO_UART_FLAG_SET_RATE      0x00000001      // set to update baud rate
-+#define UARTTIO_UART_FLAG_RESET         0x00000002      // set to reset the port
-+struct uarttio_uart {
-+      volatile u32_t                  flags;
-+
-+      volatile u32_t                  baud_rate;
-+      volatile u32_t                  current_baud_rate;
-+      u32_t                           bit_time;
-+
-+      /*
-+       * Modem status register
-+       */
-+      volatile u32_t                  status;
-+
-+      /*
-+       * Interrupt registers
-+       */
-+      volatile u32_t                  int_mask;
-+      volatile u32_t                  int_flags;
-+
-+      /*
-+       * Ports and pins
-+       */
-+      u32_t                           rx_port;
-+      u32_t                           tx_port;
-+
-+      u8_t                            rx_pin;
-+      u8_t                            tx_pin;
-+
-+      /*
-+       * Configuration Data
-+       */
-+      u8_t                            rx_bits;
-+      u8_t                            rx_stop_bits;
-+      u8_t                            tx_bits;
-+      u8_t                            tx_stop_bits;
-+
-+      /*
-+       * RX state machine data
-+       */
-+      u32_t                           rx_timer;
-+      u32_t                           rx_bit_pos;
-+      u32_t                           rx_byte;
-+      u32_t                           rx_fifo_head;
-+      u32_t                           rx_fifo_tail;
-+      u32_t                           rx_fifo_size;
-+
-+      /*
-+       * TX state machine data
-+       */
-+      u32_t                           tx_timer;
-+      u32_t                           tx_bit_pos;
-+      u32_t                           tx_byte;
-+      u32_t                           tx_fifo_head;
-+      u32_t                           tx_fifo_tail;
-+      u32_t                           tx_fifo_size;
-+
-+      /*
-+       * FIFOs
-+       */
-+      u8_t                            rx_fifo[UARTTIO_RX_FIFO_SIZE];
-+      u8_t                            tx_fifo[UARTTIO_TX_FIFO_SIZE];
-+};
-+
-+#define UARTTIO_VP_VERSION            1
-+struct uarttio_regs {
-+      u32_t                           version;
-+
-+      u32_t                           thread;
-+
-+      u32_t                           max_uarts;
-+
-+      struct uarttio_uart             uarts[0];
-+};
-+
-+#define UARTTIO_NODE_VERSION          1
-+struct uarttio_node {
-+      struct devtree_node             dn;
-+
-+      u32_t                           version;
-+      struct uarttio_regs             *regs;
-+      u32_t                           regs_sz;
-+};
-+
-+#endif /* _ASM_UBICOM32_UART_TIO_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubi32-cs4384.h
-@@ -0,0 +1,52 @@
-+/*
-+ * arch/ubicom32/include/asm/ubi32-cs4384.h
-+ *   Ubicom32 architecture CS4384 driver platform data definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+#ifndef _ASM_UBICOM32_UBI32_CS4384_H
-+#define _ASM_UBICOM32_UBI32_CS4384_H
-+
-+enum ubi32_cs4384_mclk_source {
-+      UBI32_CS4384_MCLK_PWM_0,
-+      UBI32_CS4384_MCLK_PWM_1,
-+      UBI32_CS4384_MCLK_PWM_2,
-+      UBI32_CS4384_MCLK_CLKDIV_1,
-+      UBI32_CS4384_MCLK_OTHER,
-+};
-+
-+struct ubi32_cs4384_mclk_entry {
-+      /*
-+       * Rate, in Hz, of this entry
-+       */
-+      int rate;
-+
-+      /*
-+       * The divider to program to get the rate
-+       */
-+      int div;
-+};
-+
-+struct ubi32_cs4384_platform_data {
-+      enum ubi32_cs4384_mclk_source   mclk_src;
-+
-+      int                             n_mclk;
-+      struct ubi32_cs4384_mclk_entry  *mclk_entries;
-+};
-+#endif /* _ASM_UBICOM32_UBI32_CS4384_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubi32-pcm.h
-@@ -0,0 +1,54 @@
-+/*
-+ * arch/ubicom32/include/asm/ubi32-pcm.h
-+ *   Ubicom32 architecture PCM driver platform data definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+#ifndef _ASM_UBICOM32_UBI32_PCM_H
-+#define _ASM_UBICOM32_UBI32_PCM_H
-+
-+/*
-+ * This function is called when the sample rate has changed
-+ */
-+typedef int (*ubi32_pcm_set_rate_fn_t)(void *appdata, int rate);
-+
-+struct ubi32pcm_platform_data {
-+      /*
-+       * Name of the audio node/inst
-+       */
-+      const char              *node_name;
-+      const char              *inst_name;
-+      int                     inst_num;
-+
-+      /*
-+       * Application specific data provided when calling functions
-+       */
-+      void                    *appdata;
-+
-+      /*
-+       * Functions called when various things happen
-+       */
-+      ubi32_pcm_set_rate_fn_t set_rate;
-+
-+      /*
-+       * Pointer to optional upper layer data (i.e. DAC config, etc)
-+       */
-+      void                    *priv_data;
-+};
-+#endif /* _ASM_UBICOM32_UBI32_PCM_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32bl.h
-@@ -0,0 +1,84 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32bl.h
-+ *   Ubicom32 architecture backlight driver platform data definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_UBICOM32_BL_H
-+#define _ASM_UBICOM32_UBICOM32_BL_H
-+
-+/*
-+ * Different backlight control mechanisms
-+ */
-+enum ubicom32bl_pwm_types {
-+      /*
-+       * PWM controlled backlight
-+       */
-+      UBICOM32BL_TYPE_PWM,
-+
-+      /*
-+       * HRT based PWM backlight
-+       */
-+      UBICOM32BL_TYPE_PWM_HRT,
-+
-+      /*
-+       * No dimming, just on or off
-+       */
-+      UBICOM32BL_TYPE_BINARY,
-+};
-+
-+struct ubicom32bl_platform_data {
-+      /*
-+       * Default intensity of the backlight 0-255
-+       */
-+      u8_t                            default_intensity;
-+
-+      /*
-+       * TRUE if the backlight sense is active low. (inverted)
-+       * FALSE if the backlight sense is active high.
-+       */
-+      bool                            invert;
-+
-+      /*
-+       * Type of the backlight
-+       */
-+      enum ubicom32bl_pwm_types       type;
-+
-+      /*
-+       * GPIO of the backlight if UBICOM32BL_TYPE_PWM_HRT, UBICOM32BL_TYPE_BINARY
-+       */
-+      unsigned                        gpio;
-+
-+      /*
-+       * PWM channel and parameters of the backlight if UBICOM32BL_TYPE_PWM
-+       *      pre_scaler: sets the rate at which the PWM timer is clocked. (clk_core / 2^pre_scaler)
-+       *      period: sets the period of the timer in timer cycles
-+       * The duty cycle will be directly proportional to the brightness setting.
-+       */
-+      u32_t                           pwm_channel;
-+      u8_t                            pwm_prescale;
-+      u16_t                           pwm_period;
-+};
-+
-+#endif /* _ASM_UBICOM32_UBICOM32_BL_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32-common-asm.h
-@@ -0,0 +1,49 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32-common-asm.h
-+ *   Ubicom32 atomic lock operations.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_UBICOM32_COMMON_ASM_H
-+#define _ASM_UBICOM32_UBICOM32_COMMON_ASM_H
-+
-+/*
-+ * atomic_lock_acquire macro
-+ *    Equivalent to __atomic_lock_acquire()
-+ */
-+.macro atomic_lock_acquire
-+      bset scratchpad1, scratchpad1, #ATOMIC_LOCK_BIT
-+      jmpne.f .-4
-+.endm
-+
-+/*
-+ * atomic_lock_release macro
-+ *    Equivalent to __atomic_lock_release()
-+ */
-+.macro atomic_lock_release
-+      bclr scratchpad1, scratchpad1, #ATOMIC_LOCK_BIT
-+.endm
-+
-+#endif /* _ASM_UBICOM32_UBICOM32_COMMON_ASM_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32-common.h
-@@ -0,0 +1,128 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32-common.h
-+ *   Ubicom32 atomic lock operations.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_UBICOM32_COMMON_H
-+#define _ASM_UBICOM32_UBICOM32_COMMON_H
-+
-+#define S(arg) #arg
-+#define D(arg) S(arg)
-+/*
-+ * scratchpad1 is owned by the LDSR.
-+ *
-+ * The upper bits provide 16 global spinlocks.  Acquiring one of these
-+ * global spinlocks synchornizes across multiple threads and prevents
-+ * the LDSR from delivering any interrupts while the lock is held.
-+ * Use these locks only when absolutely required.
-+ *
-+ * The lower 16 bits of scratchpad1 are used as per thread interrupt
-+ * enable/disable bits.  These bits will prevent a thread from receiving
-+ * any interrupts.
-+ *
-+ * Bit Usage:
-+ * - MT_EN_LOCK_BIT   - Protects writes to MT_EN, so code can read current value
-+ *                    then write a new value atomically (profiler for example)
-+ * - ATOMIC_LOCK_BIT - Used to provide general purpose atomic handling.
-+ * - LDSR_LOCK_BIT   - Used by the LDSR exclusively to provide protection.
-+ * - DCCR_LOCK_BIT   - Used to limit access to the DCCR cache control peripheral
-+ * - ICCR_LOCK_BIT   - Used to limit access to the ICCR cache control peripheral
-+ * - LSB 16 bits     - Used by the LDSR to represent thread enable/disable bits.
-+ */
-+#define MT_EN_LOCK_BIT        31
-+#define ATOMIC_LOCK_BIT 30
-+#define LDSR_LOCK_BIT   29
-+#define PCI_LOCK_BIT  28
-+#define ICCR_LOCK_BIT 27
-+#define DCCR_LOCK_BIT 26
-+
-+#if !defined(__ASSEMBLY__)
-+
-+#define UBICOM32_TRYLOCK(bit) \
-+      asm volatile (                                                \
-+      "       move.4 %0, #0                                   \n\t" \
-+      "       bset scratchpad1, scratchpad1, #"D(bit)"        \n\t" \
-+      "       jmpne.f 1f                                      \n\t" \
-+      "       move.4 %0, #1                                   \n\t" \
-+      "1:                                                     \n\t" \
-+              : "=r" (ret)                                          \
-+              :                                                     \
-+              : "cc", "memory"                                      \
-+      )                                                             \
-+
-+#define UBICOM32_UNLOCK(bit) \
-+      asm volatile (                                                \
-+      "       bclr scratchpad1, scratchpad1, #"D(bit)"        \n\t" \
-+              :                                                     \
-+              :                                                     \
-+              : "cc", "memory"                                      \
-+      )                                                             \
-+
-+#define UBICOM32_LOCK(bit) \
-+      asm volatile (                                                \
-+      "1:     bset scratchpad1, scratchpad1, #"D(bit)"        \n\t" \
-+      "       jmpne.f 1b                                      \n\t" \
-+              :                                                     \
-+              :                                                     \
-+              : "cc", "memory"                                      \
-+      )                                                             \
-+
-+/*
-+ * __atomic_lock_trylock()
-+ *    Attempt to acquire the lock, return TRUE if acquired.
-+ */
-+static inline int __atomic_lock_trylock(void)
-+{
-+      int ret;
-+      UBICOM32_TRYLOCK(ATOMIC_LOCK_BIT);
-+      return ret;
-+}
-+
-+/*
-+ * __atomic_lock_release()
-+ *    Release the global atomic lock.
-+ *
-+ * Note: no one is suspended waiting since this lock is a spinning lock.
-+ */
-+static inline void __atomic_lock_release(void)
-+{
-+      UBICOM32_UNLOCK(ATOMIC_LOCK_BIT);
-+}
-+
-+/*
-+ * __atomic_lock_acquire()
-+ *    Acquire the global atomic lock, spin if not available.
-+ */
-+static inline void __atomic_lock_acquire(void)
-+{
-+      UBICOM32_LOCK(ATOMIC_LOCK_BIT);
-+}
-+#else /* __ASSEMBLY__ */
-+
-+#include <asm/ubicom32-common-asm.h>
-+
-+#endif /* __ASSEMBLY__ */
-+#endif /* _ASM_UBICOM32_UBICOM32_COMMON_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32fb.h
-@@ -0,0 +1,56 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32fb.h
-+ *   Ubicom32 architecture video frame buffer definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+#ifndef _ASM_UBICOM32_UBICOM32FB_H
-+#define _ASM_UBICOM32_UBICOM32FB_H
-+
-+#include <linux/ioctl.h>
-+
-+/*
-+ * Set next frame
-+ */
-+#define UBICOM32FB_IOCTL_SET_NEXT_FRAME               _IOW('r',  1, void *)
-+#define UBICOM32FB_IOCTL_SET_NEXT_FRAME_SYNC  _IOW('r',  2, void *)
-+
-+/*
-+ * Set Mode
-+ */
-+#define UBICOM32FB_IOCTL_SET_MODE             _IOW('r',  3, void *)
-+struct ubicom32fb_mode {
-+      unsigned long   width;
-+      unsigned long   height;
-+      unsigned long   flags;
-+      void            *next_frame;
-+};
-+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_SCAN_ORDER (1 << 8)
-+
-+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_BLOCK_ORDER        (1 << 7)
-+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV            (1 << 6)
-+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_VSUB           (1 << 5)
-+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_16_255  (1 << 4)
-+
-+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_0_255   (1 << 3)
-+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_2_1               (1 << 2)
-+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_1_1               (1 << 1)
-+#define UBICOM32FB_IOCTL_SET_MODE_FLAG_SCALE_ENABLE   (1 << 0)
-+
-+#endif /* _ASM_UBICOM32_UBICOM32FB_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32hid.h
-@@ -0,0 +1,133 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32hid.h
-+ *   Ubicom32 architecture HID driver platform data definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_UBICOM32_HID_H
-+#define _ASM_UBICOM32_UBICOM32_HID_H
-+
-+enum ubicom32hid_bl_types {
-+      /*
-+       * On or off, using command SET_BL_EN, PB4
-+       */
-+      UBICOM32HID_BL_TYPE_BINARY,
-+
-+      /*
-+       * Dimmable, using command SET_PWM, PB3
-+       */
-+      UBICOM32HID_BL_TYPE_PWM,
-+};
-+
-+/*
-+ * IR code mapping to event code.
-+ *    If there are no button mappings and no ir mappings
-+ *    then no input driver will be registered.
-+ */
-+struct ubicom32hid_ir {
-+      /*
-+       * Input event code (KEY_*, SW_*, etc)
-+       */
-+      int             code;
-+
-+      /*
-+       * Input event type (EV_KEY, EV_SW, etc)
-+       */
-+      int             type;
-+
-+      /*
-+       * The IR code of this button.
-+       */
-+      uint32_t        ir_code;
-+};
-+
-+/*
-+ * Button mapping to event code.
-+ *    If there are no button mappings and no ir mappings
-+ *    then no input driver will be registered.
-+ */
-+struct ubicom32hid_button {
-+      /*
-+       * Input event code (KEY_*, SW_*, etc)
-+       */
-+      int             code;
-+
-+      /*
-+       * Input event type (EV_KEY, EV_SW, etc)
-+       */
-+      int             type;
-+
-+      /*
-+       * Bit number of this button.
-+       */
-+      uint8_t         bit;
-+};
-+
-+struct ubicom32hid_platform_data {
-+      /*
-+       * Default intensity of the backlight 0-255
-+       */
-+      u8_t                            default_intensity;
-+
-+      /*
-+       * GPIO number of the reset line and its polarity.
-+       */
-+      unsigned                        gpio_reset;
-+      int                             gpio_reset_polarity;
-+
-+      /*
-+       * TRUE if the backlight sense is active low. (inverted)
-+       * FALSE if the backlight sense is active high.
-+       */
-+      bool                            invert;
-+
-+      /*
-+       * Type of the backlight we are controlling
-+       */
-+      enum ubicom32hid_bl_types       type;
-+
-+      /*
-+       * Optional polling rate for input, in ms, defaults to 100ms
-+       */
-+      int                             poll_interval;
-+
-+      /*
-+       * Optional name to register as input device
-+       */
-+      const char                      *input_name;
-+
-+      /*
-+       * Button mapping array
-+       */
-+      const struct ubicom32hid_button *buttons;
-+      int                             nbuttons;
-+
-+      /*
-+       * IR mapping array
-+       */
-+      const struct ubicom32hid_ir     *ircodes;
-+      int                             nircodes;
-+};
-+
-+#endif /* _ASM_UBICOM32_UBICOM32_HID_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32input.h
-@@ -0,0 +1,76 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32input.h
-+ *   Ubicom32 Input driver, based on gpio-keys
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *
-+ * TODO: add groups for inputs which can be sampled together
-+ */
-+
-+#ifndef _ASM_UBICOM32_UBICOM32_INPUT_H
-+#define _ASM_UBICOM32_UBICOM32_INPUT_H
-+
-+struct ubicom32input_button {
-+      /*
-+       * Input event code (KEY_*, SW_*, etc)
-+       */
-+      int             code;
-+
-+      /*
-+       * Input event type (EV_KEY, EV_SW, etc)
-+       */
-+      int             type;
-+
-+      /*
-+       * GPIO to poll
-+       */
-+      int             gpio;
-+
-+      /*
-+       * 1 for active low, 0 for active high
-+       */
-+      int             active_low;
-+
-+      /*
-+       * Description, used for reserving GPIOs
-+       */
-+      const char      *desc;
-+};
-+
-+struct ubicom32input_platform_data {
-+      struct ubicom32input_button     *buttons;
-+      int                             nbuttons;
-+
-+      /*
-+       * Optional poll interval, in ms, defaults to 50ms
-+       */
-+      int                             poll_interval;
-+
-+      /*
-+       * Option Name of this driver
-+       */
-+      const char                      *name;
-+};
-+
-+#endif /* _ASM_UBICOM32_UBICOM32_INPUT_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32input_i2c.h
-@@ -0,0 +1,71 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32input_i2c.h
-+ *   Ubicom32 architecture Input driver over I2C platform data definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *
-+ * TODO: add groups for inputs which can be sampled together
-+ */
-+
-+#ifndef _ASM_UBICOM32_UBICOM32_INPUT_I2C_H
-+#define _ASM_UBICOM32_UBICOM32_INPUT_I2C_H
-+
-+struct ubicom32input_i2c_button {
-+      /*
-+       * Input event code (KEY_*, SW_*, etc)
-+       */
-+      int             code;
-+
-+      /*
-+       * Input event type (EV_KEY, EV_SW, etc)
-+       */
-+      int             type;
-+
-+      /*
-+       * Bit number of this button. (0 - ngpio)
-+       */
-+      int             bit;
-+
-+      /*
-+       * 1 for active low, 0 for active high
-+       */
-+      int             active_low;
-+};
-+
-+struct ubicom32input_i2c_platform_data {
-+      struct ubicom32input_i2c_button *buttons;
-+      int                             nbuttons;
-+
-+      /*
-+       * Optional poll interval, in ms, defaults to 100ms
-+       */
-+      int                             poll_interval;
-+
-+      /*
-+       * Option Name of this driver
-+       */
-+      const char                      *name;
-+};
-+
-+#endif /* _ASM_UBICOM32_UBICOM32_INPUT_I2C_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32lcd.h
-@@ -0,0 +1,38 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32lcd.h
-+ *   Ubicom32 architecture LCD driver platform data definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+#ifndef _ASM_UBICOM32_UBICOM32_LCD_H
-+#define _ASM_UBICOM32_UBICOM32_LCD_H
-+
-+#include <asm/ip5000.h>
-+
-+struct ubicom32lcd_platform_data {
-+      int                     pin_cs;
-+      int                     pin_rs;
-+      int                     pin_rd;
-+      int                     pin_wr;
-+      int                     pin_reset;
-+      int                     data_shift;
-+      struct ubicom32_io_port *port_data;
-+};
-+
-+#endif /* _ASM_UBICOM32_UBICOM32_LCD_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32lcdpower.h
-@@ -0,0 +1,39 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32lcdpower.h
-+ *   Ubicom32 architecture LCD driver platform data definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_UBICOM32_LCDPOWER_H
-+#define _ASM_UBICOM32_UBICOM32_LCDPOWER_H
-+
-+struct ubicom32lcdpower_platform_data {
-+      /*
-+       * GPIO and polarity for VGH signal.  A FALSE polarity is active low, TRUE is active high.
-+       */
-+      int             vgh_gpio;
-+      bool            vgh_polarity;
-+};
-+
-+#endif /* _ASM_UBICOM32_UBICOM32_LCDPOWER_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32ring.h
-@@ -0,0 +1,103 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32ring.h
-+ * Userspace I/O platform driver for Ubicom32 ring buffers
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#ifndef _ASM_UBICOM32_UBICOM32RING_H
-+#define _ASM_UBICOM32_UBICOM32RING_H
-+
-+#define UIO_UBICOM32RING_REG_VERSION  2
-+
-+struct uio_ubicom32ring_desc {
-+      volatile unsigned int           head;
-+      volatile unsigned int           tail;
-+      unsigned int                    entries;
-+      volatile unsigned int           ring[0];
-+};
-+
-+struct uio_ubicom32ring_regs {
-+      unsigned int                    version;
-+
-+      /*
-+       * Magic type used to identify the ring set.  Each driver will
-+       * have a different magic value.
-+       */
-+      unsigned int                    magic;
-+
-+      /*
-+       * Registers defined by the driver
-+       */
-+      unsigned int                    regs_size;
-+      void                            *regs;
-+
-+      /*
-+       * The locations of the rings
-+       *
-+       * DO NOT ADD ANYTHING BELOW THIS LINE
-+       */
-+      unsigned int                    num_rings;
-+      struct uio_ubicom32ring_desc    *rings[0];
-+};
-+
-+/*
-+ * ringtio_ring_flush
-+ */
-+static inline void ringtio_ring_flush(struct uio_ubicom32ring_desc *rd)
-+{
-+      rd->head = rd->tail = 0;
-+}
-+
-+/*
-+ * ringtio_ring_get
-+ */
-+static inline int ringtio_ring_get(struct uio_ubicom32ring_desc *rd, void **val)
-+{
-+      if (rd->head == rd->tail) {
-+              return 0;
-+      }
-+
-+      *val = (void *)rd->ring[rd->head++];
-+      if (rd->head == rd->entries) {
-+              rd->head = 0;
-+      }
-+      return 1;
-+}
-+
-+/*
-+ * ringtio_ring_put
-+ */
-+static inline int ringtio_ring_put(struct uio_ubicom32ring_desc *rd, void *val)
-+{
-+      unsigned int newtail = rd->tail + 1;
-+      if (newtail == rd->entries) {
-+              newtail = 0;
-+      }
-+
-+      if (newtail == rd->head) {
-+              return 0;
-+      }
-+
-+      rd->ring[rd->tail] = (unsigned int)val;
-+      rd->tail = newtail;
-+      return 1;
-+}
-+
-+#endif /* _ASM_UBICOM32_UBICOM32RING_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32sd.h
-@@ -0,0 +1,45 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32sd.h
-+ *   Ubicom32SD public include file
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+#ifndef _ASM_UBICOM32_UBICOM32_SD_H
-+#define _ASM_UBICOM32_UBICOM32_SD_H
-+
-+struct ubicom32sd_card {
-+      /*
-+       * GPIOs of PWR, WP and CD lines.
-+       * Polarity is 1 for active high and 0 for active low
-+       */
-+      int                             pin_pwr;
-+      bool                            pwr_polarity;
-+      int                             pin_wp;
-+      bool                            wp_polarity;
-+      int                             pin_cd;
-+      bool                            cd_polarity;
-+};
-+
-+struct ubicom32sd_platform_data {
-+      int                     ncards;
-+
-+      struct ubicom32sd_card  *cards;
-+};
-+
-+#endif /* _ASM_UBICOM32_UBICOM32_SD_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32-spi-gpio.h
-@@ -0,0 +1,62 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32-spi-gpio.h
-+ *   Platform driver data definitions for GPIO based SPI driver.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_UBICOM32_SPI_GPIO_H
-+#define _ASM_UBICOM32_UBICOM32_SPI_GPIO_H
-+
-+struct ubicom32_spi_gpio_platform_data {
-+      /*
-+       * GPIO to use for MOSI, MISO, CLK
-+       */
-+      int     pin_mosi;
-+      int     pin_miso;
-+      int     pin_clk;
-+
-+      /*
-+       * Default state of CLK line
-+       */
-+      int     clk_default;
-+
-+      /*
-+       * Number of chip selects on this bus
-+       */
-+      int     num_chipselect;
-+
-+      /*
-+       * The bus number of this chip
-+       */
-+      int     bus_num;
-+};
-+
-+struct ubicom32_spi_gpio_controller_data {
-+      /*
-+       * GPIO to use for chip select
-+       */
-+      int     pin_cs;
-+};
-+
-+#endif /* _ASM_UBICOM32_UBICOM32_SPI_GPIO_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32suart.h
-@@ -0,0 +1,36 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32suart.h
-+ *   <TODO: Replace with short file description>
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_UBICOM32_SUART_H
-+#define _ASM_UBICOM32_UBICOM32_SUART_H
-+
-+/*
-+ * Platform resource id for serdes uart clock parameter
-+ */
-+#define UBICOM32_SUART_IORESOURCE_CLOCK               (1)
-+
-+#endif /* _ASM_UBICOM32_UBICOM32_SUART_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ubicom32-tio.h
-@@ -0,0 +1,42 @@
-+/*
-+ * arch/ubicom32/include/asm/ubicom32-tio.h
-+ *   Threaded I/O interface definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_UBICOM32_TIO_H
-+#define _ASM_UBICOM32_UBICOM32_TIO_H
-+
-+extern u8_t usb_tio_read_u16(u32_t address, u16_t *data);
-+extern u8_t usb_tio_read_u8(u32_t address, u8_t *data);
-+
-+extern u8_t usb_tio_write_u16(u32_t address, u16_t data);
-+extern u8_t usb_tio_write_u8(u32_t address, u8_t data);
-+
-+extern u8_t usb_tio_read_fifo(u32_t address, u32_t buffer, u32_t bytes);
-+extern u8_t usb_tio_write_fifo(u32_t address, u32_t buffer, u32_t bytes);
-+extern u8_t usb_tio_write_fifo_sync(u32_t address, u32_t buffer, u32_t bytes);
-+extern void usb_tio_read_int_status(u8_t *int_usb, u16_t *int_tx, u16_t *int_rx);
-+
-+#endif /* _ASM_UBICOM32_UBICOM32_TIO_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/ucontext.h
-@@ -0,0 +1,39 @@
-+/*
-+ * arch/ubicom32/include/asm/ucontext.h
-+ *   Definition of ucontext structure for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_UCONTEXT_H
-+#define _ASM_UBICOM32_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 /* _ASM_UBICOM32_UCONTEXT_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/unaligned.h
-@@ -0,0 +1,44 @@
-+/*
-+ * arch/ubicom32/include/asm/unaligned.h
-+ *   Ubicom32 architecture unaligned memory access definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *
-+ * TODO: This is a copy of arm unaligned handling that probably needs
-+ * to be optimized for UBICOM32, but it works for now.
-+ */
-+
-+#ifndef _ASM_UBICOM32_UNALIGNED_H
-+#define _ASM_UBICOM32_UNALIGNED_H
-+
-+#include <asm/types.h>
-+
-+#include <linux/unaligned/le_byteshift.h>
-+#include <linux/unaligned/be_byteshift.h>
-+#include <linux/unaligned/generic.h>
-+
-+#define get_unaligned __get_unaligned_be
-+#define put_unaligned __put_unaligned_be
-+
-+#endif /* _ASM_UBICOM32_UNALIGNED_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/unistd.h
-@@ -0,0 +1,400 @@
-+/*
-+ * arch/ubicom32/include/asm/unistd.h
-+ *   Ubicom32 architecture syscall definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_UNISTD_H
-+#define _ASM_UBICOM32_UNISTD_H
-+
-+/*
-+ * This file contains the system call numbers.
-+ */
-+
-+#define __NR_restart_syscall      0
-+#define __NR_exit               1
-+#define __NR_fork               2
-+#define __NR_read               3
-+#define __NR_write              4
-+#define __NR_open               5
-+#define __NR_close              6
-+#define __NR_waitpid            7
-+#define __NR_creat              8
-+#define __NR_link               9
-+#define __NR_unlink            10
-+#define __NR_execve            11
-+#define __NR_chdir             12
-+#define __NR_time              13
-+#define __NR_mknod             14
-+#define __NR_chmod             15
-+#define __NR_chown             16
-+#define __NR_break             17
-+#define __NR_oldstat           18
-+#define __NR_lseek             19
-+#define __NR_getpid            20
-+#define __NR_mount             21
-+#define __NR_umount            22
-+#define __NR_setuid            23
-+#define __NR_getuid            24
-+#define __NR_stime             25
-+#define __NR_ptrace            26
-+#define __NR_alarm             27
-+#define __NR_oldfstat          28
-+#define __NR_pause             29
-+#define __NR_utime             30
-+#define __NR_stty              31
-+#define __NR_gtty              32
-+#define __NR_access            33
-+#define __NR_nice              34
-+#define __NR_ftime             35
-+#define __NR_sync              36
-+#define __NR_kill              37
-+#define __NR_rename            38
-+#define __NR_mkdir             39
-+#define __NR_rmdir             40
-+#define __NR_dup               41
-+#define __NR_pipe              42
-+#define __NR_times             43
-+#define __NR_prof              44
-+#define __NR_brk               45
-+#define __NR_setgid            46
-+#define __NR_getgid            47
-+#define __NR_signal            48
-+#define __NR_geteuid           49
-+#define __NR_getegid           50
-+#define __NR_acct              51
-+#define __NR_umount2           52
-+#define __NR_lock              53
-+#define __NR_ioctl             54
-+#define __NR_fcntl             55
-+#define __NR_mpx               56
-+#define __NR_setpgid           57
-+#define __NR_ulimit            58
-+#define __NR_oldolduname       59
-+#define __NR_umask             60
-+#define __NR_chroot            61
-+#define __NR_ustat             62
-+#define __NR_dup2              63
-+#define __NR_getppid           64
-+#define __NR_getpgrp           65
-+#define __NR_setsid            66
-+#define __NR_sigaction                 67
-+#define __NR_sgetmask          68
-+#define __NR_ssetmask          69
-+#define __NR_setreuid          70
-+#define __NR_setregid          71
-+#define __NR_sigsuspend                72
-+#define __NR_sigpending                73
-+#define __NR_sethostname       74
-+#define __NR_setrlimit                 75
-+#define __NR_getrlimit                 76
-+#define __NR_getrusage                 77
-+#define __NR_gettimeofday      78
-+#define __NR_settimeofday      79
-+#define __NR_getgroups                 80
-+#define __NR_setgroups                 81
-+#define __NR_select            82
-+#define __NR_symlink           83
-+#define __NR_oldlstat          84
-+#define __NR_readlink          85
-+#define __NR_uselib            86
-+#define __NR_swapon            87
-+#define __NR_reboot            88
-+#define __NR_readdir           89
-+#define __NR_mmap              90
-+#define __NR_munmap            91
-+#define __NR_truncate          92
-+#define __NR_ftruncate                 93
-+#define __NR_fchmod            94
-+#define __NR_fchown            95
-+#define __NR_getpriority       96
-+#define __NR_setpriority       97
-+#define __NR_profil            98
-+#define __NR_statfs            99
-+#define __NR_fstatfs          100
-+#define __NR_ioperm           101
-+#define __NR_socketcall               102
-+#define __NR_syslog           103
-+#define __NR_setitimer                104
-+#define __NR_getitimer                105
-+#define __NR_stat             106
-+#define __NR_lstat            107
-+#define __NR_fstat            108
-+#define __NR_olduname         109
-+#define __NR_iopl             /* 110 */ not supported
-+#define __NR_vhangup          111
-+#define __NR_idle             /* 112 */ Obsolete
-+#define __NR_vm86             /* 113 */ not supported
-+#define __NR_wait4            114
-+#define __NR_swapoff          115
-+#define __NR_sysinfo          116
-+#define __NR_ipc              117
-+#define __NR_fsync            118
-+#define __NR_sigreturn                119
-+#define __NR_clone            120
-+#define __NR_setdomainname    121
-+#define __NR_uname            122
-+#define __NR_cacheflush               123
-+#define __NR_adjtimex         124
-+#define __NR_mprotect         125
-+#define __NR_sigprocmask      126
-+#define __NR_create_module    127
-+#define __NR_init_module      128
-+#define __NR_delete_module    129
-+#define __NR_get_kernel_syms  130
-+#define __NR_quotactl         131
-+#define __NR_getpgid          132
-+#define __NR_fchdir           133
-+#define __NR_bdflush          134
-+#define __NR_sysfs            135
-+#define __NR_personality      136
-+#define __NR_afs_syscall      137 /* Syscall for Andrew File System */
-+#define __NR_setfsuid         138
-+#define __NR_setfsgid         139
-+#define __NR__llseek          140
-+#define __NR_getdents         141
-+#define __NR__newselect               142
-+#define __NR_flock            143
-+#define __NR_msync            144
-+#define __NR_readv            145
-+#define __NR_writev           146
-+#define __NR_getsid           147
-+#define __NR_fdatasync                148
-+#define __NR__sysctl          149
-+#define __NR_mlock            150
-+#define __NR_munlock          151
-+#define __NR_mlockall         152
-+#define __NR_munlockall               153
-+#define __NR_sched_setparam           154
-+#define __NR_sched_getparam           155
-+#define __NR_sched_setscheduler               156
-+#define __NR_sched_getscheduler               157
-+#define __NR_sched_yield              158
-+#define __NR_sched_get_priority_max   159
-+#define __NR_sched_get_priority_min   160
-+#define __NR_sched_rr_get_interval    161
-+#define __NR_nanosleep                162
-+#define __NR_mremap           163
-+#define __NR_setresuid                164
-+#define __NR_getresuid                165
-+#define __NR_getpagesize      166
-+#define __NR_query_module     167
-+#define __NR_poll             168
-+#define __NR_nfsservctl               169
-+#define __NR_setresgid                170
-+#define __NR_getresgid                171
-+#define __NR_prctl            172
-+#define __NR_rt_sigreturn     173
-+#define __NR_rt_sigaction     174
-+#define __NR_rt_sigprocmask   175
-+#define __NR_rt_sigpending    176
-+#define __NR_rt_sigtimedwait  177
-+#define __NR_rt_sigqueueinfo  178
-+#define __NR_rt_sigsuspend    179
-+#define __NR_pread64          180
-+#define __NR_pwrite64         181
-+#define __NR_lchown           182
-+#define __NR_getcwd           183
-+#define __NR_capget           184
-+#define __NR_capset           185
-+#define __NR_sigaltstack      186
-+#define __NR_sendfile         187
-+#define __NR_getpmsg          188     /* some people actually want streams */
-+#define __NR_putpmsg          189     /* some people actually want streams */
-+#define __NR_vfork            190
-+#define __NR_ugetrlimit               191
-+#define __NR_mmap2            192
-+#define __NR_truncate64               193
-+#define __NR_ftruncate64      194
-+#define __NR_stat64           195
-+#define __NR_lstat64          196
-+#define __NR_fstat64          197
-+#define __NR_chown32          198
-+#define __NR_getuid32         199
-+#define __NR_getgid32         200
-+#define __NR_geteuid32                201
-+#define __NR_getegid32                202
-+#define __NR_setreuid32               203
-+#define __NR_setregid32               204
-+#define __NR_getgroups32      205
-+#define __NR_setgroups32      206
-+#define __NR_fchown32         207
-+#define __NR_setresuid32      208
-+#define __NR_getresuid32      209
-+#define __NR_setresgid32      210
-+#define __NR_getresgid32      211
-+#define __NR_lchown32         212
-+#define __NR_setuid32         213
-+#define __NR_setgid32         214
-+#define __NR_setfsuid32               215
-+#define __NR_setfsgid32               216
-+#define __NR_pivot_root               217
-+#define __NR_getdents64               220
-+#define __NR_gettid           221
-+#define __NR_tkill            222
-+#define __NR_setxattr         223
-+#define __NR_lsetxattr                224
-+#define __NR_fsetxattr                225
-+#define __NR_getxattr         226
-+#define __NR_lgetxattr                227
-+#define __NR_fgetxattr                228
-+#define __NR_listxattr                229
-+#define __NR_llistxattr               230
-+#define __NR_flistxattr               231
-+#define __NR_removexattr      232
-+#define __NR_lremovexattr     233
-+#define __NR_fremovexattr     234
-+#define __NR_futex            235
-+#define __NR_sendfile64               236
-+#define __NR_mincore          237
-+#define __NR_madvise          238
-+#define __NR_fcntl64          239
-+#define __NR_readahead                240
-+#define __NR_io_setup         241
-+#define __NR_io_destroy               242
-+#define __NR_io_getevents     243
-+#define __NR_io_submit                244
-+#define __NR_io_cancel                245
-+#define __NR_fadvise64                246
-+#define __NR_exit_group               247
-+#define __NR_lookup_dcookie   248
-+#define __NR_epoll_create     249
-+#define __NR_epoll_ctl                250
-+#define __NR_epoll_wait               251
-+#define __NR_remap_file_pages 252
-+#define __NR_set_tid_address  253
-+#define __NR_timer_create     254
-+#define __NR_timer_settime    255
-+#define __NR_timer_gettime    256
-+#define __NR_timer_getoverrun 257
-+#define __NR_timer_delete     258
-+#define __NR_clock_settime    259
-+#define __NR_clock_gettime    260
-+#define __NR_clock_getres     261
-+#define __NR_clock_nanosleep  262
-+#define __NR_statfs64         263
-+#define __NR_fstatfs64                264
-+#define __NR_tgkill           265
-+#define __NR_utimes           266
-+#define __NR_fadvise64_64     267
-+#define __NR_mbind            268
-+#define __NR_get_mempolicy    269
-+#define __NR_set_mempolicy    270
-+#define __NR_mq_open          271
-+#define __NR_mq_unlink                272
-+#define __NR_mq_timedsend     273
-+#define __NR_mq_timedreceive  274
-+#define __NR_mq_notify                275
-+#define __NR_mq_getsetattr    276
-+#define __NR_waitid           277
-+#define __NR_vserver          278
-+#define __NR_add_key          279
-+#define __NR_request_key      280
-+#define __NR_keyctl           281
-+#define __NR_ioprio_set               282
-+#define __NR_ioprio_get               283
-+#define __NR_inotify_init     284
-+#define __NR_inotify_add_watch        285
-+#define __NR_inotify_rm_watch 286
-+#define __NR_migrate_pages    287
-+#define __NR_openat           288
-+#define __NR_mkdirat          289
-+#define __NR_mknodat          290
-+#define __NR_fchownat         291
-+#define __NR_futimesat                292
-+#define __NR_fstatat64                293
-+#define __NR_unlinkat         294
-+#define __NR_renameat         295
-+#define __NR_linkat           296
-+#define __NR_symlinkat                297
-+#define __NR_readlinkat               298
-+#define __NR_fchmodat         299
-+#define __NR_faccessat                300
-+#define __NR_pselect6         301
-+#define __NR_ppoll            302
-+#define __NR_unshare          303
-+#define __NR_set_robust_list  304
-+#define __NR_get_robust_list  305
-+#define __NR_splice           306
-+#define __NR_sync_file_range  307
-+#define __NR_tee              308
-+#define __NR_vmsplice         309
-+#define __NR_move_pages               310
-+#define __NR_sched_setaffinity        311
-+#define __NR_sched_getaffinity        312
-+#define __NR_kexec_load               313
-+#define __NR_getcpu           314
-+#define __NR_epoll_pwait      315
-+#define __NR_utimensat                316
-+#define __NR_signalfd         317
-+#define __NR_timerfd_create   318
-+#define __NR_eventfd          319
-+#define __NR_fallocate                320
-+#define __NR_timerfd_settime  321
-+#define __NR_timerfd_gettime  322
-+#define __NR_signalfd4                323
-+#define __NR_eventfd2         324
-+#define __NR_epoll_create1    325
-+#define __NR_dup3             326
-+#define __NR_pipe2            327
-+#define __NR_inotify_init1    328
-+
-+#ifdef __KERNEL__
-+
-+#define NR_syscalls           329
-+
-+#define __ARCH_WANT_IPC_PARSE_VERSION
-+#define __ARCH_WANT_OLD_READDIR
-+#define __ARCH_WANT_OLD_STAT
-+#define __ARCH_WANT_STAT64
-+#define __ARCH_WANT_SYS_ALARM
-+#define __ARCH_WANT_SYS_GETHOSTNAME
-+#define __ARCH_WANT_SYS_PAUSE
-+#define __ARCH_WANT_SYS_SGETMASK
-+#define __ARCH_WANT_SYS_SIGNAL
-+#define __ARCH_WANT_SYS_TIME
-+#define __ARCH_WANT_SYS_UTIME
-+#define __ARCH_WANT_SYS_WAITPID
-+#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_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")
-+#define cond_syscall(x) long x(void)  __attribute__((weak,alias("sys_ni_syscall")))
-+#endif /* __KERNEL__ */
-+
-+#endif /* _ASM_UBICOM32_UNISTD_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/user.h
-@@ -0,0 +1,82 @@
-+/*
-+ * arch/ubicom32/include/asm/user.h
-+ *   Ubicom32 architecture core file definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_USER_H
-+#define _ASM_UBICOM32_USER_H
-+
-+#include <asm/ptrace.h>
-+#include <asm/page.h>
-+/*
-+ * Adapted from <asm-powerpc/user.h>
-+ *
-+ * Core file format: The core file is written in such a way that gdb
-+ * can understand it and provide useful information to the user (under
-+ * linux we use the `trad-core' bfd, NOT the osf-core).  The 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 handy at some point.  All of the registers
-+ *    are stored as part of the upage.  The upage should always be
-+ *    only one page long.
-+ *  data: The data segment follows next.  We use current->end_text to
-+ *    current->brk to pick up all of the user variables, plus any memory
-+ *    that may have been sbrk'ed.  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 usp to
-+ *    current->start_stack, so we round each of these in order to be able
-+ *    to write an integer number of pages.
-+ */
-+
-+struct user_ubicom32fp_struct {
-+};
-+
-+struct user {
-+      struct pt_regs  regs;                   /* entire machine state */
-+      size_t          u_tsize;                /* text size (pages) */
-+      size_t          u_dsize;                /* data size (pages) */
-+      size_t          u_ssize;                /* stack size (pages) */
-+      unsigned long   start_code;             /* text starting address */
-+      unsigned long   start_data;             /* data starting address */
-+      unsigned long   start_stack;            /* stack starting address */
-+      long int        signal;                 /* signal causing core dump */
-+      unsigned long   u_ar0;                  /* help gdb find registers */
-+      unsigned long   magic;                  /* identifies a core file */
-+      char            u_comm[32];             /* user command name */
-+};
-+
-+#define NBPG                  PAGE_SIZE
-+#define UPAGES                        1
-+#define HOST_TEXT_START_ADDR  (u.start_code)
-+#define HOST_DATA_START_ADDR  (u.start_data)
-+#define HOST_STACK_END_ADDR   (u.start_stack + u.u_ssize * NBPG)
-+
-+#endif        /* _ASM_UBICOM32_USER_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/vdc_tio.h
-@@ -0,0 +1,129 @@
-+/*
-+ * arch/ubicom32/include/asm/vdc_tio.h
-+ *   Ubicom32 architecture VDC TIO definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_VDC_TIO_H
-+#define _ASM_UBICOM32_VDC_TIO_H
-+
-+#include <asm/devtree.h>
-+
-+#define VDCTIO_VP_VERSION                     5
-+
-+#define VDCTIO_SCALE_FLAG_VSUB                        (1 << 9)
-+#define VDCTIO_SCALE_FLAG_YUV_SCAN_ORDER      (1 << 8)
-+#define VDCTIO_SCALE_FLAG_YUV_BLOCK_ORDER     (1 << 7)
-+#define VDCTIO_SCALE_FLAG_YUV                 (1 << 6)
-+#define VDCTIO_SCALE_FLAG_VRANGE_16_255               (1 << 5)
-+#define VDCTIO_SCALE_FLAG_VRANGE_0_255                (1 << 4)
-+#define VDCTIO_SCALE_FLAG_HSUB_2_1            (1 << 3)
-+#define VDCTIO_SCALE_FLAG_HSUB_1_1            (1 << 2)
-+#define VDCTIO_SCALE_FLAG_SET_FRAME_BUFFER    (1 << 1)
-+#define VDCTIO_SCALE_FLAG_ENABLE              (1 << 0)
-+
-+#define VDCTIO_NEXT_FRAME_FLAG_YUV_BIT                0
-+#define VDCTIO_NEXT_FRAME_FLAG_YUV            (1 << (VDCTIO_NEXT_FRAME_FLAG_YUV_BIT))
-+
-+#define VDCTIO_CAPS_SUPPORTS_SCALING          (1 << 0)
-+
-+#define VDCTIO_COMMAND_START                  (1 << 3)
-+#define VDCTIO_COMMAND_SET_COEFF              (1 << 2)
-+#define VDCTIO_COMMAND_SET_LUT                        (1 << 1)
-+#define VDCTIO_COMMAND_SET_SCALE_MODE         (1 << 0)
-+
-+/*
-+ * Command / Data registers to access the VDC
-+ */
-+struct vdc_tio_vp_regs {
-+      /*
-+       * Version of this TIO register map
-+       */
-+      u32_t           version;
-+
-+      volatile u32_t  command;
-+
-+      /*
-+       * Next frame pointer, when the command VDCTIO_COMMAND_SET_FRAME_BUFFER is set,
-+       * the vdc will take the pointer here and display it.
-+       */
-+      void            *next_frame;
-+      u32_t           next_frame_flags;
-+
-+      /*
-+       * These map directly into the PIXP registers 0x20-0x80.
-+       * DO NOT change the order of these three variables.
-+       */
-+      u32_t           red_lut[6];
-+      u32_t           blue_lut[6];
-+      u32_t           green_lut[13];
-+
-+      /*
-+       * These map directly into the PIXP registers 0x04, 0x08
-+       */
-+      u32_t           coeff0;
-+      u32_t           coeff1;
-+
-+      /*
-+       * There are used to set the scaling parameters
-+       */
-+      u32_t           x_in;
-+      u32_t           x_out;
-+      u32_t           y_in;
-+      u32_t           y_out;
-+      u32_t           scale_flags;
-+
-+      /*
-+       * Current frame number, monotonically increasing number
-+       */
-+      u32_t           frame_number;
-+
-+      /*
-+       * These variables tell the guest OS what the underlying hardware looks like
-+       */
-+      u32_t           caps;
-+      u32_t           xres;
-+      u32_t           yres;
-+      u32_t           fb_align;
-+      u8_t            bpp;
-+      u8_t            rbits;
-+      u8_t            gbits;
-+      u8_t            bbits;
-+      u8_t            rshift;
-+      u8_t            gshift;
-+      u8_t            bshift;
-+};
-+
-+/*
-+ * Devtree node for VDC
-+ */
-+struct vdc_tio_node {
-+      struct devtree_node     dn;
-+
-+      struct vdc_tio_vp_regs  *regs;
-+};
-+
-+extern void vdc_tio_init(void);
-+
-+#endif /* _ASM_UBICOM32_VDC_TIO_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/vga.h
-@@ -0,0 +1,71 @@
-+/*
-+ * arch/ubicom32/include/asm/vga.h
-+ *   Ubicom32 low level  VGA/frame buffer definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * (c) 1998 Martin Mares <mj@ucw.cz>
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#ifndef _ASM_UBICOM32_VGA_H
-+#define _ASM_UBICOM32_VGA_H
-+
-+#include <asm/byteorder.h>
-+
-+/*
-+ *    On the PC, we can just recalculate addresses and then
-+ *    access the videoram directly without any black magic.
-+ */
-+
-+#define VGA_MAP_MEM(x, s)     (0xb0000000L + (unsigned long)(x))
-+
-+#define vga_readb(x)  (*(x))
-+#define vga_writeb(x, y)      (*(y) = (x))
-+
-+#define VT_BUF_HAVE_RW
-+/*
-+ *  These are only needed for supporting VGA or MDA text mode, which use little
-+ *  endian byte ordering.
-+ *  In other cases, we can optimize by using native byte ordering and
-+ *  <linux/vt_buffer.h> has already done the right job for us.
-+ */
-+
-+#undef scr_writew
-+#undef scr_readw
-+
-+static inline void scr_writew(u16 val, volatile u16 *addr)
-+{
-+      *addr = cpu_to_le16(val);
-+}
-+
-+static inline u16 scr_readw(volatile const u16 *addr)
-+{
-+      return le16_to_cpu(*addr);
-+}
-+
-+#define scr_memcpyw(d, s, c) memcpy(d, s, c)
-+#define scr_memmovew(d, s, c) memmove(d, s, c)
-+#define VT_BUF_HAVE_MEMCPYW
-+#define VT_BUF_HAVE_MEMMOVEW
-+
-+#endif /* _ASM_UBICOM32_VGA_H */
---- /dev/null
-+++ b/arch/ubicom32/include/asm/xor.h
-@@ -0,0 +1,33 @@
-+/*
-+ * arch/ubicom32/include/asm/xor.h
-+ *   Generic xor.h definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _ASM_UBICOM32_XOR_H
-+#define _ASM_UBICOM32_XOR_H
-+
-+#include <asm-generic/xor.h>
-+
-+#endif /* _ASM_UBICOM32_XOR_H */
---- /dev/null
-+++ b/arch/ubicom32/Kconfig
-@@ -0,0 +1,403 @@
-+#
-+# For a description of the syntax of this configuration file,
-+# see Documentation/kbuild/kconfig-language.txt.
-+#
-+
-+mainmenu "uClinux/ubicom32 (w/o MMU) Kernel Configuration"
-+
-+config UBICOM32
-+      bool
-+      select HAVE_OPROFILE
-+      default y
-+
-+config RAMKERNEL
-+      bool
-+      default y
-+
-+config CPU_BIG_ENDIAN
-+      bool
-+      default y
-+
-+config FORCE_MAX_ZONEORDER
-+      int
-+      default "14"
-+
-+config HAVE_CLK
-+      bool
-+      default y
-+
-+config MMU
-+      bool
-+      default n
-+
-+config FPU
-+      bool
-+      default n
-+
-+config ZONE_DMA
-+      bool
-+      default y
-+
-+config RWSEM_GENERIC_SPINLOCK
-+      bool
-+      default y
-+
-+config RWSEM_XCHGADD_ALGORITHM
-+      bool
-+      default n
-+
-+config ARCH_HAS_ILOG2_U32
-+      bool
-+      default n
-+
-+config ARCH_HAS_ILOG2_U64
-+      bool
-+      default n
-+
-+config GENERIC_FIND_NEXT_BIT
-+      bool
-+      default y
-+
-+config GENERIC_GPIO
-+      bool
-+      default y
-+
-+config GPIOLIB
-+      bool
-+      default y
-+
-+config GENERIC_HWEIGHT
-+      bool
-+      default y
-+
-+config GENERIC_HARDIRQS
-+      bool
-+      default y
-+
-+config STACKTRACE_SUPPORT
-+      bool
-+      default y
-+
-+config LOCKDEP_SUPPORT
-+      bool
-+      default y
-+
-+config GENERIC_CALIBRATE_DELAY
-+      bool
-+      default y
-+
-+config GENERIC_TIME
-+      bool
-+      default y
-+
-+config TIME_LOW_RES
-+      bool
-+      default y
-+
-+config GENERIC_CLOCKEVENTS
-+      bool
-+      default y
-+
-+config GENERIC_CLOCKEVENTS_BROADCAST
-+      bool
-+      depends on GENERIC_CLOCKEVENTS
-+      default y if SMP && !LOCAL_TIMERS
-+
-+config NO_IOPORT
-+      def_bool y
-+
-+config ARCH_SUPPORTS_AOUT
-+      def_bool y
-+
-+config IRQ_PER_CPU
-+      bool
-+      default y
-+
-+config SCHED_NO_NO_OMIT_FRAME_POINTER
-+      bool
-+      default y
-+
-+config UBICOM32_PLIO
-+      bool
-+      default n
-+
-+menu "Processor type and features"
-+
-+comment "Processor type will be selected by Board"
-+
-+config UBICOM32_V3
-+      bool
-+      help
-+        Ubicom IP5xxx series processor support.
-+
-+config UBICOM32_V4
-+      bool
-+      help
-+        Ubicom IP7xxx series processor support.
-+
-+comment "Board"
-+choice
-+      prompt "Board type"
-+      help
-+              Select your board.
-+
-+config NOBOARD
-+      bool "No board selected"
-+      help
-+              Default. Don't select any board specific config. Will not build unless you change!
-+
-+# Add your boards here
-+source "arch/ubicom32/mach-ip5k/Kconfig"
-+source "arch/ubicom32/mach-ip7k/Kconfig"
-+
-+endchoice
-+
-+comment "Kernel Options"
-+config SMP
-+      bool "Symmetric multi-processing support"
-+      select USE_GENERIC_SMP_HELPERS
-+      default n
-+      help
-+        Enables multithreading support.  Enabling SMP support increases
-+        the size of system data structures.  SMP support can have either
-+        positive or negative impact on performance depending on workloads.
-+
-+        If you do not know what to do here, say N.
-+config OLD_40400010_SYSTEM_CALL
-+      bool "Provide old system call interface at 0x40400010"
-+      default y
-+      help
-+        Provides the old system call interface, does not affect the
-+        new system_call interface.
-+
-+config NR_CPUS
-+      int "Number of configured CPUs"
-+      range 2 32
-+      default 2
-+      depends on SMP
-+      help
-+              Upper bound on the number of CPUs. Space is reserved
-+              at compile time for this many CPUs.
-+
-+config LOCAL_TIMERS
-+      bool "Use local timer interrupts"
-+      depends on SMP
-+      default y
-+      help
-+        Enable support for local timers on SMP platforms, rather then the
-+        legacy IPI broadcast method.  Local timers allows the system
-+        accounting to be spread across the timer interval, preventing a
-+        "thundering herd" at every timer tick.  A physical timer is allocated
-+        per cpu.
-+
-+config TIMER_EXTRA_ALLOC
-+      int "Number of additional physical timer events to create"
-+      depends on GENERIC_CLOCKEVENTS
-+      default 0
-+      help
-+              The Ubicom32 processor has a number of event timers that can be wrapped
-+              in Linux clock event structures (assuming that the timers are not being
-+              used for another purpose).  Based on the value of LOCAL_TIMERS, either
-+              2 timers will be used or a timer will be used for every CPU.  This value
-+              allows the programmer to select additional timers over that amount.
-+
-+config IRQSTACKS
-+      bool "Create separate stacks for interrupt handling"
-+      default n
-+      help
-+              Selecting this causes interrupts to be created on a separate
-+              stack instead of nesting the interrupts on the kernel stack.
-+
-+config IRQSTACKS_USEOCM
-+      bool "Use OCM for interrupt stacks"
-+      default n
-+      depends on IRQSTACKS
-+      help
-+              Selecting this cause the interrupt stacks to be placed in OCM
-+              reducing cache misses at the expense of using the OCM for servicing
-+              interrupts.
-+
-+menu "OCM Instruction Heap"
-+
-+config OCM_MODULES_RESERVATION
-+      int "OCM Instruction heap reservation. 0-192 kB"
-+      range 0 192
-+      default "0"
-+      help
-+        The minimum amount of OCM memory to reserve for kernel loadable module
-+        code. If you are not using this memory it cannot be used for anything
-+        else. Leave it as 0 if you have prebuilt modules that are compiled with
-+        OCM support.
-+
-+config OCM_MODULES_MAY_CONSUME_REMAINING_CODESPACE
-+      bool "Give all unused ocm code space to the ocm instruction heap."
-+      default n
-+      help
-+        Allow the OCM instruction heap allocation to consume any remaining
-+        unused OCM code space.  The result of this is that you will not have
-+        and deterministic results, but you will not have any waste either.
-+
-+config OCM_MODULES_FALLBACK_TO_DDR
-+      bool "Loadable Modules requiring OCM may fallback to use DDR."
-+      default n
-+      help
-+        If a module cannot get the OCM code it requires allow DDR to
-+        be used instead.
-+endmenu
-+
-+config HZ
-+      int "Frequency of 'jiffies' (for polling)"
-+      default 1000
-+      help
-+              100 is common for embedded systems, but 1000 allows
-+              you to do more drivers without actually having
-+              interrupts working properly.
-+
-+comment "RAM configuration"
-+
-+config MIN_RAMSIZE
-+      hex "Minimum Size of RAM (in bytes)"
-+      range 0x01000000 0x08000000
-+      default "0x02000000"
-+      help
-+              Define the minimum acceptable size of the system
-+              RAM. Must be at least 16MB (0x01000000)
-+
-+comment "Build options"
-+config LINKER_RELAXATION
-+      bool "Linker Relaxation"
-+      default y
-+      help
-+        Turns on linker relaxation that will produce smaller
-+        faster code. Increases link time.
-+
-+comment "Driver options"
-+menu "PCI Bus"
-+config PCI
-+      bool "PCI bus"
-+      default true
-+      help
-+        Enable/Disable PCI bus
-+      source "drivers/pci/Kconfig"
-+
-+
-+config PCI_DEV0_IDSEL
-+      hex "slot 0 address"
-+      depends on PCI
-+      default "0x01000000"
-+      help
-+        Slot 0 address.  This address should correspond to the address line
-+        which the IDSEL bit for this slot is connected to.
-+
-+config PCI_DEV1_IDSEL
-+      hex "slot 1 address"
-+      depends on PCI
-+      default "0x02000000"
-+      help
-+        Slot 1 address.  This address should correspond to the address line
-+        which the IDSEL bit for this slot is connected to.
-+endmenu
-+# End PCI
-+
-+menu "Input devices"
-+config UBICOM_INPUT
-+      bool "Ubicom polled GPIO input driver"
-+      select INPUT
-+      select INPUT_POLLDEV
-+      help
-+              Polling input driver, much like the GPIO input driver, except that it doesn't
-+              rely on interrupts.  It will report events via the input subsystem.
-+      default n
-+
-+config UBICOM_INPUT_I2C
-+      bool "Ubicom polled GPIO input driver over I2C"
-+      select INPUT
-+      select INPUT_POLLDEV
-+      help
-+              Polling input driver, much like the PCA953x driver, it can support a variety of
-+              different I2C I/O expanders.  This device polls the I2C I/O expander for events
-+              and reports them via the input subsystem.
-+      default n
-+endmenu
-+# Input devices
-+
-+source "arch/ubicom32/mach-common/Kconfig.switch"
-+
-+menu "Misc devices"
-+config UBICOM_HID
-+      bool "Ubicom HID driver"
-+      select INPUT
-+      select INPUT_POLLDEV
-+      select LCD_CLASS_DEVICE
-+      help
-+              Driver for HID chip found on some Ubicom reference designs.  This chip handles
-+              PWM, button input, and IR remote control.  It registers as an input device and
-+              a backlight device.
-+      default n
-+endmenu
-+# Misc devices
-+
-+config CMDLINE_BOOL
-+      bool "Built-in kernel command line"
-+      default n
-+      help
-+        Allow for specifying boot arguments to the kernel at
-+        build time.  On some systems (e.g. embedded ones), it is
-+        necessary or convenient to provide some or all of the
-+        kernel boot arguments with the kernel itself (that is,
-+        to not rely on the boot loader to provide them.)
-+
-+        To compile command line arguments into the kernel,
-+        set this option to 'Y', then fill in the
-+        the boot arguments in CONFIG_CMDLINE.
-+
-+        Systems with fully functional boot loaders (i.e. non-embedded)
-+        should leave this option set to 'N'.
-+
-+config CMDLINE
-+      string "Built-in kernel command string"
-+      depends on CMDLINE_BOOL
-+      default ""
-+      help
-+        Enter arguments here that should be compiled into the kernel
-+        image and used at boot time.  If the boot loader provides a
-+        command line at boot time, it is appended to this string to
-+        form the full kernel command line, when the system boots.
-+
-+        However, you can use the CONFIG_CMDLINE_OVERRIDE option to
-+        change this behavior.
-+
-+        In most cases, the command line (whether built-in or provided
-+        by the boot loader) should specify the device for the root
-+        file system.
-+
-+config CMDLINE_OVERRIDE
-+      bool "Built-in command line overrides boot loader arguments"
-+      default n
-+      depends on CMDLINE_BOOL
-+      help
-+        Set this option to 'Y' to have the kernel ignore the boot loader
-+        command line, and use ONLY the built-in command line.
-+
-+        This is used to work around broken boot loaders.  This should
-+        be set to 'N' under normal conditions.
-+
-+endmenu
-+# End Processor type and features
-+
-+source "arch/ubicom32/Kconfig.debug"
-+
-+menu "Executable file formats"
-+source "fs/Kconfig.binfmt"
-+endmenu
-+
-+source "init/Kconfig"
-+source "kernel/Kconfig.preempt"
-+source "kernel/time/Kconfig"
-+source "mm/Kconfig"
-+source "net/Kconfig"
-+source "drivers/Kconfig"
-+source "fs/Kconfig"
-+source "security/Kconfig"
-+source "crypto/Kconfig"
-+source "lib/Kconfig"
---- /dev/null
-+++ b/arch/ubicom32/Kconfig.debug
-@@ -0,0 +1,129 @@
-+menu "Kernel hacking"
-+
-+config TRACE_IRQFLAGS_SUPPORT
-+      def_bool y
-+
-+config DEBUG_VERBOSE
-+        bool "Verbose fault messages"
-+        default y
-+        select PRINTK
-+        help
-+          When a program crashes due to an exception, or the kernel detects
-+          an internal error, the kernel can print a not so brief message
-+          explaining what the problem was. This debugging information is
-+          useful to developers and kernel hackers when tracking down problems,
-+          but mostly meaningless to other people. This is always helpful for
-+          debugging but serves no purpose on a production system.
-+          Most people should say N here.
-+
-+config PROTECT_KERNEL
-+      default y
-+      bool 'Enable Kernel range register Protection'
-+      help
-+        Adds code to enable/disable range registers to protect static
-+        kernel code/data from userspace.  Currently the ranges covered
-+        do no protect kernel loadable modules or dynamically allocated
-+        kernel data.
-+
-+config NO_KERNEL_MSG
-+      bool "Suppress Kernel BUG Messages"
-+      help
-+        Do not output any debug BUG messages within the kernel.
-+
-+config EARLY_PRINTK
-+      bool "Use the driver that you selected as console also for early printk (to debug kernel bootup)."
-+      default n
-+      help
-+        If you want to use the serdes driver (console=ttyUS0) for
-+        early printk, you must also supply an additional kernel boot
-+        parameter like this:
-+
-+              serdes=ioportaddr,irq,clockrate,baud
-+
-+        For an IP7160RGW eval board, you could use this:
-+
-+              serdes=0x2004000,61,250000000,57600
-+
-+        which will let you see early printk output at 57600 baud.
-+
-+config STOP_ON_TRAP
-+      bool "Enable stopping at the LDSR for all traps"
-+      default n
-+      help
-+      Cause the LDSR to stop all threads whenever a trap is about to be serviced
-+
-+config STOP_ON_BUG
-+      bool "Enable stopping on failed BUG_ON()"
-+      default n
-+      help
-+      Cause all BUG_ON failures to stop all threads
-+
-+config DEBUG_IRQMEASURE
-+      bool "Enable IRQ handler measurements"
-+      default n
-+      help
-+      When enabled each IRQ's min/avg/max times will be printed.  If the handler
-+      re-enables interrupt, the times will show the full time including to service
-+      nested interrupts.  See /proc/irq_measurements.
-+
-+config DEBUG_PCIMEASURE
-+      bool "Enable PCI transaction measurements"
-+      default n
-+      help
-+      When enabled the system will measure the min/avg/max timer for each PCI transactions.
-+      See /proc/pci_measurements.
-+
-+config ACCESS_OK_CHECKS_ENABLED
-+      bool "Enable user space access checks"
-+      default n
-+      help
-+      Enabling this check causes the kernel to verify that addresses passed
-+      to the kernel by the user space code are within the processes
-+      address space.  On a no-mmu system, this is done by examining the
-+      processes memory data structures (adversly affecting performance) but
-+      ensuring that a process does not ask the kernel to violate another
-+      processes address space.  Sadly, the kernel uses access_ok() for
-+      address that are in the kernel which results in a large volume of
-+      false positives.
-+
-+choice
-+      prompt "Unaligned Access Support"
-+      default UNALIGNED_ACCESS_ENABLED
-+      help
-+              Kernel / Userspace unaligned access handling.
-+
-+config  UNALIGNED_ACCESS_ENABLED
-+      bool "Kernel and Userspace"
-+      help
-+
-+config  UNALIGNED_ACCESS_USERSPACE_ONLY
-+      bool "Userspace Only"
-+      help
-+
-+config  UNALIGNED_ACCESS_DISABLED
-+      bool "Disabled"
-+      help
-+
-+endchoice
-+
-+config DEBUG_STACKOVERFLOW
-+      bool "Check for stack overflows"
-+      default n
-+      depends on DEBUG_KERNEL
-+      help
-+        This option will cause messages to be printed if free kernel stack space
-+        drops below a certain limit (THREAD_SIZE /8).
-+
-+config DEBUG_STACK_USAGE
-+      bool "Stack utilization instrumentation"
-+      default n
-+      depends on DEBUG_KERNEL
-+      help
-+        Enables the display of the minimum amount of free kernel stack which each
-+        task has ever had available in the sysrq-T and sysrq-P debug output.
-+
-+        This option will slow down process creation somewhat.
-+
-+source "lib/Kconfig.debug"
-+
-+endmenu
---- /dev/null
-+++ b/arch/ubicom32/kernel/asm-offsets.c
-@@ -0,0 +1,161 @@
-+/*
-+ * arch/ubicom32/kernel/asm-offsets.c
-+ *   Ubicom32 architecture definitions needed by assembly language modules.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+/*
-+ * This program is used to generate definitions needed by
-+ * assembly language modules.
-+ *
-+ * We use the technique used in the OSF Mach kernel code:
-+ * generate asm statements containing #defines,
-+ * compile this file to assembler, and then extract the
-+ * #defines from the assembly-language output.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/stddef.h>
-+#include <linux/sched.h>
-+#include <linux/kernel_stat.h>
-+#include <linux/ptrace.h>
-+#include <linux/hardirq.h>
-+#include <asm/bootinfo.h>
-+#include <asm/irq.h>
-+#include <asm/thread_info.h>
-+
-+#define DEFINE(sym, val) \
-+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-+
-+#define BLANK() asm volatile("\n->" : : )
-+
-+int main(void)
-+{
-+      /* offsets into the task struct */
-+      DEFINE(TASK_STATE, offsetof(struct task_struct, state));
-+      DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
-+      DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
-+      DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
-+      DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
-+      DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
-+      DEFINE(TASK_MM, offsetof(struct task_struct, mm));
-+      DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
-+
-+      /* offsets into the kernel_stat struct */
-+//    DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
-+
-+      /* offsets into the irq_cpustat_t struct */
-+      DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
-+
-+      /* offsets into the thread struct */
-+      DEFINE(THREAD_D10, offsetof(struct thread_struct, d10));
-+      DEFINE(THREAD_D11, offsetof(struct thread_struct, d11));
-+      DEFINE(THREAD_D12, offsetof(struct thread_struct, d12));
-+      DEFINE(THREAD_D13, offsetof(struct thread_struct, d13));
-+      DEFINE(THREAD_A1, offsetof(struct thread_struct, a1));
-+      DEFINE(THREAD_A2, offsetof(struct thread_struct, a2));
-+      DEFINE(THREAD_A5, offsetof(struct thread_struct, a5));
-+      DEFINE(THREAD_A6, offsetof(struct thread_struct, a6));
-+      DEFINE(THREAD_SP, offsetof(struct thread_struct, sp));
-+
-+      /* offsets into the pt_regs */
-+      DEFINE(PT_D0, offsetof(struct pt_regs, dn[0]));
-+      DEFINE(PT_D1, offsetof(struct pt_regs, dn[1]));
-+      DEFINE(PT_D2, offsetof(struct pt_regs, dn[2]));
-+      DEFINE(PT_D3, offsetof(struct pt_regs, dn[3]));
-+      DEFINE(PT_D4, offsetof(struct pt_regs, dn[4]));
-+      DEFINE(PT_D5, offsetof(struct pt_regs, dn[5]));
-+      DEFINE(PT_D6, offsetof(struct pt_regs, dn[6]));
-+      DEFINE(PT_D7, offsetof(struct pt_regs, dn[7]));
-+      DEFINE(PT_D8, offsetof(struct pt_regs, dn[8]));
-+      DEFINE(PT_D9, offsetof(struct pt_regs, dn[9]));
-+      DEFINE(PT_D10, offsetof(struct pt_regs, dn[10]));
-+      DEFINE(PT_D11, offsetof(struct pt_regs, dn[11]));
-+      DEFINE(PT_D12, offsetof(struct pt_regs, dn[12]));
-+      DEFINE(PT_D13, offsetof(struct pt_regs, dn[13]));
-+      DEFINE(PT_D14, offsetof(struct pt_regs, dn[14]));
-+      DEFINE(PT_D15, offsetof(struct pt_regs, dn[15]));
-+      DEFINE(PT_A0, offsetof(struct pt_regs, an[0]));
-+      DEFINE(PT_A1, offsetof(struct pt_regs, an[1]));
-+      DEFINE(PT_A2, offsetof(struct pt_regs, an[2]));
-+      DEFINE(PT_A3, offsetof(struct pt_regs, an[3]));
-+      DEFINE(PT_A4, offsetof(struct pt_regs, an[4]));
-+      DEFINE(PT_A5, offsetof(struct pt_regs, an[5]));
-+      DEFINE(PT_A6, offsetof(struct pt_regs, an[6]));
-+      DEFINE(PT_A7, offsetof(struct pt_regs, an[7]));
-+      DEFINE(PT_SP, offsetof(struct pt_regs, an[7]));
-+
-+      DEFINE(PT_ACC0HI, offsetof(struct pt_regs, acc0[0]));
-+      DEFINE(PT_ACC0LO, offsetof(struct pt_regs, acc0[1]));
-+      DEFINE(PT_MAC_RC16, offsetof(struct pt_regs, mac_rc16));
-+
-+      DEFINE(PT_ACC1HI, offsetof(struct pt_regs, acc1[0]));
-+      DEFINE(PT_ACC1LO, offsetof(struct pt_regs, acc1[1]));
-+
-+      DEFINE(PT_SOURCE3, offsetof(struct pt_regs, source3));
-+      DEFINE(PT_INST_CNT, offsetof(struct pt_regs, inst_cnt));
-+      DEFINE(PT_CSR, offsetof(struct pt_regs, csr));
-+      DEFINE(PT_DUMMY_UNUSED, offsetof(struct pt_regs, dummy_unused));
-+
-+      DEFINE(PT_INT_MASK0, offsetof(struct pt_regs, int_mask0));
-+      DEFINE(PT_INT_MASK1, offsetof(struct pt_regs, int_mask1));
-+
-+      DEFINE(PT_PC, offsetof(struct pt_regs, pc));
-+
-+      DEFINE(PT_TRAP_CAUSE, offsetof(struct pt_regs, trap_cause));
-+
-+      DEFINE(PT_SIZE, sizeof(struct pt_regs));
-+
-+      DEFINE(PT_FRAME_TYPE, offsetof(struct pt_regs, frame_type));
-+
-+      DEFINE(PT_ORIGINAL_D0, offsetof(struct pt_regs, original_dn_0));
-+      DEFINE(PT_PREVIOUS_PC, offsetof(struct pt_regs, previous_pc));
-+
-+      /* offsets into the kernel_stat struct */
-+//    DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
-+
-+      /* signal defines */
-+      DEFINE(SIGSEGV, SIGSEGV);
-+      //DEFINE(SEGV_MAPERR, SEGV_MAPERR);
-+      DEFINE(SIGTRAP, SIGTRAP);
-+      //DEFINE(TRAP_TRACE, TRAP_TRACE);
-+
-+      DEFINE(PT_PTRACED, PT_PTRACED);
-+      DEFINE(PT_DTRACE, PT_DTRACE);
-+
-+      DEFINE(ASM_THREAD_SIZE, THREAD_SIZE);
-+
-+      /* Offsets in thread_info structure */
-+      DEFINE(TI_TASK, offsetof(struct thread_info, task));
-+      DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
-+      DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
-+      DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
-+      DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
-+      DEFINE(TI_INTR_NESTING, offsetof(struct thread_info, interrupt_nesting));
-+      DEFINE(ASM_TIF_NEED_RESCHED, TIF_NEED_RESCHED);
-+      DEFINE(ASM_TIF_SYSCALL_TRACE, TIF_SYSCALL_TRACE);
-+      DEFINE(ASM_TIF_SIGPENDING, TIF_SIGPENDING);
-+
-+      return 0;
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/devtree.c
-@@ -0,0 +1,173 @@
-+/*
-+ * arch/ubicom32/kernel/devtree.c
-+ *   Ubicom32 architecture device tree implementation.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/errno.h>
-+#include <asm/devtree.h>
-+
-+/*
-+ * The device tree.
-+ */
-+struct devtree_node *devtree;
-+
-+/*
-+ * devtree_print()
-+ *    Print the device tree.
-+ */
-+void devtree_print(void)
-+{
-+      struct devtree_node *p = devtree;
-+      printk(KERN_INFO "Device Tree:\n");
-+      while (p) {
-+              if (p->magic != DEVTREE_NODE_MAGIC) {
-+                      printk(KERN_EMERG
-+                             "device tree has improper node: %p\n", p);
-+                      return;
-+              }
-+              printk(KERN_INFO "\t%p: sendirq=%03d, recvirq=%03d, "
-+                     " name=%s\n", p, p->sendirq, p->recvirq, p->name);
-+              p = p->next;
-+      }
-+}
-+EXPORT_SYMBOL(devtree_print);
-+
-+/*
-+ * devtree_irq()
-+ *    Return the IRQ(s) associated with devtree node.
-+ */
-+int devtree_irq(struct devtree_node *dn,
-+              unsigned char *sendirq,
-+              unsigned char *recvirq)
-+{
-+      if (dn->magic != DEVTREE_NODE_MAGIC) {
-+              printk(KERN_EMERG "improper node: %p\n", dn);
-+              if (sendirq) {
-+                      *sendirq = DEVTREE_IRQ_NONE;
-+              }
-+              if (recvirq) {
-+                      *recvirq = DEVTREE_IRQ_NONE;
-+              }
-+              return -EFAULT;
-+      }
-+
-+      /*
-+       * Copy the devtree irq(s) to the output parameters.
-+       */
-+      if (sendirq) {
-+              *sendirq = dn->sendirq;
-+      }
-+      if (recvirq) {
-+              *recvirq = dn->recvirq;
-+      }
-+      return 0;
-+}
-+EXPORT_SYMBOL(devtree_irq);
-+
-+/*
-+ * devtree_find_next()
-+ *    Provide an iterator for walking the device tree.
-+ */
-+struct devtree_node *devtree_find_next(struct devtree_node **cur)
-+{
-+      struct devtree_node *p = *cur;
-+      if (!p) {
-+              *cur = devtree;
-+              return devtree;
-+      }
-+      p = p->next;
-+      *cur = p;
-+      return p;
-+}
-+
-+/*
-+ * devtree_find_by_irq()
-+ *    Return the node associated with a given irq.
-+ */
-+struct devtree_node *devtree_find_by_irq(uint8_t sendirq, uint8_t recvirq)
-+{
-+      struct devtree_node *p = devtree;
-+
-+      if (sendirq == recvirq) {
-+              printk(KERN_EMERG "identical request makes no sense sendirq = "
-+                     "%d, recvirq= %d\n", sendirq, recvirq);
-+              return NULL;
-+      }
-+
-+      while (p) {
-+              if (p->magic != DEVTREE_NODE_MAGIC) {
-+                      printk(KERN_EMERG
-+                             "device tree has improper node: %p\n", p);
-+                      return NULL;
-+              }
-+
-+              /*
-+               * See if we can find a match on the IRQ(s) specified.
-+               */
-+              if ((sendirq == p->sendirq) && (recvirq == p->recvirq)) {
-+                      return p;
-+              }
-+
-+              if ((sendirq == DEVTREE_IRQ_DONTCARE) &&
-+                  (p->recvirq == recvirq)) {
-+                      return p;
-+              }
-+
-+              if ((recvirq == DEVTREE_IRQ_DONTCARE) &&
-+                  (p->sendirq == sendirq)) {
-+                      return p;
-+              }
-+
-+              p = p->next;
-+      }
-+      return NULL;
-+}
-+EXPORT_SYMBOL(devtree_find_by_irq);
-+
-+/*
-+ * devtree_find_node()
-+ *    Find a node in the device tree by name.
-+ */
-+struct devtree_node *devtree_find_node(const char *str)
-+{
-+      struct devtree_node *p = devtree;
-+      while (p) {
-+              if (p->magic != DEVTREE_NODE_MAGIC) {
-+                      printk(KERN_EMERG
-+                             "device tree has improper node: %p\n", p);
-+                      return NULL;
-+              }
-+              if (strcmp(p->name, str) == 0) {
-+                      return p;
-+              }
-+              p = p->next;
-+      }
-+      return NULL;
-+}
-+EXPORT_SYMBOL(devtree_find_node);
---- /dev/null
-+++ b/arch/ubicom32/kernel/dma.c
-@@ -0,0 +1,60 @@
-+/*
-+ * arch/ubicom32/kernel/dma.c
-+ *   Ubicom32 architecture dynamic DMA mapping support.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *
-+ * We never have any address translations to worry about, so this
-+ * is just alloc/free.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/mm.h>
-+#include <linux/string.h>
-+#include <linux/device.h>
-+#include <linux/io.h>
-+
-+void *dma_alloc_coherent(struct device *dev, size_t size,
-+                         dma_addr_t *dma_handle, int gfp)
-+{
-+      void *ret;
-+      /* ignore region specifiers */
-+      gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
-+
-+      if (dev == NULL || (*dev->dma_mask < 0xffffffff))
-+              gfp |= GFP_DMA;
-+      ret = (void *)__get_free_pages(gfp, get_order(size));
-+
-+      if (ret != NULL) {
-+              memset(ret, 0, size);
-+              *dma_handle = virt_to_phys(ret);
-+      }
-+      return ret;
-+}
-+
-+void dma_free_coherent(struct device *dev, size_t size,
-+                       void *vaddr, dma_addr_t dma_handle)
-+{
-+      free_pages((unsigned long)vaddr, get_order(size));
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/flat.c
-@@ -0,0 +1,206 @@
-+/*
-+ * arch/ubicom32/kernel/flat.c
-+ *   Ubicom32 architecture flat executable format support.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/flat.h>
-+
-+unsigned long ubicom32_flat_get_addr_from_rp(unsigned long *rp,
-+                                           u32_t relval,
-+                                           u32_t flags,
-+                                           unsigned long *persistent)
-+{
-+      u32_t relval_reloc_type = relval >> 27;
-+      u32_t insn = *rp;
-+
-+      if (*persistent) {
-+              /*
-+               * relval holds the relocation that has to be adjusted.
-+               */
-+              if (relval == 0) {
-+                      *persistent = 0;
-+              }
-+
-+              return relval;
-+      }
-+
-+      if (relval_reloc_type == R_UBICOM32_32) {
-+              /*
-+               * insn holds the relocation
-+               */
-+              return insn;
-+      }
-+
-+      /*
-+       * We don't know this one.
-+       */
-+      return 0;
-+}
-+
-+void ubicom32_flat_put_addr_at_rp(unsigned long *rp,
-+                                u32_t val,
-+                                u32_t relval,
-+                                unsigned long *persistent)
-+{
-+      u32_t reloc_type = (relval >> 27) & 0x1f;
-+      u32_t insn = *rp;
-+
-+      /*
-+       * If persistent is set then it contains the relocation type.
-+       */
-+      if (*persistent) {
-+              /*
-+               * If persistent is set then it contains the relocation type.
-+               */
-+              reloc_type = (*persistent >> 27) & 0x1f;
-+      }
-+
-+      switch (reloc_type) {
-+      case R_UBICOM32_32:
-+              /*
-+               * Store the 32 bits as is.
-+               */
-+              *rp = val;
-+              break;
-+      case R_UBICOM32_HI24:
-+              {
-+                      /*
-+                       * 24 bit relocation that is part of the MOVEAI
-+                       * instruction. The 24 bits come from bits 7 - 30 of the
-+                       * relocation. The 24 bits eventually get split into 2
-+                       * fields in the instruction encoding.
-+                       *
-+                       * - Bits 7 - 27 of the relocation are encoded into bits
-+                       * 0 - 20 of the instruction.
-+                       *
-+                       * - Bits 28 - 30 of the relocation are encoded into bit
-+                       * 24 - 26 of the instruction.
-+                       */
-+                      u32_t mask = 0x1fffff | (0x7 << 24);
-+                      u32_t valid24bits = (val >> 7) & 0xffffff;
-+                      u32_t bot_21 = valid24bits & 0x1fffff;
-+                      u32_t upper_3_bits = ((valid24bits & 0xe00000) << 3);
-+                      insn &= ~mask;
-+
-+                      insn |= bot_21;
-+                      insn |= upper_3_bits;
-+                      *rp = insn;
-+              }
-+              break;
-+      case R_UBICOM32_LO7_S:
-+      case R_UBICOM32_LO7_2_S:
-+      case R_UBICOM32_LO7_4_S:
-+              {
-+                      /*
-+                       * Bits 0 - 6 of the relocation are encoded into the
-+                       * 7bit unsigned immediate fields of the SOURCE-1 field
-+                       * of the instruction.  The immediate value is left
-+                       * shifted by (0, 1, 2) based on the operand size.
-+                       */
-+                      u32_t mask = 0x1f | (0x3 << 8);
-+                      u32_t bottom, top;
-+                      val &= 0x7f;
-+                      if (reloc_type == R_UBICOM32_LO7_2_S) {
-+                              val >>= 1;
-+                      } else if (reloc_type == R_UBICOM32_LO7_4_S) {
-+                              val >>= 2;
-+                      }
-+
-+                      bottom  = val & 0x1f;
-+                      top = val >> 5;
-+                      insn &= ~mask;
-+                      insn |= bottom;
-+                      insn |= (top << 8);
-+                      BUG_ON(*rp != insn);
-+                      *rp = insn;
-+                      break;
-+              }
-+      case R_UBICOM32_LO7_D:
-+      case R_UBICOM32_LO7_2_D:
-+      case R_UBICOM32_LO7_4_D:
-+              {
-+                      /*
-+                       * Bits 0 - 6 of the relocation are encoded into the
-+                       * 7bit unsigned immediate fields of the DESTINATION
-+                       * field of the instruction.  The immediate value is
-+                       * left shifted by (0, 1, 2) based on the operand size.
-+                       */
-+                      u32_t mask = (0x1f | (0x3 << 8)) << 16;
-+                      u32_t bottom, top;
-+                      val &= 0x7f;
-+                      if (reloc_type == R_UBICOM32_LO7_2_D) {
-+                              val >>= 1;
-+                      } else if (reloc_type == R_UBICOM32_LO7_4_D) {
-+                              val >>= 2;
-+                      }
-+                      bottom  = (val & 0x1f) << 16;
-+                      top = (val >> 5) << 16;
-+                      insn &= ~mask;
-+                      insn |= bottom;
-+                      insn |= (top << 8);
-+                      BUG_ON(*rp != insn);
-+                      *rp = insn;
-+                      break;
-+              }
-+      case R_UBICOM32_LO7_CALLI:
-+      case R_UBICOM32_LO16_CALLI:
-+              {
-+                      /*
-+                       * Extract the offset for a CALLI instruction. The
-+                       * offsets can be either 7 bits or 18 bits. Since all
-+                       * instructions in ubicom32 architecture are at work
-+                       * aligned addresses the truncated offset is right
-+                       * shifted by 2 before being encoded in the instruction.
-+                       */
-+                      if (reloc_type == R_UBICOM32_LO7_CALLI) {
-+                              val &= 0x7f;
-+                      } else {
-+                              val &= 0x3ffff;
-+                      }
-+
-+                      val >>= 2;
-+
-+                      insn &= ~0x071f071f;
-+                      insn |= (val & 0x1f) << 0;
-+                      val >>= 5;
-+                      insn |= (val & 0x07) << 8;
-+                      val >>= 3;
-+                      insn |= (val & 0x1f) << 16;
-+                      val >>= 5;
-+                      insn |= (val & 0x07) << 24;
-+                      if (reloc_type == R_UBICOM32_LO7_CALLI) {
-+                              BUG_ON(*rp != insn);
-+                      }
-+                      *rp = insn;
-+              }
-+              break;
-+      }
-+
-+      if (*persistent) {
-+              *persistent = 0;
-+      }
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/head.S
-@@ -0,0 +1,273 @@
-+/*
-+ * arch/ubicom32/kernel/head.S
-+ *    <TODO: Replace with short file description>
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/sys.h>
-+#include <linux/linkage.h>
-+#include <asm/asm-offsets.h>
-+#include <asm/page_offset.h>
-+#define __ASM__
-+#include <asm/ip5000.h>
-+
-+
-+#define SRC_AN A3
-+#define DST_AN A4
-+
-+#define PARAM_DN D0
-+#define TMP_DN D15
-+#define TMP2_DN D14
-+
-+/*
-+ * The following code is placed at the start of the Linux section of memory.
-+ * This is the primary entry point for Linux.
-+ *
-+ * However, we also want the syscall entry/exit code to be at a fixed address.
-+ * So we take the primary entry point and reserve 16 bytes.  That address is
-+ * where the system_call entry point exists.  This 16 bytes basically allows
-+ * us to jump around the system_call entry point code to the actual startup
-+ * code.
-+ *
-+ * Linux Memory Map (see vlinux.lds.S):
-+ * 0x40400000 - Primary Entry Point for Linux (jump around code below).
-+ * 0x40400010 - Old syscall Entry Point.
-+ */
-+
-+      .sect   .skip_syscall, "ax", @progbits
-+      .global __skip_syscall_section
-+__skip_syscall_section:
-+      moveai          A3, #%hi(_start)
-+      lea.1           A3, %lo(_start)(A3)
-+      ret             A3
-+/*
-+ * __os_node_offset contains the offset from KERNELBASE to the os_node, it is
-+ * not intended to be used by anything except the boot code.
-+ */
-+__os_node_offset:
-+.long (_os_node - KERNELSTART)
-+
-+.text
-+.global       _start
-+
-+/*
-+ * start()
-+ *    This is the start of the Linux kernel.
-+ */
-+_start:
-+      move.4          SCRATCHPAD1, #0
-+
-+
-+/*
-+ * Setup the range registers... the loader has setup a few, but we will go ahead
-+ * and correct them for our own limits. Note that once set these are never
-+ * changed again.  The ranges are as follows
-+ *
-+ *  D_RANGE0 - io block (set up by loaded)
-+ *
-+ *  I_RANGE0 and D_RANGE1 - kernel/ultra loader address space bottom of ocm-> top
-+ *    of ram typically 0x3ffc0000 - 0x440000000
-+ *  I_RANGE1 - kernel / userspace transition area (aka syscalls, context switches)
-+ *    typically 0x3FFC0030 - ~0x3FFC0200
-+ *  I_RANGE2 / D_RANGE2 - slab area
-+ *    typically 0x40A00000 - ~0x44000000
-+ *  I_RANGE3
-+ *    old system call interface if enabled.
-+ *
-+ *   D_RANGE3, D_RANGE4 - unused.
-+ */
-+      moveai          SRC_AN, #%hi(PAGE_OFFSET_RAW)
-+      lea.4           SRC_AN, %lo(PAGE_OFFSET_RAW)(SRC_AN)
-+      move.4          D_RANGE1_LO, SRC_AN
-+      move.4          I_RANGE0_LO, SRC_AN
-+
-+; don't try to calculate I_RANGE_HI, see below
-+;     moveai          SRC_AN, #%hi(___init_end-4)
-+;     lea.4           SRC_AN, %lo(___init_end-4)(SRC_AN)
-+;     move.4          I_RANGE0_HI, SRC_AN
-+
-+      moveai          SRC_AN, #%hi(SDRAMSTART + CONFIG_MIN_RAMSIZE-4)
-+      lea.4           SRC_AN, %lo(SDRAMSTART + CONFIG_MIN_RAMSIZE-4)(SRC_AN)
-+      move.4          D_RANGE1_HI, SRC_AN
-+
-+; for now allow the whole ram to be executable as well so we don't run into problems
-+; once we load user more code.
-+      move.4          I_RANGE0_HI, SRC_AN
-+
-+#ifdef CONFIG_PROTECT_KERNEL
-+; when kernel protection is enabled, we only open up syscall and non kernel text
-+; for userspace apps, for now only irange registers registers 1 and 2 are used for userspace.
-+
-+      ;; syscall range
-+      moveai          SRC_AN, #%hi(__syscall_text_run_begin)
-+      lea.4           SRC_AN, %lo(__syscall_text_run_begin)(SRC_AN)
-+      move.4          I_RANGE1_LO, SRC_AN
-+      moveai          SRC_AN, #%hi(__syscall_text_run_end)
-+      lea.4           SRC_AN, %lo(__syscall_text_run_end)(SRC_AN)
-+      move.4          I_RANGE1_HI, SRC_AN
-+
-+      ;; slab instructions
-+      moveai          SRC_AN, #%hi(_edata)
-+      lea.4           SRC_AN, %lo(_edata)(SRC_AN)
-+      move.4          I_RANGE2_LO, SRC_AN
-+      ;; End of DDR is already in range0 hi so just copy it.
-+      move.4          I_RANGE2_HI, I_RANGE0_HI
-+
-+#ifdef CONFIG_OLD_40400010_SYSTEM_CALL
-+      ;; create a small hole for old syscall location
-+      moveai          SRC_AN, #%hi(0x40400000)
-+      lea.4           I_RANGE3_LO, 0x10(SRC_AN)
-+      lea.4           I_RANGE3_HI, 0x14(SRC_AN)
-+#endif
-+      ;; slab data (same as slab instructions but starting a little earlier).
-+      moveai          SRC_AN, #%hi(_data_protection_end)
-+      lea.4           SRC_AN, %lo(_data_protection_end)(SRC_AN)
-+      move.4          D_RANGE2_LO, SRC_AN
-+      move.4          D_RANGE2_HI, I_RANGE0_HI
-+
-+;; enable ranges
-+      ;; skip I_RANGE0_EN
-+      move.4          I_RANGE1_EN, #-1
-+      move.4          I_RANGE2_EN, #-1
-+#ifdef CONFIG_OLD_40400010_SYSTEM_CALL
-+      move.4          I_RANGE3_EN, #-1
-+#else
-+      move.4          I_RANGE3_EN, #0
-+#endif
-+      ;; skip D_RANGE0_EN or D_RANGE1_EN
-+      move.4          D_RANGE2_EN, #-1
-+      move.4          D_RANGE3_EN, #0
-+      move.4          D_RANGE4_EN, #0
-+#endif
-+
-+;
-+; If __ocm_free_begin is smaller than __ocm_free_end the
-+; setup OCM text and data ram banks properly
-+;
-+      moveai          DST_AN, #%hi(__ocm_free_begin)
-+      lea.4           TMP_DN, %lo(__ocm_free_begin)(DST_AN)
-+      moveai          DST_AN, #%hi(__ocm_free_end)
-+      lea.4           TMP2_DN, %lo(__ocm_free_end)(DST_AN)
-+      sub.4           #0, TMP2_DN, TMP_DN
-+      jmple.f         2f
-+      moveai          DST_AN, #%hi(__data_begin)
-+      lea.4           TMP_DN, %lo(__data_begin)(DST_AN)
-+      moveai          DST_AN, #%hi(OCMSTART)
-+      lea.4           TMP2_DN, %lo(OCMSTART)(DST_AN)
-+      sub.4           TMP_DN, TMP_DN, TMP2_DN
-+      lsr.4           TMP_DN, TMP_DN, #15
-+      lsl.4           TMP_DN, #1, TMP_DN
-+      moveai          DST_AN, #%hi(OCMC_BASE)
-+      add.4           OCMC_BANK_MASK(DST_AN), #-1, TMP_DN
-+      pipe_flush      0
-+2:
-+;
-+; Load .ocm_text
-+;
-+      moveai          DST_AN, #%hi(__ocm_text_run_end)
-+      lea.4           TMP_DN, %lo(__ocm_text_run_end)(DST_AN)
-+      moveai          DST_AN, #%hi(__ocm_text_run_begin)
-+      lea.4           DST_AN, %lo(__ocm_text_run_begin)(DST_AN)
-+      moveai          SRC_AN, #%hi(__ocm_text_load_begin)
-+      lea.4           SRC_AN, %lo(__ocm_text_load_begin)(SRC_AN)
-+      jmpt.t          2f
-+
-+1:      move.4          (DST_AN)4++, (SRC_AN)4++
-+
-+2:      sub.4           #0, DST_AN, TMP_DN
-+      jmpne.t         1b
-+;
-+; Load .syscall_text
-+;
-+      moveai          DST_AN, #%hi(__syscall_text_run_end)
-+      lea.4           TMP_DN, %lo(__syscall_text_run_end)(DST_AN)
-+      moveai          DST_AN, #%hi(__syscall_text_run_begin)
-+      lea.4           DST_AN, %lo(__syscall_text_run_begin)(DST_AN)
-+      moveai          SRC_AN, #%hi(__syscall_text_load_begin)
-+      lea.4           SRC_AN, %lo(__syscall_text_load_begin)(SRC_AN)
-+      jmpt.t          2f
-+
-+1:    move.4          (DST_AN)4++, (SRC_AN)4++
-+
-+2:    sub.4           #0, DST_AN, TMP_DN
-+      jmpne.t         1b
-+
-+;
-+; Load .ocm_data
-+;
-+      moveai          DST_AN, #%hi(__ocm_data_run_end)
-+      lea.4           TMP_DN, %lo(__ocm_data_run_end)(DST_AN)
-+      moveai          DST_AN, #%hi(__ocm_data_run_begin)
-+      lea.4           DST_AN, %lo(__ocm_data_run_begin)(DST_AN)
-+      moveai          SRC_AN, #%hi(__ocm_data_load_begin)
-+      lea.4           SRC_AN, %lo(__ocm_data_load_begin)(SRC_AN)
-+      jmpt.t          2f
-+
-+1:      move.4          (DST_AN)4++, (SRC_AN)4++
-+
-+2:      sub.4           #0, DST_AN, TMP_DN
-+      jmpne.t         1b
-+
-+; Clear .bss
-+;
-+      moveai          SRC_AN, #%hi(_ebss)
-+      lea.4           TMP_DN, %lo(_ebss)(SRC_AN)
-+      moveai          DST_AN, #%hi(_sbss)
-+      lea.4           DST_AN, %lo(_sbss)(DST_AN)
-+      jmpt.t          2f
-+
-+1:    move.4          (DST_AN)4++, #0
-+
-+2:    sub.4           #0, DST_AN, TMP_DN
-+      jmpne.t         1b
-+
-+; save our parameter to devtree (after clearing .bss)
-+      moveai          DST_AN, #%hi(devtree)
-+      lea.4           DST_AN, %lo(devtree)(DST_AN)
-+      move.4          (DST_AN), PARAM_DN
-+
-+      moveai          sp, #%hi(init_thread_union)
-+      lea.4           sp, %lo(init_thread_union)(sp)
-+      movei           TMP_DN, #ASM_THREAD_SIZE
-+      add.4           sp, sp, TMP_DN
-+      move.4          -4(sp)++, #0 ; nesting level = 0
-+      move.4          -4(sp)++, #1 ; KERNEL_THREAD
-+
-+;; ip3k-elf-gdb backend now sets scratchpad3 to 1 when either continue
-+;; or single step commands are issued. scratchpad3 is set to 0 when the
-+;; debugger detaches from the board.
-+      move.4          TMP_DN, scratchpad3
-+      lsl.4           TMP_DN, TMP_DN, #0x0
-+      jmpeq.f         _jump_to_start_kernel
-+_ok_to_set_break_points_in_linux:
-+;; THREAD_STALL
-+      move.4          mt_dbg_active_clr,#-1
-+;; stalling the threads isn't instantaneous.. need to flush the pipe.
-+      pipe_flush      0
-+      pipe_flush      0
-+
-+_jump_to_start_kernel:
-+      moveai          SRC_AN, #%hi(start_kernel)
-+      lea.4           SRC_AN, %lo(start_kernel)(SRC_AN)
-+      ret             SRC_AN
---- /dev/null
-+++ b/arch/ubicom32/kernel/init_task.c
-@@ -0,0 +1,62 @@
-+/*
-+ * arch/ubicom32/kernel/init_task.c
-+ *   Ubicom32 architecture task initialization implementation.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/mm.h>
-+#include <linux/module.h>
-+#include <linux/sched.h>
-+#include <linux/init.h>
-+#include <linux/init_task.h>
-+#include <linux/fs.h>
-+#include <linux/mqueue.h>
-+#include <linux/uaccess.h>
-+#include <asm/pgtable.h>
-+
-+///static struct fs_struct init_fs = INIT_FS;
-+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
-+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-+struct mm_struct init_mm = INIT_MM(init_mm);
-+EXPORT_SYMBOL(init_mm);
-+
-+/*
-+ * Initial task structure.
-+ *
-+ * All other task structs will be allocated on slabs in fork.c
-+ */
-+struct task_struct init_task = INIT_TASK(init_task);
-+
-+EXPORT_SYMBOL(init_task);
-+
-+/*
-+ * Initial thread structure.
-+ *
-+ * We need to make sure that this is 8192-byte aligned due to the
-+ * way process stacks are handled. This is done by having a special
-+ * "init_task" linker map entry..
-+ */
-+union thread_union init_thread_union
-+      __attribute__((__section__(".data.init_task"))) =
-+              { INIT_THREAD_INFO(init_task) };
---- /dev/null
-+++ b/arch/ubicom32/kernel/irq.c
-@@ -0,0 +1,597 @@
-+/*
-+ * arch/ubicom32/kernel/irq.c
-+ *   Ubicom32 architecture IRQ support.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com>
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/irq.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/kernel_stat.h>
-+#include <linux/module.h>
-+#include <linux/seq_file.h>
-+#include <linux/proc_fs.h>
-+#include <asm/system.h>
-+#include <asm/traps.h>
-+#include <asm/ldsr.h>
-+#include <asm/ip5000.h>
-+#include <asm/machdep.h>
-+#include <asm/asm-offsets.h>
-+#include <asm/thread.h>
-+#include <asm/devtree.h>
-+
-+unsigned int irq_soft_avail;
-+static struct irqaction ubicom32_reserve_action[NR_IRQS];
-+
-+#if !defined(CONFIG_DEBUG_IRQMEASURE)
-+#define IRQ_DECLARE_MEASUREMENT
-+#define IRQ_MEASUREMENT_START()
-+#define IRQ_MEASUREMENT_END(irq)
-+#else
-+#define IRQ_DECLARE_MEASUREMENT \
-+      int __diff;             \
-+      unsigned int __tstart;
-+
-+#define IRQ_MEASUREMENT_START() \
-+      __tstart = UBICOM32_IO_TIMER->sysval;
-+
-+#define IRQ_MEASUREMENT_END(irq) \
-+      __diff = (int)UBICOM32_IO_TIMER->sysval - (int)__tstart; \
-+      irq_measurement_update((irq), __diff);
-+
-+/*
-+ * We keep track of the time spent in both irq_enter()
-+ * and irq_exit().
-+ */
-+#define IRQ_WEIGHT 32
-+
-+struct irq_measurement {
-+      volatile unsigned int min;
-+      volatile unsigned int avg;
-+      volatile unsigned int max;
-+};
-+
-+static DEFINE_SPINLOCK(irq_measurement_lock);
-+
-+/*
-+ *  Add 1 in for softirq (irq_exit());
-+ */
-+static struct irq_measurement irq_measurements[NR_IRQS + 1];
-+
-+/*
-+ * irq_measurement_update()
-+ *    Update an entry in the measurement array for this irq.
-+ */
-+static void irq_measurement_update(int irq, int sample)
-+{
-+      struct irq_measurement *im = &irq_measurements[irq];
-+      spin_lock(&irq_measurement_lock);
-+      if ((im->min == 0) || (im->min > sample)) {
-+              im->min = sample;
-+      }
-+      if (im->max < sample) {
-+              im->max = sample;
-+      }
-+      im->avg = ((im->avg * (IRQ_WEIGHT - 1)) + sample) / IRQ_WEIGHT;
-+      spin_unlock(&irq_measurement_lock);
-+}
-+#endif
-+
-+/*
-+ * irq_kernel_stack_check()
-+ *    See if the kernel stack is within STACK_WARN of the end.
-+ */
-+static void irq_kernel_stack_check(int irq, struct pt_regs *regs)
-+{
-+#ifdef CONFIG_DEBUG_STACKOVERFLOW
-+      unsigned long sp;
-+
-+      /*
-+       * Make sure that we are not close to the top of the stack and thus
-+       * can not really service this interrupt.
-+       */
-+      asm volatile (
-+              "and.4          %0, SP, %1 \n\t"
-+              : "=d" (sp)
-+              : "d" (THREAD_SIZE - 1)
-+              : "cc"
-+      );
-+
-+      if (sp < (sizeof(struct thread_info) + STACK_WARN)) {
-+              printk(KERN_WARNING
-+                      "cpu[%d]: possible overflow detected sp remain: %p, "
-+                     "irq: %d, regs: %p\n",
-+                      thread_get_self(), (void *)sp, irq, regs);
-+              dump_stack();
-+      }
-+
-+      if (sp < (sizeof(struct thread_info) + 16)) {
-+              THREAD_STALL;
-+      }
-+#endif
-+}
-+
-+/*
-+ * irq_get_lsb()
-+ *    Get the LSB set in value
-+ */
-+static int irq_get_lsb(unsigned int value)
-+{
-+      static unsigned char irq_bits[8] = {
-+              3, 0, 1, 0, 2, 0, 1, 0
-+      };
-+      u32_t nextbit = 0;
-+
-+      value = (value >> nextbit) | (value << ((sizeof(value) * 8) - nextbit));
-+
-+      /*
-+       * It's unlikely that we find that we execute the body of this while
-+       * loop.  50% of the time we won't take this at all and then of the
-+       * cases where we do about 50% of those we only execute once.
-+       */
-+      if (!(value & 0xffff)) {
-+              nextbit += 0x10;
-+              value >>= 16;
-+      }
-+
-+      if (!(value & 0xff)) {
-+              nextbit += 0x08;
-+              value >>= 8;
-+      }
-+
-+      if (!(value & 0xf)) {
-+              nextbit += 0x04;
-+              value >>= 4;
-+      }
-+
-+      nextbit += irq_bits[value & 0x7];
-+      if (nextbit > 63) {
-+              panic("nextbit out of range: %d\n", nextbit);
-+      }
-+      return nextbit;
-+}
-+
-+/*
-+ * ubicom32_reserve_handler()
-+ *    Bogus handler associated with pre-reserved IRQ(s).
-+ */
-+static irqreturn_t ubicom32_reserve_handler(int irq, void *dev_id)
-+{
-+      BUG();
-+      return IRQ_HANDLED;
-+}
-+
-+/*
-+ * __irq_disable_vector()
-+ *    Disable the interrupt by clearing the appropriate bit in the
-+ *    LDSR Mask Register.
-+ */
-+static void __irq_disable_vector(unsigned int irq)
-+{
-+      ldsr_disable_vector(irq);
-+}
-+
-+/*
-+ * __irq_ack_vector()
-+ *    Acknowledge the specific interrupt by clearing the associate bit in
-+ *    hardware
-+ */
-+static void __irq_ack_vector(unsigned int irq)
-+{
-+      if (irq < 32) {
-+              asm volatile ("move.4 INT_CLR0, %0" : : "d" (1 << irq));
-+      } else {
-+              asm volatile ("move.4 INT_CLR1, %0" : : "d" (1 << (irq - 32)));
-+      }
-+}
-+
-+/*
-+ * __irq_enable_vector()
-+ *    Clean and then enable the interrupt by setting the appropriate bit in
-+ *    the LDSR Mask Register.
-+ */
-+static void __irq_enable_vector(unsigned int irq)
-+{
-+      /*
-+       * Acknowledge, really clear the vector.
-+       */
-+      __irq_ack_vector(irq);
-+      ldsr_enable_vector(irq);
-+}
-+
-+/*
-+ * __irq_mask_vector()
-+ */
-+static void __irq_mask_vector(unsigned int irq)
-+{
-+      ldsr_mask_vector(irq);
-+}
-+
-+/*
-+ * __irq_unmask_vector()
-+ */
-+static void __irq_unmask_vector(unsigned int irq)
-+{
-+      ldsr_unmask_vector(irq);
-+}
-+
-+/*
-+ * __irq_end_vector()
-+ *    Called once an interrupt is completed (reset the LDSR mask).
-+ */
-+static void __irq_end_vector(unsigned int irq)
-+{
-+      ldsr_unmask_vector(irq);
-+}
-+
-+#if defined(CONFIG_SMP)
-+/*
-+ * __irq_set_affinity()
-+ *    Set the cpu affinity for this interrupt.
-+ *    affinity container allocated at boot
-+ */
-+static void __irq_set_affinity(unsigned int irq, const struct cpumask *dest)
-+{
-+      smp_set_affinity(irq, dest);
-+      cpumask_copy(irq_desc[irq].affinity, dest);
-+}
-+#endif
-+
-+/*
-+ * On-Chip Generic Interrupt function handling.
-+ */
-+static struct irq_chip ubicom32_irq_chip = {
-+      .name           = "Ubicom32",
-+      .startup        = NULL,
-+      .shutdown       = NULL,
-+      .enable         = __irq_enable_vector,
-+      .disable        = __irq_disable_vector,
-+      .ack            = __irq_ack_vector,
-+      .mask           = __irq_mask_vector,
-+      .unmask         = __irq_unmask_vector,
-+      .end            = __irq_end_vector,
-+#if defined(CONFIG_SMP)
-+      .set_affinity   = __irq_set_affinity,
-+#endif
-+};
-+
-+/*
-+ * do_IRQ()
-+ *    Primary interface for handling IRQ() requests.
-+ */
-+asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
-+{
-+      struct pt_regs *oldregs;
-+      struct thread_info *ti = current_thread_info();
-+
-+      IRQ_DECLARE_MEASUREMENT;
-+
-+      /*
-+       * Mark that we are inside of an interrupt and
-+       * that interrupts are disabled.
-+       */
-+      oldregs = set_irq_regs(regs);
-+      ti->interrupt_nesting++;
-+      trace_hardirqs_off();
-+      irq_kernel_stack_check(irq, regs);
-+
-+      /*
-+       * Start the interrupt sequence
-+       */
-+      irq_enter();
-+
-+      /*
-+       * Execute the IRQ handler and any pending SoftIRQ requests.
-+       */
-+      BUG_ON(!irqs_disabled());
-+      IRQ_MEASUREMENT_START();
-+      __do_IRQ(irq);
-+      IRQ_MEASUREMENT_END(irq);
-+      BUG_ON(!irqs_disabled());
-+
-+      /*
-+       * TODO: Since IRQ's are disabled when calling irq_exit()
-+       * modify Kconfig to set __ARCH_IRQ_EXIT_IRQS_DISABLED flag.
-+       * This will slightly improve performance by enabling
-+       * softirq handling to avoid disabling/disabled interrupts.
-+       */
-+      IRQ_MEASUREMENT_START();
-+      irq_exit();
-+      IRQ_MEASUREMENT_END(NR_IRQS);
-+      BUG_ON(!irqs_disabled());
-+
-+      /*
-+       * Outside of an interrupt (or nested exit).
-+       */
-+      set_irq_regs(oldregs);
-+      trace_hardirqs_on();
-+      ti->interrupt_nesting--;
-+}
-+
-+/*
-+ * irq_soft_alloc()
-+ *    Allocate a soft IRQ.
-+ */
-+int irq_soft_alloc(unsigned int *soft)
-+{
-+      if (irq_soft_avail == 0) {
-+              printk(KERN_NOTICE "no soft irqs to allocate\n");
-+              return -EFAULT;
-+      }
-+
-+      *soft = irq_get_lsb(irq_soft_avail);
-+      irq_soft_avail &= ~(1 << *soft);
-+      return 0;
-+}
-+
-+/*
-+ * ack_bad_irq()
-+ *    Called to handle an bad irq request.
-+ */
-+void ack_bad_irq(unsigned int irq)
-+{
-+      printk(KERN_ERR "IRQ: unexpected irq=%d\n", irq);
-+      __irq_end_vector(irq);
-+}
-+
-+/*
-+ * show_interrupts()
-+ *    Return a string that displays the state of each of the interrupts.
-+ */
-+int show_interrupts(struct seq_file *p, void *v)
-+{
-+      struct irqaction *ap;
-+      int irq = *((loff_t *) v);
-+      int j;
-+
-+      if (irq >= NR_IRQS) {
-+              return 0;
-+      }
-+
-+      if (irq == 0) {
-+              seq_puts(p, "           ");
-+              for_each_online_cpu(j) {
-+                      seq_printf(p, "CPU%d       ", j);
-+              }
-+              seq_putc(p, '\n');
-+      }
-+
-+      ap = irq_desc[irq].action;
-+      if (ap) {
-+              seq_printf(p, "%3d: ", irq);
-+              for_each_online_cpu(j) {
-+                      seq_printf(p, "%10u ", kstat_irqs_cpu(irq, j));
-+              }
-+              seq_printf(p, "%14s  ", irq_desc[irq].chip->name);
-+              seq_printf(p, "%s", ap->name);
-+              for (ap = ap->next; ap; ap = ap->next) {
-+                      seq_printf(p, ", %s", ap->name);
-+              }
-+              seq_putc(p, '\n');
-+      }
-+      return 0;
-+}
-+
-+#if defined(CONFIG_DEBUG_IRQMEASURE)
-+static unsigned int irq_cycles_to_micro(unsigned int cycles, unsigned int frequency)
-+{
-+      unsigned int micro = (cycles / (frequency / 1000000));
-+      return micro;
-+}
-+
-+/*
-+ * irq_measurement_show()
-+ *    Print out the min, avg, max values for each IRQ
-+ *
-+ * By request, the max value is reset after each dump.
-+ */
-+static int irq_measurement_show(struct seq_file *p, void *v)
-+{
-+      struct irqaction *ap;
-+      unsigned int freq = processor_frequency();
-+      int irq = *((loff_t *) v);
-+
-+
-+      if (irq == 0) {
-+              seq_puts(p, "\tmin\tavg\tmax\t(micro-seconds)\n");
-+      }
-+
-+      if (irq > NR_IRQS) {
-+              return 0;
-+      }
-+
-+      if (irq == NR_IRQS) {
-+              unsigned int min, avg, max;
-+              spin_lock(&irq_measurement_lock);
-+              min = irq_cycles_to_micro(irq_measurements[irq].min, freq);
-+              avg = irq_cycles_to_micro(irq_measurements[irq].avg, freq);
-+              max = irq_cycles_to_micro(irq_measurements[irq].max, freq);
-+              irq_measurements[irq].max = 0;
-+              spin_unlock(&irq_measurement_lock);
-+              seq_printf(p, "   \t%u\t%u\t%u\tsoftirq\n", min, avg, max);
-+              return 0;
-+      }
-+
-+      ap = irq_desc[irq].action;
-+      if (ap) {
-+              unsigned int min, avg, max;
-+              spin_lock(&irq_measurement_lock);
-+              min = irq_cycles_to_micro(irq_measurements[irq].min, freq);
-+              avg = irq_cycles_to_micro(irq_measurements[irq].avg, freq);
-+              max = irq_cycles_to_micro(irq_measurements[irq].max, freq);
-+              irq_measurements[irq].max = 0;
-+              spin_unlock(&irq_measurement_lock);
-+              seq_printf(p, "%2u:\t%u\t%u\t%u\t%s\n", irq, min, avg, max, ap->name);
-+      }
-+      return 0;
-+}
-+
-+static void *irq_measurement_start(struct seq_file *f, loff_t *pos)
-+{
-+      return (*pos <= NR_IRQS) ? pos : NULL;
-+}
-+
-+static void *irq_measurement_next(struct seq_file *f, void *v, loff_t *pos)
-+{
-+      (*pos)++;
-+      if (*pos > NR_IRQS)
-+              return NULL;
-+      return pos;
-+}
-+
-+static void irq_measurement_stop(struct seq_file *f, void *v)
-+{
-+      /* Nothing to do */
-+}
-+
-+static const struct seq_operations irq_measurement_seq_ops = {
-+      .start = irq_measurement_start,
-+      .next  = irq_measurement_next,
-+      .stop  = irq_measurement_stop,
-+      .show  = irq_measurement_show,
-+};
-+
-+static int irq_measurement_open(struct inode *inode, struct file *filp)
-+{
-+      return seq_open(filp, &irq_measurement_seq_ops);
-+}
-+
-+static const struct file_operations irq_measurement_fops = {
-+      .open           = irq_measurement_open,
-+      .read           = seq_read,
-+      .llseek         = seq_lseek,
-+      .release        = seq_release,
-+};
-+
-+static int __init irq_measurement_init(void)
-+{
-+      proc_create("irq_measurements", 0, NULL, &irq_measurement_fops);
-+      return 0;
-+}
-+module_init(irq_measurement_init);
-+#endif
-+
-+/*
-+ * init_IRQ(void)
-+ *    Initialize the on-chip IRQ subsystem.
-+ */
-+void __init init_IRQ(void)
-+{
-+      int irq;
-+      struct devtree_node *p = NULL;
-+      struct devtree_node *iter = NULL;
-+      unsigned int mask = 0;
-+      unsigned int reserved = 0;
-+
-+      /*
-+       * Pull out the list of software interrupts that are avialable to
-+       * Linux and provide an allocation function for them.  The first
-+       * 24 interrupts of INT0 are software interrupts.
-+       */
-+      irq_soft_avail = 0;
-+      if (processor_interrupts(&irq_soft_avail, NULL) < 0) {
-+              printk(KERN_WARNING "No Soft IRQ(s) available\n");
-+      }
-+      irq_soft_avail &= ((1 << 24) - 1);
-+
-+      /*
-+       * Initialize all of the on-chip interrupt handling
-+       * to use a common set of interrupt functions.
-+       */
-+      for (irq = 0; irq < NR_IRQS; irq++) {
-+              irq_desc[irq].status = IRQ_DISABLED;
-+              irq_desc[irq].action = NULL;
-+              irq_desc[irq].depth = 1;
-+              set_irq_chip(irq, &ubicom32_irq_chip);
-+      }
-+
-+      /*
-+       * The sendirq of a devnode is not registered within Linux but instead
-+       * is used by the software I/O thread.  These interrupts are reserved.
-+       * The recvirq is used by Linux and registered by a device driver, these
-+       * are not reserved.
-+       *
-+       * recvirq(s) that are in the software interrupt range are not supposed
-+       * to be marked as reserved.  We track this while we scan the device
-+       * nodes.
-+       */
-+      p = devtree_find_next(&iter);
-+      while (p) {
-+              unsigned char sendirq, recvirq;
-+              devtree_irq(p, &sendirq, &recvirq);
-+
-+              /*
-+               * If the sendirq is valid, mark that irq as taken by the
-+               * devtree node.
-+               */
-+              if (sendirq < NR_IRQS) {
-+                      ubicom32_reserve_action[sendirq].handler =
-+                              ubicom32_reserve_handler;
-+                      ubicom32_reserve_action[sendirq].name = p->name;
-+                      irq_desc[sendirq].action =
-+                              &ubicom32_reserve_action[sendirq];
-+                      mask |= (1 << sendirq);
-+              }
-+
-+              /*
-+               * Track the relevant recieve IRQ(s)
-+               */
-+              if (recvirq < 24) {
-+                      mask |= (1 << recvirq);
-+              }
-+
-+              /*
-+               * Move to the next node.
-+               */
-+              p = devtree_find_next(&iter);
-+      }
-+
-+      /*
-+       * Remove these bits from the irq_soft_avail list and then use the
-+       * result as the list of pre-reserved IRQ(s).
-+       */
-+      reserved = ~irq_soft_avail & ~mask;
-+      for (irq = 0; irq < 24; irq++) {
-+              if ((reserved & (1 << irq))) {
-+                      ubicom32_reserve_action[irq].handler =
-+                              ubicom32_reserve_handler;
-+                      ubicom32_reserve_action[irq].name = "reserved";
-+                      irq_desc[irq].action = &ubicom32_reserve_action[irq];
-+              }
-+      }
-+
-+      /*
-+       * Initialize the LDSR which is the Ubicom32 programmable
-+       * interrupt controller.
-+       */
-+      ldsr_init();
-+
-+      /*
-+       * The Ubicom trap code needs a 2nd init after IRQ(s) are setup.
-+       */
-+      trap_init_interrupt();
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/ldsr.c
-@@ -0,0 +1,1185 @@
-+/*
-+ * arch/ubicom32/kernel/ldsr.c
-+ *   Ubicom32 architecture Linux Device Services Driver Interface
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *
-+ * NOTES:
-+ *
-+ * The LDSR is a programmable interrupt controller that is written in software.
-+ * It emulates the behavior of an pic by fielding the interrupts, choosing a
-+ * victim thread to take the interrupt and forcing that thread to take a context
-+ * switch to the appropriate interrupt handler.
-+ *
-+ * Because traps are treated as just a special class of interrupts, the LDSR
-+ * also handles the processing of traps.
-+ *
-+ * Because we compile Linux both UP and SMP, we need the LDSR to use
-+ * architectural locking that is not "compiled out" when compiling UP.  For now,
-+ * we use the single atomic bit lock.
-+ */
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
-+#include <linux/profile.h>
-+#include <linux/clocksource.h>
-+#include <linux/types.h>
-+#include <linux/module.h>
-+#include <linux/cpumask.h>
-+#include <linux/bug.h>
-+#include <linux/delay.h>
-+#include <asm/ip5000.h>
-+#include <asm/atomic.h>
-+#include <asm/machdep.h>
-+#include <asm/asm-offsets.h>
-+#include <asm/traps.h>
-+#include <asm/thread.h>
-+#include <asm/range-protect.h>
-+
-+/*
-+ * One can not print from the LDSR so the best we can do is
-+ * check a condition and stall all of the threads.
-+ */
-+
-+// #define DEBUG_LDSR 1
-+#if defined(DEBUG_LDSR)
-+#define DEBUG_ASSERT(cond) \
-+      if (!(cond)) { \
-+              THREAD_STALL; \
-+      }
-+#else
-+#define DEBUG_ASSERT(cond)
-+#endif
-+
-+/*
-+ * Make global so that we can use it in the RFI code in assembly.
-+ */
-+unsigned int ldsr_soft_irq_mask;
-+EXPORT_SYMBOL(ldsr_soft_irq_mask);
-+
-+static unsigned int ldsr_suspend_mask;
-+static unsigned int ldsr_soft_irq;
-+static unsigned int ldsr_stack_space[1024];
-+
-+static struct ldsr_register_bank {
-+      volatile unsigned int enabled0;
-+      volatile unsigned int enabled1;
-+      volatile unsigned int mask0;
-+      volatile unsigned int mask1;
-+      unsigned int total;
-+      unsigned int retry;
-+      unsigned int backout;
-+} ldsr_interrupt;
-+
-+/*
-+ * Which thread/cpu are we?
-+ */
-+static int ldsr_tid = -1;
-+
-+#if defined(CONFIG_IRQSTACKS)
-+/*
-+ * per-CPU IRQ stacks (thread information and stack)
-+ *
-+ * NOTE: Do not use DEFINE_PER_CPU() as it makes it harder
-+ * to find the location of ctx from assembly language.
-+ */
-+union irq_ctx {
-+      struct thread_info      tinfo;
-+      u32                     stack[THREAD_SIZE/sizeof(u32)];
-+};
-+static union irq_ctx *percpu_irq_ctxs[NR_CPUS];
-+
-+/*
-+ *  Storage for the interrupt stack.
-+ */
-+#if !defined(CONFIG_IRQSTACKS_USEOCM)
-+static char percpu_irq_stacks[(NR_CPUS * THREAD_SIZE) + (THREAD_SIZE - 1)];
-+#else
-+/*
-+ *  For OCM, the linker will ensure that space is allocated for the stack
-+ *  see (vmlinux.lds.S)
-+ */
-+static char percpu_irq_stacks[];
-+#endif
-+
-+#endif
-+
-+/*
-+ * Save trap IRQ because we need to un-suspend if it gets set.
-+ */
-+static unsigned int ldsr_trap_irq_mask;
-+static unsigned int ldsr_trap_irq;
-+
-+/*
-+ * ret_from_interrupt_to_kernel
-+ *    Just restore the context and do nothing else.
-+ */
-+asmlinkage void ret_from_interrupt_to_kernel(void)__attribute__((naked));
-+
-+/*
-+ * ret_from_interrupt_to_user
-+ *    Call scheduler if needed. Just restore the context.
-+ */
-+asmlinkage void ret_from_interrupt_to_user(void)__attribute__((naked));
-+
-+#ifdef DEBUG_LDSR
-+u32_t old_sp, old_pc, old_a0, old_a5, old_a3;
-+struct pt_regs copy_regs, *copy_save_area;
-+#endif
-+
-+int __user_mode(unsigned long sp)
-+{
-+
-+      u32_t saved_stack_base = sp & ~(ASM_THREAD_SIZE - 1);
-+#if defined(CONFIG_IRQSTACKS_USEOCM)
-+      if ((union irq_ctx *)saved_stack_base == percpu_irq_ctxs[smp_processor_id()]) {
-+              /*
-+               *  On the interrupt stack.
-+               */
-+              return 0;
-+      }
-+#endif
-+
-+      if (!(u32_t)current) {
-+              return 0;
-+      }
-+      return saved_stack_base != ((u32_t)current->stack);
-+}
-+
-+/*
-+ * ldsr_lock_release()
-+ *    Release the LDSR lock.
-+ */
-+static void ldsr_lock_release(void)
-+{
-+      UBICOM32_UNLOCK(LDSR_LOCK_BIT);
-+}
-+
-+/*
-+ * ldsr_lock_acquire()
-+ *    Acquire the LDSR lock, spin if not available.
-+ */
-+static void ldsr_lock_acquire(void)
-+{
-+      UBICOM32_LOCK(LDSR_LOCK_BIT);
-+}
-+
-+/*
-+ * ldsr_thread_irq_disable()
-+ *    Disable interrupts for the specified thread.
-+ */
-+static void ldsr_thread_irq_disable(unsigned int tid)
-+{
-+      unsigned int mask = (1 << tid);
-+
-+      asm volatile (
-+      "       or.4    scratchpad1, scratchpad1, %0    \n\t"
-+              :
-+              : "d"(mask)
-+              : "cc"
-+      );
-+}
-+
-+/*
-+ * ldsr_thread_get_interrupts()
-+ *    Get the interrupt state for all threads.
-+ */
-+static unsigned long ldsr_thread_get_interrupts(void)
-+{
-+      unsigned long ret = 0;
-+      asm volatile (
-+      "       move.4  %0, scratchpad1 \n\t"
-+              : "=r" (ret)
-+              :
-+      );
-+      return ret;
-+}
-+
-+/*
-+ * ldsr_emulate_and_run()
-+ *    Emulate the instruction and then set the thread to run.
-+ */
-+static void ldsr_emulate_and_run(unsigned int tid)
-+{
-+      unsigned int thread_mask = (1 << tid);
-+      u32_t write_csr = (tid << 15) | (1 << 14);
-+
-+      /*
-+       * Emulate the unaligned access.
-+       */
-+      unaligned_emulate(tid);
-+
-+      /*
-+       * Get the thread back in a running state.
-+       */
-+      asm volatile (
-+      "       setcsr  %0                      \n\t"
-+      "       setcsr_flush 0                  \n\t"
-+      "       move.4  trap_cause, #0          \n\t" /* Clear the trap cause
-+                                                     * register */
-+      "       setcsr  #0                      \n\t"
-+      "       setcsr_flush 0                  \n\t"
-+      "       move.4  mt_dbg_active_set, %1   \n\t" /* Activate thread even if
-+                                                     * in dbg/fault state */
-+      "       move.4  mt_active_set, %1       \n\t" /* Restart target
-+                                                     * thread. */
-+              :
-+              : "r" (write_csr), "d" (thread_mask)
-+              : "cc"
-+      );
-+      thread_enable_mask(thread_mask);
-+}
-+
-+/*
-+ * ldsr_preemptive_context_save()
-+ *    save thread context from another hardware thread.  The other thread must
-+ *    be stalled.
-+ */
-+static inline void ldsr_preemptive_context_save(u32_t thread,
-+                                              struct pt_regs *regs)
-+{
-+      /*
-+       * Save the current state of the specified thread
-+       */
-+      asm volatile (
-+      "       move.4  a3, %0                                  \n\t"
-+
-+              /* set src1 from the target thread */
-+      "       move.4  csr, %1                                 \n\t"
-+      "       setcsr_flush 0                                  \n\t"
-+      "       setcsr_flush 0                                  \n\t"
-+
-+              /* copy state from the other thread */
-+      "       move.4  "D(PT_D0)"(a3), d0                      \n\t"
-+      "       move.4  "D(PT_D1)"(a3), d1                      \n\t"
-+      "       move.4  "D(PT_D2)"(a3), d2                      \n\t"
-+      "       move.4  "D(PT_D3)"(a3), d3                      \n\t"
-+      "       move.4  "D(PT_D4)"(a3), d4                      \n\t"
-+      "       move.4  "D(PT_D5)"(a3), d5                      \n\t"
-+      "       move.4  "D(PT_D6)"(a3), d6                      \n\t"
-+      "       move.4  "D(PT_D7)"(a3), d7                      \n\t"
-+      "       move.4  "D(PT_D8)"(a3), d8                      \n\t"
-+      "       move.4  "D(PT_D9)"(a3), d9                      \n\t"
-+      "       move.4  "D(PT_D10)"(a3), d10                    \n\t"
-+      "       move.4  "D(PT_D11)"(a3), d11                    \n\t"
-+      "       move.4  "D(PT_D12)"(a3), d12                    \n\t"
-+      "       move.4  "D(PT_D13)"(a3), d13                    \n\t"
-+      "       move.4  "D(PT_D14)"(a3), d14                    \n\t"
-+      "       move.4  "D(PT_D15)"(a3), d15                    \n\t"
-+      "       move.4  "D(PT_A0)"(a3), a0                      \n\t"
-+      "       move.4  "D(PT_A1)"(a3), a1                      \n\t"
-+      "       move.4  "D(PT_A2)"(a3), a2                      \n\t"
-+      "       move.4  "D(PT_A3)"(a3), a3                      \n\t"
-+      "       move.4  "D(PT_A4)"(a3), a4                      \n\t"
-+      "       move.4  "D(PT_A5)"(a3), a5                      \n\t"
-+      "       move.4  "D(PT_A6)"(a3), a6                      \n\t"
-+      "       move.4  "D(PT_SP)"(a3), a7                      \n\t"
-+      "       move.4  "D(PT_ACC0HI)"(a3), acc0_hi             \n\t"
-+      "       move.4  "D(PT_ACC0LO)"(a3), acc0_lo             \n\t"
-+      "       move.4  "D(PT_MAC_RC16)"(a3), mac_rc16          \n\t"
-+      "       move.4  "D(PT_ACC1HI)"(a3), acc1_hi             \n\t"
-+      "       move.4  "D(PT_ACC1LO)"(a3), acc1_lo             \n\t"
-+      "       move.4  "D(PT_SOURCE3)"(a3), source3            \n\t"
-+      "       move.4  "D(PT_INST_CNT)"(a3), inst_cnt          \n\t"
-+      "       move.4  "D(PT_CSR)"(a3), csr                    \n\t"
-+      "       move.4  "D(PT_DUMMY_UNUSED)"(a3), #0            \n\t"
-+      "       move.4  "D(PT_INT_MASK0)"(a3), int_mask0        \n\t"
-+      "       move.4  "D(PT_INT_MASK1)"(a3), int_mask1        \n\t"
-+      "       move.4  "D(PT_TRAP_CAUSE)"(a3), trap_cause      \n\t"
-+      "       move.4  "D(PT_PC)"(a3), pc                      \n\t"
-+      "       move.4  "D(PT_PREVIOUS_PC)"(a3), previous_pc    \n\t"
-+              /* disable csr thread select */
-+      "       movei   csr, #0                                 \n\t"
-+      "       setcsr_flush 0                                  \n\t"
-+      :
-+      : "r" (regs->dn), "d" ((thread << 9) | (1 << 8))
-+      : "a3"
-+      );
-+}
-+
-+/*
-+ * ldsr_rotate_threads()
-+ *    Simple round robin algorithm for choosing the next cpu
-+ */
-+static int ldsr_rotate_threads(unsigned long cpus)
-+{
-+      static unsigned char ldsr_bits[8] = {
-+              3, 0, 1, 0, 2, 0, 1, 0
-+      };
-+
-+      static int nextbit;
-+      int thisbit;
-+
-+      /*
-+       * Move the interrupts down so that we consider interrupts from where
-+       * we left off, then take the interrupts we would lose and move them
-+       * to the top half of the interrupts value.
-+       */
-+      cpus = (cpus >> nextbit) | (cpus << ((sizeof(cpus) * 8) - nextbit));
-+
-+      /*
-+       * 50% of the time we won't take this at all and then of the cases where
-+       * we do about 50% of those we only execute once.
-+       */
-+      if (!(cpus & 0xffff)) {
-+              nextbit += 16;
-+              cpus >>= 16;
-+      }
-+
-+      if (!(cpus & 0xff)) {
-+              nextbit += 8;
-+              cpus >>= 8;
-+      }
-+
-+      if (!(cpus & 0xf)) {
-+              nextbit += 4;
-+              cpus >>= 4;
-+      }
-+
-+      nextbit += ldsr_bits[cpus & 0x7];
-+      thisbit = (nextbit & ((sizeof(cpus) * 8) - 1));
-+      nextbit = (thisbit + 1) & ((sizeof(cpus) * 8) - 1);
-+      DEBUG_ASSERT(thisbit < THREAD_ARCHITECTURAL_MAX);
-+      return thisbit;
-+}
-+
-+/*
-+ * ldsr_rotate_interrupts()
-+ *    Get rotating next set bit value.
-+ */
-+static int ldsr_rotate_interrupts(unsigned long long interrupts)
-+{
-+      static unsigned char ldsr_bits[8] = {
-+              3, 0, 1, 0, 2, 0, 1, 0
-+      };
-+
-+      static int nextbit;
-+      int thisbit;
-+
-+      /*
-+       * Move the interrupts down so that we consider interrupts from where
-+       * we left off, then take the interrupts we would lose and move them
-+       * to the top half of the interrupts value.
-+       */
-+      interrupts = (interrupts >> nextbit) |
-+              (interrupts << ((sizeof(interrupts) * 8) - nextbit));
-+
-+      /*
-+       * 50% of the time we won't take this at all and then of the cases where
-+       * we do about 50% of those we only execute once.
-+       */
-+      if (!(interrupts & 0xffffffff)) {
-+              nextbit += 32;
-+              interrupts >>= 32;
-+      }
-+
-+      if (!(interrupts & 0xffff)) {
-+              nextbit += 16;
-+              interrupts >>= 16;
-+      }
-+
-+      if (!(interrupts & 0xff)) {
-+              nextbit += 8;
-+              interrupts >>= 8;
-+      }
-+
-+      if (!(interrupts & 0xf)) {
-+              nextbit += 4;
-+              interrupts >>= 4;
-+      }
-+
-+      nextbit += ldsr_bits[interrupts & 0x7];
-+      thisbit = (nextbit & ((sizeof(interrupts) * 8) - 1));
-+      nextbit = (thisbit + 1) & ((sizeof(interrupts) * 8) - 1);
-+
-+      DEBUG_ASSERT(thisbit < (sizeof(interrupts) * 8));
-+      return thisbit;
-+}
-+
-+/*
-+ * ldsr_backout_or_irq()
-+ *
-+ * One way or the other this interrupt is not being
-+ * processed, make sure that it is reset.  We are
-+ * not going to call irq_end_vector() so unmask the
-+ * interrupt.
-+ */
-+static void ldsr_backout_of_irq(int vector, unsigned long tid_mask)
-+{
-+#if defined(CONFIG_SMP)
-+      if (unlikely(vector == smp_ipi_irq)) {
-+              smp_reset_ipi(tid_mask);
-+      }
-+#endif
-+      ldsr_unmask_vector(vector);
-+      ldsr_interrupt.backout++;
-+}
-+
-+#if defined(CONFIG_IRQSTACKS)
-+/*
-+ * ldsr_choose_savearea_and_returnvec()
-+ *    Test our current state (user, kernel, interrupt) and set things up.
-+ *
-+ * This version of the function uses 3 stacks and nests interrupts
-+ * on the interrupt stack.
-+ */
-+static struct pt_regs *ldsr_choose_savearea_and_returnvec(thread_t tid, u32_t linux_sp, u32_t *pvec)
-+{
-+      struct pt_regs *save_area;
-+      u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1);
-+      struct thread_info * ti= (struct thread_info *)sw_ksp[tid];
-+
-+#if defined(CONFIG_SMP)
-+      union irq_ctx *icp = percpu_irq_ctxs[tid];
-+#else
-+      union irq_ctx *icp = percpu_irq_ctxs[0];
-+#endif
-+
-+      if (masked_linux_sp == (u32_t)icp) {
-+              /*
-+               * Fault/Interrupt occurred while on the interrupt stack.
-+               */
-+              save_area = (struct pt_regs *)((char *)linux_sp - sizeof(struct pt_regs) - 8);
-+              *pvec = (u32_t)(&ret_from_interrupt_to_kernel);
-+      } else {
-+              /*
-+               *  Fault/Interrupt occurred while on user/kernel stack.  This is a new
-+               *  first use of the interrupt stack.
-+               */
-+              save_area = (struct pt_regs *) ((char *)icp + sizeof(icp->stack) - sizeof(struct pt_regs) - 8);
-+              if (masked_linux_sp == (u32_t)ti) {
-+                      *pvec  = (u32_t)(&ret_from_interrupt_to_kernel);
-+              } else {
-+                      *pvec  = (u32_t)(&ret_from_interrupt_to_user);
-+              }
-+
-+              /*
-+               * Because the softirq code will execute on the "interrupt" stack, we
-+               * need to maintain the knowledge of what "task" was executing on the
-+               * cpu.  This is done by copying the thread_info->task from the cpu
-+               * we are about to context switch into the interrupt contexts thread_info
-+               * structure.
-+               */
-+              icp->tinfo.task = ti->task;
-+              icp->tinfo.preempt_count =
-+                              (icp->tinfo.preempt_count & ~SOFTIRQ_MASK) |
-+                              (ti->preempt_count & SOFTIRQ_MASK);
-+              icp->tinfo.interrupt_nesting = 0;
-+      }
-+      save_area->nesting_level = icp->tinfo.interrupt_nesting;
-+      return save_area;
-+}
-+
-+#else
-+/*
-+ * ldsr_choose_savearea_and_returnvec()
-+ *    Test our current state (user, kernel, interrupt) and set things up.
-+ *
-+ * The version of the function uses just the user & kernel stack and
-+ * nests interrupts on the existing kernel stack.
-+ */
-+static struct pt_regs *ldsr_choose_savearea_and_returnvec(thread_t tid, u32_t linux_sp, u32_t *pvec)
-+{
-+      struct pt_regs *save_area;
-+      u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1);
-+      struct thread_info *ti = (struct thread_info *)sw_ksp[tid];
-+
-+      if (masked_linux_sp == (u32_t)ti) {
-+              /*
-+               * Fault/Interrupt occurred while on the kernel stack.
-+               */
-+              save_area = (struct pt_regs *)((char *)linux_sp - sizeof(struct pt_regs) - 8);
-+              *pvec = (u32_t) (&ret_from_interrupt_to_kernel);
-+      } else {
-+              /*
-+               *  Fault/Interrupt occurred while on user stack.
-+               */
-+              ti->interrupt_nesting = 0;
-+              save_area = (struct pt_regs *)((u32_t)ti + THREAD_SIZE - sizeof(struct pt_regs) - 8);
-+              *pvec  = (u32_t) (&ret_from_interrupt_to_user);
-+      }
-+      save_area->nesting_level = ti->interrupt_nesting;
-+      return save_area;
-+}
-+#endif
-+
-+/*
-+ * ldsr_ctxsw_thread()
-+ *    Context switch a mainline thread to execute do_IRQ() for the specified
-+ *    vector.
-+ */
-+static void ldsr_ctxsw_thread(int vector, thread_t tid)
-+{
-+      u32_t linux_sp;
-+      u32_t return_vector;
-+      struct pt_regs *save_area, *regs;
-+      u32_t thread_mask = (1 << tid);
-+      u32_t read_csr = ((tid << 9) | (1 << 8));
-+      u32_t write_csr = (tid << 15) | (1 << 14);
-+      u32_t interrupt_vector = (u32_t)(&do_IRQ);
-+
-+      unsigned int frame_type = UBICOM32_FRAME_TYPE_INTERRUPT;
-+
-+
-+      DEBUG_ASSERT(!thread_is_enabled(tid));
-+
-+      /*
-+       * Acquire the necessary global and per thread locks for tid.
-+       * As a side effect, we ensure that the thread has not trapped
-+       * and return true if it has.
-+       */
-+      if (unlikely(thread_is_trapped(tid))) {
-+              /*
-+               * Read the trap cause, the sp and clear the MT_TRAP bits.
-+               */
-+              unsigned int cause;
-+              asm volatile (
-+              "       setcsr  %3              \n\t"
-+              "       setcsr_flush 0          \n\t"
-+              "       setcsr_flush 0          \n\t"
-+              "       move.4  %0, TRAP_CAUSE  \n\t"
-+              "       move.4  %1, SP          \n\t"
-+              "       setcsr  #0              \n\t"
-+              "       setcsr_flush 0          \n\t"
-+              "       move.4  MT_BREAK_CLR, %2\n\t"
-+              "       move.4  MT_TRAP_CLR, %2 \n\t"
-+                      : "=&r" (cause), "=&r" (linux_sp)
-+                      : "r" (thread_mask), "m" (read_csr)
-+              );
-+
-+              ldsr_backout_of_irq(vector, (1 << tid));
-+
-+#if !defined(CONFIG_UNALIGNED_ACCESS_DISABLED)
-+              /*
-+               * See if the unaligned trap handler can deal with this.
-+               * If so, emulate the instruction and then just restart
-+               * the thread.
-+               */
-+              if (unaligned_only(cause)) {
-+#if defined(CONFIG_UNALIGNED_ACCESS_USERSPACE_ONLY)
-+                      /*
-+                       * Check if this is a kernel stack if so we will not
-+                       * handle the trap
-+                       */
-+                      u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1);
-+                      if ((masked_linux_sp != (u32_t)sw_ksp[tid]) &&
-+                          unaligned_only(cause)) {
-+                              ldsr_emulate_and_run(tid);
-+                              return;
-+                      }
-+#else
-+                      ldsr_emulate_and_run(tid);
-+                      return;
-+#endif
-+
-+              }
-+#endif
-+
-+              interrupt_vector = (u32_t)(&trap_handler);
-+              frame_type = UBICOM32_FRAME_TYPE_TRAP;
-+      } else {
-+              /*
-+               * Read the target thread's SP
-+               */
-+              asm volatile (
-+              "       setcsr  %1              \n\t"
-+              "       setcsr_flush 0          \n\t"
-+              "       setcsr_flush 0          \n\t"
-+              "       move.4  %0, SP          \n\t"
-+              "       setcsr  #0              \n\t"
-+              "       setcsr_flush 0          \n\t"
-+                      : "=m" (linux_sp)
-+                      : "m" (read_csr)
-+              );
-+      }
-+
-+      /*
-+       * We are delivering an interrupt, count it.
-+       */
-+      ldsr_interrupt.total++;
-+
-+      /*
-+       * At this point, we will definitely force this thread to
-+       * a new context, show its interrupts as disabled.
-+       */
-+      ldsr_thread_irq_disable(tid);
-+
-+      /*
-+       * Test our current state (user, kernel, interrupt).  Save the
-+       * appropriate data and setup for the return.
-+       */
-+      save_area = ldsr_choose_savearea_and_returnvec(tid, linux_sp, &return_vector);
-+
-+      /*
-+       *  The pt_regs (save_area) contains the type of thread that we are dealing
-+       *  with (KERNEL/NORMAL) and is copied into each pt_regs area.  We get this
-+       *  from the current tasks kernel pt_regs area that always exists at the
-+       *  top of the kernel stack.
-+       */
-+      regs = (struct pt_regs *)((u32_t)sw_ksp[tid] + THREAD_SIZE - sizeof(struct pt_regs) - 8);
-+      save_area->thread_type = regs->thread_type;
-+
-+      /*
-+       * Preserve the context of the Linux thread.
-+       */
-+      ldsr_preemptive_context_save(tid, save_area);
-+
-+      /*
-+       * Load the fram_type into the save_area.
-+       */
-+      save_area->frame_type = frame_type;
-+
-+#ifdef CONFIG_STOP_ON_TRAP
-+      /*
-+       * Before we get backtrace and showing stacks working well, it sometimes
-+       * helps to enter the debugger when a trap occurs before we change the
-+       * thread to handle the fault.  This optional code causes all threads to
-+       * stop on every trap frame.  One assumes that GDB connected via the
-+       * mailbox interface will be used to recover from this state.
-+       */
-+      if (frame_type == UBICOM32_FRAME_TYPE_TRAP) {
-+              THREAD_STALL;
-+      }
-+#endif
-+
-+#ifdef DEBUG_LDSR
-+      copy_regs = *save_area;
-+      copy_save_area = save_area;
-+
-+      old_a0 = save_area->an[0];
-+      old_a3 = save_area->an[3];
-+      old_sp = save_area->an[7];
-+      old_a5 = save_area->an[5];
-+      old_pc = save_area->pc;
-+#endif
-+
-+      /*
-+       * Now we have to switch the kernel thread to run do_IRQ function.
-+       *      Set pc to do_IRQ
-+       *      Set d0 to vector
-+       *      Set d1 to save_area.
-+       *      Set a5 to the proper return vector.
-+       */
-+      asm volatile (
-+      "       setcsr  %0                      \n\t"
-+      "       setcsr_flush 0                  \n\t"
-+      "       move.4  d0, %5                  \n\t" /* d0 = 0 vector # */
-+      "       move.4  d1, %1                  \n\t" /* d1 = save_area */
-+      "       move.4  sp, %1                  \n\t" /* sp = save_area */
-+      "       move.4  a5, %2                  \n\t" /* a5 = return_vector */
-+      "       move.4  pc, %3                  \n\t" /* pc = do_IRQ routine. */
-+      "       move.4  trap_cause, #0          \n\t" /* Clear the trap cause
-+                                                     * register */
-+      "       setcsr  #0                      \n\t"
-+      "       setcsr_flush 0                  \n\t"
-+      "       enable_kernel_ranges %4         \n\t"
-+      "       move.4  mt_dbg_active_set, %4   \n\t" /* Activate thread even if
-+                                                     * in dbg/fault state */
-+      "       move.4  mt_active_set, %4       \n\t" /* Restart target
-+                                                     * thread. */
-+              :
-+              : "r" (write_csr), "r" (save_area),
-+                "r" (return_vector), "r" (interrupt_vector),
-+                "d" (thread_mask), "r" (vector)
-+              : "cc"
-+      );
-+      thread_enable_mask(thread_mask);
-+}
-+
-+/*
-+ * ldsr_deliver_interrupt()
-+ *    Deliver the interrupt to one of the threads or all of the threads.
-+ */
-+static void ldsr_deliver_interrupt(int vector,
-+                                 unsigned long deliver_to,
-+                                 int all)
-+{
-+      unsigned long disabled_threads;
-+      unsigned long possible_threads;
-+      unsigned long trapped_threads;
-+      unsigned long global_locks;
-+
-+      /*
-+       * Disable all of the threads that we might want to send
-+       * this interrupt to.
-+       */
-+retry:
-+      DEBUG_ASSERT(deliver_to);
-+      thread_disable_mask(deliver_to);
-+
-+      /*
-+       * If any threads are in the trap state, we have to service the
-+       * trap for those threads first.
-+       */
-+      asm volatile (
-+              "move.4 %0, MT_TRAP             \n\t"
-+              : "=r" (trapped_threads)
-+              :
-+      );
-+
-+      trapped_threads &= deliver_to;
-+      if (unlikely(trapped_threads)) {
-+              /*
-+               * all traps will be handled, so clear the trap bit before restarting any threads
-+               */
-+              ubicom32_clear_interrupt(ldsr_trap_irq);
-+
-+              /*
-+               * Let the remaining untrapped threads, continue.
-+               */
-+              deliver_to &= ~trapped_threads;
-+              if (deliver_to) {
-+                      thread_enable_mask(deliver_to);
-+              }
-+
-+              /*
-+               * For the trapped threads force them to handle
-+               * a trap.
-+               */
-+              while (trapped_threads) {
-+                      unsigned long which = ffz(~trapped_threads);
-+                      trapped_threads &= ~(1 << which);
-+                      ldsr_ctxsw_thread(vector, which);
-+              }
-+              return;
-+      }
-+
-+      /*
-+       * Can we deliver an interrupt to any of the threads?
-+       */
-+      disabled_threads = ldsr_thread_get_interrupts();
-+      possible_threads = deliver_to & ~disabled_threads;
-+      if (unlikely(!possible_threads)) {
-+#if defined(CONFIG_SMP)
-+              /*
-+               * In the SMP case, we can not wait because 1 cpu might be
-+               * sending an IPI to another cpu which is currently blocked.
-+               * The only way to ensure IPI delivery is to backout and
-+               * keep trying.  For SMP, we don't sleep until the interrupts
-+               * are delivered.
-+               */
-+              thread_enable_mask(deliver_to);
-+              ldsr_backout_of_irq(vector, deliver_to);
-+              return;
-+#else
-+              /*
-+               * In the UP case, we have nothing to do so we should wait.
-+               *
-+               * Since the INT_MASK0 and INT_MASK1 are "re-loaded" before we
-+               * suspend in the outer loop, we do not need to save them here.
-+               *
-+               * We test that we were awakened for our specific interrupts
-+               * because the ldsr mask/unmask operations will force the ldsr
-+               * awake even if the interrupt on the mainline thread is not
-+               * completed.
-+               */
-+              unsigned int scratch = 0;
-+              thread_enable_mask(deliver_to);
-+              asm volatile (
-+              "       move.4  INT_MASK0, %1           \n\t"
-+              "       move.4  INT_MASK1, #0           \n\t"
-+
-+              "1:     suspend                         \n\t"
-+              "       move.4  %0, INT_STAT0           \n\t"
-+              "       and.4   %0, %0, %1              \n\t"
-+              "       jmpeq.f 1b                      \n\t"
-+
-+              "       move.4  INT_CLR0, %2            \n\t"
-+                      : "+r" (scratch)
-+                      : "d" (ldsr_suspend_mask), "r" (ldsr_soft_irq_mask)
-+                      : "cc"
-+              );
-+
-+              /*
-+               * This delay is sized to coincide with the time it takes a
-+               * thread to complete the exit (see return_from_interrupt).
-+               */
-+              ldsr_interrupt.retry++;
-+              __delay(10);
-+              goto retry;
-+#endif
-+      }
-+
-+      /*
-+       * If any of the global locks are held, we can not deliver any
-+       * interrupts, we spin delay(10) and then try again.  If our
-+       * spinning becomes a bottle neck, we will need to suspend but for
-+       * now lets just spin.
-+       */
-+      asm volatile (
-+              "move.4 %0, scratchpad1         \n\t"
-+              : "=r" (global_locks)
-+              :
-+      );
-+      if (unlikely(global_locks & 0xffff0000)) {
-+              thread_enable_mask(deliver_to);
-+
-+              /*
-+               * This delay is sized to coincide with the average time it
-+               * takes a thread to release a global lock.
-+               */
-+              ldsr_interrupt.retry++;
-+              __delay(10);
-+              goto retry;
-+      }
-+
-+      /*
-+       * Deliver to one cpu.
-+       */
-+      if (!all) {
-+              /*
-+               * Find our victim and then enable everyone else.
-+               */
-+              unsigned long victim = ldsr_rotate_threads(possible_threads);
-+              DEBUG_ASSERT((deliver_to & (1 << victim)));
-+              DEBUG_ASSERT((possible_threads & (1 << victim)));
-+
-+              deliver_to &= ~(1 << victim);
-+              if (deliver_to) {
-+                      thread_enable_mask(deliver_to);
-+              }
-+              ldsr_ctxsw_thread(vector, victim);
-+              return;
-+      }
-+
-+      /*
-+       * If we can't deliver to some threads, wake them
-+       * back up and reset things to deliver to them.
-+       */
-+      deliver_to &= ~possible_threads;
-+      if (unlikely(deliver_to)) {
-+              thread_enable_mask(deliver_to);
-+              ldsr_backout_of_irq(vector, deliver_to);
-+      }
-+
-+      /*
-+       * Deliver to all possible threads(s).
-+       */
-+      while (possible_threads) {
-+              unsigned long victim = ffz(~possible_threads);
-+              possible_threads &= ~(1 << victim);
-+              ldsr_ctxsw_thread(vector, victim);
-+      }
-+}
-+
-+/*
-+ * ldsr_thread()
-+ *    This thread acts as the interrupt controller for Linux.
-+ */
-+static void ldsr_thread(void *arg)
-+{
-+      int stat0;
-+      int stat1;
-+      int interrupt0;
-+      int interrupt1;
-+      long long interrupts;
-+      unsigned long cpus;
-+
-+#if !defined(CONFIG_SMP)
-+      /*
-+       * In a non-smp configuration, we can not use the cpu(s) arrays because
-+       * there is not a 1-1 correspondence between cpus(s) and our threads.
-+       * Thus we must get a local idea of the mainline threads and use the
-+       * one and only 1 set as the victim.  We do this once before the ldsr
-+       * loop.
-+       *
-+       * In the SMP case, we will use the cpu(s) map to determine which cpu(s)
-+       * are valid to send interrupts to.
-+       */
-+      int victim = 0;
-+      unsigned int mainline = thread_get_mainline();
-+      if (mainline == 0) {
-+              panic("no mainline Linux threads to interrupt");
-+              return;
-+      }
-+      victim = ffz(~mainline);
-+      cpus = (1 << victim);
-+#endif
-+
-+      while (1) {
-+              /*
-+               * If one changes this code not to reload the INT_MASK(s), you
-+               * need to know that code in the lock waiting above does not
-+               * reset the MASK registers back; so that code will need to be
-+               * changed.
-+               */
-+              ldsr_lock_acquire();
-+              asm volatile (
-+              "       move.4 INT_MASK0, %0    \n\t"
-+              "       move.4 INT_MASK1, %1    \n\t"
-+                      :
-+                      : "U4" (ldsr_interrupt.mask0), "U4" (ldsr_interrupt.mask1)
-+              );
-+              ldsr_lock_release();
-+              thread_suspend();
-+
-+              /*
-+               * Read the interrupt status registers
-+               */
-+              asm volatile (
-+                      "move.4 %0, INT_STAT0   \n\t"
-+                      "move.4 %1, INT_STAT1   \n\t"
-+                      : "=r" (stat0), "=r" (stat1)
-+                      :
-+              );
-+
-+              /*
-+               * We only care about interrupts that we have been told to care
-+               * about.  The interrupt must be enabled, unmasked, and have
-+               * occurred in the hardware.
-+               */
-+              ldsr_lock_acquire();
-+              interrupt0 = ldsr_interrupt.enabled0 &
-+                      ldsr_interrupt.mask0 & stat0;
-+              interrupt1 = ldsr_interrupt.enabled1 &
-+                      ldsr_interrupt.mask1 & stat1;
-+              ldsr_lock_release();
-+
-+              /*
-+               * For each interrupt in the "snapshot" we will mask the
-+               * interrupt handle the interrupt (typically calling do_IRQ()).
-+               *
-+               * The interrupt is unmasked by desc->chip->end() function in
-+               * the per chip generic interrupt handling code
-+               * (arch/ubicom32/kernel/irq.c).8
-+               */
-+              interrupts = ((unsigned long long)interrupt1 << 32) |
-+                      interrupt0;
-+              while (interrupts) {
-+                      int all = 0;
-+                      int vector = ldsr_rotate_interrupts(interrupts);
-+                      interrupts &= ~((unsigned long long)1 << vector);
-+
-+                      /*
-+                       * Now mask off this vector so that the LDSR ignores
-+                       * it until it is acknowledged.
-+                       */
-+                      ldsr_mask_vector(vector);
-+#if !defined(CONFIG_SMP)
-+                      ldsr_deliver_interrupt(vector, cpus, all);
-+#else
-+                      cpus = smp_get_affinity(vector, &all);
-+                      if (!cpus) {
-+                              /*
-+                               * No CPU to deliver to so just leave
-+                               * the interrupt unmasked and increase
-+                               * the backout count.  We will eventually
-+                               * return and deliver it again.
-+                               */
-+                              ldsr_unmask_vector(vector);
-+                              ldsr_interrupt.backout++;
-+                              continue;
-+                      }
-+                      ldsr_deliver_interrupt(vector, cpus, all);
-+#endif
-+              }
-+      }
-+
-+      /* NOTREACHED */
-+}
-+
-+/*
-+ * ldsr_mask_vector()
-+ *    Temporarily mask the interrupt vector, turn off the bit in the mask
-+ *    register.
-+ */
-+void ldsr_mask_vector(unsigned int vector)
-+{
-+      unsigned int mask;
-+      if (vector < 32) {
-+              mask = ~(1 << vector);
-+              ldsr_lock_acquire();
-+              ldsr_interrupt.mask0 &= mask;
-+              ldsr_lock_release();
-+              thread_resume(ldsr_tid);
-+              return;
-+      }
-+
-+      mask = ~(1 << (vector - 32));
-+      ldsr_lock_acquire();
-+      ldsr_interrupt.mask1 &= mask;
-+      ldsr_lock_release();
-+      thread_resume(ldsr_tid);
-+}
-+
-+/*
-+ * ldsr_unmask_vector()
-+ *    Unmask the interrupt vector so that it can be used, turn on the bit in
-+ *    the mask register.
-+ *
-+ * Because it is legal for the interrupt path to disable an interrupt,
-+ * the unmasking code must ensure that disabled interrupts are not
-+ * unmasked.
-+ */
-+void ldsr_unmask_vector(unsigned int vector)
-+{
-+      unsigned int mask;
-+      if (vector < 32) {
-+              mask = (1 << vector);
-+              ldsr_lock_acquire();
-+              ldsr_interrupt.mask0 |= (mask & ldsr_interrupt.enabled0);
-+              ldsr_lock_release();
-+              thread_resume(ldsr_tid);
-+              return;
-+      }
-+
-+      mask = (1 << (vector - 32));
-+      ldsr_lock_acquire();
-+      ldsr_interrupt.mask1 |= (mask & ldsr_interrupt.enabled1);
-+      ldsr_lock_release();
-+      thread_resume(ldsr_tid);
-+}
-+
-+/*
-+ * ldsr_enable_vector()
-+ *    The LDSR implements an interrupt controller and has a local (to the
-+ *    LDSR) copy of its interrupt mask.
-+ */
-+void ldsr_enable_vector(unsigned int vector)
-+{
-+      unsigned int mask;
-+      if (vector < 32) {
-+              mask = (1 << vector);
-+              ldsr_lock_acquire();
-+              ldsr_interrupt.enabled0 |= mask;
-+              ldsr_interrupt.mask0 |= mask;
-+              ldsr_lock_release();
-+              thread_resume(ldsr_tid);
-+              return;
-+      }
-+
-+      mask = (1 << (vector - 32));
-+      ldsr_lock_acquire();
-+      ldsr_interrupt.enabled1 |= mask;
-+      ldsr_interrupt.mask1 |= mask;
-+      ldsr_lock_release();
-+      thread_resume(ldsr_tid);
-+}
-+
-+/*
-+ * ldsr_disable_vector()
-+ *    The LDSR implements an interrupt controller and has a local (to the
-+ *    LDSR) copy of its interrupt mask.
-+ */
-+void ldsr_disable_vector(unsigned int vector)
-+{
-+      unsigned int mask;
-+
-+      if (vector < 32) {
-+              mask = ~(1 << vector);
-+              ldsr_lock_acquire();
-+              ldsr_interrupt.enabled0 &= mask;
-+              ldsr_interrupt.mask0 &= mask;
-+              ldsr_lock_release();
-+              thread_resume(ldsr_tid);
-+              return;
-+      }
-+
-+      mask = ~(1 << (vector - 32));
-+      ldsr_lock_acquire();
-+      ldsr_interrupt.enabled1 &= mask;
-+      ldsr_interrupt.mask1 &= mask;
-+      ldsr_lock_release();
-+      thread_resume(ldsr_tid);
-+}
-+
-+/*
-+ * ldsr_get_threadid()
-+ *    Return the threadid of the LDSR thread.
-+ */
-+thread_t ldsr_get_threadid(void)
-+{
-+      return ldsr_tid;
-+}
-+
-+/*
-+ * ldsr_set_trap_irq()
-+ *    Save away the trap Soft IRQ
-+ *
-+ * See the per thread lock suspend code above for an explination.
-+ */
-+void ldsr_set_trap_irq(unsigned int irq)
-+{
-+      ldsr_trap_irq = irq;
-+      ldsr_trap_irq_mask = (1 << irq);
-+      ldsr_suspend_mask |= ldsr_trap_irq_mask;
-+}
-+
-+/*
-+ * ldsr_init()
-+ *    Initialize the LDSR (Interrupt Controller)
-+ */
-+void ldsr_init(void)
-+{
-+#if defined(CONFIG_IRQSTACKS)
-+      int i;
-+      union irq_ctx *icp;
-+#endif
-+
-+      void *stack_high = (void *)ldsr_stack_space;
-+      stack_high += sizeof(ldsr_stack_space);
-+      stack_high -= 8;
-+
-+
-+      /*
-+       * Obtain a soft IRQ to use
-+       */
-+      if (irq_soft_alloc(&ldsr_soft_irq) < 0) {
-+              panic("no software IRQ is available\n");
-+              return;
-+      }
-+      ldsr_soft_irq_mask |= (1 << ldsr_soft_irq);
-+      ldsr_suspend_mask |= ldsr_soft_irq_mask;
-+
-+      /*
-+       * Now allocate and start the LDSR thread.
-+       */
-+      ldsr_tid = thread_alloc();
-+      if (ldsr_tid < 0) {
-+              panic("no thread available to run LDSR");
-+              return;
-+      }
-+
-+#if defined(CONFIG_IRQSTACKS)
-+      /*
-+       * Initialize the per-cpu irq thread_info structure that
-+       * is at the top of each per-cpu irq stack.
-+       */
-+      icp = (union irq_ctx *)
-+              (((unsigned long)percpu_irq_stacks + (THREAD_SIZE - 1)) & ~(THREAD_SIZE - 1));
-+      for (i = 0; i < NR_CPUS; i++) {
-+              struct thread_info *ti = &(icp->tinfo);
-+              ti->task = NULL;
-+              ti->exec_domain = NULL;
-+              ti->cpu = i;
-+              ti->preempt_count = 0;
-+              ti->interrupt_nesting = 0;
-+              percpu_irq_ctxs[i] = icp++;
-+      }
-+#endif
-+      thread_start(ldsr_tid, ldsr_thread, NULL,
-+                   stack_high, THREAD_TYPE_NORMAL);
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/Makefile
-@@ -0,0 +1,64 @@
-+#
-+# arch/ubicom32/kernel/Makefile
-+#     Main Makefile for the Ubicom32 arch directory.
-+#
-+# (C) Copyright 2009, Ubicom, Inc.
-+#
-+# This file is part of the Ubicom32 Linux Kernel Port.
-+#
-+# The Ubicom32 Linux Kernel Port 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.
-+#
-+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+# see <http://www.gnu.org/licenses/>.
-+#
-+# Ubicom32 implementation derived from (with many thanks):
-+#   arch/m68knommu
-+#   arch/blackfin
-+#   arch/parisc
-+#
-+
-+extra-y := head.o vmlinux.lds
-+
-+obj-y += \
-+      devtree.o \
-+      dma.o \
-+      flat.o \
-+      init_task.o \
-+      irq.o \
-+      ldsr.o \
-+      os_node.o \
-+      process.o \
-+      processor.o \
-+      ptrace.o \
-+      setup.o \
-+      signal.o \
-+      stacktrace.o \
-+      sys_ubicom32.o \
-+      syscalltable.o \
-+      thread.o \
-+      time.o \
-+      traps.o \
-+      ubicom32_context_switch.o \
-+      ubicom32_ksyms.o \
-+      ubicom32_syscall.o \
-+      unaligned_trap.o
-+
-+obj-$(CONFIG_MODULES)                         += module.o
-+obj-$(CONFIG_COMEMPCI)                                += comempci.o
-+obj-$(CONFIG_SMP)                             += smp.o topology.o
-+obj-$(CONFIG_ACCESS_OK_CHECKS_ENABLED)                += uaccess.o
-+obj-$(CONFIG_GENERIC_CLOCKEVENTS)             += timer_device.o
-+obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)   += timer_broadcast.o
-+
-+ifndef CONFIG_GENERIC_CLOCKEVENTS
-+obj-y                 += timer_tick.o
-+endif
---- /dev/null
-+++ b/arch/ubicom32/kernel/module.c
-@@ -0,0 +1,463 @@
-+/*
-+ * arch/ubicom32/kernel/module.c
-+ *   Ubicom32 architecture loadable module support.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/moduleloader.h>
-+#include <linux/bug.h>
-+#include <linux/elf.h>
-+#include <linux/vmalloc.h>
-+#include <linux/fs.h>
-+#include <linux/string.h>
-+#include <linux/kernel.h>
-+#include <asm/ocm-alloc.h>
-+
-+#if 0
-+#define DEBUGP printk
-+#else
-+#define DEBUGP(fmt...)
-+#endif
-+
-+static void _module_free_ocm(struct module *mod)
-+{
-+      printk(KERN_INFO "module arch cleanup %s: OCM instruction memory free "
-+             " of %d @%p\n", mod->name, mod->arch.ocm_inst_size,
-+             mod->arch.ocm_inst);
-+
-+      if (mod->arch.ocm_inst) {
-+              ocm_inst_free(mod->arch.ocm_inst);
-+              mod->arch.ocm_inst = 0;
-+              mod->arch.ocm_inst_size = 0;
-+      }
-+}
-+
-+void *module_alloc(unsigned long size)
-+{
-+      if (size == 0)
-+              return NULL;
-+      return vmalloc(size);
-+}
-+
-+
-+/* Free memory returned from module_alloc */
-+void module_free(struct module *mod, void *module_region)
-+{
-+      vfree(module_region);
-+      /* FIXME: If module_region == mod->init_region, trim exception
-+         table entries. */
-+
-+      /*
-+       * This is expected to be final module free, use this to prune the
-+       * ocm
-+       */
-+      if (module_region && module_region == mod->module_core)
-+              _module_free_ocm(mod);
-+
-+}
-+
-+/*
-+ * module_frob_arch_sections()
-+ *    Called from kernel/module.c allowing arch specific handling of
-+ *    sections/headers.
-+ */
-+int module_frob_arch_sections(Elf_Ehdr *hdr,
-+                            Elf_Shdr *sechdrs,
-+                            char *secstrings,
-+                            struct module *mod)
-+{
-+      Elf_Shdr *s, *sechdrs_end;
-+      void *ocm_inst = NULL;
-+      int ocm_inst_size = 0;
-+
-+      /*
-+       * Ubicom32 v3 and v4 are almost binary compatible but not completely.
-+       * To be safe check that the module was compiled with the correct -march
-+       * which is flags.
-+       */
-+#ifdef CONFIG_UBICOM32_V4
-+      if ((hdr->e_flags & 0xFFFF) != EF_UBICOM32_V4) {
-+              printk(KERN_WARNING "Module %s was not compiled for "
-+                     "ubicom32v4, elf_flags:%x,\n",
-+                     mod->name, hdr->e_flags);
-+              return -ENOEXEC;
-+      }
-+#elif defined CONFIG_UBICOM32_V3
-+      if ((hdr->e_flags & 0xFFFF) != EF_UBICOM32_V3) {
-+              printk(KERN_WARNING "Module %s was not compiled for "
-+                     "ubicom32v3, elf_flags:%x\n",
-+                     mod->name, hdr->e_flags);
-+              return -ENOEXEC;
-+      }
-+#else
-+#error Unknown/Unsupported ubicom32 architecture.
-+#endif
-+
-+      /*
-+       * XXX: sechdrs are vmalloced in kernel/module.c
-+       * and would be vfreed just after module is loaded,
-+       * so we hack to keep the only information we needed
-+       * in mod->arch to correctly free L1 I/D sram later.
-+       * NOTE: this breaks the semantic of mod->arch structure.
-+       */
-+      sechdrs_end = sechdrs + hdr->e_shnum;
-+      for (s = sechdrs; s < sechdrs_end; ++s) {
-+              if (strncmp(".ocm_text", secstrings + s->sh_name, 9) == 0)
-+                      ocm_inst_size += s->sh_size;
-+      }
-+
-+      if (!ocm_inst_size)
-+              return 0;
-+
-+      ocm_inst = ocm_inst_alloc(ocm_inst_size, 0 /* internal */);
-+      if (ocm_inst == NULL) {
-+#ifdef CONFIG_OCM_MODULES_FALLBACK_TO_DDR
-+              printk(KERN_WARNING
-+                     "module %s: OCM instruction memory allocation of %d"
-+                     "failed, fallback to DDR\n", mod->name, ocm_inst_size);
-+              return 0;
-+#else
-+              printk(KERN_ERR
-+                     "module %s: OCM instruction memory allocation of %d"
-+                     "failed.\n", mod->name, ocm_inst_size);
-+              return -ENOMEM;
-+#endif
-+      }
-+
-+      mod->arch.ocm_inst = ocm_inst;
-+      mod->arch.ocm_inst_size = ocm_inst_size;
-+
-+      printk(KERN_INFO
-+             "module %s: OCM instruction memory allocation of %d @%p\n",
-+             mod->name, mod->arch.ocm_inst_size, mod->arch.ocm_inst);
-+
-+      for (s = sechdrs; s < sechdrs_end; ++s) {
-+              if (strncmp(".ocm_text", secstrings + s->sh_name, 9) == 0) {
-+                      memcpy(ocm_inst, (void *)s->sh_addr, s->sh_size);
-+                      s->sh_flags &= ~SHF_ALLOC;
-+                      s->sh_addr = (unsigned long)ocm_inst;
-+                      ocm_inst += s->sh_size;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+int apply_relocate(Elf32_Shdr *sechdrs,
-+                 const char *strtab,
-+                 unsigned int symindex,
-+                 unsigned int relsec,
-+                 struct module *me)
-+{
-+      DEBUGP("Invalid Applying relocate section %u to %u\n", relsec,
-+             sechdrs[relsec].sh_info);
-+      return -EINVAL;
-+}
-+
-+int apply_relocate_add(Elf32_Shdr *sechdrs,
-+                     const char *strtab,
-+                     unsigned int symindex,
-+                     unsigned int relsec,
-+                     struct module *me)
-+{
-+      unsigned int i;
-+      Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
-+      Elf32_Sym *sym;
-+      uint32_t *location;
-+      uint32_t insn;
-+
-+      DEBUGP("Applying relocate_add section %u to %u\n", relsec,
-+             sechdrs[relsec].sh_info);
-+      for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
-+              uint32_t v;
-+              const int elf32_rtype = ELF32_R_TYPE(rel[i].r_info);
-+
-+              /* This is where to make the change */
-+              location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
-+                      + rel[i].r_offset;
-+              /* This is the symbol it is referring to.  Note that all
-+                 undefined symbols have been resolved.  */
-+              sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
-+                      + ELF32_R_SYM(rel[i].r_info);
-+
-+              v = rel[i].r_addend + sym->st_value;
-+
-+
-+              switch (elf32_rtype) {
-+              case R_UBICOM32_32:
-+              {
-+                      /*
-+                       * Store the 32 bit relocation as is.
-+                       */
-+                      *location = v;
-+                      break;
-+              }
-+              case R_UBICOM32_HI24:
-+              {
-+                      /*
-+                       * 24 bit relocation that is part of the MOVEAI
-+                       * instruction. The 24 bits come from bits 7 - 30 of the
-+                       * relocation. Theses bits eventually get split into 2
-+                       * fields in the instruction encoding.
-+                       *
-+                       * - Bits 7 - 27 of the relocation are encoded into bits
-+                       * 0 - 20 of the instruction.
-+                       *
-+                       *  - Bits 28 - 30 of the relocation are encoded into
-+                       *  bit 24 - 26 of the instruction.
-+                       */
-+                      uint32_t valid24 = (v >> 7) & 0xffffff;
-+                      insn = *location;
-+
-+                      insn &= ~(0x1fffff | (0x7 << 24));
-+                      insn |= (valid24 & 0x1fffff);
-+                      insn |= ((valid24 & 0xe00000) << 3);
-+                      *location = insn;
-+              }
-+              break;
-+              case R_UBICOM32_LO7_S:
-+              case R_UBICOM32_LO7_2_S:
-+              case R_UBICOM32_LO7_4_S:
-+              {
-+                      /*
-+                       * Bits 0 - 6 of the relocation are encoded into the
-+                       * 7bit unsigned immediate fields of the SOURCE-1 field
-+                       * of the instruction.  The immediate value is left
-+                       * shifted by (0, 1, 2) based on the operand size.
-+                       */
-+                      uint32_t valid7 = v & 0x7f;
-+                      insn = *location;
-+
-+                      if (elf32_rtype == R_UBICOM32_LO7_2_S) {
-+                              valid7 >>= 1;
-+                      } else if (elf32_rtype == R_UBICOM32_LO7_4_S) {
-+                              valid7 >>= 2;
-+                      }
-+
-+                      insn &= ~(0x1f | (0x3 << 8));
-+                      insn |= (valid7 & 0x1f);
-+                      insn |= ((valid7 & 0x60) << 3);
-+                      *location = insn;
-+              }
-+              break;
-+              case R_UBICOM32_LO7_D:
-+              case R_UBICOM32_LO7_2_D:
-+              case R_UBICOM32_LO7_4_D:
-+              {
-+                      /*
-+                       * Bits 0 - 6 of the relocation are encoded into the
-+                       * 7bit unsigned immediate fields of the DESTINATION
-+                       * field of the instruction.  The immediate value is
-+                       * left shifted by (0, 1, 2) based on the operand size.
-+                       */
-+                      uint32_t valid7 = v & 0x7f;
-+                      insn = *location;
-+
-+                      if (elf32_rtype == R_UBICOM32_LO7_2_D) {
-+                              valid7 >>= 1;
-+                      } else if (elf32_rtype == R_UBICOM32_LO7_4_D) {
-+                              valid7 >>= 2;
-+                      }
-+
-+                      insn &= ~((0x1f | (0x3 << 8)) << 16);
-+                      insn |= ((valid7 & 0x1f) << 16);
-+                      insn |= ((valid7 & 0x60) << 19);
-+                      *location = insn;
-+              }
-+              break;
-+              case R_UBICOM32_LO7_CALLI:
-+              case R_UBICOM32_LO16_CALLI:
-+              {
-+                      /*
-+                       * Extract the offset for a CALLI instruction. The
-+                       * offsets can be either 7 bits or 18 bits. Since all
-+                       * instructions in ubicom32 architecture are at work
-+                       * aligned addresses the truncated offset is right
-+                       * shifted by 2 before being encoded in the instruction.
-+                       */
-+                      uint32_t val;
-+                      if (elf32_rtype == R_UBICOM32_LO7_CALLI) {
-+                              val  = v & 0x7f;
-+                      } else {
-+                              val  = v & 0x3ffff;
-+                      }
-+
-+                      val >>= 2;
-+
-+                      insn = *location;
-+
-+                      insn &= ~0x071f071f;
-+                      insn |= (val & 0x1f) << 0;
-+                      val >>= 5;
-+                      insn |= (val & 0x07) << 8;
-+                      val >>= 3;
-+                      insn |= (val & 0x1f) << 16;
-+                      val >>= 5;
-+                      insn |= (val & 0x07) << 24;
-+                      *location = insn;
-+              }
-+              break;
-+              case R_UBICOM32_24_PCREL:
-+              {
-+                      /*
-+                       * Extract 26 bit signed PC relative offset for CALL
-+                       * instructions. Since instruction addresses are word
-+                       * aligned the offset is right shited by 2 before
-+                       * encoding into instruction.
-+                       */
-+                      int32_t val = v - (int32_t)location;
-+
-+                      /*
-+                       * Check that the top 7 bits are all equal to the sign
-+                       * bit (26), i.e all 0's or all 1's.  If they are not then
-+                       * the absolute difference is greater than 25 bits.
-+                       */
-+                      if (((uint32_t)val & 0xFE000000) != 0xFE000000 &&
-+                              ((uint32_t)val & 0xFE000000) != 0x0) {
-+                              /*
-+                               * The relocation is beyond our addressable
-+                               * range with a 26 bit call.
-+                               */
-+                              printk(KERN_ERR "module %s: PC Relative "
-+                                      "relocation out of range: "
-+                                      "%u (%x->%x, %x)\n",
-+                                      me->name, elf32_rtype,
-+                                      v, (uint32_t) location, val);
-+                              return -ENOEXEC;
-+                      }
-+
-+                      val = (val & 0x3ffffff) >> 2;
-+                      insn = *location;
-+                      insn = insn & 0xf8e00000;
-+
-+                      insn |= (val >> 21) << 24;
-+                      insn |= (val & 0x1fffff);
-+                      *location = insn;
-+              }
-+              break;
-+              case R_UBICOM32_LO16:
-+              case R_UBICOM32_HI16:
-+              {
-+                      /*
-+                       * 16 bit immediate value that is encoded into bit 0 -
-+                       * 15 of the instruction.
-+                       */
-+                      uint32_t val;
-+
-+                      if (elf32_rtype == R_UBICOM32_LO16) {
-+                              val  = v & 0xffff;
-+                      } else {
-+                              val  = (v >> 16) & 0xffff;
-+                      }
-+
-+                      insn = *location;
-+                      insn &= 0xffff0000;
-+
-+                      insn |= val;
-+                      *location = insn;
-+              }
-+              break;
-+              case R_UBICOM32_21_PCREL:
-+              {
-+                      /*
-+                       * Extract 23 bit signed PC relative offset for JMP<cc>
-+                       * instructions. Since instruction addresses are word
-+                       * aligned the offset is right shited by 2 before
-+                       * encoding into instruction.
-+                       */
-+                      int32_t val = v - (int32_t)location;
-+
-+                      val = (val & 0x7fffff) >> 2;
-+                      insn = *location;
-+                      insn = insn & 0xffe00000;
-+
-+                      insn |= (val >> 21) << 24;
-+                      insn |= val;
-+                      *location = insn;
-+              }
-+              break;
-+              default:
-+                      BUG();
-+                      printk(KERN_ERR "module %s: Unknown relocation: %u\n",
-+                             me->name, elf32_rtype);
-+                      return -ENOEXEC;
-+              }
-+      }
-+      return 0;
-+}
-+
-+int module_finalize(const Elf_Ehdr *hdr,
-+                  const Elf_Shdr *sechdrs,
-+                  struct module *mod)
-+{
-+      unsigned int i, strindex = 0, symindex = 0;
-+      char *secstrings;
-+      int err;
-+
-+      err = module_bug_finalize(hdr, sechdrs, mod);
-+      if (err)
-+              return err;
-+
-+      if (!mod->arch.ocm_inst) {
-+              /*
-+               * No OCM code, so nothing more to do.
-+               */
-+              return 0;
-+      }
-+
-+      secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
-+
-+      for (i = 1; i < hdr->e_shnum; i++) {
-+              /* Internal symbols and strings. */
-+              if (sechdrs[i].sh_type == SHT_SYMTAB) {
-+                      symindex = i;
-+                      strindex = sechdrs[i].sh_link;
-+              }
-+      }
-+
-+      for (i = 1; i < hdr->e_shnum; i++) {
-+              const char *strtab = (char *)sechdrs[strindex].sh_addr;
-+              unsigned int info = sechdrs[i].sh_info;
-+
-+              /* Not a valid relocation section? */
-+              if (info >= hdr->e_shnum)
-+                      continue;
-+
-+              if ((sechdrs[i].sh_type == SHT_RELA) &&
-+                  (strncmp(".rela.ocm_text",
-+                           secstrings + sechdrs[i].sh_name, 5 + 9) == 0)) {
-+                      err = apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
-+                                               symindex, i, mod);
-+                      if (err)
-+                              return err;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+void module_arch_cleanup(struct module *mod)
-+{
-+      module_bug_cleanup(mod);
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/os_node.c
-@@ -0,0 +1,88 @@
-+/*
-+ * arch/ubicom32/kernel/os_node.c
-+ *   <TODO: Replace with short file description>
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+#include "linux/types.h"
-+#include "linux/linkage.h"
-+#include "linux/uts.h"
-+#include "linux/utsrelease.h"
-+#include "linux/version.h"
-+#include <asm/ocm_size.h>
-+#include <asm/devtree.h>
-+#include <asm/ip5000.h>
-+
-+extern asmlinkage void *_start;
-+
-+/*
-+ * This file provides static information to the boot code allowing it to decide
-+ * if the os is compatible. Thus hopefully enabling the boot code to prevent
-+ * accidentally booting a kernel that has no hope of running.
-+ */
-+struct os_node {
-+      struct devtree_node node;
-+      unsigned long version; /* Always 1 */
-+      unsigned long entry_point;
-+      const char    os_name[32]; /* For diagnostic purposes only */
-+      const char    os_version_str[32];
-+      unsigned long os_version_num;
-+      unsigned long expected_ocm_code_start;/* OS Code */
-+      unsigned long expected_ocm_data_end;  /* OS Data */
-+      unsigned long expected_ram_start;
-+      unsigned long expected_ram_end;
-+      unsigned long arch_version;
-+      unsigned long expected_os_syscall_begin;
-+      unsigned long expected_os_syscall_end;
-+};
-+
-+
-+extern void __os_syscall_begin;
-+extern void __os_syscall_end;
-+/*
-+ * The os_node is only referenced by head.S and should never be modified at
-+ * run-time.
-+ */
-+asmlinkage const struct os_node _os_node = {
-+      .node = {
-+              .next = NULL,
-+              .name = { "OS" },
-+              .magic = 0x10203040,
-+      },
-+      .version = 0x10002,
-+      .entry_point = (unsigned long)&_start,
-+#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE
-+      .expected_ocm_code_start = OCMSTART + APP_OCM_CODE_SIZE,
-+      .expected_ocm_data_end   = OCMEND   - APP_OCM_DATA_SIZE,
-+#else
-+      .expected_ocm_code_start = OCMEND,
-+      .expected_ocm_data_end   = OCMEND,
-+#endif
-+      .os_name = { UTS_SYSNAME },
-+      .os_version_str = { UTS_RELEASE },
-+      .os_version_num = LINUX_VERSION_CODE,
-+      .expected_ram_start = KERNELSTART,
-+      .expected_ram_end = SDRAMSTART + CONFIG_MIN_RAMSIZE,
-+      .arch_version = UBICOM32_ARCH_VERSION,
-+      .expected_os_syscall_begin = (unsigned long)&__os_syscall_begin,
-+      .expected_os_syscall_end = (unsigned long)&__os_syscall_end,
-+
-+
-+};
---- /dev/null
-+++ b/arch/ubicom32/kernel/process.c
-@@ -0,0 +1,634 @@
-+/*
-+ * arch/ubicom32/kernel/process.c
-+ *   Ubicom32 architecture-dependent process handling.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 1995  Hamish Macdonald
-+ *
-+ * 68060 fixes by Jesper Skov
-+ *
-+ * uClinux changes
-+ * Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com>
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+/*
-+ * This file handles the architecture-dependent parts of process handling..
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/sched.h>
-+#include <linux/kernel.h>
-+#include <linux/mm.h>
-+#include <linux/smp.h>
-+#include <linux/smp_lock.h>
-+#include <linux/stddef.h>
-+#include <linux/unistd.h>
-+#include <linux/ptrace.h>
-+#include <linux/slab.h>
-+#include <linux/user.h>
-+#include <linux/a.out.h>
-+#include <linux/interrupt.h>
-+#include <linux/reboot.h>
-+#include <linux/fs.h>
-+#include <linux/pm.h>
-+
-+#include <linux/uaccess.h>
-+#include <asm/system.h>
-+#include <asm/traps.h>
-+#include <asm/machdep.h>
-+#include <asm/setup.h>
-+#include <asm/pgtable.h>
-+#include <asm/ip5000.h>
-+#include <asm/range-protect.h>
-+
-+#define DUMP_RANGE_REGISTER(REG, IDX) asm volatile ( \
-+        "       move.4          %0, "REG"_RANGE"IDX"_EN \n\t" \
-+        "       move.4          %1, "REG"_RANGE"IDX"_LO \n\t" \
-+        "       move.4          %2, "REG"_RANGE"IDX"_HI \n\t" \
-+                : "=d"(en), "=d"(lo), "=d"(hi) \
-+        ); \
-+        printk(KERN_NOTICE REG"Range"IDX": en:%08x, range: %08x-%08x\n", \
-+                (unsigned int)en, \
-+                (unsigned int)lo, \
-+                (unsigned int)hi)
-+
-+asmlinkage void ret_from_fork(void);
-+
-+void (*pm_power_off)(void) = machine_power_off;
-+EXPORT_SYMBOL(pm_power_off);
-+
-+/* machine-dependent / hardware-specific power functions */
-+void (*mach_reset)(void);
-+void (*mach_halt)(void);
-+void (*mach_power_off)(void);
-+
-+/*
-+ * cpu_idle()
-+ *    The idle thread.
-+ *
-+ * Our idle loop suspends and is woken up by a timer interrupt.
-+ */
-+void cpu_idle(void)
-+{
-+      while (1) {
-+              local_irq_disable();
-+              while (!need_resched()) {
-+                      local_irq_enable();
-+                      thread_suspend();
-+                      local_irq_disable();
-+              }
-+              local_irq_enable();
-+              preempt_enable_no_resched();
-+              schedule();
-+              preempt_disable();
-+      }
-+}
-+
-+/*
-+ * dump_fpu()
-+ *
-+ *    Fill in the fpu structure for a core dump. (just a stub as we don't have
-+ *    an fpu)
-+ */
-+int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs)
-+{
-+      return 1;
-+}
-+
-+/*
-+ * machine_restart()
-+ *    Resets the system.
-+ */
-+void machine_restart(char *__unused)
-+{
-+      /*
-+       * Disable all threads except myself. We can do this
-+       * directly without needing to call smp_send_stop
-+       * because we have a unique architecture where
-+       * one thread can disable one or more other threads.
-+       */
-+      thread_disable_others();
-+
-+      /*
-+       * Call the hardware-specific machine reset function.
-+       */
-+      if (mach_reset) {
-+              mach_reset();
-+      }
-+
-+      printk(KERN_EMERG "System Restarting\n");
-+
-+      /*
-+       * Set watchdog to trigger (after 1ms delay) (12 Mhz is the fixed OSC)
-+       */
-+      UBICOM32_IO_TIMER->tkey = TIMER_TKEYVAL;
-+      UBICOM32_IO_TIMER->wdcom = UBICOM32_IO_TIMER->mptval +
-+              (12000000 / 1000);
-+      UBICOM32_IO_TIMER->wdcfg = 0;
-+      UBICOM32_IO_TIMER->tkey = 0;
-+
-+      /*
-+       * Wait for watchdog
-+       */
-+      asm volatile (
-+              "       move.4          MT_EN, #0               \n\t"
-+              "       pipe_flush      0                       \n\t"
-+      );
-+
-+      local_irq_disable();
-+      for (;;) {
-+              thread_suspend();
-+      }
-+}
-+
-+/*
-+ * machine_halt()
-+ *    Halt the machine.
-+ *
-+ * Similar to machine_power_off, but don't shut off power.  Add code
-+ * here to freeze the system for e.g. post-mortem debug purpose when
-+ * possible.  This halt has nothing to do with the idle halt.
-+ */
-+void machine_halt(void)
-+{
-+      /*
-+       * Disable all threads except myself. We can do this
-+       * directly without needing to call smp_send_stop
-+       * because we have a unique architecture where
-+       * one thread can disable one or more other threads.
-+       */
-+      thread_disable_others();
-+
-+      /*
-+       * Call the hardware-specific machine halt function.
-+       */
-+      if (mach_halt) {
-+              mach_halt();
-+      }
-+
-+      printk(KERN_EMERG "System Halted, OK to turn off power\n");
-+      local_irq_disable();
-+      for (;;) {
-+              thread_suspend();
-+      }
-+}
-+
-+/*
-+ * machine_power_off()
-+ *    Turn the power off, if a power off handler is defined, otherwise, spin
-+ *    endlessly.
-+ */
-+void machine_power_off(void)
-+{
-+      /*
-+       * Disable all threads except myself. We can do this
-+       * directly without needing to call smp_send_stop
-+       * because we have a unique architecture where
-+       * one thread can disable one or more other threads.
-+       */
-+      thread_disable_others();
-+
-+      /*
-+       * Call the hardware-specific machine power off function.
-+       */
-+      if (mach_power_off) {
-+              mach_power_off();
-+      }
-+
-+      printk(KERN_EMERG "System Halted, OK to turn off power\n");
-+      local_irq_disable();
-+      for (;;) {
-+              thread_suspend();
-+      }
-+}
-+
-+/*
-+ * address_is_valid()
-+ *    check if an address is valid -- (for read access)
-+ */
-+static bool address_is_valid(const void *address)
-+{
-+      int addr = (int)address;
-+      unsigned long socm, eocm, sdram, edram;
-+
-+      if (addr & 3)
-+              return false;
-+
-+      processor_ocm(&socm, &eocm);
-+      processor_dram(&sdram, &edram);
-+      if (addr >= socm && addr < eocm)
-+              return true;
-+
-+      if (addr >= sdram && addr < edram)
-+              return true;
-+
-+      return false;
-+}
-+
-+/*
-+ * vma_path_name_is_valid()
-+ *    check if path_name of a vma is a valid string
-+ */
-+static bool vma_path_name_is_valid(const char *str)
-+{
-+#define MAX_NAME_LEN 256
-+      int i = 0;
-+      if (!address_is_valid(str))
-+              return false;
-+
-+      for (; i < MAX_NAME_LEN; i++, str++) {
-+              if (*str == '\0')
-+                      return true;
-+      }
-+
-+      return false;
-+}
-+
-+/*
-+ * show_vmas()
-+ *    show vma info of a process
-+ */
-+void show_vmas(struct task_struct *task)
-+{
-+#ifdef CONFIG_DEBUG_VERBOSE
-+#define UBICOM32_MAX_VMA_COUNT 1024
-+
-+      struct vm_area_struct *vma;
-+      struct file *file;
-+      char *name = "";
-+      int flags, loop = 0;
-+
-+      printk(KERN_NOTICE "Start of vma list\n");
-+
-+      if (!address_is_valid(task) || !address_is_valid(task->mm))
-+              goto error;
-+
-+      vma = task->mm->mmap;
-+      while (vma) {
-+              if (!address_is_valid(vma))
-+                      goto error;
-+
-+              flags = vma->vm_flags;
-+              file = vma->vm_file;
-+
-+              if (file) {
-+                      /* seems better to use dentry op here, but sanity check is easier this way */
-+                      if (!address_is_valid(file) || !address_is_valid(file->f_path.dentry) || !vma_path_name_is_valid(file->f_path.dentry->d_name.name))
-+                              goto error;
-+
-+                      name = (char *)file->f_path.dentry->d_name.name;
-+              }
-+
-+              /* Similar to /proc/pid/maps format */
-+              printk(KERN_NOTICE "%08lx-%08lx %c%c%c%c %08lx %s\n",
-+                      vma->vm_start,
-+                      vma->vm_end,
-+                      flags & VM_READ ? 'r' : '-',
-+                      flags & VM_WRITE ? 'w' : '-',
-+                      flags & VM_EXEC ? 'x' : '-',
-+                      flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p',
-+                      vma->vm_pgoff << PAGE_SHIFT,
-+                      name);
-+
-+              vma = vma->vm_next;
-+
-+              if (loop++ > UBICOM32_MAX_VMA_COUNT)
-+                      goto error;
-+      }
-+
-+      printk(KERN_NOTICE "End of vma list\n");
-+      return;
-+
-+error:
-+      printk(KERN_NOTICE "\nCorrupted vma list, abort!\n");
-+#endif
-+}
-+
-+/*
-+ * show_regs()
-+ *    Print out all of the registers.
-+ */
-+void show_regs(struct pt_regs *regs)
-+{
-+      unsigned int i;
-+      unsigned int en, lo, hi;
-+
-+      printk(KERN_NOTICE "regs: %p, tid: %d\n",
-+              (void *)regs,
-+              thread_get_self());
-+
-+      printk(KERN_NOTICE "pc: %08x, previous_pc: %08x\n\n",
-+              (unsigned int)regs->pc,
-+              (unsigned int)regs->previous_pc);
-+
-+      printk(KERN_NOTICE "Data registers\n");
-+      for (i = 0; i < 16; i++) {
-+              printk("D%02d: %08x, ", i, (unsigned int)regs->dn[i]);
-+              if ((i % 4) == 3) {
-+                      printk("\n");
-+              }
-+      }
-+      printk("\n");
-+
-+      printk(KERN_NOTICE "Address registers\n");
-+      for (i = 0; i < 8; i++) {
-+              printk("A%02d: %08x, ", i, (unsigned int)regs->an[i]);
-+              if ((i % 4) == 3) {
-+                      printk("\n");
-+              }
-+      }
-+      printk("\n");
-+
-+      printk(KERN_NOTICE "acc0: %08x-%08x, acc1: %08x-%08x\n",
-+              (unsigned int)regs->acc0[1],
-+              (unsigned int)regs->acc0[0],
-+              (unsigned int)regs->acc1[1],
-+              (unsigned int)regs->acc1[0]);
-+
-+      printk(KERN_NOTICE "mac_rc16: %08x, source3: %08x\n",
-+              (unsigned int)regs->mac_rc16,
-+              (unsigned int)regs->source3);
-+
-+      printk(KERN_NOTICE "inst_cnt: %08x, csr: %08x\n",
-+              (unsigned int)regs->inst_cnt,
-+              (unsigned int)regs->csr);
-+
-+      printk(KERN_NOTICE "int_mask0: %08x, int_mask1: %08x\n",
-+              (unsigned int)regs->int_mask0,
-+              (unsigned int)regs->int_mask1);
-+
-+      /*
-+       * Dump range registers
-+       */
-+      DUMP_RANGE_REGISTER("I", "0");
-+      DUMP_RANGE_REGISTER("I", "1");
-+      DUMP_RANGE_REGISTER("I", "2");
-+      DUMP_RANGE_REGISTER("I", "3");
-+      DUMP_RANGE_REGISTER("D", "0");
-+      DUMP_RANGE_REGISTER("D", "1");
-+      DUMP_RANGE_REGISTER("D", "2");
-+      DUMP_RANGE_REGISTER("D", "3");
-+      DUMP_RANGE_REGISTER("D", "4");
-+
-+      printk(KERN_NOTICE "frame_type: %d, nesting_level: %d, thread_type %d\n\n",
-+              (int)regs->frame_type,
-+              (int)regs->nesting_level,
-+              (int)regs->thread_type);
-+}
-+
-+/*
-+ * kernel_thread_helper()
-+ *    On execution d0 will be 0, d1 will be the argument to be passed to the
-+ *    kernel function.  d2 contains the kernel function that needs to get
-+ *    called. d3 will contain address to do_exit which need to get moved
-+ *    into a5. On return from fork the child thread d0 will be 0. We call
-+ *    this dummy function which in turn loads the argument
-+ */
-+asmlinkage void kernel_thread_helper(void);
-+
-+/*
-+ * kernel_thread()
-+ *    Create a kernel thread
-+ */
-+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-+{
-+      struct pt_regs regs;
-+
-+      memset(&regs, 0, sizeof(regs));
-+
-+      regs.dn[1] = (unsigned long)arg;
-+      regs.dn[2] = (unsigned long)fn;
-+      regs.dn[3] = (unsigned long)do_exit;
-+      regs.an[5] = (unsigned long)kernel_thread_helper;
-+      regs.pc = (unsigned long)kernel_thread_helper;
-+      regs.nesting_level = 0;
-+      regs.thread_type = KERNEL_THREAD;
-+
-+      return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
-+                     0, &regs, 0, NULL, NULL);
-+}
-+EXPORT_SYMBOL(kernel_thread);
-+
-+/*
-+ * flush_thread()
-+ *    XXX todo
-+ */
-+void flush_thread(void)
-+{
-+      /* XXX todo */
-+}
-+
-+/*
-+ * sys_fork()
-+ *    Not implemented on no-mmu.
-+ */
-+asmlinkage int sys_fork(struct pt_regs *regs)
-+{
-+      /* fork almost works, enough to trick you into looking elsewhere :-( */
-+      return -EINVAL;
-+}
-+
-+/*
-+ * sys_vfork()
-+ *    By the time we get here, the non-volatile registers have also been saved
-+ *    on the stack. We do some ugly pointer stuff here.. (see also copy_thread
-+ *    which does context copy).
-+ */
-+asmlinkage int sys_vfork(struct pt_regs *regs)
-+{
-+      unsigned long old_sp = regs->an[7];
-+      unsigned long old_a5 = regs->an[5];
-+      unsigned long old_return_address;
-+      long do_fork_return;
-+
-+      /*
-+       * Read the old retrun address from the stack.
-+       */
-+      if (copy_from_user(&old_return_address,
-+                         (void *)old_sp, sizeof(unsigned long))) {
-+              force_sig(SIGSEGV, current);
-+              return 0;
-+      }
-+
-+      /*
-+       * Pop the vfork call frame by setting a5 and pc to the old_return
-+       * address and incrementing the stack pointer by 4.
-+       */
-+      regs->an[5] = old_return_address;
-+      regs->pc = old_return_address;
-+      regs->an[7] += 4;
-+
-+      do_fork_return = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
-+                               regs->an[7], regs, 0, NULL, NULL);
-+
-+      /*
-+       * Now we have to test if the return code is an error. If it is an error
-+       * then restore the frame and we will execute error processing in user
-+       * space. Other wise the child and the parent will return to the correct
-+       * places.
-+       */
-+      if ((unsigned long)(do_fork_return) >= (unsigned long)(-125)) {
-+              /*
-+               * Error case. We need to restore the frame.
-+               */
-+              regs->an[5] = old_a5;
-+              regs->pc = old_a5;
-+              regs->an[7] = old_sp;
-+      }
-+
-+      return do_fork_return;
-+}
-+
-+/*
-+ * sys_clone()
-+ *    creates a child thread.
-+ */
-+asmlinkage int sys_clone(unsigned long clone_flags,
-+                       unsigned long newsp,
-+                       struct pt_regs *regs)
-+{
-+      if (!newsp)
-+              newsp = regs->an[7];
-+      return do_fork(clone_flags, newsp, regs, 0,
-+                     NULL, NULL);
-+}
-+
-+/*
-+ * copy_thread()
-+ *    low level thread copy, only used by do_fork in kernel/fork.c
-+ */
-+int copy_thread(unsigned long clone_flags,
-+              unsigned long usp, unsigned long topstk,
-+              struct task_struct *p, struct pt_regs *regs)
-+
-+{
-+      struct pt_regs *childregs;
-+
-+      childregs = (struct pt_regs *)
-+              (task_stack_page(p) + THREAD_SIZE - 8) - 1;
-+
-+      *childregs = *regs;
-+
-+      /*
-+       * Set return value for child to be 0.
-+       */
-+      childregs->dn[0] = 0;
-+
-+      if (usp)
-+              childregs->an[7] = usp;
-+      else
-+              childregs->an[7] = (unsigned long)task_stack_page(p) +
-+                      THREAD_SIZE - 8;
-+
-+      /*
-+       * Set up the switch_to frame to return to "ret_from_fork"
-+       */
-+      p->thread.a5 = (unsigned long)ret_from_fork;
-+      p->thread.sp = (unsigned long)childregs;
-+
-+      return 0;
-+}
-+
-+/*
-+ * sys_execve()
-+ *    executes a new program.
-+ */
-+asmlinkage int sys_execve(char *name, char **argv,
-+                        char **envp, struct pt_regs *regs)
-+{
-+      int error;
-+      char *filename;
-+
-+      lock_kernel();
-+      filename = getname(name);
-+      error = PTR_ERR(filename);
-+      if (IS_ERR(filename))
-+              goto out;
-+      error = do_execve(filename, argv, envp, regs);
-+      putname(filename);
-+      asm ("       .global sys_execve_complete\n"
-+           "       sys_execve_complete:");
-+out:
-+      unlock_kernel();
-+      return error;
-+}
-+
-+/*
-+ * Return saved PC of a blocked thread.
-+ */
-+unsigned long thread_saved_pc(struct task_struct *tsk)
-+{
-+      return tsk->thread.a5;
-+}
-+
-+
-+unsigned long get_wchan(struct task_struct *p)
-+{
-+      unsigned long pc;
-+
-+      /*
-+       * If we don't have a process, or it is not the current
-+       * one or not RUNNING, it makes no sense to ask for a
-+       * wchan.
-+       */
-+      if (!p || p == current || p->state == TASK_RUNNING)
-+              return 0;
-+
-+      /*
-+       * TODO: If the process is in the middle of schedule, we
-+       * are supposed to do something different but for now we
-+       * will return the same thing in both situations.
-+       */
-+      pc = thread_saved_pc(p);
-+      if (in_sched_functions(pc))
-+              return pc;
-+      return pc;
-+}
-+
-+
-+/*
-+ * Infrequently used interface to dump task registers to core files.
-+ */
-+int dump_task_regs(struct task_struct *task, elf_gregset_t *elfregs)
-+{
-+      struct pt_regs *regs = task_pt_regs(task);
-+      *(struct pt_regs *)elfregs = *regs;
-+
-+      return 1;
-+}
-+
-+/*
-+ * __switch_to is the function that implements the contex save and
-+ * switch within the kernel. Since this is a function call very few
-+ * registers have to be saved to pull this off. d0 holds prev and we
-+ * want to preserve it. prev_switch is a pointer to task->thread
-+ * structure. This is where we will save the register state. next_switch
-+ * is pointer to the next task's thread structure that holds the
-+ * registers.
-+ */
-+asmlinkage void *__switch_to(struct task_struct *prev,
-+                           struct thread_struct *prev_switch,
-+                           struct thread_struct *next_switch)
-+      __attribute__((naked));
---- /dev/null
-+++ b/arch/ubicom32/kernel/processor.c
-@@ -0,0 +1,348 @@
-+/*
-+ * arch/ubicom32/kernel/processor.c
-+ *   Ubicom32 architecture processor info implementation.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
-+#include <linux/profile.h>
-+#include <linux/clocksource.h>
-+#include <linux/types.h>
-+#include <linux/seq_file.h>
-+#include <linux/delay.h>
-+#include <linux/cpu.h>
-+#include <asm/devtree.h>
-+#include <asm/processor.h>
-+#include <asm/cpu.h>
-+#include <asm/ocm_size.h>
-+
-+struct procnode {
-+      struct devtree_node dn;
-+      unsigned int threads;
-+      unsigned int timers;
-+      unsigned int frequency;
-+      unsigned int ddr_frequency;
-+      unsigned int interrupt0;
-+      unsigned int interrupt1;
-+      void *socm;
-+      void *eocm;
-+      void *sdram;
-+      void *edram;
-+      unsigned int arch_version;
-+      void *os_syscall_begin;
-+      void *os_syscall_end;
-+};
-+
-+struct procnode *pn;
-+
-+/*
-+ * show_processorinfo()
-+ *    Print the actual processor information.
-+ */
-+static void show_processorinfo(struct seq_file *m)
-+{
-+      char *cpu, *mmu, *fpu;
-+      unsigned int clockfreq;
-+      unsigned int chipid;
-+
-+      cpu = CPU;
-+      mmu = "none";
-+      fpu = "none";
-+
-+      asm volatile (
-+      "move.4         %0, CHIP_ID     \n\t"
-+      : "=r" (chipid)
-+      );
-+
-+      /*
-+       * General Processor Information.
-+       */
-+      seq_printf(m, "Vendor:\t\t%s\n", "Ubicom");
-+      seq_printf(m, "CPU:\t\t%s\n", cpu);
-+      seq_printf(m, "MMU:\t\t%s\n", mmu);
-+      seq_printf(m, "FPU:\t\t%s\n", fpu);
-+      seq_printf(m, "Arch:\t\t%hx\n", chipid >> 16);
-+      seq_printf(m, "Rev:\t\t%hx\n", (chipid & 0xffff));
-+
-+      /*
-+       * Now compute the clock frequency in Mhz.
-+       */
-+      clockfreq = processor_frequency();
-+      seq_printf(m, "Clock Freq:\t%u.0 MHz\n",
-+                 clockfreq / 1000000);
-+      seq_printf(m, "DDR Freq:\t%u.0 MHz\n",
-+                 pn ? pn->ddr_frequency / 1000000 : 0);
-+      seq_printf(m, "BogoMips:\t%lu.%02lu\n",
-+                 (loops_per_jiffy * HZ) / 500000,
-+                 ((loops_per_jiffy * HZ) / 5000) % 100);
-+      seq_printf(m, "Calibration:\t%lu loops\n", (loops_per_jiffy * HZ));
-+}
-+
-+/*
-+ * show_cpuinfo()
-+ *    Get CPU information for use by the procfs.
-+ */
-+static int show_cpuinfo(struct seq_file *m, void *v)
-+{
-+      unsigned long n = (unsigned long)v - 1;
-+
-+#if defined(CONFIG_SMP)
-+      struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, n);
-+#endif
-+
-+      /*
-+       * Print the general processor information on the first
-+       * call.
-+       */
-+      if (n == 0) {
-+              show_processorinfo(m);
-+      }
-+
-+#if defined(CONFIG_SMP)
-+      /*
-+       * For each hwthread, print if this hwthread is running Linux
-+       * or is an I/O thread.
-+       */
-+      if (cpu_isset(n, cpu_online_map)) {
-+              seq_printf(m, "cpu[%02lu]:\tthread id - %lu\n", n, p->tid);
-+      } else {
-+              seq_printf(m, "cpu[%02lu]:\toff-line\n", n);
-+      }
-+#endif
-+      return 0;
-+
-+}
-+
-+static void *c_start(struct seq_file *m, loff_t *pos)
-+{
-+      unsigned long i = *pos;
-+
-+      return i < NR_CPUS ? (void *)(i + 1) : NULL;
-+}
-+
-+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
-+{
-+      ++*pos;
-+      return c_start(m, pos);
-+}
-+
-+static void c_stop(struct seq_file *m, void *v)
-+{
-+}
-+
-+const struct seq_operations cpuinfo_op = {
-+      .start  = c_start,
-+      .next   = c_next,
-+      .stop   = c_stop,
-+      .show   = show_cpuinfo,
-+};
-+
-+/*
-+ * processor_timers()
-+ *    Returns the timers available to Linux.
-+ */
-+unsigned int processor_timers(void)
-+{
-+      if (!pn) {
-+              return 0;
-+      }
-+      return pn->timers;
-+}
-+
-+/*
-+ * processor_threads()
-+ *    Returns the threads available to Linux.
-+ */
-+unsigned int processor_threads(void)
-+{
-+      if (!pn) {
-+              return 0;
-+      }
-+      return pn->threads;
-+}
-+
-+/*
-+ * processor_frequency()
-+ *    Returns the frequency of the system clock.
-+ */
-+unsigned int processor_frequency(void)
-+{
-+      if (!pn) {
-+              return 0;
-+      }
-+      return pn->frequency;
-+}
-+EXPORT_SYMBOL(processor_frequency);
-+
-+/*
-+ * processor_interrupts()
-+ *    Return the interrupts that are setup at boot time.
-+ */
-+int processor_interrupts(unsigned int *int0, unsigned int *int1)
-+{
-+      if (!pn) {
-+              return -EFAULT;
-+      }
-+
-+      if (int0) {
-+              *int0 = pn->interrupt0;
-+      }
-+
-+      if (int1) {
-+              *int1 = pn->interrupt1;
-+      }
-+      return 0;
-+}
-+
-+/*
-+ * processor_ocm()
-+ *    Returns the start and end of OCM available to Linux.
-+ */
-+void processor_ocm(unsigned long *socm, unsigned long *eocm)
-+{
-+      *socm = (unsigned long)pn->socm;
-+      *eocm = (unsigned long)pn->eocm;
-+}
-+
-+/*
-+ * processor_dram()
-+ *    Returns the start and end of dram available to Linux.
-+ */
-+void processor_dram(unsigned long *sdram, unsigned long *edram)
-+{
-+      *sdram = (unsigned long)pn->sdram;
-+      *edram = (unsigned long)pn->edram;
-+}
-+
-+/*
-+ * processor_validate_failed()
-+ *    Returns the dram available to Linux.
-+ */
-+static noinline void processor_validate_failed(void)
-+{
-+      while (1)
-+              THREAD_STALL;
-+}
-+
-+/*
-+ * processor_validate()
-+ *    Validates the procnode against limitations of this link/built.
-+ */
-+static void processor_validate(void)
-+{
-+      void *dram_start = (void *)(KERNELSTART);
-+      void *dram_end   = (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE);
-+#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE
-+      void *ocm_code_start = (void *)(OCMSTART + APP_OCM_CODE_SIZE);
-+      void *ocm_data_end   = (void *)(OCMEND   - APP_OCM_DATA_SIZE);
-+#endif
-+      extern void __os_syscall_begin;
-+      extern void __os_syscall_end;
-+      int proc_node_valid = 1;
-+
-+      if (!pn) {
-+              printk(KERN_ERR "ERROR: processor node not found\n");
-+              goto error;
-+      }
-+
-+
-+      if (dram_start < pn->sdram || dram_end > pn->edram) {
-+              printk(KERN_ERR "ERROR: processor dram mismatch %p-%p "
-+                     "available but we are expecting %p-%p\n",
-+                     pn->sdram, pn->edram, dram_start, dram_end);
-+              proc_node_valid = 0;
-+      } else {
-+              printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n",
-+                     pn->sdram, pn->edram, dram_start, dram_end);
-+      }
-+      if (&__os_syscall_begin < pn->os_syscall_begin ||
-+          &__os_syscall_end > pn->os_syscall_end) {
-+              printk(KERN_ERR "ERROR: processor syscall area mismatch "
-+                     "%p-%p available but we are expecting %p-%p\n",
-+                     pn->os_syscall_begin, pn->os_syscall_end,
-+                     &__os_syscall_begin, &__os_syscall_end);
-+              proc_node_valid = 0;
-+      } else {
-+              printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n",
-+                     pn->sdram, pn->edram, dram_start, dram_end);
-+      }
-+#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE
-+      if (ocm_code_start < pn->socm ||  ocm_data_end > pn->eocm) {
-+              printk(KERN_ERR "ERROR: processor ocm mismatch %p-%p "
-+                     "available but we are expecting %p-%p\n",
-+                     pn->socm, pn->eocm, ocm_code_start, ocm_data_end);
-+              proc_node_valid = 0;
-+      } else {
-+              printk(KERN_INFO "processor ocm %p-%p, expecting %p-%p\n",
-+                     pn->socm, pn->eocm, ocm_code_start, ocm_data_end);
-+
-+      }
-+#endif
-+
-+      if (UBICOM32_ARCH_VERSION != pn->arch_version) {
-+              printk(KERN_ERR "ERROR: processor arch mismatch, kernel"
-+                     "compiled for %d found %d\n",
-+                     UBICOM32_ARCH_VERSION, pn->arch_version);
-+              proc_node_valid = 0;
-+      }
-+
-+      if (proc_node_valid)
-+              return;
-+error:
-+      processor_validate_failed();
-+}
-+
-+void __init processor_init(void)
-+{
-+      /*
-+       * If we do not have a trap node in the device tree, we leave the fault
-+       * handling to the underlying hardware.
-+       */
-+      pn = (struct procnode *)devtree_find_node("processor");
-+
-+      processor_validate();
-+
-+      /*
-+       * If necessary correct the initial range registers to cover the
-+       * complete physical space
-+       */
-+      if (pn->edram > (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE)) {
-+              printk(KERN_INFO "updating range registers for expanded dram\n");
-+              asm volatile (
-+                      "       move.4 D_RANGE1_HI, %0          \t\n"
-+                      "       move.4 I_RANGE0_HI, %0          \t\n"
-+#ifdef CONFIG_PROTECT_KERNEL
-+                      "       move.4 D_RANGE2_HI, %0          \t\n"
-+                      "       move.4 I_RANGE2_HI, %0          \t\n"
-+#endif
-+              : : "a"((unsigned long)pn->edram - 4)
-+                      );
-+      }
-+
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/ptrace.c
-@@ -0,0 +1,275 @@
-+/*
-+ * arch/ubicom32/kernel/ptrace.c
-+ *   Ubicom32 architecture ptrace implementation.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * (C) 1994 by Hamish Macdonald
-+ * Taken from linux/kernel/ptrace.c and modified for M680x0.
-+ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/mm.h>
-+#include <linux/smp.h>
-+#include <linux/errno.h>
-+#include <linux/ptrace.h>
-+#include <linux/user.h>
-+#include <linux/signal.h>
-+#include <linux/uaccess.h>
-+
-+#include <asm/page.h>
-+#include <asm/pgtable.h>
-+#include <asm/system.h>
-+#include <asm/cacheflush.h>
-+#include <asm/processor.h>
-+
-+/*
-+ * ptrace_getregs()
-+ *
-+ *    Get all user integer registers.
-+ */
-+static inline int ptrace_getregs(struct task_struct *task, void __user *uregs)
-+{
-+      struct pt_regs *regs = task_pt_regs(task);
-+      return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
-+}
-+
-+/*
-+ * ptrace_get_reg()
-+ *
-+ *    Get contents of register REGNO in task TASK.
-+ */
-+static unsigned long ptrace_get_reg(struct task_struct *task, int regno)
-+{
-+      if (regno < sizeof(struct pt_regs)) {
-+              struct pt_regs *pt_regs = task_pt_regs(task);
-+              return *(unsigned long *)((long) pt_regs + regno);
-+      }
-+
-+      return -EIO;
-+}
-+
-+/*
-+ * ptrace_put_reg()
-+ *    Write contents of register REGNO in task TASK.
-+ */
-+static int ptrace_put_reg(struct task_struct *task, int regno,
-+                        unsigned long data)
-+{
-+      if (regno <= sizeof(struct pt_regs) && regno != PT_FRAME_TYPE) {
-+              struct pt_regs *pt_regs = task_pt_regs(task);
-+              *(unsigned long *)((long) pt_regs + regno) = data;
-+              return 0;
-+      }
-+      return -EIO;
-+}
-+
-+/*
-+ * ptrace_disable_single_step()
-+ *    Disable Single Step
-+ */
-+static int ptrace_disable_single_step(struct task_struct *task)
-+{
-+      /*
-+       * Single Step not yet implemented, so must always be disabled
-+       */
-+      return 0;
-+}
-+
-+/*
-+ * ptrace_disable()
-+ *    Make sure the single step bit is not set.
-+ * Called by kernel/ptrace.c when detaching..
-+ */
-+void ptrace_disable(struct task_struct *child)
-+{
-+      ptrace_disable_single_step(child);
-+}
-+
-+/*
-+ * arch_ptrace()
-+ *    architecture specific ptrace routine.
-+ */
-+long arch_ptrace(struct task_struct *child, long request, long addr, long data)
-+{
-+      int ret;
-+      switch (request) {
-+      /* when I and D space are separate, these will need to be fixed. */
-+      case PTRACE_PEEKTEXT: /* read word at location addr. */
-+      case PTRACE_PEEKDATA:
-+              ret = generic_ptrace_peekdata(child, addr, data);
-+              break;
-+
-+      /* read the word at location addr in the USER area. */
-+      case PTRACE_PEEKUSR: {
-+              unsigned long tmp;
-+
-+              ret = -EIO;
-+              if (((unsigned long) addr > PT_INTERP_FDPIC_LOADMAP)
-+                  || (addr & 3))
-+                      break;
-+
-+              tmp = 0;  /* Default return condition */
-+
-+              ret = -EIO;
-+              if (addr < sizeof(struct pt_regs)) {
-+                      tmp = ptrace_get_reg(child, addr);
-+              } else if (addr == PT_TEXT_ADDR) {
-+                      tmp = child->mm->start_code;
-+              } else if (addr == PT_TEXT_END_ADDR) {
-+                      tmp = child->mm->end_code;
-+              } else if (addr == PT_DATA_ADDR) {
-+                      tmp = child->mm->start_data;
-+              } else if (addr == PT_EXEC_FDPIC_LOADMAP) {
-+#ifdef CONFIG_BINFMT_ELF_FDPIC
-+                      tmp = child->mm->context.exec_fdpic_loadmap;
-+#endif
-+              } else if (addr == PT_INTERP_FDPIC_LOADMAP) {
-+#ifdef CONFIG_BINFMT_ELF_FDPIC
-+                      tmp = child->mm->context.interp_fdpic_loadmap;
-+#endif
-+              } else {
-+                      break;
-+              }
-+
-+              ret = put_user(tmp, (unsigned long *)data);
-+              break;
-+      }
-+
-+      case PTRACE_POKETEXT: /* write the word at location addr. */
-+      case PTRACE_POKEDATA:
-+              ret = generic_ptrace_pokedata(child, addr, data);
-+
-+              /*
-+               * If we just changed some code so we need to
-+               * correct the caches
-+               */
-+              if (request == PTRACE_POKETEXT && ret == 0) {
-+                      flush_icache_range(addr, addr + 4);
-+              }
-+              break;
-+
-+      case PTRACE_POKEUSR: /* write the word at location addr
-+                            * in the USER area */
-+              ret = -EIO;
-+
-+              if (((unsigned long) addr > PT_DATA_ADDR) || (addr & 3))
-+                      break;
-+
-+              if (addr < sizeof(struct pt_regs)) {
-+                      ret = ptrace_put_reg(child, addr, data);
-+              }
-+              break;
-+
-+      case PTRACE_SYSCALL: /* continue and stop at next (return from)
-+                            * syscall */
-+      case PTRACE_CONT: { /* restart after signal. */
-+
-+              ret = -EIO;
-+              if (!valid_signal(data))
-+                      break;
-+              if (request == PTRACE_SYSCALL)
-+                      set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-+              else
-+                      clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-+              child->exit_code = data;
-+              /* make sure the single step bit is not set. */
-+              ptrace_disable_single_step(child);
-+              wake_up_process(child);
-+              ret = 0;
-+              break;
-+      }
-+
-+      /*
-+       * make the child exit.  Best I can do is send it a sigkill.
-+       * perhaps it should be put in the status that it wants to exit.
-+       */
-+      case PTRACE_KILL: {
-+              ret = 0;
-+              if (child->exit_state == EXIT_ZOMBIE) /* already dead */
-+                      break;
-+              child->exit_code = SIGKILL;
-+              /* make sure the single step bit is not set. */
-+              ptrace_disable_single_step(child);
-+              wake_up_process(child);
-+              break;
-+      }
-+
-+      case PTRACE_DETACH:     /* detach a process that was attached. */
-+              ret = ptrace_detach(child, data);
-+              break;
-+
-+      case PTRACE_GETREGS:    /* Get all gp regs from the child. */
-+              ptrace_getregs(child, (unsigned long *)data);
-+              ret = 0;
-+              break;
-+
-+      case PTRACE_SETREGS: { /* Set all gp regs in the child. */
-+              int i;
-+              unsigned long tmp;
-+              int count = sizeof(struct pt_regs) / sizeof(unsigned long);
-+              for (i = 0; i < count; i++) {
-+                      if (get_user(tmp, (unsigned long *) data)) {
-+                              ret = -EFAULT;
-+                              break;
-+                      }
-+                      ptrace_put_reg(child, sizeof(unsigned long) * i, tmp);
-+                      data += sizeof(long);
-+              }
-+              ret = 0;
-+              break;
-+      }
-+
-+      default:
-+              return ptrace_request(child, request, addr, data);
-+              break;
-+      }
-+      return ret;
-+}
-+/*
-+ * syscall_trace
-+ *
-+ * called by syscall enter/exit when the TIF_SYSCALL_TRACE bit is set.
-+ */
-+asmlinkage void syscall_trace(void)
-+{
-+      struct task_struct *cur = current;
-+      if (!test_thread_flag(TIF_SYSCALL_TRACE))
-+              return;
-+      if (!(cur->ptrace & PT_PTRACED))
-+              return;
-+      ptrace_notify(SIGTRAP | ((cur->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 (cur->exit_code) {
-+              send_sig(cur->exit_code, current, 1);
-+              current->exit_code = 0;
-+      }
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/semaphore.c
-@@ -0,0 +1,159 @@
-+/*
-+ * arch/ubicom32/kernel/semaphore.c
-+ *   Ubicom32 architecture semaphore implementation.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+/*
-+ *  Generic semaphore code. Buyer beware. Do your own
-+ * specific changes in <asm/semaphore-helper.h>
-+ */
-+
-+#include <linux/sched.h>
-+#include <linux/err.h>
-+#include <linux/init.h>
-+#include <asm/semaphore-helper.h>
-+
-+#ifndef CONFIG_RMW_INSNS
-+spinlock_t semaphore_wake_lock;
-+#endif
-+
-+/*
-+ * Semaphores are implemented using a two-way counter:
-+ * The "count" variable is decremented for each process
-+ * that tries to sleep, while the "waking" variable is
-+ * incremented when the "up()" code goes to wake up waiting
-+ * processes.
-+ *
-+ * Notably, the inline "up()" and "down()" functions can
-+ * efficiently test if they need to do any extra work (up
-+ * needs to do something only if count was negative before
-+ * the increment operation.
-+ *
-+ * waking_non_zero() (from asm/semaphore.h) must execute
-+ * atomically.
-+ *
-+ * When __up() is called, the count was negative before
-+ * incrementing it, and we need to wake up somebody.
-+ *
-+ * This routine adds one to the count of processes that need to
-+ * wake up and exit.  ALL waiting processes actually wake up but
-+ * only the one that gets to the "waking" field first will gate
-+ * through and acquire the semaphore.  The others will go back
-+ * to sleep.
-+ *
-+ * Note that these functions are only called when there is
-+ * contention on the lock, and as such all this is the
-+ * "non-critical" part of the whole semaphore business. The
-+ * critical part is the inline stuff in <asm/semaphore.h>
-+ * where we want to avoid any extra jumps and calls.
-+ */
-+void __up(struct semaphore *sem)
-+{
-+      wake_one_more(sem);
-+      wake_up(&sem->wait);
-+}
-+
-+/*
-+ * Perform the "down" function.  Return zero for semaphore acquired,
-+ * return negative for signalled out of the function.
-+ *
-+ * If called from __down, the return is ignored and the wait loop is
-+ * not interruptible.  This means that a task waiting on a semaphore
-+ * using "down()" cannot be killed until someone does an "up()" on
-+ * the semaphore.
-+ *
-+ * If called from __down_interruptible, the return value gets checked
-+ * upon return.  If the return value is negative then the task continues
-+ * with the negative value in the return register (it can be tested by
-+ * the caller).
-+ *
-+ * Either form may be used in conjunction with "up()".
-+ *
-+ */
-+
-+
-+#define DOWN_HEAD(task_state)                                         \
-+                                                                      \
-+                                                                      \
-+      current->state = (task_state);                                  \
-+      add_wait_queue(&sem->wait, &wait);                              \
-+                                                                      \
-+      /*                                                              \
-+       * Ok, we're set up.  sem->count is known to be less than zero  \
-+       * so we must wait.                                             \
-+       *                                                              \
-+       * We can let go the lock for purposes of waiting.              \
-+       * We re-acquire it after awaking so as to protect              \
-+       * all semaphore operations.                                    \
-+       *                                                              \
-+       * If "up()" is called before we call waking_non_zero() then    \
-+       * we will catch it right away.  If it is called later then     \
-+       * we will have to go through a wakeup cycle to catch it.       \
-+       *                                                              \
-+       * Multiple waiters contend for the semaphore lock to see       \
-+       * who gets to gate through and who has to wait some more.      \
-+       */                                                             \
-+      for (;;) {
-+
-+#define DOWN_TAIL(task_state)                 \
-+              current->state = (task_state);  \
-+      }                                       \
-+      current->state = TASK_RUNNING;          \
-+      remove_wait_queue(&sem->wait, &wait);
-+
-+void __sched __down(struct semaphore *sem)
-+{
-+      DECLARE_WAITQUEUE(wait, current);
-+
-+      DOWN_HEAD(TASK_UNINTERRUPTIBLE)
-+      if (waking_non_zero(sem))
-+              break;
-+      schedule();
-+      DOWN_TAIL(TASK_UNINTERRUPTIBLE)
-+}
-+
-+int __sched __down_interruptible(struct semaphore *sem)
-+{
-+      DECLARE_WAITQUEUE(wait, current);
-+      int ret = 0;
-+
-+      DOWN_HEAD(TASK_INTERRUPTIBLE)
-+
-+      ret = waking_non_zero_interruptible(sem, current);
-+      if (ret) {
-+              if (ret == 1)
-+                      /* ret != 0 only if we get interrupted -arca */
-+                      ret = 0;
-+              break;
-+      }
-+      schedule();
-+      DOWN_TAIL(TASK_INTERRUPTIBLE)
-+      return ret;
-+}
-+
-+int __down_trylock(struct semaphore *sem)
-+{
-+      return waking_non_zero_trylock(sem);
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/setup.c
-@@ -0,0 +1,194 @@
-+/*
-+ * arch/ubicom32/kernel/setup.c
-+ *   Ubicom32 architecture-dependent parts of system setup.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 1999-2007  Greg Ungerer (gerg@snapgear.com)
-+ * Copyright (C) 1998,1999  D. Jeff Dionne <jeff@uClinux.org>
-+ * Copyleft  ()) 2000       James D. Schettine {james@telos-systems.com}
-+ * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
-+ * Copyright (C) 1995       Hamish Macdonald
-+ * Copyright (C) 2000       Lineo Inc. (www.lineo.com)
-+ * Copyright (C) 2001     Lineo, Inc. <www.lineo.com>
-+ * 68VZ328 Fixes/support    Evan Stawnyczy <e@lineo.ca>
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/delay.h>
-+#include <linux/interrupt.h>
-+#include <linux/fb.h>
-+#include <linux/module.h>
-+#include <linux/console.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/bootmem.h>
-+#include <linux/seq_file.h>
-+#include <linux/init.h>
-+
-+#include <asm/devtree.h>
-+#include <asm/setup.h>
-+#include <asm/irq.h>
-+#include <asm/machdep.h>
-+#include <asm/pgtable.h>
-+#include <asm/pgalloc.h>
-+#include <asm/ubicom32-common.h>
-+#include <asm/processor.h>
-+#include <asm/bootargs.h>
-+#include <asm/thread.h>
-+
-+unsigned long memory_start;
-+EXPORT_SYMBOL(memory_start);
-+
-+unsigned long memory_end;
-+EXPORT_SYMBOL(memory_end);
-+
-+static char __initdata command_line[COMMAND_LINE_SIZE];
-+#ifdef CONFIG_CMDLINE_BOOL
-+static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
-+#endif
-+
-+extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
-+
-+/*
-+ * setup_arch()
-+ *    Setup the architecture dependent portions of the system.
-+ */
-+void __init setup_arch(char **cmdline_p)
-+{
-+      int bootmap_size;
-+      unsigned long ram_start;
-+
-+      processor_init();
-+      bootargs_init();
-+
-+      /*
-+       * Use the link for memory_start from the link and the processor
-+       * node for memory_end.
-+       */
-+      memory_start = PAGE_ALIGN(((unsigned long)&_end));
-+      processor_dram(&ram_start, &memory_end);
-+
-+      init_mm.start_code = (unsigned long) &_stext;
-+      init_mm.end_code = (unsigned long) &_etext;
-+      init_mm.end_data = (unsigned long) &_edata;
-+      init_mm.brk = (unsigned long) 0;
-+
-+      /*
-+       * bootexec copies the original default command line to end of memory.
-+       * u-boot can modify it there (i.e. to enable network boot) and the
-+       * kernel picks up the modified version.
-+       *
-+       * mainexec creates a `new default' command_line which is in the
-+       * bootargs devnode. It is updated on every firmware update but
-+       * not used at the moment.
-+       */
-+      strlcpy(boot_command_line, (char *)(memory_end - COMMAND_LINE_SIZE), COMMAND_LINE_SIZE);
-+
-+#ifdef CONFIG_CMDLINE_BOOL
-+#ifdef CONFIG_CMDLINE_OVERRIDE
-+      strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-+#else
-+      if (builtin_cmdline[0]) {
-+              /* append boot loader cmdline to builtin */
-+              strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
-+              strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
-+              strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
-+      }
-+#endif
-+#endif
-+
-+      strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
-+      *cmdline_p = command_line;
-+
-+      parse_early_param();
-+
-+      printk(KERN_INFO "%s Processor, Ubicom, Inc. <www.ubicom.com>\n", CPU);
-+
-+#if defined(DEBUG)
-+      printk(KERN_DEBUG "KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
-+              "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext,
-+              (int) &_sdata, (int) &_edata,
-+              (int) &_sbss, (int) &_ebss);
-+      printk(KERN_DEBUG "MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ",
-+              (int) &_ebss, (int) memory_start,
-+              (int) memory_start, (int) memory_end);
-+#endif
-+
-+#ifdef DEBUG
-+      if (strlen(*cmdline_p))
-+              printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p);
-+#endif
-+
-+#if defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE)
-+      conswitchp = &dummy_con;
-+#endif
-+
-+      /*
-+       * If we have a device tree, see if we have the nodes we need.
-+       */
-+      if (devtree) {
-+              devtree_print();
-+      }
-+
-+      /*
-+       * From the arm initialization comment:
-+       *
-+       * This doesn't seem to be used by the Linux memory manager any
-+       * more, but is used by ll_rw_block.  If we can get rid of it, we
-+       * also get rid of some of the stuff above as well.
-+       *
-+       * Note: max_low_pfn and max_pfn reflect the number of _pages_ in
-+       * the system, not the maximum PFN.
-+       */
-+      max_pfn = max_low_pfn = (memory_end - PAGE_OFFSET) >> PAGE_SHIFT;
-+
-+      /*
-+       * Give all the memory to the bootmap allocator, tell it to put the
-+       * boot mem_map at the start of memory.
-+       */
-+      bootmap_size = init_bootmem_node(
-+                      NODE_DATA(0),
-+                      memory_start >> PAGE_SHIFT,     /* map goes here */
-+                      PAGE_OFFSET >> PAGE_SHIFT,      /* 0 on coldfire */
-+                      memory_end >> PAGE_SHIFT);
-+      /*
-+       * Free the usable memory, we have to make sure we do not free
-+       * the bootmem bitmap so we then reserve it after freeing it :-)
-+       */
-+      free_bootmem(memory_start, memory_end - memory_start);
-+      reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
-+
-+      /*
-+       * Get kmalloc into gear.
-+       */
-+      paging_init();
-+
-+      /*
-+       * Fix up the thread_info structure, indicate this is a mainline Linux
-+       * thread and setup the sw_ksp().
-+       */
-+      sw_ksp[thread_get_self()] = (unsigned int) current_thread_info();
-+      thread_set_mainline(thread_get_self());
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/signal.c
-@@ -0,0 +1,458 @@
-+/*
-+ * arch/ubicom32/kernel/signal.c
-+ *   Ubicom32 architecture signal handling implementation.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 1991, 1992  Linus Torvalds
-+ * Linux/m68k support by Hamish Macdonald
-+ * 68060 fixes by Jesper Skov
-+ * 1997-12-01  Modified for POSIX.1b signals by Andreas Schwab
-+ * mathemu support by Roman Zippel
-+ * ++roman (07/09/96): implemented signal stacks
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *
-+ * mathemu support by Roman Zippel
-+ *  (Note: fpstate in the signal context is completely ignored for the emulator
-+ *         and the internal floating point format is put on stack)
-+ *
-+ * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
-+ * Atari :-) Current limitation: Only one sigstack can be active at one time.
-+ * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
-+ * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
-+ * signal handlers!
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/sched.h>
-+#include <linux/mm.h>
-+#include <linux/kernel.h>
-+#include <linux/signal.h>
-+#include <linux/syscalls.h>
-+#include <linux/errno.h>
-+#include <linux/wait.h>
-+#include <linux/ptrace.h>
-+#include <linux/unistd.h>
-+#include <linux/stddef.h>
-+#include <linux/highuid.h>
-+#include <linux/tty.h>
-+#include <linux/personality.h>
-+#include <linux/binfmts.h>
-+
-+#include <asm/setup.h>
-+#include <asm/uaccess.h>
-+#include <asm/pgtable.h>
-+#include <asm/traps.h>
-+#include <asm/ucontext.h>
-+
-+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-+
-+/*
-+ * asm signal return handlers.
-+ */
-+void ret_from_user_signal(void);
-+void ret_from_user_rt_signal(void);
-+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
-+
-+/*
-+ * Common signal suspend implementation
-+ */
-+static int signal_suspend(sigset_t *saveset, struct pt_regs *regs)
-+{
-+      regs->dn[0] = -EINTR;
-+      while (1) {
-+              current->state = TASK_INTERRUPTIBLE;
-+              schedule();
-+              if (!do_signal(saveset, regs)) {
-+                      continue;
-+              }
-+              /*
-+               * If the current frame type is a signal trampoline we are
-+               * actually going to call the signal handler so we return the
-+               * desired d0 as the return value.
-+               */
-+              if (regs->frame_type == UBICOM32_FRAME_TYPE_SIGTRAMP) {
-+                      return regs->dn[0];
-+              }
-+              return -EINTR;
-+      }
-+      /*
-+       * Should never get here
-+       */
-+      BUG();
-+      return 0;
-+}
-+
-+/*
-+ * Atomically swap in the new signal mask, and wait for a signal.
-+ */
-+asmlinkage int do_sigsuspend(struct pt_regs *regs)
-+{
-+      old_sigset_t mask = regs->dn[0];
-+      sigset_t saveset;
-+
-+      mask &= _BLOCKABLE;
-+      spin_lock_irq(&current->sighand->siglock);
-+      saveset = current->blocked;
-+      siginitset(&current->blocked, mask);
-+      recalc_sigpending();
-+      spin_unlock_irq(&current->sighand->siglock);
-+
-+      /*
-+       * Call common handler
-+       */
-+      return signal_suspend(&saveset, regs);
-+}
-+
-+asmlinkage int
-+do_rt_sigsuspend(struct pt_regs *regs)
-+{
-+      sigset_t *unewset = (sigset_t *)regs->dn[0];
-+      size_t sigsetsize = (size_t)regs->dn[1];
-+      sigset_t saveset, 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);
-+
-+      spin_lock_irq(&current->sighand->siglock);
-+      saveset = current->blocked;
-+      current->blocked = newset;
-+      recalc_sigpending();
-+      spin_unlock_irq(&current->sighand->siglock);
-+
-+      /*
-+       * Call common handler
-+       */
-+      return signal_suspend(&saveset, regs);
-+}
-+
-+asmlinkage int
-+sys_sigaction(int sig, const struct old_sigaction *act,
-+            struct old_sigaction *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;
-+}
-+
-+asmlinkage int
-+do_sys_sigaltstack(struct pt_regs *regs)
-+{
-+      const stack_t *uss = (stack_t *) regs->dn[0];
-+      stack_t *uoss = (stack_t *)regs->dn[1];
-+      return do_sigaltstack(uss, uoss, regs->an[7]);
-+}
-+
-+/*
-+ * fdpic_func_descriptor describes sa_handler when the application is FDPIC
-+ */
-+struct fdpic_func_descriptor {
-+      unsigned long   text;
-+      unsigned long   GOT;
-+};
-+
-+/*
-+ * rt_sigframe is stored on the user stack immediately before (above)
-+ * the signal handlers stack.
-+ */
-+struct rt_sigframe
-+{
-+      unsigned long syscall_number;   /* This holds __NR_rt_sigreturn. */
-+      unsigned long restore_all_regs; /* This field gets set to 1 if the frame
-+                                       * type is TRAP or INTERRUPT. */
-+      siginfo_t *info;
-+      struct ucontext uc;
-+      int sig;
-+      void *pretcode;
-+};
-+
-+/*
-+ * Do a signal return; undo the signal stack.
-+ */
-+asmlinkage int do_sigreturn(unsigned long __unused)
-+{
-+      BUG();
-+      return 0;
-+}
-+
-+asmlinkage int do_rt_sigreturn(struct pt_regs *regs)
-+{
-+      unsigned long usp = regs->an[7];
-+      struct rt_sigframe *frame = (struct rt_sigframe *)(usp);
-+      sigset_t set;
-+
-+      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(&current->sighand->siglock);
-+      current->blocked = set;
-+      recalc_sigpending();
-+      spin_unlock_irq(&current->sighand->siglock);
-+
-+      if (copy_from_user(regs, &frame->uc.uc_mcontext, sizeof(struct pt_regs)))
-+              goto badframe;
-+      return regs->dn[0];
-+
-+badframe:
-+      force_sig(SIGSEGV, current);
-+      return 0;
-+}
-+
-+static inline void *
-+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
-+{
-+      unsigned long usp;
-+
-+      /* Default to using normal stack.  */
-+      usp = regs->an[7];
-+
-+      /* This is the X/Open sanctioned signal stack switching.  */
-+      if (ka->sa.sa_flags & SA_ONSTACK) {
-+              if (!sas_ss_flags(usp))
-+                      usp = current->sas_ss_sp + current->sas_ss_size;
-+      }
-+      return (void *)((usp - frame_size) & ~0x3);
-+}
-+
-+/*
-+ * signal_trampoline:  Defined in ubicom32_syscall.S
-+ */
-+asmlinkage void signal_trampoline(void)__attribute__((naked));
-+
-+static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
-+                          sigset_t *set, struct pt_regs *regs)
-+{
-+      struct rt_sigframe *frame;
-+      int err = 0;
-+
-+      frame = (struct rt_sigframe *) get_sigframe(ka, regs, sizeof(*frame));
-+
-+      /*
-+       * The 'err |=' have been may criticized as bad code style, but I
-+       * strongly suspect that we want this code to be fast.  So for
-+       * now it stays as is.
-+       */
-+      err |= __put_user( (  (current_thread_info()->exec_domain)
-+                         && (current_thread_info()->exec_domain->signal_invmap)
-+                         && (sig < 32) )
-+                         ? current_thread_info()->exec_domain->signal_invmap[sig]
-+                         : sig, &frame->sig);
-+      err |= __put_user(info, &frame->info);
-+
-+      /* Create the ucontext.  */
-+      err |= __put_user(0, &frame->uc.uc_flags);
-+      err |= __put_user(0, &frame->uc.uc_link);
-+      err |= __put_user((void *)current->sas_ss_sp,
-+                        &frame->uc.uc_stack.ss_sp);
-+      err |= __put_user(sas_ss_flags(regs->an[7]),
-+                        &frame->uc.uc_stack.ss_flags);
-+      err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
-+      err |= __put_user(__NR_rt_sigreturn, &frame->syscall_number);
-+      if ((regs->frame_type == UBICOM32_FRAME_TYPE_TRAP) ||
-+          (regs->frame_type == UBICOM32_FRAME_TYPE_INTERRUPT)) {
-+              err |= __put_user(1, &frame->restore_all_regs);
-+      } else {
-+              err |= __put_user(0, &frame->restore_all_regs);
-+      }
-+      err |= copy_to_user (&frame->uc.uc_mcontext.sc_regs, regs, sizeof(struct pt_regs));
-+      err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
-+
-+      if (err)
-+              goto give_sigsegv;
-+
-+      /*
-+       * Set up registers for signal handler NOTE: Do not modify dn[14], it
-+       * contains the userspace tls pointer, so it important that it carries
-+       * over to the signal handler.
-+       */
-+      regs->an[7] = (unsigned long)frame;
-+      regs->pc = (unsigned long) signal_trampoline;
-+      regs->an[5] = (unsigned long) signal_trampoline;
-+      regs->dn[0] = sig;
-+      regs->dn[1] = (unsigned long) frame->info;
-+      regs->dn[2] = (unsigned int) &frame->uc;
-+
-+      /*
-+       * If this is FDPIC then the signal handler is actually a function
-+       * descriptor.
-+       */
-+      if (current->personality & FDPIC_FUNCPTRS) {
-+              struct fdpic_func_descriptor __user *funcptr =
-+                      (struct fdpic_func_descriptor *) ka->sa.sa_handler;
-+              err |= __get_user(regs->dn[3], &funcptr->text);
-+              err |= __get_user(regs->an[0], &funcptr->GOT);
-+              if (err)
-+                      goto give_sigsegv;
-+
-+              /*
-+               * The funcdesc must be in a3 as this is required for the lazy
-+               * resolver in ld.so, if the application is not FDPIC a3 is not
-+               * used.
-+               */
-+              regs->an[3] = (unsigned long) funcptr;
-+
-+      } else {
-+              regs->dn[3] = (unsigned long)ka->sa.sa_handler;
-+              regs->an[0] = 0;
-+      }
-+
-+      regs->frame_type =  UBICOM32_FRAME_TYPE_SIGTRAMP;
-+
-+      return;
-+
-+give_sigsegv:
-+      /* user space exception */
-+      force_sigsegv(sig, current);
-+}
-+
-+static inline void
-+handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
-+{
-+      switch (regs->dn[0]) {
-+      case -ERESTARTNOHAND:
-+              if (!has_handler)
-+                      goto do_restart;
-+              regs->dn[0] = -EINTR;
-+              break;
-+
-+      case -ERESTARTSYS:
-+              if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
-+                      regs->dn[0] = -EINTR;
-+                      break;
-+              }
-+      /* fallthrough */
-+      case -ERESTARTNOINTR:
-+      do_restart:
-+              regs->dn[0] = regs->original_dn_0;
-+              regs->pc -= 8;
-+              regs->an[5] -= 8;
-+              break;
-+      }
-+}
-+
-+/*
-+ * OK, we're invoking a handler
-+ */
-+static void
-+handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
-+            sigset_t *oldset, struct pt_regs *regs)
-+{
-+      /* are we from a system call? */
-+      if (regs->frame_type == -1)
-+              /* If so, check system call restarting.. */
-+              handle_restart(regs, ka, 1);
-+
-+      /* set up the stack frame */
-+      setup_rt_frame(sig, ka, info, oldset, regs);
-+
-+      if (ka->sa.sa_flags & SA_ONESHOT)
-+              ka->sa.sa_handler = SIG_DFL;
-+
-+      spin_lock_irq(&current->sighand->siglock);
-+      sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-+      if (!(ka->sa.sa_flags & SA_NODEFER))
-+              sigaddset(&current->blocked,sig);
-+      recalc_sigpending();
-+      spin_unlock_irq(&current->sighand->siglock);
-+}
-+
-+/*
-+ * 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.
-+ */
-+asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
-+{
-+      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 1;
-+
-+      if (!oldset)
-+              oldset = &current->blocked;
-+
-+      signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-+      if (signr > 0) {
-+              /* Whee!  Actually deliver the signal.  */
-+              handle_signal(signr, &ka, &info, oldset, regs);
-+              return 1;
-+      }
-+
-+      /* Did we come from a system call? */
-+      if (regs->frame_type == -1) {
-+              /* Restart the system call - no handlers present */
-+              handle_restart(regs, NULL, 0);
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * sys_sigreturn()
-+ *    Return handler for signal clean-up.
-+ *
-+ * NOTE: Ubicom32 does not use this syscall.  Instead we rely
-+ * on do_rt_sigreturn().
-+ */
-+asmlinkage long sys_sigreturn(void)
-+{
-+      return -ENOSYS;
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/smp.c
-@@ -0,0 +1,806 @@
-+/*
-+ * arch/ubicom32/kernel/smp.c
-+ *   SMP implementation for Ubicom32 processors.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
-+ * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
-+ * Copyright (C) 2001,2004 Grant Grundler <grundler@parisc-linux.org>
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/spinlock.h>
-+#include <linux/slab.h>
-+
-+#include <linux/kernel.h>
-+#include <linux/bootmem.h>
-+#include <linux/module.h>
-+#include <linux/sched.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/smp.h>
-+#include <linux/kernel_stat.h>
-+#include <linux/mm.h>
-+#include <linux/err.h>
-+#include <linux/delay.h>
-+#include <linux/bitops.h>
-+#include <linux/cpu.h>
-+#include <linux/profile.h>
-+#include <linux/delay.h>
-+#include <linux/io.h>
-+#include <linux/ptrace.h>
-+#include <linux/unistd.h>
-+#include <linux/irq.h>
-+
-+#include <asm/system.h>
-+#include <asm/atomic.h>
-+#include <asm/current.h>
-+#include <asm/tlbflush.h>
-+#include <asm/timex.h>
-+#include <asm/cpu.h>
-+#include <asm/irq.h>
-+#include <asm/processor.h>
-+#include <asm/thread.h>
-+#include <asm/sections.h>
-+#include <asm/ip5000.h>
-+
-+/*
-+ * Mask the debug printout for IPI because they are too verbose
-+ * for regular debugging.
-+ */
-+
-+// #define DEBUG_SMP 1
-+#if !defined(DEBUG_SMP)
-+#define smp_debug(lvl, ...)
-+#else
-+static unsigned int smp_debug_lvl = 50;
-+#define smp_debug(lvl, printargs...)          \
-+      if (lvl >= smp_debug_lvl) {             \
-+                      printk(printargs);      \
-+      }
-+#endif
-+
-+#if !defined(DEBUG_SMP)
-+#define DEBUG_ASSERT(cond)
-+#else
-+#define DEBUG_ASSERT(cond) \
-+      if (!(cond)) { \
-+              THREAD_STALL; \
-+      }
-+#endif
-+
-+/*
-+ * List of IPI Commands (more than one can be set at a time).
-+ */
-+enum ipi_message_type {
-+      IPI_NOP,
-+      IPI_RESCHEDULE,
-+      IPI_CALL_FUNC,
-+      IPI_CALL_FUNC_SINGLE,
-+      IPI_CPU_STOP,
-+      IPI_CPU_TIMER,
-+};
-+
-+/*
-+ * We maintain a hardware thread oriented view of online threads
-+ * and those involved or needing IPI.
-+ */
-+static volatile unsigned long smp_online_threads = 0;
-+static volatile unsigned long smp_needs_ipi = 0;
-+static volatile unsigned long smp_inside_ipi = 0;
-+static unsigned long smp_irq_affinity[NR_IRQS];
-+
-+/*
-+ * What do we need to track on a per cpu/thread basis?
-+ */
-+DEFINE_PER_CPU(struct cpuinfo_ubicom32, cpu_data);
-+
-+/*
-+ * Each thread cpuinfo IPI information is guarded by a lock
-+ * that is kept local to this file.
-+ */
-+DEFINE_PER_CPU(spinlock_t, ipi_lock) = SPIN_LOCK_UNLOCKED;
-+
-+/*
-+ * The IPI(s) are based on a software IRQ through the LDSR.
-+ */
-+unsigned int smp_ipi_irq;
-+
-+/*
-+ * Define a spinlock so that only one cpu is able to modify the
-+ * smp_needs_ipi and to set/clear the IRQ at a time.
-+ */
-+DEFINE_SPINLOCK(smp_ipi_lock);
-+
-+/*
-+ * smp_halt_processor()
-+ *    Halt this hardware thread.
-+ */
-+static void smp_halt_processor(void)
-+{
-+      int cpuid = thread_get_self();
-+      cpu_clear(smp_processor_id(), cpu_online_map);
-+      local_irq_disable();
-+      printk(KERN_EMERG "cpu[%d] has halted. It is not OK to turn off power \
-+              until all cpu's are off.\n", cpuid);
-+      for (;;) {
-+              thread_suspend();
-+      }
-+}
-+
-+/*
-+ * ipi_interrupt()
-+ *    Handle an Interprocessor Interrupt.
-+ */
-+static irqreturn_t ipi_interrupt(int irq, void *dev_id)
-+{
-+      int cpuid = smp_processor_id();
-+      struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid);
-+      unsigned long ops;
-+
-+      /*
-+       * Count this now; we may make a call that never returns.
-+       */
-+      p->ipi_count++;
-+
-+      /*
-+       * We are about to process all ops.  If another cpu has stated
-+       * that we need an IPI, we will have already processed it.  By
-+       * clearing our smp_needs_ipi, and processing all ops,
-+       * we reduce the number of IPI interrupts.  However, this introduces
-+       * the possibility that smp_needs_ipi will be clear and the soft irq
-+       * will have gone off; so we need to make the get_affinity() path
-+       * tolerant of spurious interrupts.
-+       */
-+      spin_lock(&smp_ipi_lock);
-+      smp_needs_ipi &= ~(1 << p->tid);
-+      spin_unlock(&smp_ipi_lock);
-+
-+      for (;;) {
-+              /*
-+               * Read the set of IPI commands we should handle.
-+               */
-+              spinlock_t *lock = &per_cpu(ipi_lock, cpuid);
-+              spin_lock(lock);
-+              ops = p->ipi_pending;
-+              p->ipi_pending = 0;
-+              spin_unlock(lock);
-+
-+              /*
-+               * If we have no IPI commands to execute, break out.
-+               */
-+              if (!ops) {
-+                      break;
-+              }
-+
-+              /*
-+               * Execute the set of commands in the ops word, one command
-+               * at a time in no particular order.  Strip of each command
-+               * as we execute it.
-+               */
-+              while (ops) {
-+                      unsigned long which = ffz(~ops);
-+                      ops &= ~(1 << which);
-+
-+                      BUG_ON(!irqs_disabled());
-+                      switch (which) {
-+                      case IPI_NOP:
-+                              smp_debug(100, KERN_INFO "cpu[%d]: "
-+                                        "IPI_NOP\n", cpuid);
-+                              break;
-+
-+                      case IPI_RESCHEDULE:
-+                              /*
-+                               * Reschedule callback.  Everything to be
-+                               * done is done by the interrupt return path.
-+                               */
-+                              smp_debug(200, KERN_INFO "cpu[%d]: "
-+                                        "IPI_RESCHEDULE\n", cpuid);
-+                              break;
-+
-+                      case IPI_CALL_FUNC:
-+                              smp_debug(100, KERN_INFO "cpu[%d]: "
-+                                        "IPI_CALL_FUNC\n", cpuid);
-+                              generic_smp_call_function_interrupt();
-+                              break;
-+
-+                      case IPI_CALL_FUNC_SINGLE:
-+                              smp_debug(100, KERN_INFO "cpu[%d]: "
-+                                        "IPI_CALL_FUNC_SINGLE\n", cpuid);
-+                              generic_smp_call_function_single_interrupt();
-+                              break;
-+
-+                      case IPI_CPU_STOP:
-+                              smp_debug(100, KERN_INFO "cpu[%d]: "
-+                                        "IPI_CPU_STOP\n", cpuid);
-+                              smp_halt_processor();
-+                              break;
-+
-+#if !defined(CONFIG_LOCAL_TIMERS)
-+                      case IPI_CPU_TIMER:
-+                              smp_debug(100, KERN_INFO "cpu[%d]: "
-+                                        "IPI_CPU_TIMER\n", cpuid);
-+#if defined(CONFIG_GENERIC_CLOCKEVENTS)
-+                              local_timer_interrupt();
-+#else
-+                              update_process_times(user_mode(get_irq_regs()));
-+                              profile_tick(CPU_PROFILING);
-+#endif
-+#endif
-+                              break;
-+
-+                      default:
-+                              printk(KERN_CRIT "cpu[%d]: "
-+                                        "Unknown IPI: %lu\n", cpuid, which);
-+
-+                              return IRQ_NONE;
-+                      }
-+
-+                      /*
-+                       * Let in any pending interrupts
-+                       */
-+                      BUG_ON(!irqs_disabled());
-+                      local_irq_enable();
-+                      local_irq_disable();
-+              }
-+      }
-+      return IRQ_HANDLED;
-+}
-+
-+/*
-+ * ipi_send()
-+ *    Send an Interprocessor Interrupt.
-+ */
-+static void ipi_send(int cpu, enum ipi_message_type op)
-+{
-+      struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpu);
-+      spinlock_t *lock = &per_cpu(ipi_lock, cpu);
-+      unsigned long flags;
-+
-+      /*
-+       * We protect the setting of the ipi_pending field and ensure
-+       * that the ipi delivery mechanism and interrupt are atomically
-+       * handled.
-+       */
-+      spin_lock_irqsave(lock, flags);
-+      p->ipi_pending |= 1 << op;
-+      spin_unlock_irqrestore(lock, flags);
-+
-+      spin_lock_irqsave(&smp_ipi_lock, flags);
-+      smp_needs_ipi |= (1 << p->tid);
-+      ubicom32_set_interrupt(smp_ipi_irq);
-+      spin_unlock_irqrestore(&smp_ipi_lock, flags);
-+      smp_debug(100, KERN_INFO "cpu[%d]: send: %d\n", cpu, op);
-+}
-+
-+/*
-+ * ipi_send_mask
-+ *    Send an IPI to each cpu in mask.
-+ */
-+static inline void ipi_send_mask(unsigned int op, const struct cpumask mask)
-+{
-+      int cpu;
-+      for_each_cpu_mask(cpu, mask) {
-+              ipi_send(cpu, op);
-+      }
-+}
-+
-+/*
-+ * ipi_send_allbutself()
-+ *    Send an IPI to all threads but ourselves.
-+ */
-+static inline void ipi_send_allbutself(unsigned int op)
-+{
-+      int self = smp_processor_id();
-+      struct cpumask result;
-+      cpumask_copy(&result, &cpu_online_map);
-+      cpu_clear(self, result);
-+      ipi_send_mask(op, result);
-+}
-+
-+/*
-+ * smp_enable_vector()
-+ */
-+static void smp_enable_vector(unsigned int irq)
-+{
-+      ubicom32_clear_interrupt(smp_ipi_irq);
-+      ldsr_enable_vector(irq);
-+}
-+
-+/*
-+ * smp_disable_vector()
-+ *    Disable the interrupt by clearing the appropriate bit in the
-+ *    LDSR Mask Register.
-+ */
-+static void smp_disable_vector(unsigned int irq)
-+{
-+      ldsr_disable_vector(irq);
-+}
-+
-+/*
-+ * smp_mask_vector()
-+ */
-+static void smp_mask_vector(unsigned int irq)
-+{
-+      ldsr_mask_vector(irq);
-+}
-+
-+/*
-+ * smp_unmask_vector()
-+ */
-+static void smp_unmask_vector(unsigned int irq)
-+{
-+      ldsr_unmask_vector(irq);
-+}
-+
-+/*
-+ * smp_end_vector()
-+ *    Called once an interrupt is completed (reset the LDSR mask).
-+ */
-+static void smp_end_vector(unsigned int irq)
-+{
-+      struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, smp_processor_id());
-+      spin_lock(&smp_ipi_lock);
-+      smp_inside_ipi &= ~(1 << p->tid);
-+      if (smp_inside_ipi) {
-+              spin_unlock(&smp_ipi_lock);
-+              return;
-+      }
-+      spin_unlock(&smp_ipi_lock);
-+      ldsr_unmask_vector(irq);
-+      smp_debug(100, KERN_INFO "cpu[%d]: unamesk vector\n", smp_processor_id());
-+}
-+
-+/*
-+ * Special hanlder functions for SMP.
-+ */
-+static struct irq_chip ubicom32_smp_chip = {
-+      .name           = "UbicoIPI",
-+      .startup        = NULL,
-+      .shutdown       = NULL,
-+      .enable         = smp_enable_vector,
-+      .disable        = smp_disable_vector,
-+      .ack            = NULL,
-+      .mask           = smp_mask_vector,
-+      .unmask         = smp_unmask_vector,
-+      .end            = smp_end_vector,
-+};
-+
-+/*
-+ * smp_reset_ipi()
-+ *    None of these cpu(s) got their IPI, turn it back on.
-+ *
-+ * Note: This is called by the LDSR which is not a full
-+ * Linux cpu.  Thus you must use the raw form of locks
-+ * because lock debugging will not work on the partial
-+ * cpu nature of the LDSR.
-+ */
-+void smp_reset_ipi(unsigned long mask)
-+{
-+      __raw_spin_lock(&smp_ipi_lock.raw_lock);
-+      smp_needs_ipi |= mask;
-+      smp_inside_ipi &= ~mask;
-+      ubicom32_set_interrupt(smp_ipi_irq);
-+      __raw_spin_unlock(&smp_ipi_lock.raw_lock);
-+      smp_debug(100, KERN_INFO "smp: reset IPIs for: 0x%x\n", mask);
-+}
-+
-+/*
-+ * smp_get_affinity()
-+ *    Choose the thread affinity for this interrupt.
-+ *
-+ * Note: This is called by the LDSR which is not a full
-+ * Linux cpu.  Thus you must use the raw form of locks
-+ * because lock debugging will not work on the partial
-+ * cpu nature of the LDSR.
-+ */
-+unsigned long smp_get_affinity(unsigned int irq, int *all)
-+{
-+      unsigned long mask = 0;
-+
-+      /*
-+       * Most IRQ(s) are delivered in a round robin fashion.
-+       */
-+      if (irq != smp_ipi_irq) {
-+              unsigned long result = smp_irq_affinity[irq] & smp_online_threads;
-+              DEBUG_ASSERT(result);
-+              *all = 0;
-+              return result;
-+      }
-+
-+      /*
-+       * This is an IPI request.  Return all cpu(s) scheduled for an IPI.
-+       * We also track those cpu(s) that are going to be "receiving" IPI this
-+       * round.  When all CPU(s) have called smp_end_vector(),
-+       * we will unmask the IPI interrupt.
-+       */
-+      __raw_spin_lock(&smp_ipi_lock.raw_lock);
-+      ubicom32_clear_interrupt(smp_ipi_irq);
-+      if (smp_needs_ipi) {
-+              mask = smp_needs_ipi;
-+              smp_inside_ipi |= smp_needs_ipi;
-+              smp_needs_ipi = 0;
-+      }
-+      __raw_spin_unlock(&smp_ipi_lock.raw_lock);
-+      *all = 1;
-+      return mask;
-+}
-+
-+/*
-+ *  smp_set_affinity()
-+ *    Set the affinity for this irq but store the value in tid(s).
-+ */
-+void smp_set_affinity(unsigned int irq, const struct cpumask *dest)
-+{
-+      int cpuid;
-+      unsigned long *paffinity = &smp_irq_affinity[irq];
-+
-+      /*
-+       *  If none specified, all cpus are allowed.
-+       */
-+      if (cpus_empty(*dest)) {
-+              *paffinity = 0xffffffff;
-+              return;
-+      }
-+
-+      /*
-+       * Make sure to clear the old value before setting up the
-+       * list.
-+       */
-+      *paffinity = 0;
-+      for_each_cpu_mask(cpuid, *dest) {
-+              struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid);
-+              *paffinity |= (1 << p->tid);
-+      }
-+}
-+
-+/*
-+ * smp_send_stop()
-+ *    Send a stop request to all CPU but this one.
-+ */
-+void smp_send_stop(void)
-+{
-+      ipi_send_allbutself(IPI_CPU_STOP);
-+}
-+
-+/*
-+ * smp_send_timer_all()
-+ *    Send all cpu(s) but this one, a request to update times.
-+ */
-+void smp_send_timer_all(void)
-+{
-+      ipi_send_allbutself(IPI_CPU_TIMER);
-+}
-+
-+/*
-+ * smp_timer_broadcast()
-+ *    Use an IPI to broadcast a timer message
-+ */
-+void smp_timer_broadcast(const struct cpumask *mask)
-+{
-+      ipi_send_mask(IPI_CPU_TIMER, *mask);
-+}
-+
-+/*
-+ * smp_send_reschedule()
-+ *    Send a reschedule request to the specified cpu.
-+ */
-+void smp_send_reschedule(int cpu)
-+{
-+      ipi_send(cpu, IPI_RESCHEDULE);
-+}
-+
-+/*
-+ * arch_send_call_function_ipi()
-+ *    Cause each cpu in the mask to call the generic function handler.
-+ */
-+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
-+{
-+      int cpu;
-+      for_each_cpu_mask(cpu, *mask) {
-+              ipi_send(cpu, IPI_CALL_FUNC);
-+      }
-+}
-+
-+/*
-+ * arch_send_call_function_single_ipi()
-+ *    Cause the specified cpu to call the generic function handler.
-+ */
-+void arch_send_call_function_single_ipi(int cpu)
-+{
-+      ipi_send(cpu, IPI_CALL_FUNC_SINGLE);
-+}
-+
-+/*
-+ * setup_profiling_timer()
-+ *    Dummy function created to keep Oprofile happy in the SMP case.
-+ */
-+int setup_profiling_timer(unsigned int multiplier)
-+{
-+      return 0;
-+}
-+
-+/*
-+ * smp_mainline_start()
-+ *    Start a slave thread executing a mainline Linux context.
-+ */
-+static void __init smp_mainline_start(void *arg)
-+{
-+      int cpuid = smp_processor_id();
-+      struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid);
-+
-+      BUG_ON(p->tid != thread_get_self());
-+
-+      /*
-+       * Well, support 2.4 linux scheme as well.
-+       */
-+      if (cpu_test_and_set(cpuid, cpu_online_map)) {
-+              printk(KERN_CRIT "cpu[%d]: already initialized!\n", cpuid);
-+              smp_halt_processor();
-+              return;
-+      }
-+
-+      /*
-+       * Initialise the idle task for this CPU
-+       */
-+      atomic_inc(&init_mm.mm_count);
-+      current->active_mm = &init_mm;
-+      if (current->mm) {
-+              printk(KERN_CRIT "cpu[%d]: idle task already has memory "
-+                     "management\n", cpuid);
-+              smp_halt_processor();
-+              return;
-+      }
-+
-+      /*
-+       * TODO: X86 does this prior to calling notify, try to understand why?
-+       */
-+      preempt_disable();
-+
-+#if defined(CONFIG_GENERIC_CLOCKEVENTS)
-+      /*
-+       * Setup a local timer event so that this cpu will get timer interrupts
-+       */
-+      if (local_timer_setup(cpuid) == -1) {
-+              printk(KERN_CRIT "cpu[%d]: timer alloc failed\n", cpuid);
-+              smp_halt_processor();
-+              return;
-+      }
-+#endif
-+
-+      /*
-+       * Notify those interested that we are up and alive.  This must
-+       * be done before interrupts are enabled.  It must also be completed
-+       * before the bootstrap cpu returns from __cpu_up() (see comment
-+       * above cpu_set() of the cpu_online_map).
-+       */
-+      notify_cpu_starting(cpuid);
-+
-+      /*
-+       * Indicate that this thread is now online and present.   Setting
-+       * cpu_online_map has the side effect of allowing the bootstrap
-+       * cpu to continue along; so anything that MUST be done prior to the
-+       * bootstrap cpu returning from __cpu_up() needs to go above here.
-+       */
-+      cpu_set(cpuid, cpu_online_map);
-+      cpu_set(cpuid, cpu_present_map);
-+
-+      /*
-+       * Maintain a thread mapping in addition to the cpu mapping.
-+       */
-+      smp_online_threads |= (1 << p->tid);
-+
-+      /*
-+       * Enable interrupts for this thread.
-+       */
-+      local_irq_enable();
-+
-+      /*
-+       * Enter the idle loop and wait for a timer to schedule some work.
-+       */
-+      printk(KERN_INFO "cpu[%d]: entering cpu_idle()\n", cpuid);
-+      cpu_idle();
-+
-+      /* Not Reached */
-+}
-+
-+/*
-+ * smp_cpus_done()
-+ *    Called once the kernel_init() has brought up all cpu(s).
-+ */
-+void smp_cpus_done(unsigned int cpu_max)
-+{
-+      /* Do Nothing */
-+}
-+
-+/*
-+ * __cpu_up()
-+ *    Called to startup a sepcific cpu.
-+ */
-+int __cpuinit __cpu_up(unsigned int cpu)
-+{
-+      struct task_struct *idle;
-+      unsigned int *stack;
-+      long timeout;
-+      struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpu);
-+
-+      /*
-+       * Create an idle task for this CPU.
-+       */
-+      idle = fork_idle(cpu);
-+      if (IS_ERR(idle)) {
-+              panic("cpu[%d]: fork failed\n", cpu);
-+              return -ENOSYS;
-+      }
-+      task_thread_info(idle)->cpu = cpu;
-+
-+      /*
-+       * Setup the sw_ksp[] to point to this new task.
-+       */
-+      sw_ksp[p->tid] = (unsigned int)idle->stack;
-+      stack = (unsigned int *)(sw_ksp[p->tid] + PAGE_SIZE - 8);
-+
-+      /*
-+       * Cause the specified thread to execute our smp_mainline_start
-+       * function as a TYPE_NORMAL thread.
-+       */
-+      printk(KERN_INFO "cpu[%d]: launching mainline Linux thread\n", cpu);
-+      if (thread_start(p->tid, smp_mainline_start, (void *)NULL, stack,
-+                       THREAD_TYPE_NORMAL) == -1) {
-+              printk(KERN_WARNING "cpu[%d]: failed thread_start\n", cpu);
-+              return -ENOSYS;
-+      }
-+
-+      /*
-+       * Wait for the thread to start up.  The thread will set
-+       * the online bit when it is running.  Our caller execpts the
-+       * cpu to be online if we return 0.
-+       */
-+      for (timeout = 0; timeout < 10000; timeout++) {
-+              if (cpu_online(cpu)) {
-+                      break;
-+              }
-+
-+              udelay(100);
-+              barrier();
-+              continue;
-+      }
-+
-+      if (!cpu_online(cpu)) {
-+              printk(KERN_CRIT "cpu[%d]: failed to live after %ld us\n",
-+                     cpu, timeout * 100);
-+              return -ENOSYS;
-+      }
-+
-+      printk(KERN_INFO "cpu[%d]: came alive after %ld us\n",
-+             cpu, timeout * 100);
-+      return 0;
-+}
-+
-+/*
-+ * Data used by setup_irq for the IPI.
-+ */
-+static struct irqaction ipi_irq = {
-+      .name    = "ipi",
-+      .flags   = IRQF_DISABLED | IRQF_PERCPU,
-+      .handler = ipi_interrupt,
-+};
-+
-+/*
-+ * smp_prepare_cpus()
-+ *    Mark threads that are available to Linux as possible cpus(s).
-+ */
-+void __init smp_prepare_cpus(unsigned int max_cpus)
-+{
-+      int i;
-+
-+      /*
-+       * We will need a software IRQ to send IPI(s).  We will use
-+       * a single software IRQ for all IPI(s).
-+       */
-+      if (irq_soft_alloc(&smp_ipi_irq) < 0) {
-+              panic("no software IRQ is available\n");
-+              return;
-+      }
-+
-+      /*
-+       * For the IPI interrupt, we want to use our own chip definition.
-+       * This allows us to define what happens in SMP IPI without affecting
-+       * the performance of the other interrupts.
-+       *
-+       * Next, Register the IPI interrupt function against the soft IRQ.
-+       */
-+      set_irq_chip(smp_ipi_irq, &ubicom32_smp_chip);
-+      setup_irq(smp_ipi_irq, &ipi_irq);
-+
-+      /*
-+       * We use the device tree node to determine how many
-+       * free cpus we will have (up to NR_CPUS) and we indicate
-+       * that those cpus are present.
-+       *
-+       * We need to do this very early in the SMP case
-+       * because the Linux init code uses the cpu_present_map.
-+       */
-+      for_each_possible_cpu(i) {
-+              thread_t tid;
-+              struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, i);
-+
-+              /*
-+               *  Skip the bootstrap cpu
-+               */
-+              if (i == 0) {
-+                      continue;
-+              }
-+
-+              /*
-+               * If we have a free thread left in the mask,
-+               * indicate that the cpu is present.
-+               */
-+              tid = thread_alloc();
-+              if (tid == (thread_t)-1) {
-+                      break;
-+              }
-+
-+              /*
-+               * Save the hardware thread id for this cpu.
-+               */
-+              p->tid = tid;
-+              cpu_set(i, cpu_present_map);
-+              printk(KERN_INFO "cpu[%d]: added to cpu_present_map - tid: %d\n", i, tid);
-+      }
-+}
-+
-+/*
-+ * smp_prepare_boot_cpu()
-+ *    Copy the per_cpu data into the appropriate spot for the bootstrap cpu.
-+ *
-+ * The code in boot_cpu_init() has already set the boot cpu's
-+ * state in the possible, present, and online maps.
-+ */
-+void __devinit smp_prepare_boot_cpu(void)
-+{
-+      struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, 0);
-+
-+      smp_online_threads |= (1 << p->tid);
-+      printk(KERN_INFO "cpu[%d]: bootstrap CPU online - tid: %ld\n",
-+                      current_thread_info()->cpu, p->tid);
-+}
-+
-+/*
-+ * smp_setup_processor_id()
-+ *    Set the current_thread_info() structure cpu value.
-+ *
-+ * We set the value to the true hardware thread value that we are running on.
-+ * NOTE: this function overrides the weak alias function in main.c
-+ */
-+void __init smp_setup_processor_id(void)
-+{
-+      struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, 0);
-+      int i;
-+      for_each_cpu_mask(i, CPU_MASK_ALL)
-+              set_cpu_possible(i, true);
-+
-+      current_thread_info()->cpu = 0;
-+      p->tid = thread_get_self();
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/stacktrace.c
-@@ -0,0 +1,244 @@
-+/*
-+ * arch/ubicom32/kernel/stacktrace.c
-+ *   Ubicom32 architecture stack back trace implementation.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/sched.h>
-+#include <linux/stacktrace.h>
-+#include <linux/module.h>
-+#include <asm/stacktrace.h>
-+#include <asm/thread.h>
-+#include <asm/ip5000.h>
-+
-+/*
-+ * These symbols are filled in by the linker.
-+ */
-+extern unsigned long _stext;
-+extern unsigned long _etext;
-+
-+extern unsigned long __ocm_text_run_begin;
-+extern unsigned long __data_begin;
-+
-+/*
-+ * stacktrace_iterate()
-+ *    Walk the stack looking for call and calli instructions on an aligned
-+ *    boundary.
-+ *
-+ * Trace must point to the top of the current stack frame.
-+ */
-+unsigned long stacktrace_iterate(unsigned long **trace,
-+                               unsigned long stext,
-+                               unsigned long etext,
-+                               unsigned long ocm_stext,
-+                               unsigned long ocm_etext,
-+                               unsigned long sstack,
-+                               unsigned long estack)
-+{
-+      unsigned int thread_trap_en, instruction;
-+      unsigned long address;
-+      unsigned int limit = 0;
-+      unsigned long result = 0;
-+      unsigned long *sp = *trace;
-+
-+      /*
-+       * Exclude the current thread from being monitored for traps.
-+       */
-+      asm volatile(
-+              "       thread_get_self_mask d15                \n\t"
-+                      /* save current trap status */
-+              "       and.4   %0, MT_TRAP_EN, d15             \n\t"
-+              "       not.4   d15, d15                        \n\t"
-+                      /* disable trap */
-+              "       and.4   MT_TRAP_EN, MT_TRAP_EN, d15     \n\t"
-+              "       pipe_flush 0                            \n\t"
-+              : "=r" (thread_trap_en)
-+              :
-+              : "d15", "cc"
-+      );
-+
-+      while (limit++ < 256) {
-+              /*
-+               * See if we have a valid stack.
-+               */
-+              if (!between((unsigned long)sp, sstack, estack)) {
-+#ifdef TRAP_DEBUG_STACK_TRACE
-+                      printk(KERN_EMERG "stack address is out of range - "
-+                             "sp: %x, sstack: %x, estack: %x\n",
-+                             (unsigned int)sp, (unsigned int)sstack,
-+                             (unsigned int)estack);
-+#endif
-+                      result = 0;
-+                      *trace = 0;
-+                      break;
-+              }
-+
-+              /*
-+               * Get the value off the stack and back up 4 bytes to what
-+               * should be the address of a call or calli.
-+               */
-+              address = (*sp++) - 4;
-+
-+              /*
-+               * If the address is not within the text segment, skip this
-+               * value.
-+               */
-+              if (!between(address, stext, etext) &&
-+                  !between(address, ocm_stext, ocm_etext)) {
-+#ifdef TRAP_DEBUG_STACK_TRACE
-+                      printk(KERN_EMERG "not a text address - "
-+                             "address: %08x, stext: %08x, etext: %08x\n"
-+                             "ocm_stext: %08x, ocm_etext: %08x\n",
-+                             (unsigned int)address,
-+                             (unsigned int)stext,
-+                             (unsigned int)etext,
-+                             (unsigned int)ocm_stext,
-+                             (unsigned int)ocm_etext);
-+#endif
-+                      continue;
-+
-+              }
-+
-+              /*
-+               * If the address is not on an aligned boundary it can not be a
-+               * return address.
-+               */
-+              if (address & 0x3) {
-+                      continue;
-+              }
-+
-+              /*
-+               * Read the probable instruction.
-+               */
-+              instruction = *(unsigned int *)address;
-+
-+              /*
-+               * Is this a call instruction?
-+               */
-+              if ((instruction & 0xF8000000) == (u32_t)(0x1B << 27)) {
-+#ifdef TRAP_DEBUG_STACK_TRACE
-+                      printk(KERN_EMERG "call inst. result: %x, "
-+                             "test: %x\n", (unsigned int)address,
-+                             (unsigned int)instruction);
-+#endif
-+                      *trace = sp;
-+                      result = address;
-+                      break;
-+              }
-+
-+              /*
-+               * Is this a calli instruction?
-+               */
-+              if ((instruction & 0xF8000000) == (u32_t)(0x1E << 27)) {
-+#ifdef TRAP_DEBUG_STACK_TRACE
-+                      printk(KERN_EMERG "calli inst. result: %x, "
-+                             "test: %x\n", (unsigned int)address,
-+                             (unsigned int)instruction);
-+#endif
-+                      *trace = sp;
-+                      result = address;
-+                      break;
-+              }
-+      }
-+
-+      /*
-+       * Restore the current thread to be monitored for traps.
-+       */
-+      if (thread_trap_en) {
-+              asm volatile(
-+              "       thread_get_self_mask d15                \n\t"
-+              "       or.4    MT_TRAP_EN, MT_TRAP_EN, d15     \n\t"
-+                      :
-+                      :
-+                      : "d15", "cc"
-+              );
-+      }
-+      return result;
-+}
-+
-+#ifdef CONFIG_STACKTRACE
-+/*
-+ * stacktrace_save_entries()
-+ *    Save stack back trace information into the provided trace structure.
-+ */
-+void stacktrace_save_entries(struct task_struct *tsk,
-+                           struct stack_trace *trace,
-+                           unsigned long sp)
-+{
-+      unsigned long code_start = (unsigned long)&_stext;
-+      unsigned long code_end = (unsigned long)&_etext;
-+      unsigned long ocm_code_start = (unsigned long)&__ocm_text_run_begin;
-+      unsigned long ocm_code_end = (unsigned long)&__data_begin;
-+      unsigned long stack_end = (unsigned long)(tsk->stack + THREAD_SIZE - 8);
-+      unsigned long stack = (unsigned long)sp;
-+      unsigned int idx = 0;
-+      unsigned long *handle;
-+      int skip = trace->skip;
-+
-+      handle = (unsigned long *)stack;
-+      while (idx < trace->max_entries) {
-+              if (skip) {
-+                      skip--;
-+                      continue;
-+              }
-+              trace->entries[idx] = stacktrace_iterate(&handle,
-+                                      code_start, code_end,
-+                                      ocm_code_start, ocm_code_end,
-+                                      (unsigned long)stack, stack_end);
-+              if (trace->entries[idx] == 0) {
-+                      break;
-+              }
-+              idx++;
-+      }
-+}
-+
-+/*
-+ * save_stack_trace()
-+ *    Save the specified amount of the kernel stack trace information
-+ *    for the current task.
-+ */
-+void save_stack_trace(struct stack_trace *trace)
-+{
-+      unsigned long sp = 0;
-+      asm volatile (
-+      "       move.4  %0, SP          \n\t"
-+              : "=r" (sp)
-+      );
-+      stacktrace_save_entries(current, trace, sp);
-+}
-+EXPORT_SYMBOL_GPL(save_stack_trace);
-+
-+/*
-+ * save_stack_trace_tsk()
-+ *    Save the specified amount of the kernel stack trace information
-+ *    for the specified task.
-+ *
-+ * Note: We assume the specified task is not currently running.
-+ */
-+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
-+{
-+      stacktrace_save_entries(tsk, trace, tsk->thread.sp);
-+}
-+EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
-+#endif /* CONFIG_STACKTRACE */
---- /dev/null
-+++ b/arch/ubicom32/kernel/syscalltable.S
-@@ -0,0 +1,376 @@
-+/*
-+ * arch/ubicom32/kernel/syscalltable.S
-+ *    <TODO: Replace with short file description>
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+/*
-+ *
-+ *  Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com)
-+ *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>, Kenneth Albanowski <kjahds@kjahds.com>,
-+ *  Copyright (C) 2000  Lineo Inc. (www.lineo.com)
-+ *  Copyright (C) 1991, 1992  Linus Torvalds
-+ */
-+
-+#include <linux/sys.h>
-+#include <linux/linkage.h>
-+#include <asm/unistd.h>
-+
-+.text
-+ALIGN
-+      .global sys_call_table
-+sys_call_table:
-+      .long sys_ni_syscall    /* 0  -  old "setup()" system call*/
-+      .long sys_exit
-+      .long sys_fork
-+      .long sys_read
-+      .long sys_write
-+      .long sys_open          /* 5 */
-+      .long sys_close
-+      .long sys_waitpid
-+      .long sys_creat
-+      .long sys_link
-+      .long sys_unlink        /* 10 */
-+      .long execve_intercept
-+      .long sys_chdir
-+      .long sys_time
-+      .long sys_mknod
-+      .long sys_chmod         /* 15 */
-+      .long sys_chown16
-+      .long sys_ni_syscall    /* old break syscall holder */
-+      .long sys_stat
-+      .long sys_lseek
-+      .long sys_getpid        /* 20 */
-+      .long sys_mount
-+      .long sys_oldumount
-+      .long sys_setuid16
-+      .long sys_getuid16
-+      .long sys_stime         /* 25 */
-+      .long sys_ptrace
-+      .long sys_alarm
-+      .long sys_fstat
-+      .long sys_pause
-+      .long sys_utime         /* 30 */
-+      .long sys_ni_syscall    /* old stty syscall holder */
-+      .long sys_ni_syscall    /* old gtty syscall holder */
-+      .long sys_access
-+      .long sys_nice
-+      .long sys_ni_syscall    /* 35 */ /* old ftime syscall holder */
-+      .long sys_sync
-+      .long sys_kill
-+      .long sys_rename
-+      .long sys_mkdir
-+      .long sys_rmdir         /* 40 */
-+      .long sys_dup
-+      .long sys_pipe
-+      .long sys_times
-+      .long sys_ni_syscall    /* old prof syscall holder */
-+      .long sys_brk           /* 45 */
-+      .long sys_setgid16
-+      .long sys_getgid16
-+      .long sys_signal
-+      .long sys_geteuid16
-+      .long sys_getegid16     /* 50 */
-+      .long sys_acct
-+      .long sys_umount        /* recycled never used phys() */
-+      .long sys_ni_syscall    /* old lock syscall holder */
-+      .long sys_ioctl
-+      .long sys_fcntl         /* 55 */
-+      .long sys_ni_syscall    /* old mpx syscall holder */
-+      .long sys_setpgid
-+      .long sys_ni_syscall    /* old ulimit syscall holder */
-+      .long sys_ni_syscall
-+      .long sys_umask         /* 60 */
-+      .long sys_chroot
-+      .long sys_ustat
-+      .long sys_dup2
-+      .long sys_getppid
-+      .long sys_getpgrp       /* 65 */
-+      .long sys_setsid
-+      .long sys_sigaction
-+      .long sys_sgetmask
-+      .long sys_ssetmask
-+      .long sys_setreuid16    /* 70 */
-+      .long sys_setregid16
-+      .long sys_sigsuspend
-+      .long sys_sigpending
-+      .long sys_sethostname
-+      .long sys_setrlimit     /* 75 */
-+      .long sys_old_getrlimit
-+      .long sys_getrusage
-+      .long sys_gettimeofday
-+      .long sys_settimeofday
-+      .long sys_getgroups16   /* 80 */
-+      .long sys_setgroups16
-+      .long old_select
-+      .long sys_symlink
-+      .long sys_lstat
-+      .long sys_readlink      /* 85 */
-+      .long sys_uselib
-+      .long sys_ni_syscall    /* _sys_swapon */
-+      .long sys_reboot
-+      .long sys_old_readdir
-+      .long old_mmap          /* 90 */
-+      .long sys_munmap
-+      .long sys_truncate
-+      .long sys_ftruncate
-+      .long sys_fchmod
-+      .long sys_fchown16      /* 95 */
-+      .long sys_getpriority
-+      .long sys_setpriority
-+      .long sys_ni_syscall    /* old profil syscall holder */
-+      .long sys_statfs
-+      .long sys_fstatfs       /* 100 */
-+      .long sys_ni_syscall    /* ioperm for i386 */
-+      .long sys_socketcall
-+      .long sys_syslog
-+      .long sys_setitimer
-+      .long sys_getitimer     /* 105 */
-+      .long sys_newstat
-+      .long sys_newlstat
-+      .long sys_newfstat
-+      .long sys_ni_syscall
-+      .long sys_ni_syscall    /* iopl for i386 */ /* 110 */
-+      .long sys_vhangup
-+      .long sys_ni_syscall    /* obsolete idle() syscall */
-+      .long sys_ni_syscall    /* vm86old for i386 */
-+      .long sys_wait4
-+      .long sys_ni_syscall    /* 115 */ /* _sys_swapoff */
-+      .long sys_sysinfo
-+      .long sys_ipc
-+      .long sys_fsync
-+      .long sys_sigreturn
-+      .long clone_intercept   /* 120 */
-+      .long sys_setdomainname
-+      .long sys_newuname
-+      .long sys_cacheflush    /* modify_ldt for i386 */
-+      .long sys_adjtimex
-+      .long sys_ni_syscall    /* 125 */ /* _sys_mprotect */
-+      .long sys_sigprocmask
-+      .long sys_ni_syscall    /* old "creat_module" */
-+      .long sys_init_module
-+      .long sys_delete_module
-+      .long sys_ni_syscall    /* 130: old "get_kernel_syms" */
-+      .long sys_quotactl
-+      .long sys_getpgid
-+      .long sys_fchdir
-+      .long sys_bdflush
-+      .long sys_sysfs         /* 135 */
-+      .long sys_personality
-+      .long sys_ni_syscall    /* for afs_syscall */
-+      .long sys_setfsuid16
-+      .long sys_setfsgid16
-+      .long sys_llseek        /* 140 */
-+      .long sys_getdents
-+      .long sys_select
-+      .long sys_flock
-+      .long sys_ni_syscall    /* _sys_msync */
-+      .long sys_readv         /* 145 */
-+      .long sys_writev
-+      .long sys_getsid
-+      .long sys_fdatasync
-+      .long sys_sysctl
-+      .long sys_ni_syscall    /* 150 */ /* _sys_mlock */
-+      .long sys_ni_syscall    /* _sys_munlock */
-+      .long sys_ni_syscall    /* _sys_mlockall */
-+      .long sys_ni_syscall    /* _sys_munlockall */
-+      .long sys_sched_setparam
-+      .long sys_sched_getparam /* 155 */
-+      .long sys_sched_setscheduler
-+      .long sys_sched_getscheduler
-+      .long sys_sched_yield
-+      .long sys_sched_get_priority_max
-+      .long sys_sched_get_priority_min  /* 160 */
-+      .long sys_sched_rr_get_interval
-+      .long sys_nanosleep
-+      .long sys_ni_syscall    /* _sys_mremap */
-+      .long sys_setresuid16
-+      .long sys_getresuid16   /* 165 */
-+      .long sys_getpagesize   /* _sys_getpagesize */
-+      .long sys_ni_syscall    /* old "query_module" */
-+      .long sys_poll
-+      .long sys_ni_syscall    /* _sys_nfsservctl */
-+      .long sys_setresgid16   /* 170 */
-+      .long sys_getresgid16
-+      .long sys_prctl
-+      .long sys_rt_sigreturn
-+      .long sys_rt_sigaction
-+      .long sys_rt_sigprocmask /* 175 */
-+      .long sys_rt_sigpending
-+      .long sys_rt_sigtimedwait
-+      .long sys_rt_sigqueueinfo
-+      .long sys_rt_sigsuspend
-+      .long sys_pread64       /* 180 */
-+      .long sys_pwrite64
-+      .long sys_lchown16
-+      .long sys_getcwd
-+      .long sys_capget
-+      .long sys_capset        /* 185 */
-+      .long sys_sigaltstack
-+      .long sys_sendfile
-+      .long sys_ni_syscall    /* streams1 */
-+      .long sys_ni_syscall    /* streams2 */
-+      .long vfork_intercept           /* 190 */
-+      .long sys_getrlimit
-+      .long sys_mmap2
-+      .long sys_truncate64
-+      .long sys_ftruncate64
-+      .long sys_stat64        /* 195 */
-+      .long sys_lstat64
-+      .long sys_fstat64
-+      .long sys_chown
-+      .long sys_getuid
-+      .long sys_getgid        /* 200 */
-+      .long sys_geteuid
-+      .long sys_getegid
-+      .long sys_setreuid
-+      .long sys_setregid
-+      .long sys_getgroups     /* 205 */
-+      .long sys_setgroups
-+      .long sys_fchown
-+      .long sys_setresuid
-+      .long sys_getresuid
-+      .long sys_setresgid     /* 210 */
-+      .long sys_getresgid
-+      .long sys_lchown
-+      .long sys_setuid
-+      .long sys_setgid
-+      .long sys_setfsuid      /* 215 */
-+      .long sys_setfsgid
-+      .long sys_pivot_root
-+      .long sys_ni_syscall
-+      .long sys_ni_syscall
-+      .long sys_getdents64    /* 220 */
-+      .long sys_gettid
-+      .long sys_tkill
-+      .long sys_setxattr
-+      .long sys_lsetxattr
-+      .long sys_fsetxattr     /* 225 */
-+      .long sys_getxattr
-+      .long sys_lgetxattr
-+      .long sys_fgetxattr
-+      .long sys_listxattr
-+      .long sys_llistxattr    /* 230 */
-+      .long sys_flistxattr
-+      .long sys_removexattr
-+      .long sys_lremovexattr
-+      .long sys_fremovexattr
-+      .long sys_futex         /* 235 */
-+      .long sys_sendfile64
-+      .long sys_ni_syscall    /* _sys_mincore */
-+      .long sys_ni_syscall    /* _sys_madvise */
-+      .long sys_fcntl64
-+      .long sys_readahead     /* 240 */
-+      .long sys_io_setup
-+      .long sys_io_destroy
-+      .long sys_io_getevents
-+      .long sys_io_submit
-+      .long sys_io_cancel     /* 245 */
-+      .long sys_fadvise64
-+      .long sys_exit_group
-+      .long sys_lookup_dcookie
-+      .long sys_epoll_create
-+      .long sys_epoll_ctl     /* 250 */
-+      .long sys_epoll_wait
-+      .long sys_ni_syscall    /* _sys_remap_file_pages */
-+      .long sys_set_tid_address
-+      .long sys_timer_create
-+      .long sys_timer_settime /* 255 */
-+      .long sys_timer_gettime
-+      .long sys_timer_getoverrun
-+      .long sys_timer_delete
-+      .long sys_clock_settime
-+      .long sys_clock_gettime /* 260 */
-+      .long sys_clock_getres
-+      .long sys_clock_nanosleep
-+      .long sys_statfs64
-+      .long sys_fstatfs64
-+      .long sys_tgkill        /* 265 */
-+      .long sys_utimes
-+      .long sys_fadvise64_64
-+      .long sys_mbind
-+      .long sys_get_mempolicy
-+      .long sys_set_mempolicy /* 270 */
-+      .long sys_mq_open
-+      .long sys_mq_unlink
-+      .long sys_mq_timedsend
-+      .long sys_mq_timedreceive
-+      .long sys_mq_notify     /* 275 */
-+      .long sys_mq_getsetattr
-+      .long sys_waitid
-+      .long sys_ni_syscall    /* for _sys_vserver */
-+      .long sys_add_key
-+      .long sys_request_key   /* 280 */
-+      .long sys_keyctl
-+      .long sys_ioprio_set
-+      .long sys_ioprio_get
-+      .long sys_inotify_init
-+      .long sys_inotify_add_watch     /* 285 */
-+      .long sys_inotify_rm_watch
-+      .long sys_migrate_pages
-+      .long sys_openat
-+      .long sys_mkdirat
-+      .long sys_mknodat               /* 290 */
-+      .long sys_fchownat
-+      .long sys_futimesat
-+      .long sys_fstatat64
-+      .long sys_unlinkat
-+      .long sys_renameat              /* 295 */
-+      .long sys_linkat
-+      .long sys_symlinkat
-+      .long sys_readlinkat
-+      .long sys_fchmodat
-+      .long sys_faccessat             /* 300 */
-+      .long sys_ni_syscall            /* Reserved for pselect6 */
-+      .long sys_ni_syscall            /* Reserved for ppoll */
-+      .long sys_unshare
-+      .long sys_set_robust_list
-+      .long sys_get_robust_list       /* 305 */
-+      .long sys_splice
-+      .long sys_sync_file_range
-+      .long sys_tee
-+      .long sys_vmsplice
-+      .long sys_move_pages            /* 310 */
-+      .long sys_sched_setaffinity
-+      .long sys_sched_getaffinity
-+      .long sys_kexec_load
-+      .long sys_getcpu
-+      .long sys_epoll_pwait           /* 315 */
-+      .long sys_utimensat
-+      .long sys_signalfd
-+      .long sys_timerfd_create
-+      .long sys_eventfd
-+      .long sys_fallocate             /* 320 */
-+      .long sys_timerfd_settime
-+      .long sys_timerfd_gettime
-+      .long sys_ni_syscall            /* sys_signalfd4 */
-+      .long sys_ni_syscall            /* sys_eventfd2 */
-+      .long sys_ni_syscall            /* sys_epoll_create1 */
-+                                      /* 325 */
-+      .long sys_ni_syscall            /* sys_dup3 */
-+      .long sys_ni_syscall            /* sys_pipe2 */
-+      .long sys_ni_syscall            /* sys_inotify_init1 */
-+      .rept NR_syscalls-(.-sys_call_table)/4
-+              .long sys_ni_syscall
-+      .endr
---- /dev/null
-+++ b/arch/ubicom32/kernel/sys_ubicom32.c
-@@ -0,0 +1,237 @@
-+/*
-+ * arch/ubicom32/kernel/sys_ubicom32.c
-+ *   Ubicom32 architecture system call support implementation.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *
-+ * This file contains various random system calls that
-+ * have a non-standard calling sequence on the Linux/ubicom32
-+ * platform.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/sched.h>
-+#include <linux/mm.h>
-+#include <linux/smp.h>
-+#include <linux/sem.h>
-+#include <linux/msg.h>
-+#include <linux/shm.h>
-+#include <linux/stat.h>
-+#include <linux/syscalls.h>
-+#include <linux/mman.h>
-+#include <linux/file.h>
-+#include <linux/utsname.h>
-+#include <linux/ipc.h>
-+#include <linux/fs.h>
-+#include <linux/uaccess.h>
-+#include <linux/unistd.h>
-+
-+#include <asm/setup.h>
-+#include <asm/traps.h>
-+#include <asm/cacheflush.h>
-+
-+/* common code for old and new mmaps */
-+static inline long do_mmap2(
-+      unsigned long addr, unsigned long len,
-+      unsigned long prot, unsigned long flags,
-+      unsigned long fd, unsigned long pgoff)
-+{
-+      int error = -EBADF;
-+      struct file *file = NULL;
-+
-+      flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-+      if (!(flags & MAP_ANONYMOUS)) {
-+              file = fget(fd);
-+              if (!file)
-+                      goto out;
-+      }
-+
-+      down_write(&current->mm->mmap_sem);
-+      error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-+      up_write(&current->mm->mmap_sem);
-+
-+      if (file)
-+              fput(file);
-+out:
-+      return error;
-+}
-+
-+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-+      unsigned long prot, unsigned long flags,
-+      unsigned long fd, unsigned long pgoff)
-+{
-+      return do_mmap2(addr, len, prot, flags, fd, pgoff);
-+}
-+
-+/*
-+ * Perform the select(nd, in, out, ex, tv) and mmap() system
-+ * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to
-+ * handle more than 4 system call parameters, so these system calls
-+ * used a memory block for parameter passing..
-+ */
-+
-+struct mmap_arg_struct {
-+      unsigned long addr;
-+      unsigned long len;
-+      unsigned long prot;
-+      unsigned long flags;
-+      unsigned long fd;
-+      unsigned long offset;
-+};
-+
-+asmlinkage int old_mmap(struct mmap_arg_struct *arg)
-+{
-+      struct mmap_arg_struct a;
-+      int error = -EFAULT;
-+
-+      if (copy_from_user(&a, arg, sizeof(a)))
-+              goto out;
-+
-+      error = -EINVAL;
-+      if (a.offset & ~PAGE_MASK)
-+              goto out;
-+
-+      a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-+
-+      error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd,
-+                       a.offset >> PAGE_SHIFT);
-+out:
-+      return error;
-+}
-+
-+struct sel_arg_struct {
-+      unsigned long n;
-+      fd_set *inp, *outp, *exp;
-+      struct timeval *tvp;
-+};
-+
-+asmlinkage int old_select(struct sel_arg_struct *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 int sys_ipc(uint call, int first, int second,
-+                      int third, void *ptr, long fifth)
-+{
-+      int version, ret;
-+
-+      version = call >> 16; /* hack for backward compatibility */
-+      call &= 0xffff;
-+
-+      if (call <= SEMCTL)
-+              switch (call) {
-+              case SEMOP:
-+                      return sys_semop(first, (struct sembuf *)ptr, second);
-+              case SEMGET:
-+                      return sys_semget(first, second, third);
-+              case SEMCTL: {
-+                      union semun fourth;
-+                      if (!ptr)
-+                              return -EINVAL;
-+                      if (get_user(fourth.__pad, (void **) ptr))
-+                              return -EFAULT;
-+                      return sys_semctl(first, second, third, fourth);
-+                      }
-+              default:
-+                      return -EINVAL;
-+              }
-+      if (call <= MSGCTL)
-+              switch (call) {
-+              case MSGSND:
-+                      return sys_msgsnd(first, (struct msgbuf *) 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 *)ptr,
-+                                                 sizeof(tmp)))
-+                                      return -EFAULT;
-+                              return sys_msgrcv(first, tmp.msgp, second,
-+                                                 tmp.msgtyp, third);
-+                              }
-+                      default:
-+                              return sys_msgrcv(first,
-+                                                (struct msgbuf *) ptr,
-+                                                second, fifth, third);
-+                      }
-+              case MSGGET:
-+                      return sys_msgget((key_t) first, second);
-+              case MSGCTL:
-+                      return sys_msgctl(first, second,
-+                                         (struct msqid_ds *) ptr);
-+              default:
-+                      return -EINVAL;
-+              }
-+      if (call <= SHMCTL)
-+              switch (call) {
-+              case SHMAT:
-+                      switch (version) {
-+                      default: {
-+                              ulong raddr;
-+                              ret = do_shmat(first, ptr, second, &raddr);
-+                              if (ret)
-+                                      return ret;
-+                              return put_user(raddr, (ulong __user *) third);
-+                      }
-+                      }
-+              case SHMDT:
-+                      return sys_shmdt(ptr);
-+              case SHMGET:
-+                      return sys_shmget(first, second, third);
-+              case SHMCTL:
-+                      return sys_shmctl(first, second, ptr);
-+              default:
-+                      return -ENOSYS;
-+              }
-+
-+      return -EINVAL;
-+}
-+
-+/* sys_cacheflush -- flush (part of) the processor cache.  */
-+asmlinkage int
-+sys_cacheflush(unsigned long addr, int scope, int cache, unsigned long len)
-+{
-+      flush_cache_all();
-+      return 0;
-+}
-+
-+asmlinkage int sys_getpagesize(void)
-+{
-+      return PAGE_SIZE;
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/thread.c
-@@ -0,0 +1,228 @@
-+/*
-+ * arch/ubicom32/kernel/thread.c
-+ *   Ubicom32 architecture hardware thread support.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/sched.h>
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
-+#include <linux/profile.h>
-+#include <linux/clocksource.h>
-+#include <linux/types.h>
-+#include <asm/ip5000.h>
-+#include <asm/machdep.h>
-+#include <asm/asm-offsets.h>
-+#include <asm/thread.h>
-+
-+/*
-+ * TODO: At some point change the name here to be thread_ksp
-+ */
-+unsigned int sw_ksp[THREAD_ARCHITECTURAL_MAX];
-+
-+static unsigned int thread_mask = -1;
-+static unsigned int thread_mainline_mask;
-+
-+/*
-+ * thread_entry()
-+ *    Returning from the called function will disable the thread.
-+ *
-+ * This could be a naked call to allow for hwthreads that do not have stacks.
-+ * However, with -O0, the code still writes to thex stack, and this was
-+ * corrupting memory just after the callers stack.
-+ */
-+static void thread_entry(void *arg, thread_exec_fn_t exec)
-+{
-+      /*
-+       * Call thread function
-+       */
-+      exec(arg);
-+
-+      /*
-+       * Complete => Disable self
-+       */
-+      thread_disable(thread_get_self());
-+}
-+
-+/*
-+ * thread_start()
-+ *    Start the specified function on the specified hardware thread.
-+ */
-+thread_t thread_start(thread_t thread,
-+                    thread_exec_fn_t exec,
-+                    void *arg,
-+                    unsigned int *sp_high,
-+                    thread_type_t type)
-+{
-+      /*
-+       * Sanity check
-+       */
-+      unsigned int enabled, mask, csr;
-+      asm volatile (
-+              "move.4         %0, MT_EN\n\t"
-+              : "=m" (enabled)
-+      );
-+
-+      mask = 1 << thread;
-+      if (enabled & mask) {
-+              printk(KERN_WARNING "request to enable a previously enabled thread\n");
-+              return (thread_t)-1;
-+      }
-+
-+      /*
-+       * Update thread state
-+       */
-+      csr = (thread << 15) | (1 << 14);
-+      asm volatile (
-+              "setcsr         %0              \n\t"
-+              "setcsr_flush   0               \n\t"
-+
-+              "move.4         A0, #0          \n\t"
-+              "move.4         A1, #0          \n\t"
-+              "move.4         A2, #0          \n\t"
-+              "move.4         A3, #0          \n\t"
-+              "move.4         A4, #0          \n\t"
-+              "move.4         A5, #0          \n\t"
-+              "move.4         A6, #0          \n\t"
-+              "move.4         SP, %4          \n\t"   /* A7 is SP */
-+
-+              "move.4         D0, %3          \n\t"
-+              "move.4         D1, %2          \n\t"
-+              "move.4         D2, #0          \n\t"
-+              "move.4         D3, #0          \n\t"
-+              "move.4         D4, #0          \n\t"
-+              "move.4         D5, #0          \n\t"
-+              "move.4         D6, #0          \n\t"
-+              "move.4         D7, #0          \n\t"
-+              "move.4         D8, #0          \n\t"
-+              "move.4         D9, #0          \n\t"
-+              "move.4         D10, #0         \n\t"
-+              "move.4         D11, #0         \n\t"
-+              "move.4         D12, #0         \n\t"
-+              "move.4         D13, #0         \n\t"
-+              "move.4         D14, #0         \n\t"
-+              "move.4         D15, #0         \n\t"
-+
-+              "move.4         INT_MASK0, #0   \n\t"
-+              "move.4         INT_MASK1, #0   \n\t"
-+              "move.4         PC, %1          \n\t"
-+              "setcsr         #0              \n\t"
-+              "setcsr_flush   0               \n\t"
-+              :
-+              : "r" (csr), "r" (thread_entry), "r" (exec),
-+                "r" (arg), "r" (sp_high)
-+      );
-+
-+      /*
-+       * Apply HRT state
-+       */
-+      if (type & THREAD_TYPE_HRT) {
-+              asm volatile (
-+                      "or.4           MT_HRT, MT_HRT, %0\n\t"
-+                      :
-+                      : "d" (mask)
-+                      : "cc"
-+              );
-+      } else {
-+              asm volatile (
-+                      "and.4          MT_HRT, MT_HRT, %0\n\t"
-+                      :
-+                      : "d" (~mask)
-+                      : "cc"
-+              );
-+      }
-+
-+      /*
-+       * Set priority
-+       */
-+      asm volatile (
-+              "or.4           MT_HPRI, MT_HPRI, %0\n\t"
-+              :
-+              : "d" (mask)
-+              : "cc"
-+      );
-+
-+      /*
-+       * Enable thread
-+       */
-+      asm volatile (
-+              "move.4         MT_ACTIVE_SET, %0       \n\t"
-+              :
-+              : "d" (mask)
-+      );
-+      thread_enable_mask(mask);
-+      return thread;
-+}
-+
-+/*
-+ * thread_get_mainline()
-+ *    Return a mask of those threads that are Linux mainline threads.
-+ */
-+unsigned int thread_get_mainline(void)
-+{
-+      return thread_mainline_mask;
-+}
-+
-+/*
-+ * thread_set_mainline()
-+ *    Indicate that the specified thread is a Linux mainline thread.
-+ */
-+void thread_set_mainline(thread_t tid)
-+{
-+      thread_mainline_mask |= (1 << tid);
-+}
-+
-+/*
-+ * thread_alloc()
-+ *    Allocate an unused hardware thread.
-+ */
-+thread_t thread_alloc(void)
-+{
-+      thread_t tid;
-+
-+      /*
-+       * If this is the first time we are here get the list of unused
-+       * threads from the processor device tree node.
-+       */
-+      if (thread_mask == -1) {
-+              thread_mask = processor_threads();
-+      }
-+
-+      if (!thread_mask) {
-+              return (thread_t)-1;
-+      }
-+
-+      tid = ffs(thread_mask);
-+      if (tid != 0) {
-+              tid--;
-+              thread_mask &= ~(1 << tid);
-+              return tid;
-+      }
-+
-+      return (thread_t)-1;
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/time.c
-@@ -0,0 +1,212 @@
-+/*
-+ * arch/ubicom32/kernel/time.c
-+ *    Initialize the timer list and start the appropriate timers.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 1991, 1992, 1995  Linus Torvalds
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/profile.h>
-+#include <linux/smp.h>
-+#include <asm/ip5000.h>
-+#include <asm/machdep.h>
-+
-+/*
-+ * A bitmap of the timers on the processor indicates
-+ * that the timer is free or in-use.
-+ */
-+static unsigned int timers;
-+
-+/*
-+ * timer_set()
-+ *    Init the specified compare register to go off <n> cycles from now.
-+ */
-+void timer_set(int timervector, unsigned int cycles)
-+{
-+      int idx = UBICOM32_VECTOR_TO_TIMER_INDEX(timervector);
-+      UBICOM32_IO_TIMER->syscom[idx] =
-+                      UBICOM32_IO_TIMER->sysval + cycles;
-+      ldsr_enable_vector(timervector);
-+}
-+
-+/*
-+ * timer_reset()
-+ *    Set/reset the timer to go off again.
-+ *
-+ * Because sysval is a continuous timer, this function is able
-+ * to ensure that we do not have clock sku by using the previous
-+ * value in syscom to set the next value for syscom.
-+ *
-+ * Returns the number of ticks that transpired since the last event.
-+ */
-+int timer_reset(int timervector, unsigned int cycles)
-+{
-+      /*
-+       * Reset the timer in the LDSR thread to go off appropriately.
-+       *
-+       * Use the previous value of the timer to calculate the new stop
-+       * time.  This allows us to account for it taking an
-+       * indeterminate amount of time to get here.
-+       */
-+      const int timer_index = UBICOM32_VECTOR_TO_TIMER_INDEX(timervector);
-+      unsigned int prev = UBICOM32_IO_TIMER->syscom[timer_index];
-+      unsigned int next = prev + cycles;
-+      int scratchpad3;
-+      int diff;
-+      int ticks = 1;
-+
-+      /*
-+       * If the difference is negative, we have missed at least one
-+       * timer tick.
-+       *
-+       * TODO: Decide if we want to "ignore" time (as done below) or
-+       * if we want to process time (unevenly) by calling timer_tick()
-+       * lost_ticks times.
-+       */
-+      while (1) {
-+              /*
-+               * Set our future time first.
-+               */
-+              UBICOM32_IO_TIMER->syscom[timer_index] = next;
-+
-+              /*
-+               * Then check if we are really set time in the futrue.
-+               */
-+              diff = (int)next - (int)UBICOM32_IO_TIMER->sysval;
-+              if (diff >= 0) {
-+                      break;
-+              }
-+
-+              /*
-+               * Oops, we are too slow. Playing catch up.
-+               *
-+               * If the debugger is connected the there is a good
-+               * chance that we lost time because we were in a
-+               * break-point, so in this case we do not print out
-+               * diagnostics.
-+               */
-+              asm volatile ("move.4 %0, scratchpad3"
-+                            : "=r" (scratchpad3));
-+              if ((scratchpad3 & 0x1) == 0) {
-+                      /*
-+                       * No debugger attached, print to the console
-+                       */
-+                      printk(KERN_EMERG "diff: %d, timer has lost %u "
-+                             "ticks [rounded up]\n",
-+                             -diff,
-+                             (unsigned int)((-diff + cycles - 1) / cycles));
-+              }
-+
-+              do {
-+                      next += cycles;
-+                      diff = (int)next - (int)UBICOM32_IO_TIMER->sysval;
-+                      ticks++;
-+              } while (diff < 0);
-+      }
-+      return ticks;
-+}
-+
-+/*
-+ * sched_clock()
-+ *    Returns current time in nano-second units.
-+ *
-+ * Notes:
-+ * 1) This is an override for the weak alias in
-+ * kernel/sched_clock.c.
-+ * 2) Do not use xtime_lock as this function is
-+ * sometimes called with xtime_lock held.
-+ * 3) We use a retry algorithm to ensure that
-+ * we get a consistent value.
-+ * 4) sched_clock must be overwritten if IRQ tracing
-+ * is enabled because the default implementation uses
-+ * the xtime_lock sequence while holding xtime_lock.
-+ */
-+unsigned long long sched_clock(void)
-+{
-+      unsigned long long my_jiffies;
-+      unsigned long jiffies_top;
-+      unsigned long jiffies_bottom;
-+
-+      do {
-+              jiffies_top = jiffies_64 >> 32;
-+              jiffies_bottom = jiffies_64 & 0xffffffff;
-+      } while (unlikely(jiffies_top != (unsigned long)(jiffies_64 >> 32)));
-+
-+      my_jiffies = ((unsigned long long)jiffies_top << 32) | (jiffies_bottom);
-+      return (my_jiffies - INITIAL_JIFFIES) * (NSEC_PER_SEC / HZ);
-+}
-+
-+/*
-+ * timer_free()
-+ *    Free a hardware timer.
-+ */
-+void timer_free(int interrupt)
-+{
-+      unsigned int bit = interrupt - TIMER_INT(0);
-+
-+      /*
-+       * The timer had not been allocated.
-+       */
-+      BUG_ON(timers & (1 << bit));
-+      timers |= (1 << bit);
-+}
-+
-+/*
-+ * timer_alloc()
-+ *    Allocate a hardware timer.
-+ */
-+int timer_alloc(void)
-+{
-+      unsigned int bit = find_first_bit((unsigned long *)&timers, 32);
-+      if (!bit) {
-+              printk(KERN_WARNING "no more free timers\n");
-+              return -1;
-+      }
-+
-+      timers &= ~(1 << bit);
-+      return bit + TIMER_INT(0);
-+}
-+
-+/*
-+ * time_init()
-+ *    Time init function.
-+ */
-+void time_init(void)
-+{
-+      /*
-+       * Find the processor node and determine what timers are
-+       * available for us.
-+       */
-+      timers = processor_timers();
-+      if (timers == 0) {
-+              printk(KERN_WARNING "no timers are available for Linux\n");
-+              return;
-+      }
-+
-+#ifdef CONFIG_GENERIC_CLOCKEVENTS
-+      timer_device_init();
-+#else
-+      timer_tick_init();
-+#endif
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/timer_broadcast.c
-@@ -0,0 +1,102 @@
-+/*
-+ * arch/ubicom32/kernel/timer_broadcast.c
-+ *   Implements a dummy clock event for each cpu.
-+ *
-+ * Copyright (C) 2008  Paul Mundt
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *   arch/arm
-+ *   arch/sh
-+ */
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/smp.h>
-+#include <linux/jiffies.h>
-+#include <linux/percpu.h>
-+#include <linux/clockchips.h>
-+#include <linux/irq.h>
-+
-+static DEFINE_PER_CPU(struct clock_event_device, local_clockevent);
-+
-+/*
-+ *  The broadcast trick only works when the timer will be used in a periodic mode.
-+ *  If the user has configured either NO_HZ or HIGH_RES_TIMERS they must have
-+ *  a per cpu timer.
-+ */
-+#if defined(CONFIG_NO_HZ) || defined(CONFIG_HIGH_RES_TIMERS)
-+#error "Tickless and High Resolution Timers require per-CPU local timers: CONFIG_LOCAL_TIMERS"
-+#endif
-+
-+/*
-+ * local_timer_interrupt()
-+ *    Used on SMP for local timer interrupt sent via an IPI.
-+ */
-+void local_timer_interrupt(void)
-+{
-+      struct clock_event_device *dev = &__get_cpu_var(local_clockevent);
-+
-+      dev->event_handler(dev);
-+}
-+
-+/*
-+ * dummy_timer_set_next_event()
-+ *    Cause the timer to go off "cycles" from now.
-+ */
-+static int dummy_timer_set_next_event(unsigned long cycles, struct clock_event_device *dev)
-+{
-+      return 0;
-+}
-+
-+/*
-+ * dummy_timer_set_mode()
-+ *    Do Nothing.
-+ */
-+static void dummy_timer_set_mode(enum clock_event_mode mode,
-+                               struct clock_event_device *clk)
-+{
-+}
-+
-+/*
-+ * local_timer_setup()
-+ *    Adds a clock event for the specified cpu.
-+ */
-+int __cpuinit local_timer_setup(unsigned int cpu)
-+{
-+      struct clock_event_device *dev = &per_cpu(local_clockevent, cpu);
-+
-+      dev->name               = "timer-dummy";
-+      dev->features           = CLOCK_EVT_FEAT_DUMMY;
-+      dev->rating             = 200;
-+      dev->mult               = 1;
-+      dev->set_mode           = dummy_timer_set_mode;
-+      dev->set_next_event     = dummy_timer_set_next_event;
-+      dev->broadcast          = smp_timer_broadcast;
-+      dev->cpumask            = cpumask_of_cpu(cpu);
-+      dev->irq                = -1;
-+      printk(KERN_NOTICE "timer[%d]: %s - created\n", dev->irq, dev->name);
-+
-+      clockevents_register_device(dev);
-+      return 0;
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/timer_device.c
-@@ -0,0 +1,301 @@
-+/*
-+ * arch/ubicom32/kernel/timer_device.c
-+ *   Implements a Ubicom32 clock device and event devices.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/types.h>
-+#include <linux/clockchips.h>
-+#include <linux/clocksource.h>
-+#include <linux/spinlock.h>
-+#include <asm/ip5000.h>
-+#include <asm/machdep.h>
-+
-+#if defined(CONFIG_SMP)
-+#include <asm/smp.h>
-+#endif
-+
-+#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
-+#define MAX_TIMERS (2 + CONFIG_TIMER_EXTRA_ALLOC)
-+#else
-+#define MAX_TIMERS (NR_CPUS + CONFIG_TIMER_EXTRA_ALLOC)
-+#endif
-+
-+#if (MAX_TIMERS > 10)
-+#error "Ubicom32 only has 10 timers"
-+#endif
-+
-+static unsigned int frequency;
-+static struct clock_event_device timer_device_devs[MAX_TIMERS];
-+static struct irqaction timer_device_irqs[MAX_TIMERS];
-+static int timer_device_next_timer = 0;
-+
-+DEFINE_SPINLOCK(timer_device_lock);
-+
-+/*
-+ * timer_device_set_next_event()
-+ *    Cause the timer to go off "cycles" from now.
-+ */
-+static int timer_device_set_next_event(unsigned long cycles, struct clock_event_device *dev)
-+{
-+      timer_set(dev->irq, cycles);
-+      return 0;
-+}
-+
-+/*
-+ * timer_device_set_mode()
-+ *    Handle the mode switch for a clock event device.
-+ */
-+static void timer_device_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
-+{
-+      switch (mode) {
-+      case CLOCK_EVT_MODE_SHUTDOWN:
-+              /*
-+               * Make sure the vector is disabled
-+               * until the next event is set.
-+               */
-+              printk(KERN_NOTICE "timer[%d]: shutdown\n", dev->irq);
-+              ldsr_disable_vector(dev->irq);
-+              break;
-+
-+      case CLOCK_EVT_MODE_ONESHOT:
-+              /*
-+               * Make sure the vector is disabled
-+               * until the next event is set.
-+               */
-+              printk(KERN_NOTICE "timer[%d]: oneshot\n", dev->irq);
-+              ldsr_disable_vector(dev->irq);
-+              break;
-+
-+      case CLOCK_EVT_MODE_PERIODIC:
-+              /*
-+               * The periodic request is 1 per jiffies
-+               */
-+              printk(KERN_NOTICE "timer[%d]: periodic: %d cycles\n",
-+                      dev->irq, frequency / CONFIG_HZ);
-+              timer_set(dev->irq, frequency / CONFIG_HZ);
-+              break;
-+
-+      case CLOCK_EVT_MODE_UNUSED:
-+      case CLOCK_EVT_MODE_RESUME:
-+              printk(KERN_WARNING "timer[%d]: unimplemented mode: %d\n",
-+                      dev->irq, mode);
-+              break;
-+      };
-+}
-+
-+/*
-+ * timer_device_event()
-+ *    Call the device's event handler.
-+ *
-+ * The pointer is initialized by the generic Linux code
-+ * to the function to be called.
-+ */
-+static irqreturn_t timer_device_event(int irq, void *dev_id)
-+{
-+      struct clock_event_device *dev = (struct clock_event_device *)dev_id;
-+
-+      if (dev->mode == CLOCK_EVT_MODE_PERIODIC) {
-+              /*
-+               * The periodic request is 1 per jiffies
-+               */
-+              timer_reset(dev->irq, frequency / CONFIG_HZ);
-+      } else {
-+              /*
-+               * The timer will go off again at the rollover
-+               * point.  We must disable the IRQ to prevent
-+               * getting a spurious interrupt.
-+               */
-+              ldsr_disable_vector(dev->irq);
-+      }
-+
-+      if (!dev->event_handler) {
-+              printk(KERN_CRIT "no registered event handler\n");
-+              return IRQ_HANDLED;
-+      }
-+
-+      dev->event_handler(dev);
-+      return IRQ_HANDLED;
-+}
-+
-+/*
-+ * timer_device_clockbase_read()
-+ *    Provide a primary clocksource around the sysval timer.
-+ */
-+static cycle_t timer_device_clockbase_read(void)
-+{
-+      return (cycle_t)UBICOM32_IO_TIMER->sysval;
-+}
-+
-+/*
-+ * Primary Clock Source Description
-+ *
-+ * We use 24 for the shift factor because we want
-+ * to ensure there are less than 2^24 clocks
-+ * in a jiffie of 10 ms.
-+ */
-+static struct clocksource timer_device_clockbase = {
-+      .name   = "sysval",
-+      .rating = 400,
-+      .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
-+      .mask   = CLOCKSOURCE_MASK(32),
-+      .shift  = 24,
-+      .mult   = 0,
-+      .read   = timer_device_clockbase_read,
-+};
-+
-+/*
-+ * timer_device_alloc_event()
-+ *    Allocate a timer device event.
-+ */
-+static int timer_device_alloc_event(const char *name, int cpuid, const cpumask_t *mask)
-+{
-+      struct clock_event_device *dev;
-+      struct irqaction *action;
-+
-+      /*
-+       * Are we out of configured timers?
-+       */
-+      spin_lock(&timer_device_lock);
-+      if (timer_device_next_timer >= MAX_TIMERS) {
-+              spin_unlock(&timer_device_lock);
-+              printk(KERN_WARNING "out of timer event entries\n");
-+              return -1;
-+      }
-+      dev = &timer_device_devs[timer_device_next_timer];
-+      action = &timer_device_irqs[timer_device_next_timer];
-+      timer_device_next_timer++;
-+      spin_unlock(&timer_device_lock);
-+
-+      /*
-+       * Now allocate a timer to ourselves.
-+       */
-+      dev->irq = timer_alloc();
-+      if (dev->irq == -1) {
-+              spin_lock(&timer_device_lock);
-+              timer_device_next_timer--;
-+              spin_unlock(&timer_device_lock);
-+              printk(KERN_WARNING "out of hardware timers\n");
-+              return -1;
-+      }
-+
-+      /*
-+       * Init the IRQ action structure.  Make sure
-+       * this in place before you register the clock
-+       * event device.
-+       */
-+      action->name = name;
-+      action->flags = IRQF_DISABLED | IRQF_TIMER;
-+      action->handler = timer_device_event;
-+      cpumask_copy(&action->mask, mask);
-+      action->dev_id = dev;
-+      setup_irq(dev->irq, action);
-+      irq_set_affinity(dev->irq, mask);
-+      ldsr_disable_vector(dev->irq);
-+
-+      /*
-+       * init clock dev structure.
-+       *
-+       * The min_delta_ns is chosen to ensure that setting next
-+       * event will never be requested with too small of value.
-+       */
-+      dev->name = name;
-+      dev->rating = timer_device_clockbase.rating;
-+      dev->shift = timer_device_clockbase.shift;
-+      dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
-+      dev->set_mode = timer_device_set_mode;
-+      dev->set_next_event = timer_device_set_next_event;
-+      dev->mult = div_sc(frequency, NSEC_PER_SEC, dev->shift);
-+      dev->max_delta_ns = clockevent_delta2ns(0xffffffff, dev);
-+      dev->min_delta_ns = clockevent_delta2ns(100, dev);
-+      dev->cpumask = mask;
-+      printk(KERN_NOTICE "timer[%d]: %s - created\n", dev->irq, dev->name);
-+
-+      /*
-+       * Now register the device.
-+       */
-+      clockevents_register_device(dev);
-+      return dev->irq;
-+}
-+
-+#if defined(CONFIG_LOCAL_TIMERS)
-+/*
-+ * local_timer_setup()
-+ *    Allocation function for creating a per cpu local timer.
-+ */
-+int __cpuinit local_timer_setup(unsigned int cpu)
-+{
-+      return timer_device_alloc_event("timer-cpu", cpu, cpumask_of(cpu));
-+}
-+#endif
-+
-+/*
-+ * timer_device_init()
-+ *    Create and init a generic clock driver for Ubicom32.
-+ */
-+void timer_device_init(void)
-+{
-+      int i;
-+
-+      /*
-+       * Get the frequency from the processor device tree node or use
-+       * the default if not available. We will store this as the frequency
-+       * of the timer to avoid future calculations.
-+       */
-+      frequency = processor_frequency();
-+      if (frequency == 0) {
-+              frequency = CLOCK_TICK_RATE;
-+      }
-+
-+      /*
-+       * Setup the primary clock source around sysval.  Linux does not
-+       * supply a Mhz multiplier so convert down to khz.
-+       */
-+      timer_device_clockbase.mult =
-+              clocksource_khz2mult(frequency / 1000,
-+                      timer_device_clockbase.shift);
-+      if (clocksource_register(&timer_device_clockbase)) {
-+              printk(KERN_ERR "timer: clocksource failed to register\n");
-+              return;
-+      }
-+
-+      /*
-+       * Always allocate a primary timer.
-+       */
-+      timer_device_alloc_event("timer-primary", -1, CPU_MASK_ALL_PTR);
-+
-+#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
-+      /*
-+       * If BROADCAST is selected we need to add a broadcast timer.
-+       */
-+      timer_device_alloc_event("timer-broadcast", -1, CPU_MASK_ALL_PTR);
-+#endif
-+
-+      /*
-+       * Allocate extra timers that are requested.
-+       */
-+      for (i = 0; i < CONFIG_TIMER_EXTRA_ALLOC; i++) {
-+              timer_device_alloc_event("timer-extra", -1, CPU_MASK_ALL_PTR);
-+      }
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/timer_tick.c
-@@ -0,0 +1,109 @@
-+/*
-+ * arch/ubicom32/kernel/timer_tick.c
-+ *    Impelemets a perodic timer.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 1991, 1992, 1995  Linus Torvalds
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/profile.h>
-+
-+#include <asm/ip5000.h>
-+#include <asm/machdep.h>
-+#if defined(CONFIG_SMP)
-+#include <asm/smp.h>
-+#endif
-+
-+static unsigned int timervector;
-+static unsigned int frequency;
-+
-+/*
-+ * timer_tick()
-+ *    Kernel system timer support. Needs to keep up the real-time clock,
-+ *    as well as call the "do_timer()" routine every clocktick.
-+ */
-+static irqreturn_t timer_tick(int irq, void *dummy)
-+{
-+      int ticks;
-+
-+      BUG_ON(!irqs_disabled());
-+      ticks = timer_reset(timervector, frequency);
-+
-+      write_seqlock(&xtime_lock);
-+      do_timer(ticks);
-+      write_sequnlock(&xtime_lock);
-+
-+      update_process_times(user_mode(get_irq_regs()));
-+      profile_tick(CPU_PROFILING);
-+
-+#if defined(CONFIG_SMP)
-+      smp_send_timer_all();
-+#endif
-+      return(IRQ_HANDLED);
-+}
-+
-+/*
-+ * Data used by setup_irq for the timer.
-+ */
-+static struct irqaction timer_irq = {
-+      .name    = "timer",
-+      .flags   = IRQF_DISABLED | IRQF_TIMER,
-+      .handler = timer_tick,
-+};
-+
-+/*
-+ * timer_tick_init()
-+ *    Implements a periodic timer
-+ *
-+ * This implementation directly calls the timer_tick() and move
-+ * the Linux kernel forward.  This is used when the user has not
-+ * selected GENERIC_CLOCKEVENTS.
-+ */
-+void timer_tick_init(void)
-+{
-+      /*
-+       * Now allocate a timer to ourselves.
-+       */
-+      timervector = timer_alloc();
-+      if (timervector == -1) {
-+              printk(KERN_WARNING "where did the timer go?\n");
-+              return;
-+      }
-+
-+      setup_irq(timervector, &timer_irq);
-+
-+      /*
-+       * Get the frequency from the processor device tree node or use
-+       * the default if not available. We will store this as the frequency
-+       * of the timer to avoid future calculations.
-+       */
-+      frequency = processor_frequency();
-+      if (frequency == 0) {
-+              frequency = CLOCK_TICK_RATE;
-+      }
-+      frequency /= CONFIG_HZ;
-+
-+      printk(KERN_NOTICE "timer will interrupt every: %d cycles\n", frequency);
-+      timer_set(timervector, frequency);
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/topology.c
-@@ -0,0 +1,47 @@
-+/*
-+ * arch/ubicom32/kernel/topology.c
-+ *   Ubicom32 architecture sysfs topology information.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/smp.h>
-+#include <linux/cpu.h>
-+#include <linux/cache.h>
-+
-+static struct cpu cpu_devices[NR_CPUS] __read_mostly;
-+
-+static int __init topology_init(void)
-+{
-+      int num;
-+
-+      for_each_present_cpu(num) {
-+              cpu_devices[num].hotpluggable = 0;
-+              register_cpu(&cpu_devices[num], num);
-+      }
-+      return 0;
-+}
-+
-+subsys_initcall(topology_init);
---- /dev/null
-+++ b/arch/ubicom32/kernel/traps.c
-@@ -0,0 +1,514 @@
-+/*
-+ * arch/ubicom32/kernel/traps.c
-+ *   Ubicom32 architecture trap handling support.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+/*
-+ * Sets up all exception vectors
-+ */
-+#include <linux/sched.h>
-+#include <linux/signal.h>
-+#include <linux/kernel.h>
-+#include <linux/mm.h>
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/a.out.h>
-+#include <linux/user.h>
-+#include <linux/string.h>
-+#include <linux/linkage.h>
-+#include <linux/init.h>
-+#include <linux/ptrace.h>
-+#include <linux/kallsyms.h>
-+#include <linux/compiler.h>
-+#include <linux/stacktrace.h>
-+#include <linux/personality.h>
-+
-+#include <asm/uaccess.h>
-+#include <asm/stacktrace.h>
-+#include <asm/devtree.h>
-+#include <asm/setup.h>
-+#include <asm/fpu.h>
-+#include <asm/system.h>
-+#include <asm/traps.h>
-+#include <asm/pgtable.h>
-+#include <asm/processor.h>
-+#include <asm/machdep.h>
-+#include <asm/siginfo.h>
-+#include <asm/ip5000.h>
-+#include <asm/thread.h>
-+
-+#define TRAP_MAX_STACK_DEPTH 20
-+
-+/*
-+ * These symbols are filled in by the linker.
-+ */
-+extern unsigned long _stext;
-+extern unsigned long _etext;
-+
-+extern unsigned long __ocm_text_run_begin;
-+extern unsigned long __data_begin;
-+
-+extern void show_vmas(struct task_struct *task);
-+
-+const char *trap_cause_strings[] = {
-+      /*0*/   "inst address decode error",
-+      /*1*/   "inst sync error",
-+      /*2*/   "inst illegal",
-+      /*3*/   "src1 address decode error",
-+      /*4*/   "dst address decode error",
-+      /*5*/   "src1 alignment error",
-+      /*6*/   "dst alignment error",
-+      /*7*/   "src1 sync error",
-+      /*8*/   "dst sync error",
-+      /*9*/   "DCAPT error",
-+      /*10*/  "inst range error",
-+      /*11*/  "src1 range error",
-+      /*12*/  "dst range error",
-+};
-+
-+/*
-+ * The device tree trap node definition.
-+ */
-+struct trapnode {
-+      struct devtree_node dn;
-+      unsigned int intthread;
-+};
-+
-+static struct trapnode *tn;;
-+
-+/*
-+ * trap_interrupt_handler()
-+ *    Software Interrupt to ensure that a trap is serviced.
-+ */
-+static irqreturn_t trap_interrupt_handler(int irq, void *dummy)
-+{
-+      /* Do Nothing */
-+      return IRQ_HANDLED;
-+}
-+
-+/*
-+ * Data used by setup_irq for the timer.
-+ */
-+static struct irqaction trap_irq = {
-+      .name    = "trap",
-+      .flags   = IRQF_DISABLED,
-+      .handler = trap_interrupt_handler,
-+};
-+
-+/*
-+ * trap_cause_to_str()
-+ *    Convert a trap_cause into a series of printk
-+ */
-+static void trap_cause_to_str(long status)
-+{
-+      int bit;
-+
-+      if ((status & ((1 << TRAP_CAUSE_TOTAL) - 1)) == 0) {
-+              printk(KERN_NOTICE "decode: UNKNOWN CAUSES\n");
-+              return;
-+      }
-+
-+      for (bit = 0; bit < TRAP_CAUSE_TOTAL; bit++) {
-+              if (status & (1 << bit)) {
-+                      printk(KERN_NOTICE "\tdecode: %08x %s\n",
-+                             1 << bit, trap_cause_strings[bit]);
-+              }
-+      }
-+}
-+
-+/*
-+ * trap_print_information()
-+ *    Print the cause of the trap and additional info.
-+ */
-+static void trap_print_information(const char *str, struct pt_regs *regs)
-+{
-+      printk(KERN_WARNING "\n");
-+
-+      if (current) {
-+              printk(KERN_WARNING "Process %s (pid: %d)\n",
-+                      current->comm, current->pid);
-+      }
-+
-+      if (current && current->mm) {
-+              printk(KERN_NOTICE "text = 0x%p-0x%p  data = 0x%p-0x%p\n"
-+                      KERN_NOTICE "bss = 0x%p-0x%p   user-stack = 0x%p\n"
-+                      KERN_NOTICE "\n",
-+                      (void *)current->mm->start_code,
-+                      (void *)current->mm->end_code,
-+                      (void *)current->mm->start_data,
-+                      (void *)current->mm->end_data,
-+                      (void *)current->mm->end_data,
-+                      (void *)current->mm->brk,
-+                      (void *)current->mm->start_stack);
-+      }
-+
-+      printk(KERN_WARNING "%s: Causes: 0x%08x\n", str,
-+                      (unsigned int)regs->trap_cause);
-+      trap_cause_to_str(regs->trap_cause);
-+      show_regs(regs);
-+      show_stack(NULL, (unsigned long *)regs->an[7]);
-+      printk(KERN_NOTICE "--- End Trap --- \n");
-+}
-+
-+/*
-+ * dump_stack()
-+ *    Dump the stack of the current task.
-+ */
-+void dump_stack(void)
-+{
-+      show_stack(NULL, NULL);
-+}
-+EXPORT_SYMBOL(dump_stack);
-+
-+/*
-+ * show_stack()
-+ *    Print out information from the current stack.
-+ */
-+void show_stack(struct task_struct *task, unsigned long *sp)
-+{
-+      /*
-+       *  Allocate just enough entries on the stack.
-+       */
-+      unsigned int calls[TRAP_MAX_STACK_DEPTH];
-+      unsigned long code_start;
-+      unsigned long code_end;
-+      unsigned long ocm_code_start = (unsigned long)&__ocm_text_run_begin;
-+      unsigned long ocm_code_end = (unsigned long)&__data_begin;
-+      unsigned long stack_end = (unsigned long)(current->stack + THREAD_SIZE - 8);
-+      unsigned long stack = (unsigned long)sp;
-+      int kernel_stack = 1;
-+
-+      processor_dram(&code_start, &code_end);
-+
-+      /*
-+       * Which task are we talking about.
-+       */
-+      if (!task) {
-+              task = current;
-+      }
-+
-+      /*
-+       * Find the stack for the task if one was not specified.  Otherwise
-+       * use the specified stack.
-+       */
-+      if (!stack) {
-+              if (task != current) {
-+                      stack = task->thread.sp;
-+                      stack_end = (unsigned long)task->stack + THREAD_SIZE - 8;
-+              } else {
-+                      asm volatile (
-+                              "move.4         %0, SP          \n\t"
-+                              : "=r" (stack)
-+                      );
-+              }
-+      }
-+
-+      printk(KERN_NOTICE "Starting backtrace: PID %d '%s'\n",
-+                      task->pid, task->comm);
-+
-+      /*
-+       * We do 2 passes the first pass is Kernel stack is the second
-+       * User stack.
-+       */
-+      while (kernel_stack) {
-+              unsigned long *handle;
-+              unsigned int i, idx = 0;
-+              struct pt_regs *pt = task_pt_regs(task);
-+
-+              /*
-+               * If the task is in user mode, reset the start
-+               * and end values for text.
-+               */
-+              if (__user_mode(stack)) {
-+                      if (!(task->personality & FDPIC_FUNCPTRS)) {
-+                              printk(KERN_NOTICE "  User Stack:\n");
-+                              code_start = task->mm->start_code;
-+                              code_end = task->mm->end_code;
-+                      } else {
-+                              printk(KERN_NOTICE "  User Stack (fdpic):\n");
-+                              show_vmas(task);
-+                      }
-+                      stack_end = task->mm->start_stack;
-+                      ocm_code_end = ocm_code_start = 0;
-+                      kernel_stack = 0;
-+              } else {
-+                      printk(KERN_NOTICE "  Kernel Stack:\n");
-+              }
-+
-+              /*
-+               * Collect the stack back trace information.
-+               */
-+              printk("    code[0x%lx-0x%lx]", code_start, code_end);
-+              if (ocm_code_start) {
-+                      printk(" ocm_code[0x%lx-0x%lx]",
-+                             ocm_code_start, ocm_code_end);
-+              }
-+              printk("\n    stack[0x%lx-0x%lx]\n", stack, stack_end);
-+
-+              handle = (unsigned long*)stack;
-+              while (idx < TRAP_MAX_STACK_DEPTH) {
-+                      calls[idx] = stacktrace_iterate(&handle,
-+                                      code_start, code_end,
-+                                      ocm_code_start, ocm_code_end,
-+                                      (unsigned long)stack, stack_end);
-+                      if (calls[idx] == 0) {
-+                              break;
-+                      }
-+                      idx++;
-+              }
-+
-+              /*
-+               * Now print out the data.
-+               */
-+              printk(KERN_NOTICE "  CALL && CALLI on stack:");
-+              for (i = 0; i < idx; i++) {
-+                      printk("%s0x%x, ", (i & 0x3) == 0 ?  "\n    " : "",
-+                                      calls[i]);
-+              }
-+              printk(idx == TRAP_MAX_STACK_DEPTH ? "...\n" : "\n");
-+
-+              /*
-+               * If we are doing user stack we are done
-+               */
-+              if (!kernel_stack) {
-+                      break;
-+              }
-+
-+              /*
-+               * Does this kernel stack have a mm (i.e. is it user)
-+               */
-+              if (!task->mm) {
-+                      printk("No mm for userspace stack.\n");
-+                      break;
-+              }
-+              /*
-+               * Get the user-mode stack (if any)
-+               */
-+              stack = pt->an[7];
-+              printk(KERN_NOTICE "Userspace stack at 0x%lx frame type %d\n",
-+                              stack, (int)pt->frame_type);
-+              if (!__user_mode(stack)) {
-+                      break;
-+              }
-+      }
-+}
-+
-+/*
-+ * die_if_kernel()
-+ *    Determine if we are in kernel mode and if so print stuff out and die.
-+ */
-+void die_if_kernel(char *str, struct pt_regs *regs, long trap_cause)
-+{
-+      unsigned int s3value;
-+
-+      if (user_mode(regs)) {
-+              return;
-+      }
-+
-+      console_verbose();
-+      trap_print_information(str, regs);
-+
-+      /*
-+       * If the debugger is attached via the hardware mailbox protocol,
-+       * go into an infinite loop and the debugger will figure things out.
-+       */
-+      asm volatile (
-+            "move.4 %0, scratchpad3"
-+            : "=r" (s3value)
-+      );
-+      if (s3value) {
-+              asm volatile("1:        jmpt.t 1b");
-+      }
-+
-+      /*
-+       * Set the debug taint value.
-+       */
-+      add_taint(TAINT_DIE);
-+      do_exit(SIGSEGV);
-+}
-+
-+/*
-+ * trap_handler()
-+ *    Handle traps.
-+ *
-+ * Traps are treated as interrupts and registered with the LDSR.  When
-+ * the LDSR takes the interrupt, it will determine if a trap has occurred
-+ * and service the trap prior to servicing the interrupt.
-+ *
-+ * This function is directly called by the LDSR.
-+ */
-+void trap_handler(int irq, struct pt_regs *regs)
-+{
-+      int sig = SIGSEGV;
-+      siginfo_t info;
-+      unsigned int trap_cause = regs->trap_cause;
-+
-+      BUG_ON(!irqs_disabled());
-+
-+      /*
-+       * test if in kernel and die.
-+       */
-+      die_if_kernel("Kernel Trap", regs, trap_cause);
-+
-+      /*
-+       * User process problem, setup a signal for this process
-+       */
-+      if ((trap_cause & (1 << TRAP_CAUSE_DST_RANGE_ERR)) ||
-+          (trap_cause & (1 << TRAP_CAUSE_SRC1_RANGE_ERR)) ||
-+          (trap_cause & (1 << TRAP_CAUSE_I_RANGE_ERR))) {
-+              sig = SIGSEGV;
-+              info.si_code = SEGV_MAPERR;
-+      } else if ((trap_cause & (1 << TRAP_CAUSE_DST_MISALIGNED)) ||
-+                 (trap_cause & (1 << TRAP_CAUSE_SRC1_MISALIGNED))) {
-+              sig = SIGBUS;
-+              info.si_code = BUS_ADRALN;
-+      } else if ((trap_cause & (1 << TRAP_CAUSE_DST_DECODE_ERR)) ||
-+                 (trap_cause & (1 << TRAP_CAUSE_SRC1_DECODE_ERR))) {
-+              sig = SIGILL;
-+              info.si_code = ILL_ILLOPN;
-+      } else if ((trap_cause & (1 << TRAP_CAUSE_ILLEGAL_INST))) {
-+              /*
-+               * Check for software break point and if found signal trap
-+               * not illegal instruction.
-+               */
-+              unsigned long instruction;
-+              if (between(regs->pc, KERNELSTART, memory_end) &&
-+                      (regs->pc & 3) == 0 &&
-+                      get_user(instruction, (unsigned long *)regs->pc) == 0) {
-+
-+                      /*
-+                       * This used to be 0xaabbccdd but it turns out
-+                       * that is now valid in ubicom32v4 isa so we
-+                       * have switched to 0xfabbccdd
-+                       */
-+                      if ((instruction == 0xfabbccdd) ||
-+                          (instruction == 0xaabbccdd)) {
-+                              sig = SIGTRAP;
-+                              info.si_code = TRAP_BRKPT;
-+                              goto send_signal;
-+                      }
-+              }
-+              sig = SIGILL;
-+              info.si_code = ILL_ILLOPC;
-+      } else if ((trap_cause & (1 << TRAP_CAUSE_I_DECODE_ERR))) {
-+              sig = SIGILL;
-+              info.si_code = ILL_ILLOPC;
-+      } else if ((trap_cause & (1 << TRAP_CAUSE_DCAPT))) {
-+              sig = SIGTRAP;
-+              info.si_code = TRAP_TRACE;
-+      }
-+
-+      /*
-+       * Print a trap information block to the console, do not
-+       * print this above the case because we don't want it
-+       * printed for software break points.
-+       */
-+      trap_print_information("User Trap", regs);
-+
-+send_signal:
-+
-+      force_sig_info(sig, &info, current);
-+
-+      /*
-+       * Interrupts are disabled, re-enable them now.
-+       */
-+      if (!irqs_disabled()) {
-+              printk(KERN_EMERG "interrupts enabled on exit, irq=%d, regs=%p",
-+                              irq, regs);
-+              BUG();
-+      }
-+}
-+
-+/*
-+ * trap_init_interrupt()
-+ *    We need a 2nd trap handling init that will occur after init_IRQ().
-+ */
-+void __init trap_init_interrupt(void)
-+{
-+      int err;
-+      unsigned char tirq;
-+      struct devtree_node *dn = (struct devtree_node *)tn;
-+
-+      /*
-+       * Now setup the Software IRQ so that if a trap occurs the LDSR
-+       * is started.  The irq is there just to "force" the LDSR to run.
-+       */
-+      if (!tn) {
-+              printk(KERN_WARNING "trap_init_interrupt skipped.\n");
-+              return;
-+      }
-+
-+      err = devtree_irq(dn, NULL, &tirq);
-+      if (err) {
-+              printk(KERN_WARNING "error obtaining trap irq value: %d\n",
-+                      err);
-+              return;
-+      }
-+
-+      if (tirq == DEVTREE_IRQ_NONE) {
-+              printk(KERN_WARNING "trap irq not available: %d\n", tirq);
-+              return;
-+      }
-+
-+      err = setup_irq(tirq, &trap_irq);
-+      if (err) {
-+              printk(KERN_WARNING "trap irq setup failed: %d\n", err);
-+              return;
-+      }
-+
-+      /*
-+       * Let ultra know which thread is handling the traps and
-+       * what the interrupt to use is.
-+       */
-+      tn->intthread = ldsr_get_threadid();
-+
-+      /*
-+       * Tell the LDSR about our IRQ so that it will unsuspend
-+       * if one occurs while waiting for the per thread lock.
-+       */
-+      ldsr_set_trap_irq(tirq);
-+}
-+
-+/*
-+ * trap_init()
-+ *    init trap handling
-+ *
-+ * Trap handling is done through the ldsr.  Every time an interrupt
-+ * occurs, the LDSR looks for threads that are listed in the TRAP
-+ * register and forces a call to the trap handler.
-+ */
-+void __init trap_init(void)
-+{
-+      /*
-+       * If we do not have a trap node in the device tree, we leave the fault
-+       * handling to the underlying hardware.
-+       */
-+      tn = (struct trapnode *)devtree_find_node("traps");
-+      if (!tn) {
-+              printk(KERN_WARNING "traps are not handled by linux\n");
-+              return;
-+      }
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/uaccess.c
-@@ -0,0 +1,109 @@
-+/*
-+ * arch/ubicom32/include/asm/uaccess.c
-+ *   User space memory access functions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/sched.h>
-+#include <linux/mm.h>
-+#include <linux/string.h>
-+#include <linux/module.h>
-+
-+#include <asm/segment.h>
-+#include <asm/uaccess.h>
-+
-+extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
-+
-+/*
-+ * __access_ok()
-+ *    Check that the address is in the current processes.
-+ *
-+ * NOTE: The kernel uses "pretend" user addresses that wind
-+ * up calling access_ok() so this approach has only marginal
-+ * value because you wind up with lots of false positives.
-+ */
-+int __access_ok(unsigned long addr, unsigned long size)
-+{
-+      // struct vm_area_struct *vma;
-+
-+      /*
-+       * Don't do anything if we are not a running system yet.
-+       */
-+      if (system_state != SYSTEM_RUNNING) {
-+              return 1;
-+      }
-+
-+      /*
-+       * It appears that Linux will call this function even when we are not
-+       * in the context of a user space application that has a VM address
-+       * space.  So we must check that current and mm are valid before
-+       * performing the check.
-+       */
-+      if ((!current) || (!current->mm)) {
-+              return 1;
-+      }
-+
-+      /*
-+       * We perform some basic checks on the address to ensure that it
-+       * is at least within the range of DRAM.
-+       */
-+      if ((addr < (int)&_etext) || (addr > memory_end)) {
-+              printk(KERN_WARNING "pid=%d[%s]: range [%lx - %lx] not in memory area: [%lx - %lx]\n",
-+                      current->pid, current->comm,
-+                      addr, addr + size,
-+                      memory_start, memory_end);
-+              return 0;
-+      }
-+
-+      /*
-+       * For nommu Linux we can check this by looking at the allowed
-+       * memory map for the process.
-+       *
-+       * TODO: Since the kernel passes addresses in it's own space as though
-+       * they were user address, we can not validate the addresses this way.
-+       */
-+#if 0
-+      if (!down_read_trylock(&current->mm->mmap_sem)) {
-+              return 1;
-+      }
-+      vma = find_vma(current->mm, addr);
-+      if (!vma) {
-+              up_read(&current->mm->mmap_sem);
-+              printk(KERN_WARNING "pid=%d[%s]: possible invalid acesss on range: [%lx - %lx]\n",
-+                              current->pid, current->comm, addr, addr + size);
-+              return 1;
-+      }
-+      if ((addr + size) > vma->vm_end) {
-+              up_read(&current->mm->mmap_sem);
-+              printk(KERN_WARNING "pid=%d[%s]: possible invalid length on range: [%lx - %lx]\n",
-+                              current->pid, current->comm, addr, addr + size);
-+              return 1;
-+      }
-+      up_read(&current->mm->mmap_sem);
-+#endif
-+      return 1;
-+}
-+
-+EXPORT_SYMBOL(__access_ok);
---- /dev/null
-+++ b/arch/ubicom32/kernel/ubicom32_context_switch.S
-@@ -0,0 +1,359 @@
-+/*
-+ * arch/ubicom32/kernel/ubicom32_context_switch.S
-+ *    Implements context switch and return functions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/sys.h>
-+#include <linux/linkage.h>
-+#include <asm/asm-offsets.h>
-+#include <asm/ubicom32-common.h>
-+#include <asm/ip5000.h>
-+#include <asm/range-protect.h>
-+
-+/*
-+ * begin_restore_context()
-+ *    Restore most of the context from sp (struct pt_reg *)
-+ *
-+ * This *can* be called without the global atomic lock. (because sp is
-+ * not restored!)  Only d15 and a3 are allowed to be used after this
-+ * before calling complete_restore_context
-+ */
-+.macro begin_restore_context
-+      move.4  d0, PT_D0(sp)
-+      move.4  d1, PT_D1(sp)
-+      move.4  d2, PT_D2(sp)
-+      move.4  d3, PT_D3(sp)
-+      move.4  d4, PT_D4(sp)
-+      move.4  d5, PT_D5(sp)
-+      move.4  d6, PT_D6(sp)
-+      move.4  d7, PT_D7(sp)
-+      move.4  d8, PT_D8(sp)
-+      move.4  d9, PT_D9(sp)
-+      move.4  d10, PT_D10(sp)
-+      move.4  d11, PT_D11(sp)
-+      move.4  d12, PT_D12(sp)
-+      move.4  d13, PT_D13(sp)
-+      move.4  d14, PT_D14(sp)
-+;;    move.4  d15, PT_D15(sp)
-+      move.4  a0, PT_A0(sp)
-+      move.4  a1, PT_A1(sp)
-+      move.4  a2, PT_A2(sp)
-+;;    move.4  a3, PT_A3(sp)
-+      move.4  a4, PT_A4(sp)
-+      move.4  a5, PT_A5(sp)
-+      move.4  a6, PT_A6(sp)
-+      move.4  acc0_hi, PT_ACC0HI(sp)
-+      move.4  acc0_lo, PT_ACC0LO(sp)
-+      move.4  mac_rc16, PT_MAC_RC16(sp)
-+      move.4  acc1_hi, PT_ACC1HI(sp)
-+      move.4  acc1_lo, PT_ACC1LO(sp)
-+      move.4  source3, PT_SOURCE3(sp)
-+      move.4  int_mask0, PT_INT_MASK0(sp)
-+      move.4  int_mask1, PT_INT_MASK1(sp)
-+.endm
-+
-+/*
-+ * complete_restore_context()
-+ *    Completely restore the context from sp (struct pt_reg *)
-+ *
-+ * Note: Recovered PC and CSR are saved on the stack and are to be
-+ * popped off before returning.
-+ */
-+.macro complete_restore_context
-+      move.4  a3, sp
-+      move.4  d15, PT_D15(sp)
-+      move.4  sp, PT_SP(a3)           ; Recover Stack pointer from save area
-+      move.4  -4(sp)++, PT_PC(a3)     ; Recover saved PC and save to stack
-+      move.4  -4(sp)++, PT_CSR(a3)    ; Recover saved csr and save to stack
-+      move.4  a3, PT_A3(a3)
-+.endm
-+
-+/*
-+ * old restore_context macro
-+ */
-+.macro restore_context
-+      begin_restore_context
-+      complete_restore_context
-+.endm
-+
-+/*
-+ * ldsr_thread_enable_interrupts()
-+ *    An assembly version of the enable interrupts function.
-+ *
-+ * The stack is fair game but all registers MUST be preserved.
-+ *
-+ */
-+.macro ldsr_thread_enable_interrupts
-+      move.4  -4(sp)++, d3    ; Push d3
-+      move.4  -4(sp)++, a3    ; Push a3
-+
-+      /*
-+       * Read the ROSR and obtain ~(1 << tid)
-+       */
-+      lsr.4   d3, rosr, #0x2  ; Move the thread portion of ROSR into d3
-+      lsl.4   d3, #1, d3      ; perform a (1 << tid)
-+      not.4   d3, d3          ; Negate the value of d3 == ~(1 << threadid)
-+
-+      /*
-+       * Get the value of the ldsr_soft_irq_mask
-+       */
-+      moveai  a3, #%hi(ldsr_soft_irq_mask)
-+      move.4  a3, %lo(ldsr_soft_irq_mask)(a3)
-+
-+      /*
-+       * Now re-enable interrupts for this thread and then
-+       * wakeup the LDSR.
-+       */
-+      and.4   scratchpad1, scratchpad1, d3
-+      move.4  int_set0, a3
-+
-+      /*
-+       * Restore the registers.
-+       */
-+      move.4  a3, (sp)4++
-+      move.4  d3, (sp)4++
-+.endm
-+
-+/*
-+ * ret_from_interrupt_to_kernel()
-+ *    RFI function that is where do_IRQ() returns to if the thread was
-+ *    in kernel space.
-+ */
-+      .section .text.ret_from_interrupt_to_kernel, "ax", @progbits
-+      .global ret_from_interrupt_to_kernel
-+ret_from_interrupt_to_kernel:
-+      begin_restore_context           ; Restore the thread context
-+      atomic_lock_acquire             ; Enter critical section
-+      complete_restore_context        ; Restore the thread context
-+      atomic_lock_release             ; Leave critical section
-+      ldsr_thread_enable_interrupts   ; enable the threads interrupts
-+      move.4  csr, (sp)4++            ; Restore csr from the stack
-+      ret     (sp)4++
-+
-+/*
-+ * ret_from_interrupt_to_user()
-+ *    RFI function that is where do_IRQ() returns to if the thread was
-+ *    in user space.
-+ *
-+ * TODO: Do we really need the critical section handling in this code?
-+ *
-+ */
-+      .section .text.ret_from_interrupt_to_user, "ax", @progbits
-+      .global ret_from_interrupt_to_user
-+ret_from_interrupt_to_user:
-+      ldsr_thread_enable_interrupts                   ; enable the threads interrupts
-+      /*
-+       * Set a1 to the thread info pointer, no need to save it as we are
-+       * restoring userspace and will never return
-+       */
-+      movei   d0, #(~(ASM_THREAD_SIZE-1))
-+      and.4   a1, sp, d0
-+
-+      /*
-+       * Test if the scheduler needs to be called.
-+       */
-+      btst    TI_FLAGS(a1), #ASM_TIF_NEED_RESCHED
-+      jmpeq.t 2f
-+      call    a5, schedule                    ; Call the scheduler. I will come back here.
-+
-+      /*
-+       * See if we have pending signals and call do_signal
-+       * if needed.
-+       */
-+2:
-+      btst    TI_FLAGS(a1), #ASM_TIF_SIGPENDING       ; Any signals needed?
-+      jmpeq.t 1f
-+
-+      /*
-+       * Now call do_signal()
-+       */
-+      move.4  d0, #0                                  ; oldset pointer is NULL
-+      move.4  d1, sp                                  ; d1 is the regs pointer
-+      call    a5, do_signal                           ; Call do_signal()
-+
-+      /*
-+       * Back from do_signal(), re-enter critical section.
-+       */
-+1:
-+      begin_restore_context                           ; Restore the thread context
-+      atomic_lock_acquire                             ; Enter critical section
-+      call a3, __complete_and_return_to_userspace     ; jump to unprotected section
-+
-+/*
-+ * restore_all_registers()
-+ *
-+ * restore_all_registers will be the alternate exit route for
-+ * preempted processes that have called a signal handler
-+ * and are returning back to user space.
-+ */
-+      .section .text.restore_all_registers, "ax", @progbits
-+      .global restore_all_registers
-+restore_all_registers:
-+      begin_restore_context                   ; Restore the thread context
-+      atomic_lock_acquire                     ; Enter critical section
-+      call a3, __complete_and_return_to_userspace
-+
-+/*
-+ * __complete_and_return_to_userspace
-+ *
-+ * restores the second half of the context and returns
-+ * You must have the atomic lock when you call this function
-+ */
-+      .section .kernel_unprotected, "ax", @progbits
-+__complete_and_return_to_userspace:
-+      disable_kernel_ranges_for_current d15   ; disable kernel ranges
-+      complete_restore_context                ; restore previous context
-+      atomic_lock_release                     ; Leave critical section
-+      move.4  csr, (sp)4++                    ; Restore csr from the stack
-+      ret     (sp)4++
-+
-+/*
-+ * ret_from_fork()
-+ *    Called on the child's return from fork system call.
-+ */
-+      .section .text.ret_from_fork, "ax", @progbits
-+      .global ret_from_fork
-+ret_from_fork:
-+      ;;;  d0 contains the arg for schedule_tail
-+      ;;;  the others we don't care about as they are in PT_REGS (sp)
-+      call   a5, schedule_tail
-+
-+      atomic_lock_acquire             ; Enter critical section
-+
-+      move.4  a3, sp
-+      move.4  d0, PT_D0(a3)           ; Restore D0
-+      move.4  d1, PT_D1(a3)           ; Restore D1
-+      move.4  d2, PT_D2(a3)           ; Restore D2
-+      move.4  d3, PT_D3(a3)           ; Restore D3
-+      move.4  d10, PT_D10(a3)         ; Restore D10
-+      move.4  d11, PT_D11(a3)         ; Restore D11
-+      move.4  d12, PT_D12(a3)         ; Restore D12
-+      move.4  d13, PT_D13(a3)         ; Restore D13
-+      move.4  a1, PT_A1(a3)           ; Restore A1
-+      move.4  a2, PT_A2(a3)           ; Restore A2
-+      move.4  a5, PT_A5(a3)           ; Restore A5
-+      move.4  a6, PT_A6(a3)           ; Restore A6
-+      ;;  I think atomic_lock_acquire could be moved here..
-+      move.4  sp, PT_SP(a3)           ; Restore sp
-+      move.4  a4, PT_PC(a3)           ; Restore pc in register a4
-+      move.4  PT_FRAME_TYPE(a3), #0   ; Clear frame_type to indicate it is invalid.
-+
-+#ifdef CONFIG_PROTECT_KERNEL
-+      call a3, __ret_from_fork_bottom_half
-+      .section .kernel_unprotected, "ax", @progbits
-+__ret_from_fork_bottom_half:
-+      disable_kernel_ranges_for_current d15
-+#endif
-+      atomic_lock_release             ; Leave critical section
-+      calli   a4, 0(a4)               ; Return.
-+
-+/*
-+ * __switch_to()
-+ *
-+ * Call with:
-+ *    void *__switch_to(struct task_struct *prev, struct thread_struct *prev_switch,
-+ *                            struct thread_struct *next_switch)
-+ */
-+      .section .text.__switch_to, "ax", @progbits
-+      .global __switch_to
-+__switch_to:
-+
-+      /*
-+       * Set up register a3 to point to save area.
-+       */
-+      movea   a3, d1                  ; a3 now holds prev_switch
-+      move.4  (a3)4++, d10
-+      move.4  (a3)4++, d11
-+      move.4  (a3)4++, d12
-+      move.4  (a3)4++, d13
-+      move.4  (a3)4++, a1
-+      move.4  (a3)4++, a2
-+      move.4  (a3)4++, a5
-+      move.4  (a3)4++, a6
-+      move.4  (a3)4++, a7
-+
-+      /*
-+       * Set up register a3 to point to restore area.
-+       */
-+      movea   a3, d2                  ; a3 now holds next_switch
-+      move.4  d10 , (a3)4++
-+      move.4  d11 , (a3)4++
-+      move.4  d12 , (a3)4++
-+      move.4  d13 , (a3)4++
-+      move.4  a1 , (a3)4++
-+      move.4  a2 , (a3)4++
-+      move.4  a5 , (a3)4++
-+      move.4  a6 , (a3)4++
-+      move.4  a7 , (a3)4++
-+
-+      /*
-+       * Load the sw_ksp with the proper thread_info pointer.
-+       */
-+      movei   d15, #(~(ASM_THREAD_SIZE-1))
-+      and.4   a3, sp, d15             ; a3 now has the thread info pointer
-+      moveai  a4, #%hi(sw_ksp)
-+      lea.1   a4, %lo(sw_ksp)(a4)     ; a4 now has the base address of sw_ksp array
-+      lsr.4   d15, ROSR, #2           ; Thread number - bit's 6 through 31 are zeroes anyway.
-+      move.4  (a4, d15), a3           ; Load the thread info pointer into the hw_ksp array..
-+
-+      /*
-+       * We are done with context switch. Time to return..
-+       */
-+      calli   a5, 0(a5)
-+      .size __switch_to, . - __switch_to
-+
-+/*
-+ * ubicom32_emulate_insn()
-+ *    Emulates the instruction.
-+ *
-+ * Call with:
-+ *    unsigned int ubicom32_emulate_insn(int source1, int source2, int source3, int *save_acc, int *save_csr);
-+ */
-+      .section .text.ubicom32_emulate_insn, "ax", @progbits
-+      .global ubicom32_emulate_insn
-+      .global trap_emulate
-+ubicom32_emulate_insn:
-+      movea   a3, d3          ; a3 holds save_acc pointer
-+      movea   a4, d4          ; a4 hods save_csr pointer
-+      move.4  source3, d2
-+      move.4  acc0_lo, (a3)
-+      move.4  acc0_hi, 4(a3)
-+      move.4  acc1_lo, 8(a3)
-+      move.4  acc1_hi, 12(a3)
-+      move.4  mac_rc16, 16(a3)
-+      move.4  CSR, (a4)
-+      setcsr_flush 0
-+
-+trap_emulate:
-+      move.4  d0, d1
-+      setcsr_flush 0
-+      move.4  (a4), CSR       ; Save csr
-+      move.4  (a3), acc0_lo
-+      move.4  4(a3), acc0_hi
-+      move.4  8(a3), acc1_lo
-+      move.4  12(a3), acc1_hi
-+      move.4  16(a3), mac_rc16
-+      ret     a5
-+      .size ubicom32_emulate_insn, . - ubicom32_emulate_insn
---- /dev/null
-+++ b/arch/ubicom32/kernel/ubicom32_ksyms.c
-@@ -0,0 +1,98 @@
-+/*
-+ * arch/ubicom32/kernel/ubicom32_ksyms.c
-+ *   Ubicom32 architecture compiler support and misc symbols.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/module.h>
-+#include <linux/linkage.h>
-+#include <linux/sched.h>
-+#include <linux/string.h>
-+#include <linux/mm.h>
-+#include <linux/user.h>
-+#include <linux/elfcore.h>
-+#include <linux/in6.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/semaphore.h>
-+
-+#include <asm/setup.h>
-+#include <asm/machdep.h>
-+#include <asm/pgalloc.h>
-+#include <asm/irq.h>
-+#include <asm/checksum.h>
-+#include <asm/current.h>
-+
-+/* platform dependent support */
-+
-+EXPORT_SYMBOL(__ioremap);
-+EXPORT_SYMBOL(iounmap);
-+
-+EXPORT_SYMBOL(ip_fast_csum);
-+
-+
-+/* Networking helper routines. */
-+EXPORT_SYMBOL(csum_partial_copy_nocheck);
-+
-+/* The following are special because they're not called
-+   explicitly (the C compiler generates them).  Fortunately,
-+   their interface isn't gonna change any time soon now, so
-+   it's OK to leave it out of version control.  */
-+EXPORT_SYMBOL(memcpy);
-+EXPORT_SYMBOL(memset);
-+EXPORT_SYMBOL(memmove);
-+
-+#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4
-+/*
-+ * 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 __divdi3(void);
-+extern void __lshrdi3(void);
-+extern void __modsi3(void);
-+extern void __muldi3(void);
-+extern void __udivsi3(void);
-+extern void __umodsi3(void);
-+
-+/* gcc lib functions */
-+EXPORT_SYMBOL(__ashldi3);
-+EXPORT_SYMBOL(__ashrdi3);
-+EXPORT_SYMBOL(__divsi3);
-+EXPORT_SYMBOL(__divdi3);
-+EXPORT_SYMBOL(__lshrdi3);
-+EXPORT_SYMBOL(__modsi3);
-+EXPORT_SYMBOL(__muldi3);
-+EXPORT_SYMBOL(__udivsi3);
-+EXPORT_SYMBOL(__umodsi3);
-+#else
-+extern void __libgcc_udivmodsi(void);
-+extern void __libgcc_divmodsi(void);
-+
-+EXPORT_SYMBOL(__libgcc_udivmodsi);
-+EXPORT_SYMBOL(__libgcc_divmodsi);
-+#endif
---- /dev/null
-+++ b/arch/ubicom32/kernel/ubicom32_syscall.S
-@@ -0,0 +1,694 @@
-+/*
-+ * arch/ubicom32/kernel/ubicom32_syscall.S
-+ *    <TODO: Replace with short file description>
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/sys.h>
-+#include <linux/linkage.h>
-+#include <linux/unistd.h>
-+
-+#include <asm/ubicom32-common.h>
-+#include <asm/thread_info.h>
-+#include <asm/asm-offsets.h>
-+#include <asm/range-protect.h>
-+
-+/*
-+ * __old_system_call()
-+ */
-+      .section .old_syscall_entry.text, "ax", @progbits
-+#ifdef CONFIG_OLD_40400010_SYSTEM_CALL
-+__old_system_call:
-+      call a3, system_call
-+      .size __old_system_call, . - __old_system_call ;
-+#else
-+      /*
-+       * something that will crash the userspace application, but
-+       * should not take down the kernel, if protection is enabled
-+       * this will never even get executed.
-+       */
-+      .long   0xFABBCCDE                      ; illegal instruction
-+      bkpt #-1                                ; we will never get here
-+#endif
-+
-+/*
-+ * system_call()
-+ */
-+      .section .syscall_entry.text, "ax", @progbits
-+      .global system_call
-+system_call:
-+      /*
-+       * Regular ABI rules for function calls apply for syscall.  d8 holds
-+       * the syscall number. We will use that to index into the syscall table.
-+       * d0 - d5 hold the parameters.
-+       *
-+       * First we get the current thread_info and swap to the kernel stack.
-+       * This is done by reading the current thread and looking up the ksp
-+       * from the sw_ksp array and storing it in a3.
-+       *
-+       * Then we reserve space for the syscall context a struct pt_regs and
-+       * save it using a4 initially and later as sp.
-+       * Once sp is set to the kernel sp we can leave the critical section.
-+       *
-+       * For the user case the kernel stack will have the following layout.
-+       *
-+       *  a3           ksp[0] +-----------------------+
-+       *                      | Thread info area      |
-+       *                      | struct thread_info    |
-+       *                      +-----------------------+
-+       *                      :                       :
-+       *                      |   Kernel Stack Area   |
-+       *                      |                       |
-+       *  a4 / sp >>>         +-----------------------+
-+       *                      | Context save area     |
-+       *                      | struct pt_reg         |
-+       *  ksp[THREAD_SIZE-8]  +-----------------------+
-+       *                      | 8 Byte Buffer Zone    |
-+       *  ksp[THREAD_SIZE]    +-----------------------+
-+
-+       *
-+       * For kernel syscalls the layout is as follows.
-+       *
-+       *  a3           ksp[0] +-----------------------+
-+       *                      | Thread info area      |
-+       *                      | struct thread_info    |
-+       *                      +-----------------------+
-+       *                      :                       :
-+       *                      |   Kernel Stack Area   |
-+       *                      |                       |
-+       *  a4 / sp >>>         +-----------------------+
-+       *                      | Context save area     |
-+       *                      | struct pt_reg         |
-+       * sp at syscall entry  +-----------------------+
-+       *                      | Callers Kernel Stack  |
-+       *                      :                       :
-+       *
-+       * Once the context is saved we optionally call syscall_trace and setup
-+       * the exit routine and jump to the syscall.
-+       */
-+
-+      /*
-+       * load the base address for sw_ksp into a3
-+       * Note.. we cannot access it just yet as protection is still on.
-+       */
-+      moveai  a3, #%hi(sw_ksp)
-+      lea.1   a3, %lo(sw_ksp)(a3)
-+
-+      /*
-+       * Enter critical section .
-+       *
-+       * The 'critical' aspects here are the switching the to the ksp and
-+       * changing the protection registers, these both use per thread
-+       * information so we need to protect from a context switch. For now this
-+       * is done using the global atomic lock.
-+       */
-+      atomic_lock_acquire
-+
-+      thread_get_self d15                     ; Load current thread number
-+#ifdef CONFIG_PROTECT_KERNEL
-+      lsl.4   d9, #1, d15                     ; Convert to thread bit
-+      enable_kernel_ranges d9
-+#endif
-+      /*
-+       * in order to reduce the size of code in the syscall section we get
-+       * out of it right now
-+       */
-+      call a4, __system_call_bottom_half
-+      .size system_call, . - system_call
-+
-+      .section .text.__system_call_bottom_half, "ax", @progbits
-+__system_call_bottom_half:
-+
-+      /*
-+       * We need to Determine if this is a kernel syscall or user syscall.
-+       * Start by loading the pointer for the thread_info structure for the
-+       * current process in to a3.
-+       */
-+      move.4  a3, (a3, d15)                   ; a3 = sw_ksp[d15]
-+
-+      /*
-+       * Now if this is a kernel thread the same value can be a acheived by
-+       * masking off the lower bits on the current stack pointer.
-+       */
-+      movei   d9, #(~(ASM_THREAD_SIZE-1))     ; load mask
-+      and.4   d9, sp, d9                      ; apply mask
-+
-+      /*
-+       * d9 now has the masked version of the sp. If this is identical to
-+       * what is in a3 then don't switch to ksp as we are already in the
-+       * kernel.
-+       */
-+      sub.4   #0, a3, d9
-+
-+      /*
-+       * if d9 and a3 are not equal. We are usespace and have to shift to
-+       * ksp.
-+       */
-+      jmpne.t 1f
-+
-+      /*
-+       * Kernel Syscall.
-+       *
-+       * The kernel has called this routine. We have to pdec space for pt_regs
-+       * from sp.
-+       */
-+      pdec    a4, PT_SIZE(sp)                 ; a4 = ksp - PT_SIZE
-+      jmpt.t  2f
-+
-+      /*
-+       * Userspace Syscall.
-+       *
-+       * Add THREAD_SIZE and subtract PT_SIZE to create the proper ksp
-+       */
-+1:    movei   d15, #(ASM_THREAD_SIZE - 8 - PT_SIZE)
-+      lea.1   a4, (a3, d15)                   ; a4 = ksp + d15
-+
-+      /*
-+       * Replace user stack pointer with kernel stack pointer (a4)
-+       * Load -1 into frame_type in save area to indicate this is system call
-+       * frame.
-+       */
-+2:    move.4  PT_A7(a4), a7                   ; Save old sp/A7 on kernel stack
-+      move.4  PT_FRAME_TYPE(a4), #-1          ; Set the frame type.
-+      move.4  sp, a4                          ; Change to ksp.
-+      /*
-+       * We are now officially back in the kernel!
-+       */
-+
-+      /*
-+       * Now that we are on the ksp we can leave the critical section
-+       */
-+      atomic_lock_release
-+
-+      /*
-+       * We need to save a0 because we need to be able to restore it in
-+       * the event that we need to handle a signal.  It's not generally
-+       * a callee-saved register but is the GOT pointer.
-+       */
-+      move.4  PT_A0(sp), a0                   ; Save A0 on kernel stack
-+
-+      /*
-+       * We still need to save d10-d13, a1, a2, a5, a6 in the kernel frame
-+       * for this process, we also save the system call params in the case of
-+       * syscall restart. (note a7 was saved above)
-+       */
-+      move.4  PT_A1(sp), a1                   ; Save A1 on kernel stack
-+      move.4  PT_A2(sp), a2                   ; Save A2 on kernel stack
-+      move.4  PT_A5(sp), a5                   ; Save A5 on kernel stack
-+      move.4  PT_A6(sp), a6                   ; Save A6 on kernel stack
-+      move.4  PT_PC(sp), a5                   ; Save A5 at the PC location
-+      move.4  PT_D10(sp), d10                 ; Save D10 on kernel stack
-+      move.4  PT_D11(sp), d11                 ; Save D11 on kernel stack
-+      move.4  PT_D12(sp), d12                 ; Save D12 on kernel stack
-+      move.4  PT_D13(sp), d13                 ; Save D13 on kernel stack
-+
-+      /*
-+       * Now save the syscall parameters
-+       */
-+      move.4  PT_D0(sp), d0                   ; Save d0 on kernel stack
-+      move.4  PT_ORIGINAL_D0(sp), d0          ; Save d0 on kernel stack
-+      move.4  PT_D1(sp), d1                   ; Save d1 on kernel stack
-+      move.4  PT_D2(sp), d2                   ; Save d2 on kernel stack
-+      move.4  PT_D3(sp), d3                   ; Save d3 on kernel stack
-+      move.4  PT_D4(sp), d4                   ; Save d4 on kernel stack
-+      move.4  PT_D5(sp), d5                   ; Save d5 on kernel stack
-+      move.4  PT_D8(sp), d8                   ; Save d8 on kernel stack
-+
-+      /*
-+       * Test if syscalls are being traced and if they are jump to syscall
-+       * trace (it will comeback here)
-+       */
-+      btst    TI_FLAGS(a3), #ASM_TIF_SYSCALL_TRACE
-+      jmpne.f .Lsystem_call__trace
-+.Lsystem_call__trace_complete:
-+      /*
-+       * Check for a valid call number [ 0 <= syscall_number < NR_syscalls ]
-+       */
-+      cmpi    d8, #0
-+      jmplt.f 3f
-+      cmpi    d8, #NR_syscalls
-+      jmplt.t 4f
-+
-+      /*
-+       * They have passed an invalid number. Call sys_ni_syscall staring by
-+       * load a4 with the base address of sys_ni_syscall
-+       */
-+3:    moveai  a4, #%hi(sys_ni_syscall)
-+      lea.1   a4, %lo(sys_ni_syscall)(a4)
-+      jmpt.t  5f                              ; Jump to regular processing
-+
-+      /*
-+       * Validated syscall, load the syscall table base address into a3 and
-+       * read the syscall ptr out.
-+       */
-+4:    moveai  a3, #%hi(sys_call_table)
-+      lea.1   a3, %lo(sys_call_table)(a3)     ; a3 = sys_call_table
-+      move.4  a4, (a3, d8)                    ; a4 = sys_call_table[d8]
-+
-+      /*
-+       * Before calling the syscall, setup a5 so that syscall_exit is called
-+       * on return from syscall
-+       */
-+5:    moveai  a5, #%hi(syscall_exit)          ; Setup return address
-+      lea.1   a5, %lo(syscall_exit)(a5)       ; from system call
-+
-+      /*
-+       * If the syscall is __NR_rt_rigreturn then we have to test d1 to
-+       * figure out if we have to change change the return routine to restore
-+       * all registers.
-+       */
-+      cmpi    d8, #__NR_rt_sigreturn
-+      jmpeq.f 6f
-+
-+      /*
-+       * Launch system call (it will return through a5 - syscall_exit)
-+       */
-+      calli   a3, 0(a4)
-+
-+      /*
-+       * System call is rt_sigreturn. Test d1. If it is 1 we have to
-+       * change the return address to restore_all_registers
-+       */
-+6:    cmpi    d1, #1
-+      jmpne.t 7f
-+
-+      moveai  a5, #%hi(restore_all_registers)  ; Setup return address
-+      lea.1   a5, %lo(restore_all_registers)(a5) ; to restore_all_registers.
-+
-+      /*
-+       * Launch system call  (it will return through a5)
-+       */
-+7:    calli   a3, 0(a4)                        ; Launch system call
-+
-+.Lsystem_call__trace:
-+      /*
-+       * Syscalls are being traced.
-+       * Call syscall_trace, (return here)
-+       */
-+      call    a5, syscall_trace
-+
-+      /*
-+       * Restore syscall state (it would have been discarded during the
-+       * syscall trace)
-+       */
-+      move.4  d0, PT_D0(sp)                   ; Restore d0 from kernel stack
-+      move.4  d1, PT_D1(sp)                   ; Restore d1 from kernel stack
-+      move.4  d2, PT_D2(sp)                   ; Restore d2 from kernel stack
-+      move.4  d3, PT_D3(sp)                   ; Restore d3 from kernel stack
-+      move.4  d4, PT_D4(sp)                   ; Restore d4 from kernel stack
-+      move.4  d5, PT_D5(sp)                   ; Restore d5 from kernel stack
-+      /* add this back if we ever have a syscall with 7 args */
-+      move.4  d8, PT_D8(sp)                   ; Restore d8 from kernel stack
-+
-+      /*
-+       * return to syscall
-+       */
-+      jmpt.t .Lsystem_call__trace_complete
-+      .size __system_call_bottom_half, . - __system_call_bottom_half
-+
-+/*
-+ * syscall_exit()
-+ */
-+      .section .text.syscall_exit
-+      .global syscall_exit
-+syscall_exit:
-+      /*
-+       * d0 contains the return value. We should move that into the kernel
-+       * stack d0 location.  We will be transitioning from kernel to user
-+       * mode. Test the flags and see if we have to call schedule. If we are
-+       * going to truly exit then all that has to be done is that from the
-+       * kernel stack we have to restore d0, a0, a1, a2, a5, a6 and sp (a7)bb
-+       * and then return via a5.
-+       */
-+
-+      /*
-+       * Save d0 to pt_regs
-+       */
-+      move.4  PT_D0(sp), d0                   ; Save d0 into the kernel stack
-+
-+      /*
-+       * load the thread_info structure by masking off the THREAD_SIZE
-+       * bits.
-+       *
-+       * Note: we used to push a1, but now we don't as we are going
-+       * to eventually restore it to the userspace a1.
-+       */
-+      movei   d9, #(~(ASM_THREAD_SIZE-1))
-+      and.4   a1, sp, d9
-+
-+      /*
-+       * Are any interesting bits set on TI flags, if there are jump
-+       * aside to post_processing.
-+       */
-+      move.4  d9, #(_TIF_SYSCALL_TRACE | _TIF_NEED_RESCHED | _TIF_SIGPENDING)
-+      and.4   #0, TI_FLAGS(a1), d9
-+      jmpne.f .Lsyscall_exit__post_processing ; jump to handler
-+.Lsyscall_exit__post_processing_complete:
-+
-+      move.4  d0, PT_D0(sp)                   ; Restore D0 from kernel stack
-+      move.4  d1, PT_D1(sp)                   ; Restore d1 from kernel stack
-+      move.4  d2, PT_D2(sp)                   ; Restore d2 from kernel stack
-+      move.4  d3, PT_D3(sp)                   ; Restore d3 from kernel stack
-+      move.4  d4, PT_D4(sp)                   ; Restore d4 from kernel stack
-+      move.4  d5, PT_D5(sp)                   ; Restore d5 from kernel stack
-+      move.4  d8, PT_D8(sp)                   ; Restore d8 from kernel stack
-+      move.4  d10, PT_D10(sp)                 ; Restore d10 from kernel stack
-+      move.4  d11, PT_D11(sp)                 ; Restore d11 from kernel stack
-+      move.4  d12, PT_D12(sp)                 ; Restore d12 from kernel stack
-+      move.4  d13, PT_D13(sp)                 ; Restore d13 from kernel stack
-+      move.4  a1, PT_A1(sp)                   ; Restore A1 from kernel stack
-+      move.4  a2, PT_A2(sp)                   ; Restore A2 from kernel stack
-+      move.4  a5, PT_A5(sp)                   ; Restore A5 from kernel stack
-+      move.4  a6, PT_A6(sp)                   ; Restore A6 from kernel stack
-+      move.4  a0, PT_A0(sp)                   ; Restore A6 from kernel stack
-+
-+      /*
-+       * this is only for debug, and could be removed for production builds
-+       */
-+      move.4  PT_FRAME_TYPE(sp), #0           ; invalidate frame_type
-+
-+#ifdef CONFIG_PROTECT_KERNEL
-+
-+      call a4, __syscall_exit_bottom_half
-+
-+      .section .kernel_unprotected, "ax", @progbits
-+__syscall_exit_bottom_half:
-+      /*
-+       * Enter critical section
-+       */
-+      atomic_lock_acquire
-+      disable_kernel_ranges_for_current d15
-+#endif
-+      /*
-+       * Lastly restore userspace stack ptr
-+       *
-+       * Note: that when protection is on we need to hold the lock around the
-+       * stack swap as well because otherwise the protection could get
-+       * inadvertently disabled again at the end of a context switch.
-+       */
-+      move.4  a7, PT_A7(sp)                   ; Restore A7 from kernel stack
-+
-+      /*
-+       * We are now officially back in userspace!
-+       */
-+
-+#ifdef CONFIG_PROTECT_KERNEL
-+      /*
-+       * Leave critical section and return to user space.
-+       */
-+      atomic_lock_release
-+#endif
-+      calli   a5, 0(a5)                       ; Back to userspace code.
-+
-+      bkpt #-1                                ; we will never get here
-+
-+      /*
-+       * Post syscall processing. (unlikely part of syscall_exit)
-+       *
-+       * Are we tracing syscalls. If TIF_SYSCALL_TRACE is set, call
-+       * syscall_trace routine and return here.
-+       */
-+      .section .text.syscall_exit, "ax", @progbits
-+.Lsyscall_exit__post_processing:
-+      btst    TI_FLAGS(a1), #ASM_TIF_SYSCALL_TRACE
-+      jmpeq.t 1f
-+      call    a5, syscall_trace
-+
-+      /*
-+       * Do we need to resched ie call schedule. If TIF_NEED_RESCHED is set,
-+       * call the scheduler, it will come back here.
-+       */
-+1:    btst    TI_FLAGS(a1), #ASM_TIF_NEED_RESCHED
-+      jmpeq.t 2f
-+      call    a5, schedule
-+
-+      /*
-+       * Do we need to post a signal, if TIF_SIGPENDING is set call the
-+       * do_signal.
-+       */
-+2:    btst    TI_FLAGS(a1), #ASM_TIF_SIGPENDING
-+      jmpeq.t .Lsyscall_exit__post_processing_complete
-+
-+      /*
-+       * setup the do signal call
-+       */
-+      move.4  d0, #0                          ; oldset pointer is NULL
-+      lea.1   d1, (sp)                        ; d1 is the regs pointer.
-+      call    a5, do_signal
-+
-+      jmpt.t  .Lsyscall_exit__post_processing_complete
-+
-+/*    .size syscall_exit, . - syscall_exit */
-+
-+/*
-+ * kernel_execve()
-+ *    kernel_execv is called when we the kernel is starting a
-+ *    userspace application.
-+ */
-+      .section .kernel_unprotected, "ax", @progbits
-+      .global kernel_execve
-+kernel_execve:
-+      move.4  -4(sp)++, a5                    ; Save return address
-+      /*
-+       * Call execve
-+       */
-+      movei   d8, #__NR_execve                ; call execve
-+      call    a5, system_call
-+      move.4  a5, (sp)4++
-+
-+      /*
-+       * protection was enabled again at syscall exit, but we want
-+       * to return to kernel so we enable it again.
-+       */
-+#ifdef CONFIG_PROTECT_KERNEL
-+      /*
-+       * We are entering the kernel so we need to disable the protection.
-+       * Enter critical section, disable ranges and leave critical section.
-+       */
-+      call a3, __enable_kernel_ranges ;  and jump back to kernel
-+#else
-+      ret a5                                  ; jump back to the kernel
-+#endif
-+
-+      .size kernel_execve, . - kernel_execve
-+
-+/*
-+ * signal_trampoline()
-+ *
-+ *    Deals with transitioning from to userspace signal handlers and returning
-+ *    to userspace, only called from the kernel.
-+ *
-+ */
-+      .section .kernel_unprotected, "ax", @progbits
-+      .global signal_trampoline
-+signal_trampoline:
-+      /*
-+       * signal_trampoline is called when we are jumping from the kernel to
-+       * the userspace signal handler.
-+       *
-+       * The following registers are relevant. (set setup_rt_frame)
-+       *   sp is the user space stack not the kernel stack
-+       *  d0 = signal number
-+       *  d1 = siginfo_t *
-+       *  d2 = ucontext *
-+       *  d3 = the user space signal handler
-+       *  a0 is set to the GOT if userspace application is FDPIC, otherwise 0
-+       *  a3 is set to the FD for the signal if userspace application is FDPIC
-+       */
-+#ifdef CONFIG_PROTECT_KERNEL
-+      /*
-+       * We are leaving the kernel so we need to enable the protection.
-+       * Enter critical section, disable ranges and leave critical section.
-+       */
-+      atomic_lock_acquire                     ; Enter critical section
-+      disable_kernel_ranges_for_current d15   ; disable kernel ranges
-+      atomic_lock_release                     ; Leave critical section
-+#endif
-+      /*
-+       * The signal handler pointer is in register d3 so tranfer it to a4 and
-+       * call it
-+       */
-+      movea   a4, d3                          ; signal handler
-+      calli   a5, 0(a4)
-+
-+      /*
-+       * Return to userspace through rt_syscall which is stored on top of the
-+       * stack d1 contains ret_via_interrupt status.
-+       */
-+      move.4  d8, (sp)                        ; d8 (syscall #) = rt_syscall
-+      move.4  d1, 4(sp)                       ; d1 = ret_via_interrupt
-+      call    a5, system_call         ; as we are 'in' the kernel
-+                                              ; we can call kernel_syscall
-+
-+      bkpt #-1                                ; will never get here.
-+      .size signal_trampoline, . - signal_trampoline
-+
-+/*
-+ * kernel_thread_helper()
-+ *
-+ *    Entry point for kernel threads (only referenced by kernel_thread()).
-+ *
-+ *    On execution d0 will be 0, d1 will be the argument to be passed to the
-+ *    kernel function.
-+ *    d2 contains the kernel function that needs to get called.
-+ *    d3 will contain address to do_exit which needs to get moved into a5.
-+ *
-+ *    On return from fork the child thread d0 will be 0. We call this dummy
-+ *    function which in turn loads the argument
-+ */
-+      .section .kernel_unprotected, "ax", @progbits
-+      .global kernel_thread_helper
-+kernel_thread_helper:
-+      /*
-+       * Create a kernel thread. This is called from ret_from_vfork (a
-+       * userspace return routine) so we need to put it in an unprotected
-+       * section and re-enable protection before calling the vector in d2.
-+       */
-+
-+#ifdef CONFIG_PROTECT_KERNEL
-+      /*
-+       * We are entering the kernel so we need to disable the protection.
-+       * Enter critical section, disable ranges and leave critical section.
-+       */
-+      call a5, __enable_kernel_ranges
-+#endif
-+      /*
-+       * Move argument for kernel function into d0, and set a5 return address
-+       * (a5) to do_exit and return through a2
-+       */
-+      move.4  d0, d1                          ; d0 = arg
-+      move.4  a5, d3                          ; a5 = do_exit
-+      ret     d2                              ; call function ptr in d2
-+      .size kernel_thread_helper, . - kernel_thread_helper
-+
-+#ifdef CONFIG_PROTECT_KERNEL
-+      .section .kernel_unprotected, "ax", @progbits
-+__enable_kernel_ranges:
-+      atomic_lock_acquire                     ; Enter critical section
-+      enable_kernel_ranges_for_current d15
-+      atomic_lock_release                     ; Leave critical section
-+      calli a5, 0(a5)
-+      .size __enable_kernel_ranges, . - __enable_kernel_ranges
-+
-+#endif
-+
-+/*
-+ * The following system call intercept functions where we setup the
-+ * input to the real system call.  In all cases these are just taking
-+ * the current sp which is pointing to pt_regs and pushing it into the
-+ * last arg of the system call.
-+ *
-+ * i.e. the public definition of sys_execv is
-+ *    sys_execve(     char *name,
-+ *                    char **argv,
-+ *                    char **envp )
-+ * but process.c defines it as
-+ *    sys_execve(     char *name,
-+ *                    char **argv,
-+ *                    char **envp,
-+ *                    struct pt_regs *regs )
-+ *
-+ * so execve_intercept needs to populate the 4th arg with pt_regs*,
-+ * which is the stack pointer as we know we must be coming out of
-+ * system_call
-+ *
-+ * The intercept vectors are referenced by syscalltable.S
-+ */
-+
-+/*
-+ * execve_intercept()
-+ */
-+      .section .text.execve_intercept, "ax", @progbits
-+      .global execve_intercept
-+execve_intercept:
-+      move.4  d3, sp  ; Save pt_regs address
-+      call    a3, sys_execve
-+
-+      .size execve_intercept, . - execve_intercept
-+
-+/*
-+ * vfork_intercept()
-+ */
-+      .section .text.vfork_intercept, "ax", @progbits
-+      .global vfork_intercept
-+vfork_intercept:
-+      move.4  d0, sp  ; Save pt_regs address
-+      call    a3, sys_vfork
-+
-+      .size vfork_intercept, . - vfork_intercept
-+
-+/*
-+ * clone_intercept()
-+ */
-+      .section .text.clone_intercept, "ax", @progbits
-+      .global clone_intercept
-+clone_intercept:
-+      move.4  d2, sp  ; Save pt_regs address
-+      call    a3, sys_clone
-+
-+      .size clone_intercept, . - clone_intercept
-+
-+/*
-+ * sys_sigsuspend()
-+ */
-+      .section .text.sigclone_intercept, "ax", @progbits
-+      .global sys_sigsuspend
-+sys_sigsuspend:
-+      move.4  d0, sp  ; Pass pointer to pt_regs in d0
-+      call    a3, do_sigsuspend
-+
-+      .size sys_sigsuspend, . - sys_sigsuspend
-+
-+/*
-+ * sys_rt_sigsuspend()
-+ */
-+      .section .text.sys_rt_sigsuspend, "ax", @progbits
-+      .global sys_rt_sigsuspend
-+sys_rt_sigsuspend:
-+      move.4  d0, sp  ; Pass pointer to pt_regs in d0
-+      call    a3, do_rt_sigsuspend
-+
-+      .size sys_rt_sigsuspend, . - sys_rt_sigsuspend
-+
-+/*
-+ * sys_rt_sigreturn()
-+ */
-+      .section .text.sys_rt_sigreturn, "ax", @progbits
-+      .global sys_rt_sigreturn
-+sys_rt_sigreturn:
-+      move.4  d0, sp  ; Pass pointer to pt_regs in d0
-+      call    a3, do_rt_sigreturn
-+
-+      .size sys_rt_sigreturn, . - sys_rt_sigreturn
-+
-+/*
-+ * sys_sigaltstack()
-+ */
-+      .section .text.sys_sigaltstack, "ax", @progbits
-+      .global sys_sigaltstack
-+sys_sigaltstack:
-+      move.4  d0, sp  ; Pass pointer to pt_regs in d0
-+      call    a3, do_sys_sigaltstack
-+
-+      .size sys_sigaltstack, . - sys_sigaltstack
---- /dev/null
-+++ b/arch/ubicom32/kernel/unaligned_trap.c
-@@ -0,0 +1,698 @@
-+/*
-+ * arch/ubicom32/kernel/unaligned_trap.c
-+ *   Handle unaligned traps in both user or kernel space.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <asm/cacheflush.h>
-+#include <asm/traps.h>
-+
-+#define FALSE 0
-+#define TRUE 1
-+
-+/* no possible trap */
-+#define UNUSED 0
-+/* possible source operand trap */
-+#define SRC 1
-+#define SRC_2 2
-+/* possible destination operand trap */
-+#define DEST 3
-+#define DEST_2 4
-+/* can be either source or destination or both */
-+#define TWO_OP 5
-+#define TWO_OP_2 6
-+
-+/* TODO: What is the real value here, put something in to make it compile for
-+ * now */
-+#define MOVE_2        0x0d
-+#define LSL_2 0x11
-+#define LSR_2 0x13
-+#define MOVEI 0x19
-+#define CMPI  0x18
-+
-+static int op_format[32] =
-+{
-+      TWO_OP,         /* 0x00 */
-+      UNUSED,
-+      SRC,
-+      UNUSED,
-+      TWO_OP,         /* 0x04 */
-+      TWO_OP,
-+      SRC,
-+      UNUSED,
-+      TWO_OP_2,       /* 0x08 */
-+      TWO_OP,
-+      TWO_OP_2,
-+      TWO_OP,
-+      TWO_OP_2,       /* 0x0C */
-+      TWO_OP,
-+      TWO_OP_2,
-+      TWO_OP,
-+      TWO_OP,         /* 0x10 */
-+      TWO_OP_2,
-+      TWO_OP,
-+      TWO_OP,
-+      UNUSED,         /* 0x14 */
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,
-+      SRC_2,          /* 0x18 */
-+      DEST_2,
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,         /* 0x1C */
-+      UNUSED,
-+      UNUSED,         /* unaligned CALLI will not be fixed. */
-+      UNUSED
-+};
-+
-+static int op_0_format[32] =
-+{
-+      UNUSED,         /* 0x00 */
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,         /* 0x04 - ret don't fix - bad ret is always wrong */
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,         /* 0x08 */
-+      UNUSED,
-+      TWO_OP,
-+      TWO_OP_2,
-+      TWO_OP,         /* 0x0c */
-+      TWO_OP_2,
-+      TWO_OP,
-+      UNUSED,         /* .1 can't trap */
-+      UNUSED,         /* 0x10 */
-+      UNUSED,
-+      SRC,
-+      UNUSED,
-+      UNUSED,         /* 0x14 */
-+      TWO_OP_2,
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,         /* 0x18 */
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,
-+      DEST,           /* 0x1c */
-+      DEST,
-+      DEST,
-+      DEST,           /* all lea have 32-bit destination */
-+};
-+
-+static int op_2_format[32] =
-+{
-+      UNUSED,         /* 0x00 */
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,         /* 0x04 */
-+      UNUSED,
-+      SRC,
-+      UNUSED,
-+      UNUSED,         /* 0x08 crcgen is .1 */
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,         /* 0x0c */
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,
-+      SRC,            /* 0x10 */
-+      SRC_2,
-+      SRC,
-+      SRC_2,
-+      SRC,            /* 0x14 */
-+      SRC_2,
-+      SRC,
-+      UNUSED,
-+      UNUSED,         /* 0x18 */
-+      UNUSED,
-+      SRC,
-+      UNUSED,
-+      SRC,            /* 0x1c */
-+      UNUSED,
-+      SRC_2,
-+      UNUSED,
-+};
-+
-+static int op_6_format[32] =
-+{
-+      SRC_2,          /* 0x00 */
-+      SRC_2,
-+      SRC_2,
-+      SRC_2,
-+      SRC_2,          /* 0x04 */
-+      SRC_2,
-+      UNUSED,
-+      SRC_2,
-+      SRC,            /* 0x08 MULS.4 */
-+      SRC_2,
-+      SRC,
-+      UNUSED,
-+      UNUSED,         /* 0x0c */
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,
-+      SRC,            /* 0x10 */
-+      SRC_2,
-+      SRC,
-+      SRC_2,
-+      UNUSED,         /* 0x14 */
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,         /* 0x18 */
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,         /* 0x1c */
-+      UNUSED,
-+      UNUSED,
-+      UNUSED,
-+};
-+
-+/*
-+ * unaligned_get_address()
-+ *    get an address using save_an and save_dn registers, and updates save_an
-+ *    with side effects
-+ */
-+unsigned char *unaligned_get_address(int thread, int specifier, int four_byte,
-+                                   unsigned int save_an[],
-+                                   unsigned int save_dn[], int *write_back_an)
-+{
-+      unsigned char *address;
-+
-+      int areg = (specifier >> 5) & 7;
-+      if ((specifier >> 8) == 2) {
-+              int offset = specifier & 0xf;
-+              offset = ((offset << 28) >> 28);
-+              if (likely(four_byte)) {
-+                      offset <<= 2;
-+              } else {
-+                      offset <<= 1;
-+              }
-+              if (specifier & 0x10) {
-+                      address = (unsigned char *)(save_an[areg] + offset);
-+              } else {
-+                      address = (unsigned char *)save_an[areg];
-+              }
-+              save_an[areg] = save_an[areg] + offset;
-+
-+              /*
-+               * Let caller know An registers have been modified.
-+               */
-+              *write_back_an = 1;
-+      } else if ((specifier >> 8) == 3) {
-+              int dreg = specifier & 0xf;
-+              if (likely(four_byte)) {
-+                      address = (unsigned char *)(save_an[areg] +
-+                                                  (save_dn[dreg] << 2));
-+              } else {
-+                      address = (unsigned char *)(save_an[areg] +
-+                                                  (save_dn[dreg] << 1));
-+              }
-+      } else {
-+              int offset = ((specifier >> 3) & 0x60) | (specifier & 0x1f);
-+              if (likely(four_byte)) {
-+                      address = (unsigned char *)(save_an[areg] +
-+                                                  (offset << 2));
-+              } else {
-+                      address = (unsigned char *)(save_an[areg] +
-+                                                  (offset << 1));
-+              }
-+      }
-+
-+      return address;
-+}
-+
-+static        int save_dn[16];
-+static        int save_an[8];
-+static        int save_acc[5];
-+
-+/*
-+ * unaligned_emulate()
-+ *    emulate the instruction at thread's pc that has taken an unaligned data
-+ *    trap.
-+ *
-+ * source or destination or both might be unaligned
-+ * the instruction must have a memory source or destination or both
-+ * the emulated instruction is copied and executed in this thread
-+ *
-+ *    TODO: Protection is handled outside of this function
-+ *    TODO: handling simultaneous unaligned and memory protection traps
-+ *
-+ *    Get thread state
-+ *            the PC and instruction (and local copy, emulate_inst), and An
-+ *            and Dn registers
-+ *            All implicit soruce state (source3, CSR, accumulators)
-+
-+ *    if the instruction has a memory source
-+ *            Use the instruction, An and Dn registers to form src_address
-+ *            get unaligned source data from src_address (usually sign
-+ *            extended)
-+ *                    (2 bytes, with or without sign extension, or 4 bytes)
-+ *            modify emulate_inst to use d0 as source
-+ *    else
-+ *            get the soure operand from one of thread's registers
-+ *    if instruction has a memory destination
-+ *            Use the instruction, An and Dn registers to form dest_address
-+ *            modify emulate_inst to use d0 as destination
-+ *    if there was a memory source
-+ *            put the source data in thread's d0
-+ *    get the source-2 Dn operand and source 3 operand from thread
-+ *    execute modified inst
-+ *            (save it, flush caches, set up local values for implicit
-+ *            sources, execute, save explicit and implicit results)
-+ *    if inst has destination address
-+ *            copy result to dest_address, possibly unaligned, 1, 2, or 4
-+ *            bytes
-+ *    restore thread's implicit results (modified address registers, CSR,
-+ *    accumulators) add 4 to thread's pc
-+ */
-+void unaligned_emulate(unsigned int thread)
-+{
-+      unsigned int pc;
-+      unsigned int inst;
-+      unsigned int op;
-+      unsigned int subop;
-+      int format;
-+      unsigned int emulate_inst;
-+      int four_byte;
-+      int src_operand, dest_operand;
-+      int save_csr;
-+      int source3;
-+      unsigned int source1;
-+      unsigned int source_data;
-+      unsigned char *dest_address = NULL;
-+      int source2 = 0;
-+      unsigned int result;
-+      unsigned int write_back_an = 0;
-+      unsigned int chip_id_copy;
-+
-+      extern unsigned int trap_emulate;
-+      extern unsigned int ubicom32_emulate_insn(int source1, int source2,
-+                                                int source3, int *save_acc,
-+                                                int *save_csr);
-+
-+      /*
-+       * get the chip_id
-+       */
-+      asm volatile (
-+      "       move.4          %0, chip_id             \n\t" /* get chip_id. */
-+              : "=r"(chip_id_copy)
-+              :
-+      );
-+
-+      /*
-+       * get the pc
-+       */
-+      asm volatile (
-+      "       move.4          CSR, %1         \n\t" /* set source thread in
-+                                                     * CSR */
-+      "       setcsr_flush    0               \n\t"
-+      "       move.4          %0, pc          \n\t"
-+      "       move.4          CSR, #0         \n\t" /* restore CSR */
-+      "       setcsr_flush    0               \n\t"
-+              : "=a"(pc)
-+              : "d" ((1 << 8) | (thread << 9))
-+              : "cc"
-+      );
-+
-+      inst = *((unsigned int *)pc);
-+      op = inst >> 27;
-+      if (unlikely(op == 2 || op == 6)) {
-+              subop = (inst >> 21) & 0x1f;
-+      } else {
-+              subop = (inst >> 11) & 0x1f;
-+      }
-+      format = op_format[op];
-+      emulate_inst = inst;
-+
-+      if (op == 0) {
-+              format = op_0_format[subop];
-+      } else if (op == 2) {
-+              format = op_2_format[subop];
-+      } else if (op == 6) {
-+              format = op_6_format[subop];
-+      }
-+
-+      if (unlikely(format == UNUSED)) {
-+              /*
-+               * We are not going to emulate this. Bump PC by 4 and move on.
-+               */
-+              asm volatile (
-+              "       move.4          CSR, %0                 \n\t"
-+              "       setcsr_flush    0                       \n\t"
-+              "       move.4          pc, %1                  \n\t"
-+              "       setcsr          #0                      \n\t"
-+              "       setcsr_flush    0                       \n\t"
-+                      :
-+                      : "d"((1 << 14) | (thread << 15)), "d"(pc + 4)
-+                      : "cc"
-+              );
-+              return;
-+      }
-+
-+      four_byte = (format == TWO_OP || format == DEST || format == SRC);
-+
-+      /*
-+       * source or destination memory operand needs emulation
-+       */
-+      src_operand = (format == SRC ||
-+                     format == SRC_2 ||
-+                     format == TWO_OP ||
-+                     format == TWO_OP_2) &&
-+              ((inst >> 8) & 7) > 1;
-+
-+      dest_operand = (format == DEST ||
-+                      format == DEST_2 ||
-+                      format == TWO_OP ||
-+                      format == TWO_OP_2) &&
-+              ((inst >> 24) & 7) > 1;
-+
-+      /*
-+       * get thread's implicit sources (not covered by source context select).
-+       * data and address registers and CSR (for flag bits) and src3 and
-+       * accumulators
-+       */
-+      asm volatile (
-+      "       move.4          CSR, %2         \n\t"   /* set source thread in
-+                                                       * CSR */
-+      "       setcsr_flush    0               \n\t"
-+      "       move.4          (%3), d0        \n\t"   /* get dn registers */
-+      "       move.4          4(%3), d1       \n\t"
-+      "       move.4          8(%3), d2       \n\t"
-+      "       move.4          12(%3), d3      \n\t"
-+      "       move.4          16(%3), d4      \n\t"
-+      "       move.4          20(%3), d5      \n\t"
-+      "       move.4          24(%3), d6      \n\t"
-+      "       move.4          28(%3), d7      \n\t"
-+      "       move.4          32(%3), d8      \n\t"
-+      "       move.4          36(%3), d9      \n\t"
-+      "       move.4          40(%3), d10     \n\t"
-+      "       move.4          44(%3), d11     \n\t"
-+      "       move.4          48(%3), d12     \n\t"
-+      "       move.4          52(%3), d13     \n\t"
-+      "       move.4          56(%3), d14     \n\t"
-+      "       move.4          60(%3), d15     \n\t"
-+      "       move.4          (%4), a0        \n\t"   /* get an registers */
-+      "       move.4          4(%4), a1       \n\t"
-+      "       move.4          8(%4), a2       \n\t"
-+      "       move.4          12(%4), a3      \n\t"
-+      "       move.4          16(%4), a4      \n\t"
-+      "       move.4          20(%4), a5      \n\t"
-+      "       move.4          24(%4), a6      \n\t"
-+      "       move.4          28(%4), a7      \n\t"
-+      "       move.4          %0, CSR         \n\t"   /* get csr and source3
-+                                                       * implicit operands */
-+      "       move.4          %1, source3     \n\t"
-+      "       move.4          (%5), acc0_lo   \n\t"   /* get accumulators */
-+      "       move.4          4(%5), acc0_hi  \n\t"
-+      "       move.4          8(%5), acc1_lo  \n\t"
-+      "       move.4          12(%5), acc1_hi \n\t"
-+      "       move.4          16(%5), mac_rc16        \n\t"
-+      "       move.4          CSR, #0         \n\t"   /* restore CSR */
-+      "       setcsr_flush    0               \n\t"
-+              : "=m"(save_csr), "=m"(source3)
-+              : "d"((1 << 8) | (thread << 9)),
-+                "a"(save_dn), "a"(save_an), "a"(save_acc)
-+              : "cc"
-+      );
-+
-+      /*
-+       * turn off thread select bits if they were on
-+       */
-+      BUG_ON((save_csr & 0x04100) != 0);
-+      if (unlikely(save_csr & 0x04100)) {
-+              /*
-+               * Things are in funny state as thread select bits are on in
-+               * csr. PANIC.
-+               */
-+              panic("In unaligned trap handler. Trap thread CSR has thread "
-+                    "select bits on.\n");
-+      }
-+
-+      save_csr = save_csr & 0x1000ff;
-+
-+      /*
-+       * get the source1 operand
-+       */
-+      source1 = 0;
-+      if (src_operand) {
-+              unsigned char *src_address;
-+
-+              /*
-+               * source1 comes from memory
-+               */
-+              BUG_ON(!(format == TWO_OP || format == TWO_OP_2 ||
-+                       format == SRC || format == SRC_2));
-+              src_address = unaligned_get_address(thread, inst & 0x7ff,
-+                                                  four_byte, save_an,
-+                                                  save_dn, &write_back_an);
-+
-+              /*
-+               * get data (possibly unaligned)
-+               */
-+              if (likely(four_byte)) {
-+                      source_data = (*src_address << 24) |
-+                              (*(src_address + 1) << 16) |
-+                              (*(src_address + 2) << 8) |
-+                              *(src_address + 3);
-+                      source1 = source_data;
-+              } else {
-+                      source1 = *src_address << 8 |
-+                              *(src_address + 1);
-+
-+                      /*
-+                       * Source is not extended if the instrution is MOVE.2 or
-+                       * if the cpu CHIP_ID >= 0x30000 and the instruction is
-+                       * either LSL.2 or LSR.2.  All other cases have to be
-+                       * sign extended.
-+                       */
-+                      if ((!(op == 2 && subop == MOVE_2)) &&
-+                          (!((chip_id_copy >= 0x30000) &&
-+                             (subop == LSL_2 || subop == LSR_2)))) {
-+                              /*
-+                               * Have to sign extend the .2 entry.
-+                               */
-+                              source1 = ((unsigned int)
-+                                         ((signed int)
-+                                          ((signed short) source1)));
-+                      }
-+              }
-+      } else if (likely(op != MOVEI)) {
-+              /*
-+               * source1 comes from a register, using move.4 d0, src1
-+               * unaligned_emulate_get_source is pointer to code to insert remulated instruction
-+               */
-+              extern unsigned int unaligned_emulate_get_src;
-+              *((int *)&unaligned_emulate_get_src) &= ~(0x7ff);
-+              *((int *)&unaligned_emulate_get_src) |= (inst & 0x7ff);
-+              flush_dcache_range((unsigned long)(&unaligned_emulate_get_src),
-+                                 (unsigned long)(&unaligned_emulate_get_src) + 4);
-+
-+              asm volatile (
-+                      /* source1 uses thread's registers */
-+              "       move.4          CSR, %1                 \n\t"
-+              "       setcsr_flush 0                          \n\t"
-+              "unaligned_emulate_get_src:                     \n\t"
-+              "       move.4  %0, #0                          \n\t"
-+              "       setcsr          #0                      \n\t"
-+              "       setcsr_flush    0                       \n\t"
-+                      : "=d" (source1)
-+                      : "d" ((1 << 8) | (thread << 9))
-+                      : "cc"
-+              );
-+      }
-+
-+      /*
-+       * get the destination address
-+       */
-+      if (dest_operand) {
-+              BUG_ON(!(format == TWO_OP || format == TWO_OP_2 ||
-+                       format == DEST || format == DEST_2));
-+              dest_address = unaligned_get_address(thread,
-+                                                   ((inst >> 16) & 0x7ff),
-+                                                   four_byte, save_an,
-+                                                   save_dn, &write_back_an);
-+      }
-+
-+      if (write_back_an) {
-+              /*
-+               * restore any modified An registers
-+               */
-+              asm volatile (
-+              "       move.4          CSR, %0                 \n\t"
-+              "       setcsr_flush    0                       \n\t"
-+              "       move.4          a0, (%1)                \n\t"
-+              "       move.4          a1, 4(%1)               \n\t"
-+              "       move.4          a2, 8(%1)               \n\t"
-+              "       move.4          a3, 12(%1)              \n\t"
-+              "       move.4          a4, 16(%1)              \n\t"
-+              "       move.4          a5, 20(%1)              \n\t"
-+              "       move.4          a6, 24(%1)              \n\t"
-+              "       move.4          a7, 28(%1)              \n\t"
-+              "       setcsr          #0                      \n\t"
-+              "       setcsr_flush    0                       \n\t"
-+                      :
-+                      : "d" ((1 << 14) | (thread << 15)), "a" (save_an)
-+                      : "cc"
-+              );
-+      }
-+
-+      /*
-+       * get source 2 register if needed, and modify inst to use d1 for
-+       * source-2 source-2 will come from this thread, not the trapping thread
-+       */
-+      source2 = 0;
-+      if ((op >= 8 && op <= 0x17) ||
-+          ((op == 2 || op == 6) && (inst & 0x4000000))) {
-+              int src_dn = (inst >> 11) & 0xf;
-+              source2 = save_dn[src_dn];
-+              /*
-+               * force the emulated instruction to use d1 for source2 operand
-+               */
-+              emulate_inst = (emulate_inst & 0xffff07ff) | 0x800;
-+      }
-+
-+      if (likely(op != MOVEI)) {
-+              /*
-+               * change emulated instruction source1 to d0
-+               */
-+              emulate_inst &= ~0x7ff;
-+              emulate_inst |= 1 << 8;
-+      }
-+
-+      if (unlikely(op == 6 || op == 2)) {
-+              /*
-+               * Set destination to d0
-+               */
-+              emulate_inst &= ~(0xf << 16);
-+      } else if (likely(op != CMPI)) {
-+              /*
-+               * Set general destination field to d0.
-+               */
-+              emulate_inst &= ~(0x7ff << 16);
-+              emulate_inst |= 1 << 24;
-+      }
-+
-+      /*
-+       * execute emulated instruction d0, to d0, no memory access
-+       * source2 if needed will be in d1
-+       * source3, CSR, and accumulators are set up before execution
-+       */
-+      *((unsigned int *)&trap_emulate) = emulate_inst;
-+      flush_dcache_range((unsigned long)(&trap_emulate),
-+                         (unsigned long)(&trap_emulate) + 4);
-+
-+      result = ubicom32_emulate_insn(source1, source2, source3,
-+                                     save_acc, &save_csr);
-+
-+      /*
-+       * set the result value
-+       */
-+      if (dest_operand) {
-+              /*
-+               * copy result to memory
-+               */
-+              if (four_byte) {
-+                      *dest_address++ =
-+                              (unsigned char)((result >> 24) & 0xff);
-+                      *dest_address++ =
-+                              (unsigned char)((result >> 16) & 0xff);
-+              }
-+              *dest_address++ = (unsigned char)((result >> 8) & 0xff);
-+              *dest_address = (unsigned char)(result & 0xff);
-+      } else if (likely(op != CMPI)) {
-+              /*
-+               * copy result to a register, using move.4 dest, result
-+               */
-+              extern unsigned int unaligned_trap_set_result;
-+              *((unsigned int *)&unaligned_trap_set_result) &= ~0x7ff0000;
-+
-+              if (op == 2 || op == 6) {
-+                      *((unsigned int *)&unaligned_trap_set_result) |=
-+                              ((inst & 0x000f0000) | 0x01000000);
-+              } else {
-+                      *((unsigned int *)&unaligned_trap_set_result) |=
-+                              (inst & 0x7ff0000);
-+              }
-+              flush_dcache_range((unsigned long)&unaligned_trap_set_result,
-+                                 ((unsigned long)(&unaligned_trap_set_result) + 4));
-+
-+              asm volatile (
-+                      /* result uses thread's registers */
-+              "       move.4          CSR, %1                 \n\t"
-+              "       setcsr_flush 0                          \n\t"
-+              "unaligned_trap_set_result:                     \n\t"
-+              "       move.4 #0, %0                           \n\t"
-+              "       setcsr          #0                      \n\t"
-+              "       setcsr_flush    0                       \n\t"
-+                      :
-+                      : "d"(result), "d" ((1 << 14) | (thread << 15))
-+                      : "cc"
-+              );
-+      }
-+
-+      /*
-+       * bump PC in thread and restore implicit register changes
-+       */
-+      asm volatile (
-+      "       move.4          CSR, %0                 \n\t"
-+      "       setcsr_flush    0                       \n\t"
-+      "       move.4          pc, %1                  \n\t"
-+      "       move.4          acc0_lo, (%3)           \n\t"
-+      "       move.4          acc0_hi, 4(%3)          \n\t"
-+      "       move.4          acc1_lo, 8(%3)          \n\t"
-+      "       move.4          acc1_hi, 12(%3)         \n\t"
-+      "       move.4          mac_rc16, 16(%3)        \n\t"
-+      "       move.4          CSR, %2                 \n\t"
-+      "       setcsr          #0                      \n\t"
-+      "       setcsr_flush    0                       \n\t"
-+              :
-+              : "d"((1 << 14) | (thread << 15)),
-+                "d"(pc + 4), "d"(save_csr), "a"(save_acc)
-+              : "cc"
-+      );
-+}
-+
-+/*
-+ * unaligned_only()
-+ *    Return true if either of the unaligned causes are set (and no others).
-+ */
-+int unaligned_only(unsigned int cause)
-+{
-+      unsigned int unaligned_cause_mask =
-+              (1 << TRAP_CAUSE_DST_MISALIGNED) |
-+              (1 << TRAP_CAUSE_SRC1_MISALIGNED);
-+
-+      BUG_ON(cause == 0);
-+      return (cause & unaligned_cause_mask) == cause;
-+}
---- /dev/null
-+++ b/arch/ubicom32/kernel/vmlinux.lds.S
-@@ -0,0 +1,370 @@
-+/*
-+ * arch/ubicom32/kernel/vmlinux.lds.S
-+ *    vmlinux primary linker script
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <asm-generic/vmlinux.lds.h>
-+#include <asm/ocm_size.h>
-+#include <asm/memory_map.h>
-+#include <asm/thread_info.h>
-+#include <linux/threads.h>
-+
-+/*
-+ * Sanity checks to prevent errors later on that are much harder to understand
-+ */
-+#if !defined APP_OCM_CODE_SIZE
-+#error APP_OCM_CODE_SIZE has not been defined in ocm_size.h
-+#endif
-+
-+#if !defined APP_OCM_DATA_SIZE
-+#error APP_OCM_DATA_SIZE has not been defined in ocm_size.h
-+#endif
-+
-+/*
-+ * The `free' ocm area that ultra does not use.
-+ */
-+#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE
-+#define OCM_FREE_START        (OCMSTART + APP_OCM_CODE_SIZE)
-+#define OCM_FREE_LENGTH       (OCMSIZE - APP_OCM_CODE_SIZE - APP_OCM_DATA_SIZE)
-+#else
-+#define OCM_FREE_START OCMEND
-+#define OCM_FREE_LENGTH 0
-+#endif
-+
-+/*
-+ * If you want to limit OCM use for text/data or completely disable it
-+ * you can change these values.
-+ */
-+#define OCM_TEXT_LENGTH       OCM_FREE_LENGTH
-+#define OCM_DATA_LENGTH       OCM_FREE_LENGTH
-+
-+#define       RAM_START       KERNELSTART
-+#define       RAM_LENGTH      ((SDRAMSTART + CONFIG_MIN_RAMSIZE) - RAM_START)
-+#define       TEXT            ram
-+#define       DATA            ram
-+#define       INIT            ram
-+#define       BSS             ram
-+
-+#ifndef DATA_ADDR
-+#define       DATA_ADDR
-+#endif
-+
-+#include <asm-generic/vmlinux.lds.h>
-+
-+OUTPUT_ARCH(ubicom32)
-+ENTRY(_start)
-+
-+MEMORY {
-+      ram             : ORIGIN = RAM_START, LENGTH = RAM_LENGTH
-+      syscall         : ORIGIN = OS_SYSCALL_BEGIN, LENGTH = (OS_SYSCALL_END - OS_SYSCALL_BEGIN)
-+      ocm             : ORIGIN = OCM_FREE_START, LENGTH = OCM_FREE_LENGTH
-+}
-+
-+jiffies = jiffies_64 + 4;
-+
-+/*
-+ * Fixed locations required by gdb coredumps.
-+ *
-+ * Note that the names are what gdb is expecting so renaming will break
-+ * the toolchain.
-+ */
-+__ocm_begin           = OCMSTART;
-+__ocm_limit           = __ocm_begin + OCMSIZE;
-+__sdram_begin         = SDRAMSTART;
-+__sdram_limit         = __sdram_begin + CONFIG_MIN_RAMSIZE;
-+__filemedia_begin_addr        = FLASHSTART;
-+__filemedia_end_addr  = __filemedia_begin_addr + 0x00800000;
-+
-+/*
-+ * For internal diagnostics
-+ */
-+__os_syscall_begin    = OS_SYSCALL_BEGIN;
-+__os_syscall_end      = OS_SYSCALL_END;
-+
-+SECTIONS {
-+
-+      .fixed_text : {
-+              _begin = .;
-+              *(.skip_syscall)
-+              *(.old_syscall_entry.text)
-+              __fixed_text_end = .;
-+      } > TEXT
-+      . = _begin + SIZEOF(.fixed_text) ;
-+
-+      /*
-+       * System call text in lower ocm (fixed location, can never change)
-+       */
-+      __syscall_text_load_begin = .;
-+      __syscall_text_run_begin = OS_SYSCALL_BEGIN;
-+
-+      .syscall_text __syscall_text_run_begin : AT(__syscall_text_load_begin) {
-+              *(.syscall_entry.text) /* Must be at OS_SYSCALL_BEGIN 0x3ffc0040 */
-+              *(.kernel_unprotected)
-+              . = ALIGN(4);
-+              __syscall_text_run_end = .;
-+      } > syscall /* .syscall_text */
-+      . = __syscall_text_load_begin + __syscall_text_run_end - __syscall_text_run_begin ;
-+      __ocm_text_load_begin = .;
-+      __ocm_text_run_begin = OCM_FREE_START ;
-+      .ocm_text __ocm_text_run_begin : AT(__ocm_text_load_begin) {
-+#if OCM_TEXT_LENGTH
-+              *(.ocm_text)
-+              *(.sched.text)
-+              *(.spinlock.text)
-+#include <asm/ocm_text.lds.inc>
-+              . = ALIGN(4);
-+#endif
-+              __ocm_text_run_end = .;
-+              __data_begin = ALIGN(OCM_SECTOR_SIZE);
-+      } > ocm /* .ocm_text */
-+
-+      .ocm_module_text __ocm_text_run_end (NOLOAD) : AT(__ocm_text_run_end) {
-+              __ocm_inst_heap_begin = .;
-+              /* Reserve the min requested */
-+              . += (CONFIG_OCM_MODULES_RESERVATION) * 1024;
-+#ifdef CONFIG_OCM_MODULES_MAY_CONSUME_REMAINING_CODESPACE
-+              /* Round up to OCM sector size (we cannot use it for data) */
-+              . = ALIGN(OCM_SECTOR_SIZE);
-+#endif
-+              __ocm_inst_heap_end = .;
-+              /* update __data_begin */
-+              __data_begin = ALIGN(OCM_SECTOR_SIZE);
-+      } > ocm  /* .ocm_module_text */
-+
-+      . = __ocm_text_load_begin + __ocm_text_run_end - __ocm_text_run_begin ;
-+      __ocm_text_load_end = .;
-+
-+      __ocm_data_load_begin = .;
-+      __ocm_data_run_begin = __data_begin ;
-+#if OCM_DATA_LENGTH
-+      .ocm_data __ocm_data_run_begin : AT(__ocm_data_load_begin) {
-+#if defined(CONFIG_IRQSTACKS_USEOCM)
-+              percpu_irq_stacks = .;
-+              . += NR_CPUS * THREAD_SIZE;
-+#endif
-+              *(.ocm_data)
-+              . = ALIGN(4) ;
-+              __ocm_data_run_end = .;
-+      } > ocm
-+      . = __ocm_data_load_begin + __ocm_data_run_end - __ocm_data_run_begin ;
-+#else
-+      __ocm_data_run_end = __ocm_data_run_begin;
-+#endif
-+      __ocm_data_load_end = .;
-+
-+      __ocm_free_begin = __ocm_data_run_end;
-+      __ocm_free_end = OCM_FREE_START + OCM_FREE_LENGTH;
-+
-+      .text __ocm_data_load_end : AT(__ocm_data_load_end) {
-+              . = ALIGN(4);
-+              _stext = .;
-+              _text = .;
-+              TEXT_TEXT
-+              SCHED_TEXT
-+              LOCK_TEXT
-+              *(.text.lock)
-+              *(.text.__libgcc_udivmodsi)
-+              *(.text.__libgcc_divmodsi)
-+              *(.text.__libgcc_muldi3)
-+              *(.text.__libgcc_udivmoddi)
-+              *(.text.__libgcc_divmoddi)
-+              *(.text.*)
-+#if OCM_TEXT_LENGTH == 0
-+              *(.ocm_text)
-+              *(.sched.text)
-+              *(.spinlock.text)
-+#endif
-+              . = ALIGN(16);          /* Exception table              */
-+              __start___ex_table = .;
-+              *(__ex_table)
-+              __stop___ex_table = .;
-+
-+              *(.rodata) *(.rodata.*)
-+              *(__vermagic)           /* Kernel version magic */
-+              *(__markers_strings)
-+              *(.rodata1)
-+              *(.rodata.str1.1)
-+              *(__tracepoints_strings)
-+
-+               /* PCI quirks */
-+              __start_pci_fixups_early = . ;
-+                      *(.pci_fixup_early)
-+              __end_pci_fixups_early = . ;
-+              __start_pci_fixups_header = . ;
-+                      *(.pci_fixup_header)
-+              __end_pci_fixups_header = . ;
-+              __start_pci_fixups_final = . ;
-+                      *(.pci_fixup_final)
-+              __end_pci_fixups_final = . ;
-+              __start_pci_fixups_enable = . ;
-+                      *(.pci_fixup_enable)
-+              __end_pci_fixups_enable = . ;
-+              __start_pci_fixups_resume = . ;
-+                     *(.pci_fixup_resume)
-+              __end_pci_fixups_resume = . ;
-+              __start_pci_fixups_resume_early = . ;
-+                     *(.pci_fixup_resume_early)
-+              __end_pci_fixups_resume_early = . ;
-+              __start_pci_fixups_suspend  = . ;
-+                     *(.pci_fixup_suspend)
-+              __end_pci_fixups_suspend = . ;
-+
-+              __start_builtin_fw = . ;
-+                      *(.builtin_fw)
-+              __end_builtin_fw = . ;
-+
-+
-+              /* Kernel symbol table: Normal symbols */
-+              . = ALIGN(4);
-+              __start___ksymtab = .;
-+              *(__ksymtab)
-+              __stop___ksymtab = .;
-+
-+              /* Kernel symbol table: GPL-only symbols */
-+              __start___ksymtab_gpl = .;
-+              *(__ksymtab_gpl)
-+              __stop___ksymtab_gpl = .;
-+
-+              /* Kernel symbol table: Normal unused symbols */
-+              __start___ksymtab_unused = .;
-+              *(__ksymtab_unused)
-+              __stop___ksymtab_unused = .;
-+
-+              /* Kernel symbol table: GPL-only unused symbols */
-+              __start___ksymtab_unused_gpl = .;
-+              *(__ksymtab_unused_gpl)
-+              __stop___ksymtab_unused_gpl = .;
-+
-+              /* Kernel symbol table: GPL-future symbols */
-+              __start___ksymtab_gpl_future = .;
-+              *(__ksymtab_gpl_future)
-+              __stop___ksymtab_gpl_future = .;
-+
-+              /* Kernel symbol table: Normal symbols */
-+              __start___kcrctab = .;
-+              *(__kcrctab)
-+              __stop___kcrctab = .;
-+
-+              /* Kernel symbol table: GPL-only symbols */
-+              __start___kcrctab_gpl = .;
-+              *(__kcrctab_gpl)
-+              __stop___kcrctab_gpl = .;
-+
-+              /* Kernel symbol table: GPL-future symbols */
-+              __start___kcrctab_gpl_future = .;
-+              *(__kcrctab_gpl_future)
-+              __stop___kcrctab_gpl_future = .;
-+
-+              /* Kernel symbol table: strings */
-+              *(__ksymtab_strings)
-+
-+              /* Built-in module parameters */
-+              . = ALIGN(4) ;
-+              __start___param = .;
-+              *(__param)
-+              __stop___param = .;
-+
-+              . = ALIGN(4) ;
-+              _etext = . ;
-+      } > TEXT
-+
-+      .data DATA_ADDR : {
-+              . = ALIGN(4);
-+              _sdata = . ;
-+              DATA_DATA
-+#if OCM_DATA_LENGTH == 0
-+              *(.ocm_data)
-+#endif
-+              . = ALIGN(8192) ;
-+              _data_protection_end = .;
-+              *(.data.init_task)
-+              . = ALIGN(4);
-+              _edata = . ;
-+      } > DATA
-+
-+      .init : {
-+              . = ALIGN(4096);
-+              __init_begin = .;
-+              _sinittext = .;
-+              INIT_TEXT
-+              _einittext = .;
-+              *(.init.rodata)
-+              INIT_DATA
-+              . = ALIGN(16);
-+              __setup_start = .;
-+              *(.init.setup)
-+              __setup_end = .;
-+              __initcall_start = .;
-+              INITCALLS
-+              __initcall_end = .;
-+              __con_initcall_start = .;
-+              *(.con_initcall.init)
-+              __con_initcall_end = .;
-+              ___security_initcall_start = .;
-+              *(.security_initcall.init)
-+              ___security_initcall_end = .;
-+#ifdef CONFIG_BLK_DEV_INITRD
-+              . = ALIGN(4);
-+              __initramfs_start = .;
-+              *(.init.ramfs)
-+              __initramfs_end = .;
-+#endif
-+              . = ALIGN(4096);
-+              __per_cpu_start = .;
-+                      *(.data.percpu)
-+                      *(.data.percpu.shared_aligned)
-+              __per_cpu_end = .;
-+
-+              . = ALIGN(4096);
-+              __init_end = .;
-+      } > INIT
-+
-+        .eh_frame   :
-+        {
-+          PROVIDE (___eh_frame_begin = .);
-+          *(.eh_frame)
-+          LONG (0);
-+          PROVIDE (___eh_frame_end = .);
-+        } > INIT
-+
-+      /DISCARD/ : {
-+              EXIT_TEXT
-+              EXIT_DATA
-+              *(.exitcall.exit)
-+      }
-+
-+      .bss : {
-+              . = ALIGN(4);
-+              _sbss = . ;
-+              *(.bss)
-+              *(COMMON)
-+              . = ALIGN(4) ;
-+              _ebss = . ;
-+              _end = . ;
-+      } > BSS
-+
-+      NOTES > BSS
-+
-+}
---- /dev/null
-+++ b/arch/ubicom32/lib/checksum.c
-@@ -0,0 +1,250 @@
-+/*
-+ * arch/ubicom32/lib/checksum.c
-+ *   Optimized checksum utilities for IP.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+/*
-+ * 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.
-+ *
-+ *            IP/TCP/UDP checksumming routines
-+ *
-+ * Authors:   Jorge Cwik, <jorge@laser.satlink.net>
-+ *            Arnt Gulbrandsen, <agulbra@nvg.unit.no>
-+ *            Tom May, <ftom@netcom.com>
-+ *            Andreas Schwab, <schwab@issan.informatik.uni-dortmund.de>
-+ *            Lots of code moved from tcp.c and ip.c; see those files
-+ *            for more names.
-+ *
-+ * 03/02/96   Jes Sorensen, Andreas Schwab, Roman Hodek:
-+ *            Fixed some nasty bugs, causing some horrible crashes.
-+ *            A: At some points, the sum (%0) was used as
-+ *            length-counter instead of the length counter
-+ *            (%1). Thanks to Roman Hodek for pointing this out.
-+ *            B: GCC seems to mess up if one uses too many
-+ *            data-registers to hold input values and one tries to
-+ *            specify d0 and d1 as scratch registers. Letting gcc choose these
-+ *            registers itself solves the problem.
-+ *
-+ *            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.
-+ */
-+
-+/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access kills, so most
-+   of the assembly has to go. */
-+
-+#include <linux/module.h>
-+#include <net/checksum.h>
-+
-+static unsigned long do_csum(const unsigned char * buff, int len)
-+{
-+      int count;
-+      unsigned long result = 0;
-+
-+      /*
-+       * The following optimized assembly code cannot handle data length less than 7 bytes!
-+       */
-+      if (likely(len >= 7)) {
-+              len -= (4 - (int)buff) & 3;
-+              count = len >> 2;
-+              asm (
-+              "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
-+              "       and.4           d15, #(32-1), d15       \n\t"   // d15 = (-m) & (32 - 1)
-+
-+              "       bfextu          d14, %0, #2             \n\t"   // test 2 LSB of buff
-+              "       jmpne.w.f       100f                    \n\t"
-+              "       add.4           %1, #0, %1              \n\t"   // clear C
-+              "       moveai          a3, #%%hi(1f)           \n\t"   // table jump
-+              "       lea.1           a3, %%lo(1f)(a3)        \n\t"
-+              "       lea.4           a3, (a3,d15)            \n\t"
-+              "       calli           a3, 0(a3)               \n\t"
-+
-+              "100:   sub.4           %0, %0, d14             \n\t"
-+              "       sub.4           d14, #4, d14            \n\t"
-+              "       lsl.4           d14, d14, #3            \n\t"
-+              "       add.4           %1, #0, %1              \n\t"   // clear C
-+              "       moveai          a3, #%%hi(1f)           \n\t"   // table jump
-+              "       lea.1           a3, %%lo(1f)(a3)        \n\t"
-+              "       lea.4           a3, (a3,d15)            \n\t"
-+              "       bfextu          %1, (%0)4++, d14        \n\t"   // read first partial word
-+              "       calli           a3, 0(a3)               \n\t"
-+#if 1
-+              "200:   lsl.4           %3, %3, #3              \n\t"
-+              "       bfrvrs          d15, (%0), #0           \n\t"   // read last word (partial)
-+              "       bfextu          d15, d15, %3            \n\t"
-+              "       bfrvrs          d15, d15, #0            \n\t"
-+              "       add.4           %1, d15, %1             \n\t"
-+              "       addc            %1, #0, %1              \n\t"   // sample C again
-+              "       jmpt.w.t        2f                      \n\t"
-+#else
-+              "200:   move.1          d15, 0(%0)              \n\t"
-+              "       lsl.4           d15, d15, #8            \n\t"
-+              "       add.4           %1, d15, %1             \n\t"
-+              "       addc            %1, #0, %1              \n\t"   // sample C again
-+              "       add.4           %3, #-1, %3             \n\t"
-+              "       jmpeq.w.t       2f                      \n\t"
-+
-+              "       move.1          d15, 1(%0)              \n\t"
-+              "       add.4           %1, d15, %1             \n\t"
-+              "       addc            %1, #0, %1              \n\t"   // sample C again
-+              "       add.4           %3, #-1, %3             \n\t"
-+              "       jmpeq.w.t       2f                      \n\t"
-+
-+              "       move.1          d15, 2(%0)              \n\t"
-+              "       lsl.4           d15, d15, #8            \n\t"
-+              "       add.4           %1, d15, %1             \n\t"
-+              "       addc            %1, #0, %1              \n\t"   // sample C again
-+              "       jmpt.w.t        2f                      \n\t"
-+#endif
-+#if defined(IP7000) || defined(IP7000_REV2)
-+              "300:   swapb.2         %1, %1                  \n\t"
-+#else
-+              "300:   shmrg.2         %1, %1, %1              \n\t"
-+              "       lsr.4           %1, %1, #8              \n\t"
-+              "       bfextu          %1, %1, #16             \n\t"
-+#endif
-+              "       jmpt.w.t        3f                      \n\t"
-+
-+              "1:     add.4           %1, (%0)4++, %1         \n\t"   // first add without C
-+              "       .rept           31                      \n\t"
-+              "       addc            %1, (%0)4++, %1         \n\t"
-+              "       .endr                                   \n\t"
-+              "       addc            %1, #0, %1              \n\t"   // sample C again
-+              "       add.4           %2, #-32, %2            \n\t"
-+              "       jmpgt.w.t       1b                      \n\t"
-+
-+              "       and.4           %3, #3, %3              \n\t"   // check n
-+              "       jmpne.w.f       200b                    \n\t"
-+
-+              "2:     .rept           2                       \n\t"
-+              "       lsr.4           d15, %1, #16            \n\t"
-+              "       bfextu          %1, %1, #16             \n\t"
-+              "       add.4           %1, d15, %1             \n\t"
-+              "       .endr                                   \n\t"
-+              "       btst            d14, #3                 \n\t"   // start from odd address (<< 3)?
-+              "       jmpne.w.f       300b                    \n\t"
-+              "3:                                             \n\t"
-+
-+                      : "+a"(buff), "+d"(result), "+d"(count), "+d"(len)
-+                      :
-+                      : "d15", "d14", "a3", "cc"
-+              );
-+
-+              return result;
-+      }
-+
-+      /*
-+       * handle a few bytes and fold result into 16-bit
-+       */
-+      while (len-- > 0) {
-+              result += (*buff++ << 8);
-+              if (len) {
-+                      result += *buff++;
-+                      len--;
-+              }
-+      }
-+      asm (
-+      "       .rept           2                       \n\t"
-+      "       lsr.4           d15, %0, #16            \n\t"
-+      "       bfextu          %0, %0, #16             \n\t"
-+      "       add.4           %0, d15, %0             \n\t"
-+      "       .endr                                   \n\t"
-+              : "+d" (result)
-+              :
-+              : "d15", "cc"
-+      );
-+
-+      return result;
-+}
-+
-+/*
-+ *    This is a version of ip_compute_csum() optimized for IP headers,
-+ *    which always checksum on 4 octet boundaries.
-+ */
-+__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
-+{
-+      return (__force __sum16)~do_csum(iph,ihl*4);
-+}
-+
-+/*
-+ * 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
-+ */
-+__wsum csum_partial(const void *buff, int len, __wsum sum)
-+{
-+      unsigned int result = do_csum(buff, len);
-+
-+      /* add in old sum, and carry.. */
-+      result += (__force u32)sum;
-+      if ((__force u32)sum > result)
-+              result += 1;
-+      return (__force __wsum)result;
-+}
-+
-+EXPORT_SYMBOL(csum_partial);
-+
-+/*
-+ * this routine is used for miscellaneous IP-like checksums, mainly
-+ * in icmp.c
-+ */
-+__sum16 ip_compute_csum(const void *buff, int len)
-+{
-+      return (__force __sum16)~do_csum(buff,len);
-+}
-+
-+/*
-+ * copy from fs while checksumming, otherwise like csum_partial
-+ */
-+
-+__wsum
-+csum_partial_copy_from_user(const void __user *src, void *dst,
-+                          int len, __wsum sum, int *csum_err)
-+{
-+      if (csum_err) *csum_err = 0;
-+      memcpy(dst, (__force const void *)src, len);
-+      return csum_partial(dst, len, sum);
-+}
-+
-+/*
-+ * copy from ds while checksumming, otherwise like csum_partial
-+ */
-+
-+__wsum
-+csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
-+{
-+      memcpy(dst, src, len);
-+      return csum_partial(dst, len, sum);
-+}
---- /dev/null
-+++ b/arch/ubicom32/lib/delay.c
-@@ -0,0 +1,49 @@
-+/*
-+ * arch/ubicom32/lib/delay.c
-+ *   Ubicom32 implementation of udelay()
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/module.h>
-+#include <asm/param.h>
-+#include <asm/delay.h>
-+#include <asm/ip5000.h>
-+
-+/*
-+ * read_current_timer()
-+ *    Return the current value of sysval.
-+ */
-+int __devinit read_current_timer(unsigned long *timer_val)
-+{
-+      *timer_val = (long)(UBICOM32_IO_TIMER->sysval);
-+      return 0;
-+}
-+
-+
-+void udelay(unsigned long usecs)
-+{
-+      _udelay(usecs);
-+}
-+EXPORT_SYMBOL(udelay);
---- /dev/null
-+++ b/arch/ubicom32/lib/Makefile
-@@ -0,0 +1,32 @@
-+#
-+# arch/ubicom32/lib/Makefile
-+#     <TODO: Replace with short file description>
-+#
-+# (C) Copyright 2009, Ubicom, Inc.
-+#
-+# This file is part of the Ubicom32 Linux Kernel Port.
-+#
-+# The Ubicom32 Linux Kernel Port 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.
-+#
-+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+# see <http://www.gnu.org/licenses/>.
-+#
-+# Ubicom32 implementation derived from (with many thanks):
-+#   arch/m68knommu
-+#   arch/blackfin
-+#   arch/parisc
-+#
-+#
-+# Makefile for m68knommu specific library files..
-+#
-+
-+lib-y := checksum.o delay.o mem_ubicom32.o
---- /dev/null
-+++ b/arch/ubicom32/lib/mem_ubicom32.c
-@@ -0,0 +1,343 @@
-+/*
-+ * arch/ubicom32/lib/mem_ubicom32.c
-+ *   String functions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/compiler.h>
-+
-+#define LIKELY likely
-+#define UNLIKELY unlikely
-+
-+typedef u32_t addr_t;
-+
-+/*
-+ * memcpy()
-+ */
-+void *memcpy(void *dest, const void *src, size_t n)
-+{
-+      void *dest_ret = dest;
-+
-+      if (LIKELY((((addr_t)dest ^ (addr_t)src) & 3) == 0) && LIKELY(n > 6)) {
-+              size_t m;
-+              n -= (4 - (addr_t)dest) & 0x03;
-+              m = n >> 2;
-+              asm volatile (
-+              "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
-+              "       and.4           d15, #(32-1), d15       \n\t"   // d15 = (-m) & (32 - 1)
-+              "       moveai          a3, #%%hi(1f)           \n\t"
-+              "       lea.1           a3, %%lo(1f)(a3)        \n\t"
-+              "       lea.4           a3, (a3,d15)            \n\t"
-+
-+              "       bfextu          d15, %0, #2             \n\t"   // d15 = (dest & 3)
-+              "       jmpne.w.f       100f                    \n\t"
-+              "       calli           a3, 0(a3)               \n\t"   // 4-byte alignment
-+
-+              "100:   cmpi            d15, #2                 \n\t"
-+              "       jmpne.s.f       101f                    \n\t"
-+              "       move.2          (%0)2++, (%1)2++        \n\t"
-+              "       calli           a3, 0(a3)               \n\t"   // 2-byte alignment
-+
-+              "101:   move.1          (%0)1++, (%1)1++        \n\t"
-+              "       jmpgt.s.f       102f                    \n\t"   // 3-byte alignment
-+              "       move.2          (%0)2++, (%1)2++        \n\t"   // 1-byte alignment
-+              "102:   calli           a3, 0(a3)               \n\t"
-+
-+              "200:   cmpi            %3, #2                  \n\t"
-+              "       jmplt.s.f       201f                    \n\t"
-+              "       move.2          (%0)2++, (%1)2++        \n\t"
-+              "       jmpeq.s.t       2f                      \n\t"
-+              "201:   move.1          (%0)1++, (%1)1++        \n\t"
-+              "       jmpt.w.t        2f                      \n\t"
-+
-+              "1:     .rept           25                      \n\t"
-+              "       movea           (%0)4++, (%1)4++        \n\t"
-+              "       .endr                                   \n\t"
-+              "       .rept           7                       \n\t"
-+              "       move.4          (%0)4++, (%1)4++        \n\t"
-+              "       .endr                                   \n\t"
-+              "       add.4           %2, #-32, %2            \n\t"
-+              "       jmpgt.w.f       1b                      \n\t"
-+
-+              "       and.4           %3, #3, %3              \n\t"   // check n
-+              "       jmpne.w.f       200b                    \n\t"
-+              "2:                                             \n\t"
-+                      : "+a" (dest), "+a" (src), "+d" (m), "+d" (n)
-+                      :
-+                      : "d15", "a3", "memory", "cc"
-+              );
-+
-+              return dest_ret;
-+      }
-+
-+      if (LIKELY((((addr_t)dest ^ (addr_t)src) & 1) == 0) && LIKELY(n > 2)) {
-+              size_t m;
-+              n -= (addr_t)dest & 0x01;
-+              m = n >> 1;
-+              asm volatile (
-+              "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
-+              "       and.4           d15, #(32-1), d15       \n\t"   // d15 = (-m) & (32 - 1)
-+              "       moveai          a3, #%%hi(1f)           \n\t"
-+              "       lea.1           a3, %%lo(1f)(a3)        \n\t"
-+              "       lea.4           a3, (a3,d15)            \n\t"
-+
-+              "       btst            %0, #0                  \n\t"   // check bit 0
-+              "       jmpne.w.f       100f                    \n\t"
-+              "       calli           a3, 0(a3)               \n\t"   // 4-byte alignment
-+
-+              "100:   move.1          (%0)1++, (%1)1++        \n\t"
-+              "       calli           a3, 0(a3)               \n\t"
-+
-+              "200:   move.1          (%0)1++, (%1)1++        \n\t"
-+              "       jmpt.w.t        2f                      \n\t"
-+
-+              "1:     .rept           32                      \n\t"
-+              "       move.2          (%0)2++, (%1)2++        \n\t"
-+              "       .endr                                   \n\t"
-+              "       add.4           %2, #-32, %2            \n\t"
-+              "       jmpgt.w.f       1b                      \n\t"
-+
-+              "       and.4           %3, #1, %3              \n\t"   // check n
-+              "       jmpne.w.f       200b                    \n\t"
-+              "2:                                             \n\t"
-+
-+                      : "+a" (dest), "+a" (src), "+d" (m), "+d" (n)
-+                      :
-+                      : "d15", "a3", "memory", "cc"
-+              );
-+
-+              return dest_ret;
-+      }
-+
-+      asm volatile (
-+      "       sub.4           d15, #0, %2             \n\t"
-+      "       jmpeq.w.f       2f                      \n\t"
-+      "       and.4           d15, #(16-1), d15       \n\t"   // d15 = (-n) & (16 - 1)
-+      "       moveai          a3, #%%hi(1f)           \n\t"
-+      "       lea.1           a3, %%lo(1f)(a3)        \n\t"
-+      "       lea.4           a3, (a3,d15)            \n\t"
-+      "       calli           a3, 0(a3)               \n\t"
-+
-+      "1:     .rept           16                      \n\t"
-+      "       move.1          (%0)1++, (%1)1++        \n\t"
-+      "       .endr                                   \n\t"
-+      "       add.4           %2, #-16, %2            \n\t"
-+      "       jmpgt.w.f       1b                      \n\t"
-+      "2:                                             \n\t"
-+
-+              : "+a" (dest), "+a" (src), "+d" (n)
-+              :
-+              : "d15", "a3", "memory", "cc"
-+      );
-+
-+      return dest_ret;
-+}
-+
-+/*
-+ * memset()
-+ */
-+void *memset(void *s, int c, size_t n)
-+{
-+      void *s_ret = s;
-+
-+      if (LIKELY(n > 6)) {
-+              size_t m;
-+              n -= (4 - (addr_t)s) & 0x03;
-+              m = n >> 2;
-+              asm volatile (
-+              "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
-+              "       and.4           d15, #(32-1), d15       \n\t"   // d15 = (-m) & (32 - 1)
-+              "       shmrg.1         %1, %1, %1              \n\t"
-+              "       shmrg.2         %1, %1, %1              \n\t"   // %1 = (c<<24)|(c<<16)|(c<<8)|c
-+              "       moveai          a3, #%%hi(1f)           \n\t"
-+              "       lea.1           a3, %%lo(1f)(a3)        \n\t"
-+              "       lea.4           a3, (a3,d15)            \n\t"
-+
-+              "       bfextu          d15, %0, #2             \n\t"   // d15 = (s & 3)
-+              "       jmpne.w.f       100f                    \n\t"
-+              "       calli           a3, 0(a3)               \n\t"   // 4-byte alignment
-+
-+              "100:   cmpi            d15, #2                 \n\t"
-+              "       jmpne.s.f       101f                    \n\t"
-+              "       move.2          (%0)2++, %1             \n\t"
-+              "       calli           a3, 0(a3)               \n\t"   // 2-byte alignment
-+
-+              "101:   move.1          (%0)1++, %1             \n\t"
-+              "       jmpgt.s.f       102f                    \n\t"   // 3-byte alignment
-+              "       move.2          (%0)2++, %1             \n\t"   // 1-byte alignment
-+              "102:   calli           a3, 0(a3)               \n\t"
-+
-+              "200:   cmpi            %3, #2                  \n\t"
-+              "       jmplt.s.f       201f                    \n\t"
-+              "       move.2          (%0)2++, %1             \n\t"
-+              "       jmpeq.s.t       2f                      \n\t"
-+              "201:   move.1          (%0)1++, %1             \n\t"
-+              "       jmpt.w.t        2f                      \n\t"
-+
-+              "1:     .rept           25                      \n\t"
-+              "       movea           (%0)4++, %1             \n\t"
-+              "       .endr                                   \n\t"
-+              "       .rept           7                       \n\t"
-+              "       move.4          (%0)4++, %1             \n\t"
-+              "       .endr                                   \n\t"
-+              "       add.4           %2, #-32, %2            \n\t"
-+              "       jmpgt.w.f       1b                      \n\t"
-+
-+              "       and.4           %3, #3, %3              \n\t"   // test bit 1 of n
-+              "       jmpne.w.f       200b                    \n\t"
-+              "2:                                             \n\t"
-+
-+                      : "+a" (s), "+d" (c), "+d" (m), "+d" (n)
-+                      :
-+                      : "d15", "a3", "memory", "cc"
-+              );
-+
-+              return s_ret;
-+      }
-+
-+      asm volatile (
-+      "       sub.4           d15, #0, %2             \n\t"
-+      "       jmpeq.w.f       2f                      \n\t"
-+      "       and.4           d15, #(8-1), d15        \n\t"   // d15 = (-%2) & (16 - 1)
-+      "       moveai          a3, #%%hi(1f)           \n\t"
-+      "       lea.1           a3, %%lo(1f)(a3)        \n\t"
-+      "       lea.4           a3, (a3,d15)            \n\t"
-+      "       calli           a3, 0(a3)               \n\t"
-+
-+      "1:     .rept           8                       \n\t"
-+      "       move.1          (%0)1++, %1             \n\t"
-+      "       .endr                                   \n\t"
-+      "2:                                             \n\t"
-+
-+              : "+a" (s), "+d" (c), "+d" (n)
-+              :
-+              : "d15", "a3", "memory", "cc"
-+      );
-+
-+      return s_ret;
-+}
-+
-+void *memmove(void *dest, const void *src, size_t n)
-+{
-+      char *tmp;
-+      const char *s;
-+
-+      if (n == 0)
-+              return dest;
-+
-+      tmp = dest;
-+      s = src;
-+
-+      /*
-+       * Will perform 16-bit move if possible
-+       */
-+      if (likely((((u32)dest | (u32)src | n) & 1) == 0)) {
-+              if (dest <= src) {
-+                      asm volatile (
-+                      "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
-+                      "       and.4           d15, #(32-2), d15       \n\t"   // d15 = (- count) & (32 - 2)
-+                      "       moveai          a3, #%%hi(1f)           \n\t"
-+                      "       lea.1           a3, %%lo(1f)(a3)        \n\t"
-+                      "       lea.2           a3, (a3,d15)            \n\t"
-+                      "       calli           a3, 0(a3)               \n\t"
-+
-+                      "1:     .rept           16                      \n\t"
-+                      "       move.2          (%0)2++, (%1)2++        \n\t"
-+                      "       .endr                                   \n\t"
-+                      "       add.4           %2, #-32, %2            \n\t"
-+                      "       jmpgt.w.f       1b                      \n\t"
-+
-+                      : "+a" (tmp), "+a" (s), "+d" (n)
-+                      :
-+                      : "d15", "a3", "memory", "cc"
-+                      );
-+              } else {
-+                      tmp += n;
-+                      s += n;
-+                      asm volatile (
-+                      "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
-+                      "       and.4           d15, #(32-2), d15       \n\t"   // d15 = (- count) & (32 - 2)
-+                      "       moveai          a3, #%%hi(1f)           \n\t"
-+                      "       lea.1           a3, %%lo(1f)(a3)        \n\t"
-+                      "       lea.2           a3, (a3,d15)            \n\t"
-+                      "       calli           a3, 0(a3)               \n\t"
-+
-+                      "1:     .rept           16                      \n\t"
-+                      "       move.2          -2(%0)++, -2(%1)++      \n\t"
-+                      "       .endr                                   \n\t"
-+                      "       add.4           %2, #-32, %2            \n\t"
-+                      "       jmpgt.w.f       1b                      \n\t"
-+
-+                      : "+a" (tmp), "+a" (s), "+d" (n)
-+                      :
-+                      : "d15", "a3", "memory", "cc"
-+                      );
-+              }
-+              return dest;
-+      }
-+
-+      if (dest <= src) {
-+              asm volatile (
-+              "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
-+              "       and.4           d15, #(16-1), d15       \n\t"   // d15 = (- count) & (16 - 1)
-+              "       moveai          a3, #%%hi(1f)           \n\t"
-+              "       lea.1           a3, %%lo(1f)(a3)        \n\t"
-+              "       lea.4           a3, (a3,d15)            \n\t"
-+              "       calli           a3, 0(a3)               \n\t"
-+
-+              "1:     .rept           16                      \n\t"
-+              "       move.1          (%0)1++, (%1)1++        \n\t"
-+              "       .endr                                   \n\t"
-+              "       add.4           %2, #-16, %2            \n\t"
-+              "       jmpgt.w.f       1b                      \n\t"
-+              : "+a" (tmp), "+a" (s), "+d" (n)
-+              :
-+              : "d15", "a3", "memory", "cc"
-+              );
-+      } else {
-+              tmp += n;
-+              s += n;
-+              asm volatile (
-+              "       sub.4           d15, #0, %2             \n\t"   // set up for jump table
-+              "       and.4           d15, #(16-1), d15       \n\t"   // d15 = (- count) & (16 - 1)
-+              "       moveai          a3, #%%hi(1f)           \n\t"
-+              "       lea.1           a3, %%lo(1f)(a3)        \n\t"
-+              "       lea.4           a3, (a3,d15)            \n\t"
-+              "       calli           a3, 0(a3)               \n\t"
-+
-+              "1:     .rept           16                      \n\t"
-+              "       move.1          -1(%0)++, -1(%1)++      \n\t"
-+              "       .endr                                   \n\t"
-+              "       add.4           %2, #-16, %2            \n\t"
-+              "       jmpgt.w.f       1b                      \n\t"
-+              : "+a" (tmp), "+a" (s), "+d" (n)
-+              :
-+              : "d15", "a3", "memory", "cc"
-+              );
-+      }
-+      return dest;
-+}
---- /dev/null
-+++ b/arch/ubicom32/mach-common/audio.c
-@@ -0,0 +1,134 @@
-+/*
-+ * arch/ubicom32/mach-common/audio.c
-+ *   Generic initialization for Ubicom32 Audio
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/platform_device.h>
-+#include <linux/types.h>
-+
-+#include <asm/devtree.h>
-+#include <asm/audio.h>
-+#include <asm/ubi32-pcm.h>
-+
-+/*
-+ * The number of audio devices currently allocated, used for .id
-+ */
-+static int __initdata audio_device_count;
-+
-+/*
-+ * The maximum number of resources (cards) that the audio will have.
-+ * Currently 3, a register space, and up to 2 interrupts.
-+ */
-+#define AUDIO_MAX_RESOURCES   3
-+
-+/*
-+ * audio_device_alloc
-+ *    Checks the device tree and allocates a platform_device if found
-+ */
-+struct platform_device * __init audio_device_alloc(const char *driver_name,
-+              const char *node_name, const char *inst_name, int priv_bytes)
-+{
-+      struct platform_device *pdev;
-+      struct resource *res;
-+      struct audio_node *audio_node;
-+      struct ubi32pcm_platform_data *pdata;
-+      struct audio_dev_regs *adr;
-+      int idx;
-+
-+      /*
-+       * Check the device tree for the audio node
-+       */
-+      audio_node = (struct audio_node *)devtree_find_node(node_name);
-+      if (!audio_node) {
-+              printk(KERN_WARNING "audio device '%s' not found\n", node_name);
-+              return NULL;
-+      }
-+
-+      if (audio_node->version != AUDIONODE_VERSION) {
-+              printk(KERN_WARNING "audio node not compatible\n");
-+              return NULL;
-+      }
-+
-+      /*
-+       * Find the instance in this node
-+       */
-+      adr = audio_node->regs->adr;
-+      for (idx = 0; idx < audio_node->regs->max_devs; idx++) {
-+              if ((adr->version == AUDIO_DEV_REGS_VERSION) &&
-+                 (strcmp(adr->name, inst_name) == 0)) {
-+                      break;
-+              }
-+              adr++;
-+      }
-+      if (idx == audio_node->regs->max_devs) {
-+              printk(KERN_WARNING "audio inst '%s' not found in device '%s'\n", inst_name, node_name);
-+              return NULL;
-+      }
-+
-+      /*
-+       * Dynamically create the platform_device structure and resources
-+       */
-+      pdev = kzalloc(sizeof(struct platform_device) +
-+                     sizeof(struct ubi32pcm_platform_data) +
-+                     priv_bytes , GFP_KERNEL);
-+      if (!pdev) {
-+              printk(KERN_WARNING "audio could not alloc pdev\n");
-+              return NULL;
-+      }
-+
-+      res = kzalloc(sizeof(struct resource) * AUDIO_MAX_RESOURCES,
-+                      GFP_KERNEL);
-+      if (!res) {
-+              kfree(pdev);
-+              printk(KERN_WARNING "audio could not alloc res\n");
-+              return NULL;
-+      }
-+
-+      pdev->name = driver_name;
-+      pdev->id = audio_device_count++;
-+      pdev->resource = res;
-+
-+      /*
-+       * Fill in the resources and platform data from devtree information
-+       */
-+      res[0].start = (u32_t)(audio_node->regs);
-+      res[0].end = (u32_t)(audio_node->regs);
-+      res[0].flags = IORESOURCE_MEM;
-+      res[1 + AUDIO_TX_IRQ_RESOURCE].start = audio_node->dn.sendirq;
-+      res[1 + AUDIO_TX_IRQ_RESOURCE].flags = IORESOURCE_IRQ;
-+      res[1 + AUDIO_RX_IRQ_RESOURCE].start = audio_node->dn.recvirq;
-+      res[1 + AUDIO_RX_IRQ_RESOURCE].flags = IORESOURCE_IRQ;
-+      pdev->num_resources = 3;
-+
-+      printk(KERN_INFO "Audio.%d '%s':'%s' found irq=%d/%d.%d regs=%p pdev=%p/%p\n",
-+              pdev->id, node_name, inst_name, audio_node->dn.sendirq,
-+              audio_node->dn.recvirq, idx, audio_node->regs, pdev, res);
-+      pdata = (struct ubi32pcm_platform_data *)(pdev + 1);
-+      pdev->dev.platform_data = pdata;
-+      pdata->node_name = node_name;
-+      pdata->inst_name = inst_name;
-+      pdata->inst_num = idx;
-+      if (priv_bytes) {
-+              pdata->priv_data = pdata + 1;
-+      }
-+
-+      return pdev;
-+}
---- /dev/null
-+++ b/arch/ubicom32/mach-common/board.c
-@@ -0,0 +1,63 @@
-+/*
-+ * arch/ubicom32/mach-common/board.c
-+ *   Board init and support code.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/cpu.h>
-+#include <asm/devtree.h>
-+
-+struct boardnode {
-+      struct devtree_node dn;
-+      const char *revision;
-+};
-+
-+static const struct boardnode *bn;
-+
-+/*
-+ * board_get_revision()
-+ *    Returns revision string of the board.
-+ */
-+const char *board_get_revision(void)
-+{
-+      if (!bn) {
-+              return "NULL";
-+      }
-+
-+      return bn->revision;
-+}
-+
-+/*
-+ * board_init
-+ */
-+void __init board_init(void)
-+{
-+      bn = (struct boardnode *)devtree_find_node("board");
-+      if (!bn) {
-+              printk(KERN_WARNING "board node not found\n");
-+              return;
-+      }
-+}
---- /dev/null
-+++ b/arch/ubicom32/mach-common/bootargs.c
-@@ -0,0 +1,63 @@
-+/*
-+ * arch/ubicom32/mach-common/bootargs.c
-+ *   Board init and support code.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/cpu.h>
-+#include <asm/devtree.h>
-+
-+struct bootargsnode {
-+      struct devtree_node dn;
-+      const char cmdline[512];
-+};
-+
-+static const struct bootargsnode *ban;
-+
-+/*
-+ * bootargs_get_cmdline()
-+ *    Returns kernel boot arguments set by the bootloader.
-+ */
-+const char *bootargs_get_cmdline(void)
-+{
-+      if (!ban) {
-+              return "";
-+      }
-+
-+      return ban->cmdline;
-+}
-+
-+/*
-+ * bootargs_init
-+ */
-+void __init bootargs_init(void)
-+{
-+      ban = (struct bootargsnode *)devtree_find_node("bootargs");
-+      if (!ban) {
-+              printk(KERN_WARNING "bootargs node not found\n");
-+              return;
-+      }
-+}
---- /dev/null
-+++ b/arch/ubicom32/mach-common/cachectl.c
-@@ -0,0 +1,136 @@
-+/*
-+ * arch/ubicom32/mach-common/cachectl.c
-+ *   Architecture cache control support
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/module.h>
-+#include <asm/cachectl.h>
-+
-+/*
-+ * The write queue flush procedure in mem_cache_control needs to make
-+ * DCACHE_WRITE_QUEUE_LENGTH writes to DDR (not OCM). Here we reserve some
-+ * memory for this operation.
-+ * Allocate array of cache lines of least DCACHE_WRITE_QUEUE_LENGTH + 1 words in
-+ * length rounded up to the nearest cache line.
-+ */
-+#define CACHE_WRITE_QUEUE_FLUSH_AREA_SIZE \
-+      ALIGN(sizeof(int) * (DCACHE_WRITE_QUEUE_LENGTH + 1), CACHE_LINE_SIZE)
-+
-+static char cache_write_queue_flush_area[CACHE_WRITE_QUEUE_FLUSH_AREA_SIZE]
-+      __attribute__((aligned(CACHE_LINE_SIZE)));
-+
-+/*
-+ * ONE_CCR_ADDR_OP is a helper macro that executes a single CCR operation.
-+ */
-+#define ONE_CCR_ADDR_OP(cc, op_addr, op)                              \
-+      do {                                                            \
-+              asm volatile (                                          \
-+              "       btst    "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_VALID)"                         \n\t" \
-+              "       jmpne.f .-4                                                             \n\t" \
-+              "       move.4  "D(CCR_ADDR)"(%0), %1                                           \n\t" \
-+              "       move.1  "D(CCR_CTRL+3)"(%0), %2                                         \n\t" \
-+              "       bset    "D(CCR_CTRL)"(%0), "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_VALID)"      \n\t" \
-+              "       cycles  2                                                               \n\t" \
-+              "       btst    "D(CCR_CTRL)"(%0), #"D(CCR_CTRL_DONE)"                          \n\t" \
-+              "       jmpeq.f .-4                                                             \n\t" \
-+                      :                                               \
-+                      : "a"(cc), "r"(op_addr), "r"(op & 0xff)         \
-+                      : "cc"                                          \
-+              );                                                      \
-+      } while (0)
-+
-+/*
-+ * mem_cache_control()
-+ *    Special cache control operation
-+ */
-+void mem_cache_control(unsigned long cc, unsigned long begin_addr,
-+                     unsigned long end_addr, unsigned long op)
-+{
-+      unsigned long op_addr;
-+      int dccr = cc == DCCR_BASE;
-+      if (dccr && op == CCR_CTRL_FLUSH_ADDR) {
-+              /*
-+               * We ensure all previous writes have left the data cache write
-+               * queue by sending DCACHE_WRITE_QUEUE_LENGTH writes (to
-+               * different words) down the queue.  If this is not done it's
-+               * possible that the data we are trying to flush hasn't even
-+               * entered the data cache.
-+               * The +1 ensure that the final 'flush' is actually a flush.
-+               */
-+              int *flush_area = (int *)cache_write_queue_flush_area;
-+              asm volatile(
-+                      "       .rept "D(DCACHE_WRITE_QUEUE_LENGTH + 1)"        \n\t"
-+                      "       move.4 (%0)4++, d0                              \n\t"
-+                      "       .endr                                           \n\t"
-+                      : "+a"(flush_area)
-+                      );
-+      }
-+
-+      if (dccr)
-+              UBICOM32_LOCK(DCCR_LOCK_BIT);
-+      else
-+              UBICOM32_LOCK(ICCR_LOCK_BIT);
-+
-+      /*
-+       * Calculate the cache lines we need to operate on that include
-+       * begin_addr though end_addr.
-+       */
-+      begin_addr = begin_addr & ~(CACHE_LINE_SIZE - 1);
-+      end_addr = (end_addr + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1);
-+      op_addr = begin_addr;
-+
-+      do {
-+              ONE_CCR_ADDR_OP(cc, op_addr, op);
-+              op_addr += CACHE_LINE_SIZE;
-+      } while (likely(op_addr < end_addr));
-+
-+      if (dccr && op == CCR_CTRL_FLUSH_ADDR) {
-+              /*
-+               * It turns out that when flushing the data cache the last flush
-+               * isn't actually complete at this point. This is because there
-+               * is another write buffer on the DDR side of the cache that is
-+               * arbitrated with the I-Cache.
-+               *
-+               * The only foolproof method that ensures that the last data
-+               * cache flush *actually* completed is to do another flush on a
-+               * dirty cache line. This flush will block until the DDR write
-+               * buffer is empty.
-+               *
-+               * Rather than creating a another dirty cache line, we use the
-+               * flush_area above as we know that it is dirty from previous
-+               * writes.
-+               */
-+              ONE_CCR_ADDR_OP(cc, cache_write_queue_flush_area, op);
-+      }
-+
-+      if (dccr)
-+              UBICOM32_UNLOCK(DCCR_LOCK_BIT);
-+      else
-+              UBICOM32_UNLOCK(ICCR_LOCK_BIT);
-+
-+}
-+EXPORT_SYMBOL(mem_cache_control);
---- /dev/null
-+++ b/arch/ubicom32/mach-common/common.c
-@@ -0,0 +1,64 @@
-+/*
-+ * arch/ubicom32/mach-common/common.c
-+ *   Common platform support.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/list.h>
-+#include <linux/errno.h>
-+#include <linux/err.h>
-+#include <linux/string.h>
-+#include <linux/clk.h>
-+#include <linux/mutex.h>
-+#include <linux/platform_device.h>
-+
-+
-+/* Minimum CLK support */
-+
-+struct clk *clk_get(struct device *dev, const char *id)
-+{
-+      return ERR_PTR(-ENOENT);
-+}
-+EXPORT_SYMBOL(clk_get);
-+
-+void clk_put(struct clk *clk)
-+{
-+}
-+EXPORT_SYMBOL(clk_put);
-+
-+int clk_enable(struct clk *clk)
-+{
-+      return 0;
-+}
-+EXPORT_SYMBOL(clk_enable);
-+
-+
-+void clk_disable(struct clk *clk)
-+{
-+}
-+EXPORT_SYMBOL(clk_disable);
---- /dev/null
-+++ b/arch/ubicom32/mach-common/io.c
-@@ -0,0 +1,250 @@
-+/*
-+ * arch/ubicom32/mach-common/io.c
-+ *   PCI I/O memory read/write support functions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/io.h>
-+
-+#ifdef CONFIG_PCI
-+unsigned char  ioread8(void __iomem *addr)
-+{
-+      if (IS_PCI_ADDRESS(addr))
-+              return ubi32_pci_read_u8(addr);
-+      else
-+              return (unsigned char)(*(volatile unsigned char *)addr);
-+}
-+EXPORT_SYMBOL(ioread8);
-+
-+unsigned short  ioread16(void __iomem *addr)
-+{
-+      if (IS_PCI_ADDRESS(addr))
-+              return ubi32_pci_read_u16(addr);
-+      else
-+              return (unsigned short)(*(volatile unsigned short *)addr);
-+}
-+EXPORT_SYMBOL(ioread16);
-+
-+unsigned int  ioread32(void __iomem *addr)
-+{
-+      if (IS_PCI_ADDRESS(addr))
-+              return ubi32_pci_read_u32(addr);
-+      else
-+              return (unsigned int)(*(volatile unsigned int *)addr);
-+}
-+EXPORT_SYMBOL(ioread32);
-+
-+void iowrite32(unsigned int val, void __iomem *addr)
-+{
-+      if (IS_PCI_ADDRESS(addr))
-+              ubi32_pci_write_u32(val, addr);
-+      else
-+              *(volatile unsigned int *)addr = val;
-+}
-+EXPORT_SYMBOL(iowrite32);
-+
-+void iowrite16(unsigned short val, void __iomem *addr)
-+{
-+      if (IS_PCI_ADDRESS(addr))
-+              ubi32_pci_write_u16(val, addr);
-+      else
-+              *(volatile unsigned short *)addr = val;
-+}
-+EXPORT_SYMBOL(iowrite16);
-+
-+void iowrite8(unsigned char val, void __iomem *addr)
-+{
-+      if (IS_PCI_ADDRESS(addr))
-+              ubi32_pci_write_u8(val, addr);
-+      else
-+              *(volatile unsigned char *)addr = val;
-+}
-+EXPORT_SYMBOL(iowrite8);
-+
-+void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned len)
-+{
-+      if (IS_PCI_ADDRESS(from)) {
-+              if ((((u32_t)from & 0x3) == 0) && (((u32_t)to & 0x3) == 0)) {
-+                      while ((int)len >= 4) {
-+                              *(u32_t *)to = ubi32_pci_read_u32(from);
-+                              to += 4;
-+                              from += 4;
-+                              len -= 4;
-+                      }
-+              } else if ((((u32_t)from & 0x1) == 0) &&
-+                         (((u32_t)to & 0x1) == 0)) {
-+                      while ((int)len >= 2) {
-+                               *(u16_t *)to = ubi32_pci_read_u16(from);
-+                               to += 2;
-+                               from += 2;
-+                               len -= 2;
-+                      }
-+              }
-+
-+              while (len) {
-+                      *(u8_t *)to = ubi32_pci_read_u8(from);
-+                      to++;
-+                      from++;
-+                      len--;
-+              }
-+      } else
-+              memcpy(to, (void *)from, len);
-+}
-+EXPORT_SYMBOL(memcpy_fromio);
-+
-+void memcpy_toio(volatile void __iomem *to, const void *from, unsigned len)
-+{
-+      if (IS_PCI_ADDRESS(to)) {
-+              if ((((u32_t)from & 0x3) == 0) && (((u32_t)to & 0x3) == 0)) {
-+                      while ((int)len >= 4) {
-+                              ubi32_pci_write_u32(*(u32_t *)from, to);
-+                              to += 4;
-+                              from += 4;
-+                              len -= 4;
-+                      }
-+              } else if ((((u32_t)from & 0x1) == 0) &&
-+                         (((u32_t)to & 0x1) == 0)) {
-+                      while ((int)len >= 2) {
-+                              ubi32_pci_write_u16(*(u16_t *)from, to);
-+                              to += 2;
-+                              from += 2;
-+                              len -= 2;
-+                      }
-+              }
-+
-+              while (len) {
-+                      ubi32_pci_write_u8(*(u8_t *)from, to);
-+                      from++;
-+                      to++;
-+                      len--;
-+              }
-+      } else
-+              memcpy((void *)to, from, len);
-+
-+}
-+EXPORT_SYMBOL(memcpy_toio);
-+
-+void memset_io(volatile void __iomem *addr, int val, size_t len)
-+{
-+      if (IS_PCI_ADDRESS(addr)) {
-+              while (len) {
-+                      ubi32_pci_write_u8((unsigned char)val, addr);
-+                      addr++;
-+                      len--;
-+              }
-+      } else
-+              memset((void *)addr, val, len);
-+
-+}
-+EXPORT_SYMBOL(memset_io);
-+
-+void ioread8_rep(void __iomem *port, void *buf, unsigned long count)
-+{
-+      if (IS_PCI_ADDRESS(port)) {
-+              while (count) {
-+                      *(u8_t *)buf = ioread8(port);
-+                      buf++;
-+                      count--;
-+              }
-+      } else {
-+              insb((unsigned int)port, buf, count);
-+      }
-+
-+}
-+EXPORT_SYMBOL(ioread8_rep);
-+
-+void ioread16_rep(void __iomem *port, void *buf, unsigned long count)
-+{
-+      if (IS_PCI_ADDRESS(port)) {
-+              while (count) {
-+                      *(u16_t *)buf = ioread16(port);
-+                      buf += 2;
-+                      count--;
-+              }
-+      } else {
-+              insw((unsigned int)port, buf, count);
-+      }
-+}
-+EXPORT_SYMBOL(ioread16_rep);
-+
-+void ioread32_rep(void __iomem *port, void *buf, unsigned long count)
-+{
-+       if (IS_PCI_ADDRESS(port)) {
-+              while (count) {
-+                      *(u32_t *)buf = ioread32(port);
-+                      buf += 4;
-+                      count--;
-+              }
-+      } else {
-+              insl((unsigned int)port, buf, count);
-+      }
-+}
-+EXPORT_SYMBOL(ioread32_rep);
-+
-+void  iowrite8_rep(void __iomem *port, const void *buf, unsigned long count)
-+{
-+        if (IS_PCI_ADDRESS(port)) {
-+              while (count) {
-+                      iowrite8(*(u8_t *)buf, port);
-+                      buf++;
-+                      count--;
-+              }
-+      } else {
-+              outsb((unsigned int)port, buf, count);
-+      }
-+
-+}
-+EXPORT_SYMBOL(iowrite8_rep);
-+
-+void  iowrite16_rep(void __iomem *port, const void *buf, unsigned long count)
-+{
-+      if (IS_PCI_ADDRESS(port)) {
-+              while (count) {
-+                      iowrite16(*(u16_t *)buf, port);
-+                      buf += 2;
-+                      count--;
-+              }
-+      } else {
-+              outsw((unsigned int)port, buf, count);
-+      }
-+}
-+EXPORT_SYMBOL(iowrite16_rep);
-+
-+void  iowrite32_rep(void __iomem *port, const void *buf, unsigned long count)
-+{
-+      if (IS_PCI_ADDRESS(port)) {
-+              while (count) {
-+                      iowrite32(*(u32_t *)buf, port);
-+                      buf += 4;
-+                      count--;
-+              }
-+      } else {
-+              outsl((unsigned int)port, buf, count);
-+      }
-+}
-+EXPORT_SYMBOL(iowrite32_rep);
-+
-+#endif /* CONFIG_PCI */
---- /dev/null
-+++ b/arch/ubicom32/mach-common/Kconfig.switch
-@@ -0,0 +1,12 @@
-+menuconfig UBICOM_SWITCH
-+      tristate "Switch devices"
-+      help
-+              This option provides Ethernet switch management options via proc fs
-+
-+if UBICOM_SWITCH
-+config UBICOM_SWITCH_BCM539X
-+      tristate "Broadcom BCM539X series (SPI)"
-+      depends on SPI_MASTER
-+      help
-+              Supports Broadcom BCM539X Gigabit Ethernet Switches over SPI
-+endif
---- /dev/null
-+++ b/arch/ubicom32/mach-common/Makefile
-@@ -0,0 +1,41 @@
-+#
-+# arch/ubicom32/mach-common/Makefile
-+#     Makefile for Ubicom32 generic drivers/code.
-+#
-+# (C) Copyright 2009, Ubicom, Inc.
-+#
-+# This file is part of the Ubicom32 Linux Kernel Port.
-+#
-+# The Ubicom32 Linux Kernel Port 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.
-+#
-+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+# see <http://www.gnu.org/licenses/>.
-+#
-+# Ubicom32 implementation derived from (with many thanks):
-+#   arch/m68knommu
-+#   arch/blackfin
-+#   arch/parisc
-+#
-+
-+obj-y += cachectl.o common.o usb_tio.o usb.o ubi32-gpio.o board.o bootargs.o profile.o
-+obj-$(CONFIG_PCI) += pci.o io.o
-+
-+obj-$(CONFIG_FB_UBICOM32) += vdc_tio.o
-+obj-$(CONFIG_UBICOM_HID) += ubicom32hid.o
-+obj-$(CONFIG_UBICOM_INPUT) += ubicom32input.o
-+obj-$(CONFIG_UBICOM_INPUT_I2C) += ubicom32input_i2c.o
-+obj-$(CONFIG_UBICOM_SWITCH) += switch-core.o
-+obj-$(CONFIG_UBICOM_SWITCH_BCM539X) += switch-bcm539x.o
-+obj-$(CONFIG_UIO_UBICOM32RING) += ring_tio.o
-+obj-$(CONFIG_SND_UBI32) += audio.o
-+obj-$(CONFIG_UBICOM32_PLIO) += plio.o
-+
---- /dev/null
-+++ b/arch/ubicom32/mach-common/pci.c
-@@ -0,0 +1,1157 @@
-+/*
-+ * arch/ubicom32/mach-common/pci.c
-+ *    PCI interface management.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/pci.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/seq_file.h>
-+#include <linux/proc_fs.h>
-+
-+#include <asm/devtree.h>
-+#include <asm/ip5000.h>
-+#include <asm/ubicom32-common.h>
-+
-+static int debug_pci = 1 ;
-+
-+/* #define PCI_USE_INTERNAL_LOCK 1 */
-+
-+#ifdef PCI_USE_INTERNAL_LOCK
-+#define PCI_LOCK(lock, irqflag)       pci_lock_acquire(irqflag)
-+#define PCI_UNLOCK(lock, irqflag) pci_lock_release(irqflag)
-+#elif defined(CONFIG_SMP)
-+static DEFINE_SPINLOCK(pci_master_lock);
-+#define PCI_LOCK(lock, irqflag)       spin_lock_irqsave(lock, irqflag)
-+#define PCI_UNLOCK(lock, irqflag) spin_unlock_irqrestore(lock, irqflag)
-+#else
-+#define PCI_LOCK(lock, irqflag)               local_irq_save(irqflag)
-+#define PCI_UNLOCK(lock, irqflag)     local_irq_restore(irqflag)
-+#endif
-+
-+#define PCI_DEV0_IDSEL CONFIG_PCI_DEV0_IDSEL
-+#define PCI_DEV1_IDSEL CONFIG_PCI_DEV1_IDSEL
-+
-+/*
-+ * PCI commands
-+ */
-+#define PCI_CMD_INT_ACK               0x00    /* not supported */
-+#define PCI_CMD_SPECIAL               0x01    /* not supported */
-+#define PCI_CMD_IO_READ               0x02
-+#define PCI_CMD_IO_WRITE      0x03
-+#define PCI_CMD_MEM_READ      0x06
-+#define PCI_CMD_MEM_WRITE     0x07
-+#define PCI_CMD_CFG_READ      0x0a
-+#define PCI_CMD_CFG_WRITE     0x0b
-+#define PCI_CMD_MEM_READ_MULT 0x0c    /* not supported */
-+#define PCI_CMD_DUAL_ADDR     0x0d    /* not supported */
-+#define PCI_CMD_MEM_READ_LINE 0x0e    /* not supported */
-+#define PCI_CMD_MEM_WRITE_INVAL       0x0f    /* not supported */
-+/*
-+ * Status codes, returned by pci_read_u32() and pci_write_u32()
-+ */
-+#define PCI_RESP_IN_PROGRESS  0xff  /* request still in queue */
-+#define PCI_RESP_OK           0
-+/*
-+ * The following codes indicate that the request has completed
-+ */
-+#define PCI_RESP_NO_DEVSEL            1  /* timeout before target asserted
-+                                          * DEVSEL! */
-+#define PCI_RESP_LOST_DEVSEL          2  /* had DEVSEL, but went away before
-+                                          * transfer completed! */
-+#define PCI_RESP_BAD_TRDY             3  /* target asserted TRDY without
-+                                          * DEVSEL! */
-+#define PCI_RESP_NO_TRDY              4  /* timeout before target asserted
-+                                          * TRDY! */
-+#define PCI_RESP_BAD_STOP             5  /* target asserted STOP and TRDY
-+                                          * without DEVSEL! */
-+#define PCI_RESP_TARGET_ABORT         6
-+#define PCI_RESP_TARGET_RETRY         7
-+#define       PCI_RESP_TARGET_DISCONNECT      8
-+#define PCI_RESP_MISMATCH             9  /* data read back doesn't match data
-+                                          * written - debug only, the core PCI
-+                                          * routines never return this */
-+#define PCI_RESP_DET_SERR             10
-+#define PCI_RESP_DET_PERR             11
-+#define PCI_RESP_MALFORMED_REQ                12 /* Could be due to misaligned
-+                                          * requests or invalid address */
-+#define PCI_RESP_NO_RESOURCE          13 /* Could be memory or other resourse
-+                                          * like queue space */
-+#define PCI_RESP_ERROR                        14 /* All emcompassing error */
-+
-+/* registers in PCI config space */
-+#define PCI_DEVICE_VENDOR_ID_REG      0x00
-+#define PCI_STATUS_COMMAND_REG                0x04
-+#define PCI_CLASS_REVISION_REG                0x08
-+#define PCI_BHLC_REG                  0x0c  /* BIST, Header type, Latency
-+                                             * timer, Cache line size */
-+#define PCI_BASE_ADDR_REG             0x10
-+#define PCI_BASE_REG_COUNT            6
-+#define CARDBUS_CIS_PTR_REG           0x28
-+#define PCI_SUB_SYSTEM_ID_REG         0x2c
-+#define PCI_EXP_ROM_ADDR_REG          0x30
-+#define PCI_CAP_PTR_REG                       0x34
-+#define PCI_LGPL_REG                  0x3C  /* max Latency, min Gnt, interrupt
-+                                             * Pin, interrupt Line */
-+
-+struct pci_master_request {
-+      volatile u32_t pci_address;     /* must be 4-byte aligned */
-+      volatile u32_t data;            /* must be 4-byte aligned */
-+      volatile u8_t cmd;
-+      volatile u8_t byte_valid;
-+      volatile u8_t status;
-+};
-+
-+struct pci_devnode {
-+      struct devtree_node dn;
-+      u32_t pci_idsel_0;
-+      u32_t pci_idsel_1;
-+      u32_t pci_cpu_address;
-+      struct pci_master_request volatile *volatile req;
-+};
-+
-+static struct pci_master_request req; /* globally used for faster master write
-+                                       * (discarding result when possible) */
-+static struct pci_devnode *pci_node;
-+
-+#if !defined(CONFIG_DEBUG_PCIMEASURE)
-+#define PCI_DECLARE_MEASUREMENT
-+#define PCI_MEASUREMENT_START()
-+#define PCI_MEASUREMENT_END(idx)
-+#else
-+#define PCI_DECLARE_MEASUREMENT \
-+      int __diff;             \
-+      unsigned int __tstart;
-+
-+#define PCI_MEASUREMENT_START() \
-+      __tstart = UBICOM32_IO_TIMER->sysval;
-+
-+#define PCI_MEASUREMENT_END(idx) \
-+      __diff = (int)UBICOM32_IO_TIMER->sysval - (int)__tstart; \
-+      pci_measurement_update((idx), __diff);
-+
-+#define PCI_WEIGHT 32
-+
-+struct pci_measurement {
-+      volatile unsigned int min;
-+      volatile unsigned int avg;
-+      volatile unsigned int max;
-+};
-+
-+enum pci_measurement_list {
-+      PCI_MEASUREMENT_READ32,
-+      PCI_MEASUREMENT_WRITE32,
-+      PCI_MEASUREMENT_READ16,
-+      PCI_MEASUREMENT_WRITE16,
-+      PCI_MEASUREMENT_READ8,
-+      PCI_MEASUREMENT_WRITE8,
-+      PCI_MEASUREMENT_LAST,
-+};
-+
-+static const char *pci_measurement_name_list[PCI_MEASUREMENT_LAST] = {
-+      "READ32",
-+      "WRITE32",
-+      "READ16",
-+      "WRITE16",
-+      "READ8",
-+      "WRITE8"
-+};
-+static struct pci_measurement pci_measurements[PCI_MEASUREMENT_LAST];
-+
-+/*
-+ * pci_measurement_update()
-+ *    Update an entry in the measurement array for this idx.
-+ */
-+static void pci_measurement_update(int idx, int sample)
-+{
-+      struct pci_measurement *pm = &pci_measurements[idx];
-+      if ((pm->min == 0) || (pm->min > sample)) {
-+              pm->min = sample;
-+      }
-+      if (pm->max < sample) {
-+              pm->max = sample;
-+      }
-+      pm->avg = ((pm->avg * (PCI_WEIGHT - 1)) + sample) / PCI_WEIGHT;
-+}
-+#endif
-+
-+#if defined(PCI_USE_INTERNAL_LOCK)
-+/*
-+ * pci_lock_release()
-+ *    Release the PCI lock.
-+ */
-+static void pci_lock_release(unsigned long irqflag)
-+{
-+      UBICOM32_UNLOCK(PCI_LOCK_BIT);
-+}
-+
-+/*
-+ * pci_lock_acquire()
-+ *    Acquire the PCI lock, spin if not available.
-+ */
-+static void pci_lock_acquire(unsigned long irqflag)
-+{
-+      UBICOM32_LOCK(PCI_LOCK_BIT);
-+}
-+#endif
-+
-+/*
-+ * pci_set_hrt_interrupt()
-+ */
-+static inline void pci_set_hrt_interrupt(struct pci_devnode *pci_node)
-+{
-+      ubicom32_set_interrupt(pci_node->dn.sendirq);
-+}
-+
-+/*
-+ * pci_read_u32()
-+ *    Synchronously read 32 bits from PCI space.
-+ */
-+u8 pci_read_u32(u8 pci_cmd, u32 address, u32 *data)
-+{
-+      u8 status;
-+      unsigned long irqflag;
-+
-+
-+      /*
-+       * Fill in the request.
-+       */
-+      volatile struct pci_master_request lreq;
-+      PCI_DECLARE_MEASUREMENT;
-+
-+      lreq.pci_address = address;
-+      lreq.cmd = pci_cmd;
-+      lreq.byte_valid = 0xf;          /* enable all bytes */
-+
-+      /*
-+       * Wait for any previous request to complete and then make this request.
-+       */
-+      PCI_MEASUREMENT_START();
-+      PCI_LOCK(&pci_master_lock, irqflag);
-+      while (unlikely(pci_node->req == &req))
-+              ;
-+      pci_node->req = &lreq;
-+      pci_set_hrt_interrupt(pci_node);
-+      PCI_UNLOCK(&pci_master_lock, irqflag);
-+
-+      /*
-+       * Wait for the result to show up.
-+       */
-+      while (unlikely(pci_node->req == &lreq))
-+              ;
-+      status = lreq.status;
-+      if (likely(status == PCI_RESP_OK))
-+              *data = le32_to_cpu(lreq.data);
-+      else
-+              *data = 0;
-+      PCI_MEASUREMENT_END(PCI_MEASUREMENT_READ32);
-+      return status;
-+}
-+
-+/*
-+ * pci_write_u32()
-+ *    Asyncrhnously or synchronously write 32 bits to PCI master space.
-+ */
-+u8 pci_write_u32(u8 pci_cmd, u32 address, u32 data)
-+{
-+      unsigned long irqflag;
-+      PCI_DECLARE_MEASUREMENT;
-+
-+      /*
-+       * Wait for any previous write or pending read to complete.
-+       *
-+       * We use a global data block because once we write the request
-+       * we do not wait for it to complete before exiting.
-+       */
-+      PCI_MEASUREMENT_START();
-+      PCI_LOCK(&pci_master_lock, irqflag);
-+      while (unlikely(pci_node->req == &req))
-+              ;
-+      req.pci_address = address;
-+      req.data = cpu_to_le32(data);
-+      req.cmd = pci_cmd;
-+      req.byte_valid = 0xf;           /* enable all bytes */
-+      pci_node->req = &req;
-+      pci_set_hrt_interrupt(pci_node);
-+      PCI_UNLOCK(&pci_master_lock, irqflag);
-+      PCI_MEASUREMENT_END(PCI_MEASUREMENT_WRITE32);
-+      return PCI_RESP_OK;
-+}
-+
-+/*
-+ * pci_read_u16()
-+ *    Synchronously read 16 bits from PCI space.
-+ */
-+u8 pci_read_u16(u8 pci_cmd, u32 address, u16 *data)
-+{
-+      u8 status;
-+      unsigned long irqflag;
-+
-+      /*
-+       * Fill in the request.
-+       */
-+      volatile struct pci_master_request lreq;
-+      PCI_DECLARE_MEASUREMENT;
-+
-+      lreq.pci_address = address & ~2;
-+      lreq.cmd = pci_cmd;
-+      lreq.byte_valid = (address & 2) ? 0xc : 0x3;
-+
-+      /*
-+       * Wait for any previous request to complete and then make this request.
-+       */
-+      PCI_MEASUREMENT_START();
-+      PCI_LOCK(&pci_master_lock, irqflag);
-+      while (unlikely(pci_node->req == &req))
-+              ;
-+      pci_node->req = &lreq;
-+      pci_set_hrt_interrupt(pci_node);
-+      PCI_UNLOCK(&pci_master_lock, irqflag);
-+
-+      /*
-+       * Wait for the result to show up.
-+       */
-+      while (unlikely(pci_node->req == &lreq))
-+              ;
-+      status = lreq.status;
-+      if (likely(status == PCI_RESP_OK)) {
-+              lreq.data = le32_to_cpu(lreq.data);
-+              *data = (u16)((address & 2) ? (lreq.data >> 16) : lreq.data);
-+      } else
-+              *data = 0;
-+      PCI_MEASUREMENT_END(PCI_MEASUREMENT_READ16);
-+      return status;
-+}
-+
-+/*
-+ * pci_write_u16()
-+ *    Asyncrhnously or synchronously write 16 bits to PCI master space.
-+ */
-+u8 pci_write_u16(u8 pci_cmd, u32 address, u16 data)
-+{
-+      unsigned long irqflag;
-+      PCI_DECLARE_MEASUREMENT;
-+
-+      /*
-+       * Wait for any previous write or pending read to complete.
-+       *
-+       * We use a global data block because once we write the request
-+       * we do not wait for it to complete before exiting.
-+       */
-+      PCI_MEASUREMENT_START();
-+      PCI_LOCK(&pci_master_lock, irqflag);
-+      while (unlikely(pci_node->req == &req))
-+              ;
-+      req.pci_address = address & ~2;
-+      req.data = (u32)data;
-+      req.data = cpu_to_le32((address & 2) ? (req.data << 16) : req.data);
-+      req.cmd = pci_cmd;
-+      req.byte_valid = (address & 2) ? 0xc : 0x3;
-+      pci_node->req = &req;
-+      pci_set_hrt_interrupt(pci_node);
-+      PCI_UNLOCK(&pci_master_lock, irqflag);
-+      PCI_MEASUREMENT_END(PCI_MEASUREMENT_WRITE16);
-+      return PCI_RESP_OK;
-+}
-+
-+/*
-+ * pci_read_u8()
-+ *    Synchronously read 8 bits from PCI space.
-+ */
-+u8 pci_read_u8(u8 pci_cmd, u32 address, u8 *data)
-+{
-+      u8 status;
-+      unsigned long irqflag;
-+
-+      /*
-+       * Fill in the request.
-+       */
-+      volatile struct pci_master_request lreq;
-+      PCI_DECLARE_MEASUREMENT;
-+
-+      lreq.pci_address = address & ~3;
-+      lreq.cmd = pci_cmd;
-+      lreq.byte_valid = 1 << (address & 0x3);
-+
-+      /*
-+       * Wait for any previous request to complete and then make this request.
-+       */
-+      PCI_MEASUREMENT_START();
-+      PCI_LOCK(&pci_master_lock, irqflag);
-+      while (unlikely(pci_node->req == &req))
-+              ;
-+      pci_node->req = &lreq;
-+      pci_set_hrt_interrupt(pci_node);
-+      PCI_UNLOCK(&pci_master_lock, irqflag);
-+
-+      /*
-+       * Wait for the result to show up.
-+       */
-+      while (unlikely(pci_node->req == &lreq))
-+              ;
-+      status = lreq.status;
-+      if (likely(status == PCI_RESP_OK)) {
-+              *data = (u8)(lreq.data >> (24 - ((address & 0x3) << 3)));
-+      } else
-+              *data = 0;
-+      PCI_MEASUREMENT_END(PCI_MEASUREMENT_READ8);
-+      return status;
-+}
-+
-+/*
-+ * pci_write_u8()
-+ *    Asyncrhnously or synchronously write 8 bits to PCI master space.
-+ */
-+u8 pci_write_u8(u8 pci_cmd, u32 address, u8 data)
-+{
-+      unsigned long irqflag;
-+      PCI_DECLARE_MEASUREMENT;
-+
-+      /*
-+       * Wait for any previous write or pending read to complete.
-+       *
-+       * We use a global data block because once we write the request
-+       * we do not wait for it to complete before exiting.
-+       */
-+      PCI_MEASUREMENT_START();
-+      PCI_LOCK(&pci_master_lock, irqflag);
-+      while (unlikely(pci_node->req == &req))
-+              ;
-+      req.pci_address = address & ~3;
-+      req.data = ((u32)data << (24 - ((address & 0x3) << 3)));
-+      req.cmd = pci_cmd;
-+      req.byte_valid = 1 << (address & 0x3);
-+      pci_node->req = &req;
-+      pci_set_hrt_interrupt(pci_node);
-+      PCI_UNLOCK(&pci_master_lock, irqflag);
-+      PCI_MEASUREMENT_END(PCI_MEASUREMENT_WRITE8);
-+      return PCI_RESP_OK;
-+}
-+
-+unsigned int ubi32_pci_read_u32(const volatile void __iomem *addr)
-+{
-+      unsigned int data;
-+      pci_read_u32(PCI_CMD_MEM_READ, (u32)addr, &data);
-+      return data;
-+}
-+EXPORT_SYMBOL(ubi32_pci_read_u32);
-+
-+unsigned short ubi32_pci_read_u16(const volatile void __iomem *addr)
-+{
-+      unsigned short data;
-+      pci_read_u16(PCI_CMD_MEM_READ, (u32)addr, &data);
-+      return data;
-+}
-+EXPORT_SYMBOL(ubi32_pci_read_u16);
-+
-+unsigned char  ubi32_pci_read_u8(const volatile void __iomem *addr)
-+{
-+      unsigned char  data;
-+      pci_read_u8(PCI_CMD_MEM_READ, (u32)addr, &data);
-+      return data;
-+}
-+EXPORT_SYMBOL(ubi32_pci_read_u8);
-+
-+void ubi32_pci_write_u32(unsigned int val, const volatile void __iomem *addr)
-+{
-+      pci_write_u32(PCI_CMD_MEM_WRITE, (u32)addr, val);
-+}
-+EXPORT_SYMBOL(ubi32_pci_write_u32);
-+
-+void ubi32_pci_write_u16(unsigned short val, const volatile void __iomem *addr)
-+{
-+      pci_write_u16(PCI_CMD_MEM_WRITE, (u32)addr, val);
-+}
-+EXPORT_SYMBOL(ubi32_pci_write_u16);
-+
-+void ubi32_pci_write_u8(unsigned char val, const void volatile __iomem *addr)
-+{
-+      pci_write_u8(PCI_CMD_MEM_WRITE, (u32)addr, val);
-+}
-+EXPORT_SYMBOL(ubi32_pci_write_u8);
-+
-+#if defined(CONFIG_DEBUG_PCIMEASURE)
-+static unsigned int pci_cycles_to_nano(unsigned int cycles, unsigned int frequency)
-+{
-+      unsigned int nano = ((cycles * 1000) / (frequency / 1000000));
-+      return nano;
-+}
-+
-+/*
-+ * pci_measurement_show()
-+ *    Print out the min, avg, max values for each PCI transaction type.
-+ *
-+ * By request, the max value is reset after each dump.
-+ */
-+static int pci_measurement_show(struct seq_file *p, void *v)
-+{
-+      unsigned int min, avg, max;
-+      unsigned int freq = processor_frequency();
-+      int trans = *((loff_t *) v);
-+
-+      if (trans == 0) {
-+              seq_puts(p, "min\tavg\tmax\t(nano-seconds)\n");
-+      }
-+
-+      if (trans >= PCI_MEASUREMENT_LAST) {
-+              return 0;
-+      }
-+
-+      min = pci_cycles_to_nano(pci_measurements[trans].min, freq);
-+      avg = pci_cycles_to_nano(pci_measurements[trans].avg, freq);
-+      max = pci_cycles_to_nano(pci_measurements[trans].max, freq);
-+      pci_measurements[trans].max = 0;
-+      seq_printf(p, "%u\t%u\t%u\t%s\n", min, avg, max, pci_measurement_name_list[trans]);
-+      return 0;
-+}
-+
-+static void *pci_measurement_start(struct seq_file *f, loff_t *pos)
-+{
-+      return (*pos < PCI_MEASUREMENT_LAST) ? pos : NULL;
-+}
-+
-+static void *pci_measurement_next(struct seq_file *f, void *v, loff_t *pos)
-+{
-+      (*pos)++;
-+      if (*pos >= PCI_MEASUREMENT_LAST)
-+              return NULL;
-+      return pos;
-+}
-+
-+static void pci_measurement_stop(struct seq_file *f, void *v)
-+{
-+      /* Nothing to do */
-+}
-+
-+static const struct seq_operations pci_measurement_seq_ops = {
-+      .start = pci_measurement_start,
-+      .next  = pci_measurement_next,
-+      .stop  = pci_measurement_stop,
-+      .show  = pci_measurement_show,
-+};
-+
-+static int pci_measurement_open(struct inode *inode, struct file *filp)
-+{
-+      return seq_open(filp, &pci_measurement_seq_ops);
-+}
-+
-+static const struct file_operations pci_measurement_fops = {
-+      .open           = pci_measurement_open,
-+      .read           = seq_read,
-+      .llseek         = seq_lseek,
-+      .release        = seq_release,
-+};
-+
-+static int __init pci_measurement_init(void)
-+{
-+      proc_create("pci_measurements", 0, NULL, &pci_measurement_fops);
-+      return 0;
-+}
-+module_init(pci_measurement_init);
-+#endif
-+
-+static int ubi32_pci_read_config(struct pci_bus *bus, unsigned int devfn,
-+                               int where, int size, u32 *value)
-+{
-+      u8 cmd;
-+      u32 addr;
-+      u8  data8;
-+      u16 data16;
-+
-+      u8 slot = PCI_SLOT(devfn);
-+      u8 fn = PCI_FUNC(devfn);
-+
-+      if (slot > 1) {
-+              return PCIBIOS_DEVICE_NOT_FOUND;
-+      } else if (slot == 0) {
-+              addr = PCI_DEV0_IDSEL + where;
-+      } else {
-+              addr = PCI_DEV1_IDSEL + where;
-+      }
-+
-+      addr += (fn << 8);
-+
-+      cmd = PCI_CMD_CFG_READ;
-+      if (size == 1) {
-+              pci_read_u8(cmd, addr, &data8);
-+              *value = (u32)data8;
-+      } else if (size == 2) {
-+              pci_read_u16(cmd, addr, &data16);
-+              *value = (u32)data16;
-+      } else {
-+              pci_read_u32(cmd, addr, value);
-+      }
-+
-+      return PCIBIOS_SUCCESSFUL;
-+}
-+
-+static int ubi32_pci_write_config(struct pci_bus *bus, unsigned int devfn,
-+                                int where, int size, u32 value)
-+{
-+      u8 cmd;
-+      u32 addr;
-+      u8 slot = PCI_SLOT(devfn);
-+      u8 fn = PCI_FUNC(devfn);
-+
-+      if (slot > 1) {
-+              return PCIBIOS_DEVICE_NOT_FOUND;
-+      } else if (slot == 0) {
-+              addr = PCI_DEV0_IDSEL + where;
-+      } else {
-+              addr = PCI_DEV1_IDSEL + where;
-+      }
-+
-+      addr += (fn << 8);
-+
-+      cmd = PCI_CMD_CFG_WRITE;
-+      if (size == 1) {
-+              pci_write_u8(cmd, addr, (u8)value);
-+      } else if (size == 2) {
-+              pci_write_u16(cmd, addr, (u16)value);
-+      } else {
-+              pci_write_u32(cmd, addr, value);
-+      }
-+
-+      return PCIBIOS_SUCCESSFUL;
-+}
-+
-+int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size)
-+{
-+      return -EIO;
-+}
-+EXPORT_SYMBOL(pci_set_dma_max_seg_size);
-+
-+int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
-+{
-+      return -EIO;
-+}
-+EXPORT_SYMBOL(pci_set_dma_seg_boundary);
-+
-+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
-+{
-+      resource_size_t start = pci_resource_start(dev, bar);
-+      resource_size_t len   = pci_resource_len(dev, bar);
-+      unsigned long flags = pci_resource_flags(dev, bar);
-+
-+      if (!len || !start) {
-+              return NULL;
-+      }
-+
-+      if (maxlen && len > maxlen) {
-+              len = maxlen;
-+      }
-+
-+      if (flags & IORESOURCE_IO) {
-+              return ioport_map(start, len);
-+      }
-+
-+      if (flags & IORESOURCE_MEM) {
-+              if (flags & IORESOURCE_CACHEABLE) {
-+                      return ioremap(start, len);
-+              }
-+              return ioremap_nocache(start, len);
-+      }
-+      return NULL;
-+}
-+EXPORT_SYMBOL(pci_iomap);
-+
-+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
-+{
-+      if ((unsigned long)addr >= VMALLOC_START &&
-+          (unsigned long)addr < VMALLOC_END) {
-+              iounmap(addr);
-+      }
-+}
-+EXPORT_SYMBOL(pci_iounmap);
-+
-+/*
-+ *  From arch/arm/kernel/bios32.c
-+ *
-+ *  PCI bios-type initialisation for PCI machines
-+ *
-+ *  Bits taken from various places.
-+ */
-+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 = kzalloc(sizeof(struct pci_sys_data), GFP_KERNEL);
-+              if (!sys)
-+                      panic("PCI: unable to allocate sys data!");
-+
-+              sys->hw      = hw;
-+              sys->busnr   = busnr;
-+              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;
-+              }
-+      }
-+}
-+
-+/*
-+ * 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;
-+}
-+
-+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;
-+              /*
-+               * 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 * __init pcibios_setup(char *str)
-+{
-+      if (!strcmp(str, "debug")) {
-+              debug_pci = 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);
-+}
-+
-+
-+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)) ||
-+              (dev->vendor == PCI_VENDOR_ID_ITE &&
-+               dev->device == PCI_DEVICE_ID_ITE_8152);
-+
-+}
-+
-+/*
-+ * 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 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) {
-+              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
-+
-+/**
-+ * 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;
-+}
-+
-+
-+struct pci_ops ubi32_pci_ops = {
-+      .read   = ubi32_pci_read_config,
-+      .write  = ubi32_pci_write_config,
-+};
-+
-+static struct pci_bus *ubi32_pci_scan_bus(int nr, struct pci_sys_data *sys)
-+{
-+      return pci_scan_bus(sys->busnr, &ubi32_pci_ops, sys);
-+}
-+
-+#define UBI32_PCI_MEM_BASE PCI_DEV_REG_BASE
-+#define UBI32_PCI_MEM_LEN  0x80000000
-+
-+#define UBI32_PCI_IO_BASE 0x0
-+#define UBI32_PCI_IO_END  0x0
-+
-+static struct resource ubi32_pci_mem = {
-+      .name   = "PCI memory space",
-+      .start  = UBI32_PCI_MEM_BASE,
-+      .end    = UBI32_PCI_MEM_BASE + UBI32_PCI_MEM_LEN - 1,
-+      .flags  = IORESOURCE_MEM,
-+};
-+
-+static struct resource ubi32_pci_io = {
-+      .name   = "PCI IO space",
-+      .start  = UBI32_PCI_IO_BASE,
-+      .end    = UBI32_PCI_IO_END,
-+      .flags  = IORESOURCE_IO,
-+};
-+
-+static int __init ubi32_pci_setup(int nr, struct pci_sys_data *sys)
-+{
-+      if (nr > 0)
-+              return 0;
-+
-+      request_resource(&iomem_resource, &ubi32_pci_mem);
-+      request_resource(&ioport_resource, &ubi32_pci_io);
-+
-+      sys->resource[0] = &ubi32_pci_io;
-+      sys->resource[1] = &ubi32_pci_mem;
-+      sys->resource[2] = NULL;
-+
-+      return 1;
-+}
-+
-+static void __init ubi32_pci_preinit(void)
-+{
-+}
-+
-+static int __init ubi32_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-+{
-+      return pci_node->dn.recvirq;
-+}
-+
-+struct hw_pci ubi32_pci __initdata = {
-+      .nr_controllers = 1,
-+      .preinit        = ubi32_pci_preinit,
-+      .setup          = ubi32_pci_setup,
-+      .scan           = ubi32_pci_scan_bus,
-+      .map_irq        = ubi32_pci_map_irq,
-+};
-+
-+static int __init ubi32_pci_init(void)
-+{
-+      pci_node = (struct pci_devnode *)devtree_find_node("pci");
-+      if (pci_node == NULL) {
-+              printk(KERN_WARNING "PCI init failed\n");
-+              return -ENOSYS;
-+      }
-+      pci_common_init(&ubi32_pci);
-+      return 0;
-+}
-+
-+subsys_initcall(ubi32_pci_init);
-+
-+/*
-+ * workaround for dual PCI card interrupt
-+ */
-+#define PCI_COMMON_INT_BIT (1 << 19)
-+void ubi32_pci_int_wr(void)
-+{
-+      volatile unsigned int pci_int_line;
-+      pci_int_line = UBICOM32_IO_PORT(RB)->gpio_in;
-+      if (!(pci_int_line & PCI_COMMON_INT_BIT))
-+      {
-+              ubicom32_set_interrupt(pci_node->dn.recvirq);
-+      }
-+}
-+EXPORT_SYMBOL(ubi32_pci_int_wr);
---- /dev/null
-+++ b/arch/ubicom32/mach-common/plio.c
-@@ -0,0 +1,92 @@
-+/*
-+ * plio.c
-+ *    PLIO state machine support functions
-+ *
-+ * Copyright Â© 2009 Ubicom Inc. <www.ubicom.com>.  All rights reserved.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/string.h>
-+#include <linux/delay.h>
-+#include <asm/plio.h>
-+
-+/*
-+ * plio_reset
-+ *    Select and reset PLIO function
-+ */
-+static void plio_reset(const plio_fctl_t *plio_fctl) {
-+      plio_io_function_t plio_function = {
-+              .fn_sel         = PLIO_FN,
-+              .fn_reset       = 1,
-+      };
-+
-+      /*
-+       * enable extension port
-+       */
-+      PEXT_NBR->function = plio_function;
-+
-+      /*
-+       * program clock dividers
-+       */
-+      PLIO_NBR->fctl2 = plio_fctl->fctl2;
-+
-+      /*
-+       * select plio function and assert function reset
-+       */
-+      plio_function.br_thread = thread_get_self();
-+      plio_function.fn_reset = 1;
-+      PLIO_NBR->function = plio_function;
-+
-+      /*
-+       * program plio controls
-+       */
-+      PLIO_NBR->fctl0 = plio_fctl->fctl0;
-+      PLIO_NBR->fctl1 = plio_fctl->fctl1;
-+
-+      /*
-+       * deassert function reset
-+       */
-+      plio_function.fn_reset = 0;
-+      PLIO_NBR->function = plio_function;
-+}
-+
-+/*
-+ * plio_init
-+ *    configure and initialize PLIO.
-+ */
-+void plio_init(const plio_fctl_t *plio_fctl, const plio_config_t *plio_config, const plio_sram_t plio_sram_cfg[], int sram_cfg_size){
-+      /*
-+       * first reset to start plio clock
-+       */
-+      plio_reset(plio_fctl);
-+
-+      udelay(1);
-+
-+      /*
-+       * configure pfsm
-+       */
-+      PLIO_NBR->fctl0.pfsm_prog = 1;
-+      memcpy(PLIO_BR->pfsm_sram, plio_sram_cfg, sram_cfg_size);
-+      PLIO_NBR->fctl0.pfsm_prog = 0;
-+
-+      /*
-+       * program rest of plio
-+       */
-+      memcpy(&PLIO_BR->config, plio_config, sizeof(plio_config_t));
-+}
---- /dev/null
-+++ b/arch/ubicom32/mach-common/profile.c
-@@ -0,0 +1,549 @@
-+/*
-+ * arch/ubicom32/mach-common/profile.c
-+ *   Implementation for Ubicom32 Profiler
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/platform_device.h>
-+#include "profile.h"
-+#include <linux/seq_file.h>
-+#include <linux/proc_fs.h>
-+#include <linux/mm.h>
-+#include <linux/mmzone.h>
-+#include <linux/fs.h>
-+#include <linux/page-flags.h>
-+#include <asm/uaccess.h>
-+#include <asm/devtree.h>
-+#include <asm/profilesample.h>
-+#include <asm/memory_map.h>
-+#include <asm/page.h>
-+#include <asm/ip5000.h>
-+
-+/*
-+ * spacs for all memory blocks so we can hold locks for short time when walking tables
-+ */
-+#define PROFILE_NUM_MAPS 5000
-+static struct profile_map profile_pm[PROFILE_NUM_MAPS];
-+
-+static struct profilenode *node = NULL;
-+static int profile_first_packet = 1;
-+
-+static int profile_open(struct inode *inode, struct file *filp)
-+{
-+      if (!node) {
-+              return -ENOENT;
-+      }
-+      node->busy = 1;
-+      if (!node->enabled) {
-+              node->enabled = 1;
-+              node->busy = 0;
-+              profile_first_packet = 1;
-+              return 0;
-+      }
-+      node->busy = 0;
-+      return -EBUSY;
-+}
-+
-+static int profile_sequence_num;
-+
-+/*
-+ * make a packet full of sample data
-+ */
-+static int profile_make_data_packet(char *buf, int count)
-+{
-+      int samples;            /* number of samples requested */
-+      int i;
-+      struct profile_header ph;
-+      char *ptr;
-+
-+      if (count < sizeof(struct profile_header) + sizeof(struct profile_sample)) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * fill in the packet header
-+       */
-+      memset(&ph, 0, sizeof(struct profile_header));
-+      ph.magic = PROF_MAGIC + PROFILE_VERSION;
-+      ph.header_size = sizeof(struct profile_header);
-+      ph.clocks = node->clocks;
-+      for (i = 0; i < PROFILE_MAX_THREADS; ++i) {
-+              ph.instruction_count[i] = node->inst_count[i];
-+      }
-+      ph.profile_instructions = 0;
-+      ph.enabled = node->enabled_threads;
-+      ph.hrt = node->hrt;
-+      ph.high = 0;
-+      ph.profiler_thread = node->profiler_thread;
-+      ph.clock_freq = node->clock_freq;
-+      ph.seq_num = profile_sequence_num++;
-+      ph.cpu_id = node->cpu_id;
-+      ph.perf_counters[0] = node->stats[0];
-+      ph.perf_counters[1] = node->stats[1];
-+      ph.perf_counters[2] = node->stats[2];
-+      ph.perf_counters[3] = node->stats[3];
-+      ph.ddr_freq = node->ddr_freq;
-+
-+      ptr = buf + sizeof(struct profile_header);
-+
-+      samples = (count - sizeof(struct profile_header)) / sizeof(struct profile_sample);
-+      for (i = 0; i < samples && node->count; ++i) {
-+              if (copy_to_user(ptr, &node->samples[node->tail], sizeof(struct profile_sample)) != 0) {
-+                      return -EFAULT;
-+              }
-+              node->count--;
-+              node->tail++;
-+              if (node->tail >= node->max_samples) {
-+                      node->tail = 0;
-+              }
-+              ptr += sizeof(struct profile_sample);
-+      }
-+      ph.sample_count = i;
-+      if (copy_to_user(buf, &ph, sizeof(struct profile_header)) != 0) {
-+              return -EFAULT;
-+      }
-+      if (ph.sample_count == 0)
-+              return 0;
-+      else
-+              return sizeof(struct profile_header) + ph.sample_count * sizeof(struct profile_sample);
-+}
-+
-+static void profile_get_memory_stats(unsigned int *total_free, unsigned int *max_free)
-+{
-+      struct list_head *p;
-+      struct zone *zone;
-+      unsigned int size;
-+
-+      *total_free = 0;
-+      *max_free = 0;
-+
-+      /*
-+       * get all the free regions.  In each zone, the array of free_area lists contains the first page of each frame of size 1 << order
-+       */
-+      for_each_zone(zone) {
-+              unsigned long order, flags, i;
-+
-+              if (!populated_zone(zone))
-+                      continue;
-+
-+              if (!is_normal(zone))
-+                      continue;
-+
-+              spin_lock_irqsave(&zone->lock, flags);
-+              for_each_migratetype_order(order, i) {
-+                      size = ((1 << order) << PAGE_SHIFT) >> 10;
-+                      list_for_each(p, &(zone->free_area[order].free_list[i])) {
-+                              if (size > *max_free) {
-+                                      *max_free = size;
-+                              }
-+                              *total_free += size;
-+                      }
-+              }
-+              spin_unlock_irqrestore(&zone->lock, flags);
-+      }
-+}
-+
-+struct profile_counter_pkt profile_builtin_stats[] =
-+{
-+      {
-+      "Free memory(KB)", 0
-+      },
-+      {
-+      "Max free Block(KB)", 0
-+      }
-+};
-+
-+/*
-+ * make a packet full of performance counters
-+ */
-+static char prof_pkt[PROFILE_MAX_PACKET_SIZE];
-+static int profile_make_stats_packet(char *buf, int count)
-+{
-+      char *ptr = prof_pkt;
-+      struct profile_header_counters hdr;
-+      int stat_count = 0;
-+      int i;
-+      unsigned int total_free, max_free;
-+      int builtin_count = sizeof(profile_builtin_stats) / sizeof(struct profile_counter_pkt);
-+
-+      if (count > PROFILE_MAX_PACKET_SIZE) {
-+              count = PROFILE_MAX_PACKET_SIZE;
-+      }
-+      stat_count = (count - sizeof(struct profile_header_counters)) / sizeof (struct profile_counter_pkt);
-+      stat_count -= builtin_count;
-+
-+      if (stat_count <= 0) {
-+              return 0;
-+      }
-+
-+      if (stat_count > node->num_counters) {
-+              stat_count = node->num_counters;
-+      }
-+
-+      hdr.magic = PROF_MAGIC_COUNTERS;
-+      hdr.ultra_sample_time = node->clocks;
-+      hdr.ultra_count = stat_count;
-+      hdr.linux_sample_time = UBICOM32_IO_TIMER->sysval;
-+      hdr.linux_count = builtin_count;
-+      memcpy(ptr, (void *)&hdr, sizeof(struct profile_header_counters));
-+      ptr += sizeof(struct profile_header_counters);
-+
-+
-+      for (i = 0; i < stat_count; ++i) {
-+              memcpy(ptr, (void *)(&(node->counters[i])), sizeof(struct profile_counter));
-+              ptr += sizeof(struct profile_counter);
-+      }
-+
-+      /*
-+       * built in statistics
-+       */
-+      profile_get_memory_stats(&total_free, &max_free);
-+      profile_builtin_stats[0].value = total_free;
-+      profile_builtin_stats[1].value = max_free;
-+      memcpy(ptr, (void *)profile_builtin_stats, sizeof(profile_builtin_stats));
-+      ptr += sizeof(profile_builtin_stats);
-+
-+      if (copy_to_user(buf, prof_pkt, ptr - prof_pkt) != 0) {
-+              return -EFAULT;
-+      }
-+      return ptr - prof_pkt;
-+}
-+
-+/*
-+ * return a udp packet ready to send to the profiler tool
-+ * when there are no packets left to make, return 0
-+ */
-+static int profile_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
-+{
-+      int result = 0;
-+      if (!node) {
-+              return -ENOENT;
-+      }
-+      node->busy = 1;
-+      if (!node->enabled) {
-+              node->busy = 0;
-+              return -EPERM;
-+      }
-+      if (!node->samples) {
-+              node->busy = 0;
-+              return -ENOMEM;
-+      }
-+
-+      if (profile_first_packet) {
-+              result = profile_make_stats_packet(buf, count);
-+              profile_first_packet = 0;
-+      }
-+      if (result == 0) {
-+              result = profile_make_data_packet(buf, count);
-+              if (result == 0) {
-+                      profile_first_packet = 1;
-+              }
-+      }
-+      node->busy = 0;
-+      return result;
-+
-+}
-+
-+static int profile_release(struct inode *inode, struct file *filp)
-+{
-+      if (!node) {
-+              return -ENOENT;
-+      }
-+      node->busy = 1;
-+      if (node->enabled) {
-+              node->enabled = 0;
-+              node->count = 0;
-+              node->tail = node->head;
-+              node->busy = 0;
-+              return 0;
-+      }
-+      node->busy = 0;
-+      profile_first_packet = 1;
-+      return -EBADF;
-+}
-+
-+static const struct file_operations profile_fops = {
-+      .open           = profile_open,
-+      .read           = profile_read,
-+      .release        = profile_release,
-+};
-+
-+static int page_aligned(void *x)
-+{
-+      return !((unsigned int)x & ((1 << PAGE_SHIFT) - 1));
-+}
-+
-+static int profile_maps_open(struct inode *inode, struct file *filp)
-+{
-+      struct rb_node *rb;
-+      int num = 0;
-+      int slab_start;
-+      struct vm_area_struct *vma;
-+      int type = PROFILE_MAP_TYPE_UNKNOWN;
-+      int flags, i;
-+      struct list_head *p;
-+      struct zone *zone;
-+
-+      /*
-+       * get the slab data (first so dups will show up as vmas)
-+       */
-+      slab_start = num;
-+      num += kmem_cache_block_info("size-512", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
-+      num += kmem_cache_block_info("size-1024", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
-+      num += kmem_cache_block_info("size-2048", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
-+      num += kmem_cache_block_info("size-4096", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
-+      num += kmem_cache_block_info("size-8192", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
-+
-+      for (i = slab_start; i < num; ++i) {
-+              profile_pm[i].type_size |= PROFILE_MAP_TYPE_SMALL << PROFILE_MAP_TYPE_SHIFT;
-+      }
-+
-+      slab_start = num;
-+      num += kmem_cache_block_info("dentry", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
-+      num += kmem_cache_block_info("inode_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
-+      num += kmem_cache_block_info("sysfs_dir_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
-+      num += kmem_cache_block_info("proc_inode_cache", (struct kmem_cache_size_info *)&profile_pm[num], PROFILE_NUM_MAPS - num);
-+
-+      for (i = slab_start; i < num; ++i) {
-+              profile_pm[i].type_size |= PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT;
-+      }
-+
-+      /*
-+       * get all the vma regions (allocated by mmap, most likely
-+       */
-+#if 0
-+      down_read(&nommu_vma_sem);
-+      for (rb = rb_first(&nommu_vma_tree); rb && num < PROFILE_NUM_MAPS; rb = rb_next(rb)) {
-+              vma = rb_entry(rb, struct vm_area_struct, vm_rb);
-+              profile_pm[num].start = (vma->vm_start - SDRAMSTART) >> PAGE_SHIFT;
-+              profile_pm[num].type_size = (vma->vm_end - vma->vm_start + (1 << PAGE_SHIFT) - 1) >> PAGE_SHIFT;
-+              flags = vma->vm_flags & 0xf;
-+              if (flags == (VM_READ | VM_EXEC)) {
-+                      type = PROFILE_MAP_TYPE_TEXT;
-+              } else if (flags == (VM_READ | VM_WRITE | VM_EXEC)) {
-+                      type = PROFILE_MAP_TYPE_STACK;
-+              } else if (flags == (VM_READ | VM_WRITE)) {
-+                      type = PROFILE_MAP_TYPE_APP_DATA;
-+              }
-+              profile_pm[num].type_size |= type << PROFILE_MAP_TYPE_SHIFT;
-+              num++;
-+      }
-+      up_read(&nommu_vma_sem);
-+      if (rb) {
-+              return -ENOMEM;
-+      }
-+#endif
-+
-+      /*
-+       * get all the free regions.  In each zone, the array of free_area lists contains the first page of each frame of size 1 << order
-+       */
-+      for_each_zone(zone) {
-+              unsigned long order, flags, i;
-+              struct page *page;
-+
-+              if (!populated_zone(zone))
-+                      continue;
-+
-+              if (!is_normal(zone))
-+                      continue;
-+
-+              spin_lock_irqsave(&zone->lock, flags);
-+              for_each_migratetype_order(order, i) {
-+                      list_for_each(p, &(zone->free_area[order].free_list[i])) {
-+                              page = list_entry(p, struct page, lru);
-+                              profile_pm[num].start = ((page_to_phys(page) - SDRAMSTART) >> PAGE_SHIFT) - 0x40;
-+                              profile_pm[num].type_size = (PROFILE_MAP_TYPE_FREE << PROFILE_MAP_TYPE_SHIFT) | order;
-+                              num++;
-+                              if (num >= PROFILE_NUM_MAPS) {
-+                                      spin_unlock_irqrestore(&zone->lock, flags);
-+                                      return -ENOMEM;
-+                              }
-+                      }
-+              }
-+              spin_unlock_irqrestore(&zone->lock, flags);
-+      }
-+
-+      /*
-+       * get the filesystem inodes
-+       */
-+      list_for_each(p, &(super_blocks)) {
-+              struct super_block *sb;
-+              struct list_head *q;
-+              if (num >= PROFILE_NUM_MAPS)
-+                      break;
-+              sb = list_entry(p, struct super_block, s_list);
-+              if (page_aligned(sb)) {
-+                      profile_pm[num].start = ((unsigned int)sb - SDRAMSTART) >> PAGE_SHIFT;
-+                      profile_pm[num].type_size = (PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT);
-+                      num++;
-+              }
-+              list_for_each(q, &(sb->s_inodes)) {
-+                      struct inode *in;
-+                      if (num >= PROFILE_NUM_MAPS)
-+                              break;
-+                      in = list_entry(q, struct inode, i_sb_list);
-+                      if (page_aligned(in)) {
-+                              profile_pm[num].start = ((unsigned int)in - SDRAMSTART) >> PAGE_SHIFT;
-+                              profile_pm[num].type_size = (PROFILE_MAP_TYPE_FS << PROFILE_MAP_TYPE_SHIFT);
-+                              num++;
-+                      }
-+              }
-+      }
-+
-+      /*
-+       * get the buffer cache pages
-+       */
-+      for (i = 0; i < num_physpages && num < PROFILE_NUM_MAPS; ++i) {
-+              if ((mem_map + i)->flags & (1 << PG_lru)) {
-+                      int start = i;
-+                      while ((mem_map + i)->flags & (1 << PG_lru) && i < num_physpages)
-+                              i++;
-+                      profile_pm[num].start = start;
-+                      profile_pm[num].type_size = (i - start) | (PROFILE_MAP_TYPE_CACHE << PROFILE_MAP_TYPE_SHIFT);
-+                      num++;
-+              }
-+      }
-+
-+      filp->private_data = (void *)num;
-+      return 0;
-+}
-+
-+/*
-+ * return one packet of map data, or 0 if all maps have been returned already
-+ */
-+static int profile_maps_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
-+{
-+      struct profile_header_maps header;
-+      char *p = buf + sizeof(header);
-+      int total = (int)filp->private_data;
-+
-+      header.count = (count - sizeof(header)) / sizeof(struct profile_map);
-+      if (header.count > PROFILE_MAX_MAPS) {
-+              header.count = PROFILE_MAX_MAPS;;
-+      }
-+      if (header.count > total - *f_pos) {
-+              header.count = total - *f_pos;
-+      }
-+
-+      if (header.count == 0) {
-+              return 0;
-+      }
-+
-+      header.magic = PROF_MAGIC_MAPS;
-+      header.page_shift = PAGE_SHIFT;
-+
-+      if (copy_to_user(buf, &header, sizeof(header)) != 0) {
-+              return -EFAULT;
-+      }
-+      if (copy_to_user(p, (void *)&profile_pm[*f_pos], sizeof(struct profile_map) * header.count) != 0) {
-+              return -EFAULT;
-+      }
-+      *f_pos += header.count;
-+
-+      return sizeof(header) + sizeof(struct profile_map) * header.count;
-+}
-+
-+static int profile_maps_release(struct inode *inode, struct file *filp)
-+{
-+      return 0;
-+}
-+
-+static const struct file_operations profile_maps_fops = {
-+      .open           = profile_maps_open,
-+      .read           = profile_maps_read,
-+      .release        = profile_maps_release,
-+};
-+
-+static int profile_rate_show(struct seq_file *m, void *v)
-+{
-+      if (node) {
-+              seq_printf(m, "%d samples per second.  %d virtual counters.\n", node->rate, node->num_counters);
-+      } else {
-+              seq_printf(m, "Profiler is not initialized.\n");
-+      }
-+      return 0;
-+}
-+
-+static int profile_rate_open(struct inode *inode, struct file *filp)
-+{
-+      return single_open(filp, profile_rate_show, NULL);
-+}
-+
-+static int profile_rate_write(struct file *filp, const char *buf, size_t len, loff_t *off)
-+{
-+      *off = 0;
-+      return 0;
-+}
-+
-+static const struct file_operations profile_rate_fops = {
-+      .open           = profile_rate_open,
-+      .read           = seq_read,
-+      .llseek         = seq_lseek,
-+      .release        = single_release,
-+      .write          = profile_rate_write,
-+};
-+
-+int ubi32_profile_init_module(void)
-+{
-+      struct proc_dir_entry *pdir;
-+
-+      /*
-+       * find the device
-+       */
-+      node = (struct profilenode *)devtree_find_node("profiler");
-+      if (!node) {
-+              printk(KERN_INFO "Profiler does not exist.\n");
-+              return -ENODEV;
-+      }
-+
-+      /*
-+       * allocate the sample buffer
-+       */
-+      node->max_samples = PROFILE_MAX_SAMPLES;
-+      node->samples = kmalloc(node->max_samples * sizeof(struct profile_sample), GFP_KERNEL);
-+      if (!node->samples) {
-+              printk(KERN_INFO "Profiler sample buffer kmalloc failed.\n");
-+              return -ENOMEM;
-+      }
-+
-+      /*
-+       * connect to the file system
-+       */
-+      pdir = proc_mkdir("profile", NULL);
-+      if (!pdir) {
-+              return -ENOMEM;
-+      }
-+      if (!proc_create("data", 0, pdir, &profile_fops)) {
-+              return -ENOMEM;
-+      }
-+      if (!proc_create("rate", 0, pdir, &profile_rate_fops)) {
-+              return -ENOMEM;
-+      }
-+      if (!proc_create("maps", 0, pdir, &profile_maps_fops)) {
-+              return -ENOMEM;
-+      }
-+      return 0;
-+}
-+
-+
-+module_init(ubi32_profile_init_module);
-+
-+MODULE_AUTHOR("David Fotland");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/arch/ubicom32/mach-common/profile.h
-@@ -0,0 +1,82 @@
-+/*
-+ * arch/ubicom32/mach-common/profile.h
-+ *   Private data for the profile module
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/types.h>
-+#include <asm/devtree.h>
-+#include "profpkt.h"
-+
-+#ifndef _PROFILE_H_
-+#define _PROFILE_H_
-+
-+#define PROFILE_MAX_THREADS 16
-+#define PROFILE_MAX_SAMPLES 1024
-+
-+struct profile_sample;
-+struct oprofile_sample;
-+
-+/*
-+ * values chosen so all counter values fit in a single UDP packet
-+ */
-+#define PROFILE_NODE_MAX_COUNTERS 32
-+
-+struct profile_counter {
-+      char name[PROFILE_COUNTER_NAME_LENGTH];
-+      unsigned int value;
-+};
-+
-+struct profilenode {
-+      struct devtree_node dn;
-+      volatile u32_t enabled;                 /* Is the profiler enabled to take samples? */
-+      volatile u32_t busy;                    /* set when the samples are being read by the driver */
-+      volatile u32_t rate;                    /* What is the sampling rate? */
-+      volatile u32_t enabled_threads;         /* which threads were enabled at the last sample time */
-+      volatile u32_t hrt;                     /* HRT threads */
-+      volatile u32_t profiler_thread;         /* thread running the profile sampler */
-+      volatile u32_t clocks;                  /* system clock timer at last sample */
-+      volatile u32_t clock_freq;              /* clock frequency in Hz */
-+      volatile u32_t ddr_freq;                /* memory frequency */
-+      volatile u32_t cpu_id;                  /* chip_id register */
-+      volatile u32_t inst_count[PROFILE_MAX_THREADS];         /* sampled instruction counts at most recent sample */
-+      volatile u32_t stats[4];                                /* contents of the cache statistics counters */
-+      volatile u16_t head;                    /* sample taker puts samples here */
-+      volatile u16_t tail;                    /* packet filler takes samples here */
-+      volatile u16_t count;                   /* number of valid samples */
-+      volatile u16_t max_samples;             /* how many samples can be in the samples array */
-+      struct profile_sample *samples;         /* samples array allocated by the linux driver */
-+      volatile u32_t num_counters;            /* how many registered performance counters */
-+      volatile struct profile_counter counters[PROFILE_NODE_MAX_COUNTERS];
-+
-+      /* unimplemented interface for future oprofile work */
-+      volatile u16_t oprofile_head;           /* sample taker puts samples here */
-+      volatile u16_t oprofile_tail;           /* packet filler takes samples here */
-+      volatile u16_t oprofile_count;          /* how many oprofile sampels are are in use */
-+      volatile u16_t oprofile_max_samples;    /* samples array size for oprofile samples */
-+      struct oprofile_sample *oprofile_samples;       /* oprofile sample buffer */
-+};
-+
-+#endif
---- /dev/null
-+++ b/arch/ubicom32/mach-common/profpkt.h
-@@ -0,0 +1,158 @@
-+
-+/*
-+ * arch/ubicom32/mach-common/profpkt.c
-+ *   Ubicom32 Profiler packet formats for communication between the linux proc driver and the profiler display tool
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#define PROFILE_PORT 51080
-+#define PROFILE_POSIX_NAME_LENGTH 32
-+
-+/*
-+ * profile UDP packet format for communicating between ip3k and host
-+ *
-+ * every packet starts with a header, followed by samples.
-+ * samples are only taken for non-hrt threads that are
-+ * active
-+ */
-+#define PROF_MAGIC 0x3ea0
-+#define PROF_MAGIC_COUNTERS 0x9ea0
-+#define PROF_MAGIC_MAPS 0xaea0
-+
-+/*
-+ * Versions (31 max):
-+ * 1 to 4 were before 6.0 release,  development versions
-+ * 5 was forward compatible version, shipped with 6.0 and 6.1
-+ * 6 adds heap packets, and clock_freq to header, shipped with 6.2
-+ * 7 adds a sequence numbers to check for dropped packets, shipped with 6.3.5
-+ * 8 adds mqueue timing information, shipped with 6.3.5
-+ * 9 adds sdram heap size information, shipped with 6.4
-+ * 10 adds heapmem heap callers and long latency stack traces.  shipped with 6.4
-+ * 11 adds support for Mars (IP5K).  shipped with 6.10
-+ * 12 adds more support for Mars.  Shipped with 7.0
-+ * 13 adds per sample latency measurement.  Shipped with 7.2
-+ * 14 changes the heap format and adds a string packet.  Shipped with 7.4
-+ * 15 adds dsr stats and posix.  shipped with 7.6
-+ * 16 corrects maximum packet count for Ares.  ships with 7.9
-+ * 17 adds a5 register value to sample
-+ */
-+
-+#define PROFILE_VERSION 17
-+#define PROFILE_MAX_PACKET_SIZE 1440
-+
-+#define PROFILE_MAX_THREADS 16
-+
-+/*
-+ * each packet starts with a profile_header, then sample_count samples
-+ * samples are gprof samples of pc, the return address, condition codes, and
-+ * active threads
-+ */
-+struct profile_header {
-+      u16_t magic;                    /* magic number and version */
-+      u8_t header_size;               /* number of bytes in profile header */
-+      u8_t sample_count;              /* number of samples in the packet */
-+      u32_t clocks;                   /* clock counter value */
-+      u32_t instruction_count[PROFILE_MAX_THREADS];
-+                                      /* instructions executed per thread */
-+      u32_t profile_instructions;     /* instructions executed by profiler mainline */
-+      u16_t enabled;                  /* which threads are enabled */
-+      u16_t hrt;                      /* which threads are hrt */
-+      u16_t high;                     /* which threads are high priority */
-+      u16_t profiler_thread;          /* which thread runs the profiler */
-+      u32_t heap_free;                /* current free on-cihp heap space in bytes */
-+      u32_t heap_low_water;           /* on-chip heap low water mark */
-+      u32_t netpage_free;             /* number of free on-chip net pages */
-+      u32_t netpage_low_water;        /* low water mark on free on-chip netpages */
-+      u32_t min_sp[PROFILE_MAX_THREADS];
-+                                      /* stack pointer values per thread */
-+      u32_t clock_freq;               /* clock frequency (Hz) of system being analyzed */
-+      u32_t seq_num;                  /* to detect dropped profiler packets */
-+      u32_t timing_sequence;          /* sample number since boot */
-+      u32_t timing_interval;          /* second per sample timing interval */
-+      u32_t timing_worst_time;        /* duration of longest finction called, in core clocks */
-+      u32_t timing_function;          /* address of longest function */
-+      u32_t timing_average;           /* average time of all functions in last interval */
-+      u32_t timing_count;             /* number of functions called in last interval */
-+      u32_t extheap_free;             /* current free extmem heap space in bytes */
-+      u32_t extheap_low_water;        /* extmem heap low water mark */
-+      u32_t cpu_id;                   /* CHIP_ID register contents */
-+      u32_t perf_counters[4];         /* contents of the CPU performance counters */
-+      u8_t perf_config[4];            /* what is being counted */
-+      u32_t ddr_freq;                 /* DDR clock frequency */
-+      u32_t extnetpage_free;          /* number of free off chip net pages */
-+      u32_t extnetpage_low_water;     /* low water mark on off-chip free netpages */
-+      u32_t dsr_max_latency;          /* max time to process a dsr interrupt, in clocks, since last packet */
-+      u32_t dsr_ave_latency;          /* average dsr latency over last DSR_STATS_RECENT_COUNT interrupts */
-+      u32_t dsr_count;                /* number of dsr interrupts since last packet */
-+};
-+
-+struct profile_header_counters {
-+      u16_t magic;
-+      u16_t ultra_count;              /* how many ultra counters follow this */
-+      u32_t ultra_sample_time;        /* in chip clocks */
-+      u32_t linux_count;              /* how many linux counters follow this */
-+      u32_t linux_sample_time;
-+};
-+
-+/*
-+ * values chosen so all counter values fit in a single 1400 byte UDP packet
-+ */
-+#define PROFILE_COUNTER_NAME_LENGTH 20
-+#define PROFILE_MAX_COUNTERS ((PROFILE_MAX_PACKET_SIZE - sizeof(struct profile_header_counters)) / (PROFILE_COUNTER_NAME_LENGTH + 4))
-+
-+struct profile_counter_pkt {
-+      char name[PROFILE_COUNTER_NAME_LENGTH];
-+      unsigned int value;
-+};
-+
-+/*
-+ * send memory maps from linux to profiler tool
-+ */
-+
-+struct profile_header_maps {
-+      u16_t magic;
-+      u16_t count;
-+      u32_t page_shift;
-+};
-+
-+#define PROFILE_MAP_NUM_TYPES 32
-+
-+/* types 0-15: size field is order.  True size is 2^order */
-+#define PROFILE_MAP_TYPE_UNKNOWN 0
-+#define PROFILE_MAP_TYPE_FREE 1
-+#define PROFILE_MAP_TYPE_SMALL 2
-+#define PROFILE_MAP_TYPE_FS 3
-+/* types 16-31: size field is pages.  True size is (1 << PAGE_SHIFT) * size */
-+#define PROFILE_MAP_SIZE_TYPE 16
-+#define PROFILE_MAP_TYPE_TEXT 16
-+#define PROFILE_MAP_TYPE_STACK 17
-+#define PROFILE_MAP_TYPE_APP_DATA 18
-+#define PROFILE_MAP_TYPE_CACHE 19
-+#define PROFILE_MAP_RESERVED 24
-+
-+#define PROFILE_MAP_TYPE_SHIFT 11
-+#define PROFILE_MAP_SIZE_MASK 0x7ff
-+
-+struct profile_map {
-+      u16_t start;            /* start page number of segment, relative to start of DRAM */
-+      u16_t type_size;        /* type (4 bits) of the segment and size in pages (12 bits) */
-+};
-+
-+#define PROFILE_MAX_MAPS (PROFILE_MAX_PACKET_SIZE - sizeof(struct profile_header_maps)) / sizeof(struct profile_map)
---- /dev/null
-+++ b/arch/ubicom32/mach-common/ring_tio.c
-@@ -0,0 +1,123 @@
-+/*
-+ * arch/ubicom32/mach-common/ring_tio.c
-+ *   Generic initialization for UIO Ubicom32 Ring
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/platform_device.h>
-+#include <linux/types.h>
-+
-+#include <asm/devtree.h>
-+#include <asm/ring_tio.h>
-+
-+static const char *ring_tio_driver_name = "uio_ubicom32ring";
-+
-+/*
-+ * The number of ring_tio's currently allocated, used for .id
-+ */
-+static int __initdata ring_tio_count;
-+
-+/*
-+ * The maximum number of resources that the ring_tio will have.
-+ * Currently 3, a register space, and up to 2 interrupts.
-+ */
-+#define RING_TIO_MAX_RESOURCES        3
-+
-+/*
-+ * ring_tio_init
-+ *    Checks the device tree and instantiates the driver if found
-+ */
-+void __init ring_tio_init(const char *node_name)
-+{
-+      struct platform_device *pdev;
-+      struct resource *res;
-+      int resource_idx = 0;
-+      struct ring_tio_node *ring_node;
-+
-+      /*
-+       * Check the device tree for the ring_tio
-+       */
-+      ring_node = (struct ring_tio_node *)devtree_find_node(node_name);
-+      if (!ring_node) {
-+              printk(KERN_WARNING "Ring TIO '%s' not found\n", node_name);
-+              return;
-+      }
-+
-+      if (ring_node->version != RING_TIO_NODE_VERSION) {
-+              printk(KERN_WARNING "ring_tio not compatible\n");
-+              return;
-+      }
-+
-+      /*
-+       * Dynamically create the platform_device structure and resources
-+       */
-+      pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
-+      if (!pdev) {
-+              printk(KERN_WARNING "ring_tio could not alloc pdev\n");
-+              return;
-+      }
-+
-+      res = kzalloc(sizeof(struct resource) * RING_TIO_MAX_RESOURCES,
-+                      GFP_KERNEL);
-+      if (!res) {
-+              kfree(pdev);
-+              printk(KERN_WARNING "ring_tio could not alloc res\n");
-+              return;
-+      }
-+
-+      pdev->name = ring_tio_driver_name;
-+      pdev->id = ring_tio_count++;
-+      pdev->resource = res;
-+
-+      /*
-+       * Fill in the resources and platform data from devtree information
-+       */
-+      res[resource_idx].start = (u32_t)(ring_node->regs);
-+      res[resource_idx].end = (u32_t)(ring_node->regs);
-+      res[resource_idx].flags = IORESOURCE_MEM;
-+      resource_idx++;
-+
-+      if (ring_node->dn.sendirq != 0xFF) {
-+              res[resource_idx].start = ring_node->dn.sendirq;
-+              res[resource_idx].flags = IORESOURCE_IRQ;
-+              resource_idx++;
-+      }
-+
-+      if (ring_node->dn.recvirq != 0xFF) {
-+              res[resource_idx].start = ring_node->dn.recvirq;
-+              res[resource_idx].flags = IORESOURCE_IRQ;
-+              resource_idx++;
-+      }
-+      pdev->num_resources = resource_idx;
-+
-+      printk(KERN_INFO "RingTIO.%d '%s' found irq=%d/%d regs=%p pdev=%p/%p\n",
-+              ring_tio_count - 1, node_name, ring_node->dn.sendirq,
-+              ring_node->dn.recvirq, ring_node->regs, pdev, res);
-+
-+      /*
-+       * Try to get the device registered
-+       */
-+      pdev->dev.platform_data = (void *)node_name;
-+      if (platform_device_register(pdev) < 0) {
-+              printk(KERN_WARNING "Ring failed to register\n");
-+              kfree(pdev);
-+              kfree(res);
-+      }
-+}
---- /dev/null
-+++ b/arch/ubicom32/mach-common/switch-bcm539x.c
-@@ -0,0 +1,1195 @@
-+/*
-+ * arch/ubicom32/mach-common/switch-bcm539x.c
-+ *   BCM539X switch driver, SPI mode
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/platform_device.h>
-+#include <linux/spi/spi.h>
-+#include <linux/gpio.h>
-+#include <linux/delay.h>
-+#include <linux/mii.h>
-+
-+#include <asm/switch-dev.h>
-+#include <asm/ubicom32-spi-gpio.h>
-+#include "switch-core.h"
-+#include "switch-bcm539x-reg.h"
-+
-+#define DRIVER_NAME "bcm539x-spi"
-+#define DRIVER_VERSION "1.0"
-+
-+#undef BCM539X_DEBUG
-+#define BCM539X_SPI_RETRIES   100
-+
-+struct bcm539x_data {
-+      struct switch_device                    *switch_dev;
-+
-+      /*
-+       * Our private data
-+       */
-+      struct spi_device                       *spi;
-+      struct switch_core_platform_data        *pdata;
-+
-+      /*
-+       * Last page we accessed
-+       */
-+      u8_t                                    last_page;
-+
-+      /*
-+       * 539x Device ID
-+       */
-+      u8_t                                    device_id;
-+};
-+
-+/*
-+ * bcm539x_wait_status
-+ *    Waits for the specified bit in the status register to be set/cleared.
-+ */
-+static int bcm539x_wait_status(struct bcm539x_data *bd, u8_t mask, int set)
-+{
-+      u8_t txbuf[2];
-+      u8_t rxbuf;
-+      int i;
-+      int ret;
-+
-+      txbuf[0] = BCM539X_CMD_READ;
-+      txbuf[1] = BCM539X_GLOBAL_SPI_STATUS;
-+      for (i = 0; i < BCM539X_SPI_RETRIES; i++) {
-+              ret = spi_write_then_read(bd->spi, txbuf, 2, &rxbuf, 1);
-+              rxbuf &= mask;
-+              if ((set && rxbuf) || (!set && !rxbuf)) {
-+                      return 0;
-+              }
-+              udelay(1);
-+      }
-+
-+      return -EIO;
-+}
-+
-+/*
-+ * bcm539x_set_page
-+ *    Sets the register page for access (only if necessary)
-+ */
-+static int bcm539x_set_page(struct bcm539x_data *bd, u8_t page)
-+{
-+      u8_t txbuf[3];
-+
-+      if (page == bd->last_page) {
-+              return 0;
-+      }
-+
-+      bd->last_page = page;
-+
-+      txbuf[0] = BCM539X_CMD_WRITE;
-+      txbuf[1] = BCM539X_GLOBAL_PAGE;
-+      txbuf[2] = page;
-+
-+      return spi_write(bd->spi, txbuf, 3);
-+}
-+
-+/*
-+ * bcm539x_write_bytes
-+ *    Writes a number of bytes to a given page and register
-+ */
-+static int bcm539x_write_bytes(struct bcm539x_data *bd, u8_t page,
-+                             u8_t reg, void *buf, u8_t len)
-+{
-+      int ret;
-+      u8_t *txbuf;
-+
-+      txbuf = kmalloc(2 + len, GFP_KERNEL);
-+      if (!txbuf) {
-+              return -ENOMEM;
-+      }
-+
-+      /*
-+       * Make sure the chip has finished processing our previous request
-+       */
-+      ret = bcm539x_wait_status(bd, BCM539X_GLOBAL_SPI_ST_SPIF, 0);
-+      if (ret) {
-+              goto done;
-+      }
-+
-+      /*
-+       * Set the page
-+       */
-+      ret = bcm539x_set_page(bd, page);
-+      if (ret) {
-+              goto done;
-+      }
-+
-+      /*
-+       * Read the data
-+       */
-+      txbuf[0] = BCM539X_CMD_WRITE;
-+      txbuf[1] = reg;
-+      memcpy(&txbuf[2], buf, len);
-+
-+#ifdef BCM539X_DEBUG
-+      {
-+              int i;
-+              printk("write page %02x reg %02x len=%d buf=", page, reg, len);
-+              for (i = 0; i < len + 2; i++) {
-+                      printk("%02x ", txbuf[i]);
-+              }
-+              printk("\n");
-+      }
-+#endif
-+
-+      ret = spi_write(bd->spi, txbuf, 2 + len);
-+
-+done:
-+      kfree(txbuf);
-+      return ret;
-+}
-+
-+/*
-+ * bcm539x_write_32
-+ *    Writes 32 bits of data to the given page and register
-+ */
-+static inline int bcm539x_write_32(struct bcm539x_data *bd, u8_t page,
-+                                 u8_t reg, u32_t data)
-+{
-+      data = cpu_to_le32(data);
-+      return bcm539x_write_bytes(bd, page, reg, &data, 4);
-+}
-+
-+/*
-+ * bcm539x_write_16
-+ *    Writes 16 bits of data to the given page and register
-+ */
-+static inline int bcm539x_write_16(struct bcm539x_data *bd, u8_t page,
-+                                 u8_t reg, u16_t data)
-+{
-+      data = cpu_to_le16(data);
-+      return bcm539x_write_bytes(bd, page, reg, &data, 2);
-+}
-+
-+/*
-+ * bcm539x_write_8
-+ *    Writes 8 bits of data to the given page and register
-+ */
-+static inline int bcm539x_write_8(struct bcm539x_data *bd, u8_t page,
-+                                u8_t reg, u8_t data)
-+{
-+      return bcm539x_write_bytes(bd, page, reg, &data, 1);
-+}
-+
-+/*
-+ * bcm539x_read_bytes
-+ *    Reads a number of bytes from a given page and register
-+ */
-+static int bcm539x_read_bytes(struct bcm539x_data *bd, u8_t page,
-+                            u8_t reg, void *buf, u8_t len)
-+{
-+      u8_t txbuf[2];
-+      int ret;
-+
-+      /*
-+       * (1) Make sure the chip has finished processing our previous request
-+       */
-+      ret = bcm539x_wait_status(bd, BCM539X_GLOBAL_SPI_ST_SPIF, 0);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      /*
-+       * (2) Set the page
-+       */
-+      ret = bcm539x_set_page(bd, page);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      /*
-+       * (3) Kick off the register read
-+       */
-+      txbuf[0] = BCM539X_CMD_READ;
-+      txbuf[1] = reg;
-+      ret = spi_write_then_read(bd->spi, txbuf, 2, txbuf, 1);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      /*
-+       * (4) Wait for RACK
-+       */
-+      ret = bcm539x_wait_status(bd, BCM539X_GLOBAL_SPI_ST_RACK, 1);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      /*
-+       * (5) Read the data
-+       */
-+      txbuf[0] = BCM539X_CMD_READ;
-+      txbuf[1] = BCM539X_GLOBAL_SPI_DATA0;
-+
-+      ret = spi_write_then_read(bd->spi, txbuf, 2, buf, len);
-+
-+#ifdef BCM539X_DEBUG
-+      {
-+              int i;
-+              printk("read page %02x reg %02x len=%d rxbuf=",
-+                     page, reg, len);
-+              for (i = 0; i < len; i++) {
-+                      printk("%02x ", ((u8_t *)buf)[i]);
-+              }
-+              printk("\n");
-+      }
-+#endif
-+
-+      return ret;
-+}
-+
-+/*
-+ * bcm539x_read_32
-+ *    Reads an 32 bit number from a given page and register
-+ */
-+static int bcm539x_read_32(struct bcm539x_data *bd, u8_t page,
-+                         u8_t reg, u32_t *buf)
-+{
-+      int ret = bcm539x_read_bytes(bd, page, reg, buf, 4);
-+      *buf = le32_to_cpu(*buf);
-+      return ret;
-+}
-+
-+/*
-+ * bcm539x_read_16
-+ *    Reads an 16 bit number from a given page and register
-+ */
-+static int bcm539x_read_16(struct bcm539x_data *bd, u8_t page,
-+                         u8_t reg, u16_t *buf)
-+{
-+      int ret = bcm539x_read_bytes(bd, page, reg, buf, 2);
-+      *buf = le16_to_cpu(*buf);
-+      return ret;
-+}
-+
-+/*
-+ * bcm539x_read_8
-+ *    Reads an 8 bit number from a given page and register
-+ */
-+static int bcm539x_read_8(struct bcm539x_data *bd, u8_t page,
-+                        u8_t reg, u8_t *buf)
-+{
-+      return bcm539x_read_bytes(bd, page, reg, buf, 1);
-+}
-+
-+/*
-+ * bcm539x_set_mode
-+ */
-+static int bcm539x_set_mode(struct bcm539x_data *bd, int state)
-+{
-+      u8_t buf;
-+      int ret;
-+
-+      ret = bcm539x_read_8(bd, PAGE_PORT_TC, REG_CTRL_MODE, &buf);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      buf &= ~(1 << 1);
-+      buf |= state ? (1 << 1) : 0;
-+
-+      ret = bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_MODE, buf);
-+      return ret;
-+}
-+
-+/*
-+ * bcm539x_handle_reset
-+ */
-+static int bcm539x_handle_reset(struct switch_device *dev, char *buf, int inst)
-+{
-+      struct bcm539x_data *bd =
-+              (struct bcm539x_data *)switch_get_drvdata(dev);
-+      int ret;
-+
-+      ret = bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_SRST,
-+                            (1 << 7) | (1 << 4));
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      udelay(20);
-+
-+      ret = bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_SRST, 0);
-+      return ret;
-+}
-+
-+/*
-+ * bcm539x_handle_vlan_ports_read
-+ */
-+static int bcm539x_handle_vlan_ports_read(struct switch_device *dev,
-+                                        char *buf, int inst)
-+{
-+      struct bcm539x_data *bd =
-+              (struct bcm539x_data *)switch_get_drvdata(dev);
-+      int j;
-+      int len = 0;
-+      u8_t rxbuf8;
-+      u32_t rxbuf32;
-+      int ret;
-+
-+      ret = bcm539x_write_16(bd, PAGE_VTBL, REG_VTBL_INDX_5395, inst);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      ret = bcm539x_write_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395,
-+                            (1 << 7) | 1);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      /*
-+       * Wait for completion
-+       */
-+      for (j = 0; j < BCM539X_SPI_RETRIES; j++) {
-+              ret = bcm539x_read_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395,
-+                                   &rxbuf8);
-+              if (ret) {
-+                      return ret;
-+              }
-+              if (!(rxbuf8 & (1 << 7))) {
-+                      break;
-+              }
-+      }
-+
-+      if (j == BCM539X_SPI_RETRIES) {
-+              return -EIO;
-+      }
-+
-+      /*
-+       * Read the table entry
-+       */
-+      ret = bcm539x_read_32(bd, PAGE_VTBL, REG_VTBL_ENTRY_5395, &rxbuf32);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      for (j = 0; j < 9; j++) {
-+              if (rxbuf32 & (1 << j)) {
-+                      u16_t rxbuf16;
-+                      len += sprintf(buf + len, "%d", j);
-+                      if (rxbuf32 & (1 << (j + 9))) {
-+                              buf[len++] = 'u';
-+                      } else {
-+                              buf[len++] = 't';
-+                      }
-+                      ret = bcm539x_read_16(bd, PAGE_VLAN,
-+                                            REG_VLAN_PTAG0 + (j << 1),
-+                                            &rxbuf16);
-+                      if (ret) {
-+                              return ret;
-+                      }
-+                      if (rxbuf16 == inst) {
-+                              buf[len++] = '*';
-+                      }
-+                      buf[len++] = '\t';
-+              }
-+      }
-+
-+      len += sprintf(buf + len, "\n");
-+      buf[len] = '\0';
-+
-+      return len;
-+}
-+
-+/*
-+ * bcm539x_handle_vlan_ports_write
-+ */
-+static int bcm539x_handle_vlan_ports_write(struct switch_device *dev,
-+                                         char *buf, int inst)
-+{
-+      struct bcm539x_data *bd =
-+              (struct bcm539x_data *)switch_get_drvdata(dev);
-+      int j;
-+      u32_t untag;
-+      u32_t ports;
-+      u32_t def;
-+
-+      u8_t rxbuf8;
-+      u16_t rxbuf16;
-+      int ret;
-+
-+      switch_parse_vlan_ports(dev, buf, &untag, &ports, &def);
-+
-+#ifdef BCM539X_DEBUG
-+      printk(KERN_DEBUG "'%s' inst=%d untag=%08x ports=%08x def=%08x\n",
-+              buf, inst, untag, ports, def);
-+#endif
-+
-+      if (!ports) {
-+              return 0;
-+      }
-+
-+      /*
-+       * Change default vlan tag
-+       */
-+      for (j = 0; j < 9; j++) {
-+              if ((untag | def) & (1 << j)) {
-+                      ret = bcm539x_write_16(bd, PAGE_VLAN,
-+                                             REG_VLAN_PTAG0 + (j << 1),
-+                                             inst);
-+                      if (ret) {
-+                              return ret;
-+                      }
-+                      continue;
-+              }
-+
-+              if (!(dev->port_mask[0] & (1 << j))) {
-+                      continue;
-+              }
-+
-+              /*
-+               * Remove any ports which are not listed anymore as members of
-+               * this vlan
-+               */
-+              ret = bcm539x_read_16(bd, PAGE_VLAN,
-+                                    REG_VLAN_PTAG0 + (j << 1), &rxbuf16);
-+              if (ret) {
-+                      return ret;
-+              }
-+              if (rxbuf16 == inst) {
-+                      ret = bcm539x_write_16(bd, PAGE_VLAN,
-+                                             REG_VLAN_PTAG0 + (j << 1), 0);
-+                      if (ret) {
-+                              return ret;
-+                      }
-+              }
-+      }
-+
-+      /*
-+       * Write the VLAN table
-+       */
-+      ret = bcm539x_write_16(bd, PAGE_VTBL, REG_VTBL_INDX_5395, inst);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      ret = bcm539x_write_32(bd, PAGE_VTBL, REG_VTBL_ENTRY_5395,
-+                             (untag << 9) | ports);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      ret = bcm539x_write_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395,
-+                            (1 << 7) | 0);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      /*
-+       * Wait for completion
-+       */
-+      for (j = 0; j < BCM539X_SPI_RETRIES; j++) {
-+              ret = bcm539x_read_bytes(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395,
-+                                       &rxbuf8, 1);
-+              if (ret) {
-+                      return ret;
-+              }
-+              if (!(rxbuf8 & (1 << 7))) {
-+                      break;
-+              }
-+      }
-+
-+      return (j < BCM539X_SPI_RETRIES) ? 0 : -EIO;
-+}
-+
-+/*
-+ * Handlers for <this_driver>/vlan/<vlan_id>
-+ */
-+static const struct switch_handler bcm539x_switch_handlers_vlan_dir[] = {
-+      {
-+              .name   = "ports",
-+              .read   = bcm539x_handle_vlan_ports_read,
-+              .write  = bcm539x_handle_vlan_ports_write,
-+      },
-+      {
-+      },
-+};
-+
-+/*
-+ * bcm539x_handle_vlan_delete_write
-+ */
-+static int bcm539x_handle_vlan_delete_write(struct switch_device *dev,
-+                                          char *buf, int inst)
-+{
-+      struct bcm539x_data *bd =
-+              (struct bcm539x_data *)switch_get_drvdata(dev);
-+      int vid;
-+      u8_t rxbuf8;
-+      u32_t txbuf;
-+      int j;
-+      int ret;
-+
-+      vid = simple_strtoul(buf, NULL, 0);
-+      if (!vid) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Disable this VLAN
-+       *
-+       * Go through the port-based vlan registers and clear the appropriate
-+       * ones out
-+       */
-+      for (j = 0; j < 9; j++) {
-+              u16_t rxbuf16;
-+              ret = bcm539x_read_16(bd, PAGE_VLAN, REG_VLAN_PTAG0 + (j << 1),
-+                                    &rxbuf16);
-+              if (ret) {
-+                      return ret;
-+              }
-+              if (rxbuf16 == vid) {
-+                      txbuf = 0;
-+                      ret = bcm539x_write_16(bd, PAGE_VLAN,
-+                                             REG_VLAN_PTAG0 + (j << 1),
-+                                             txbuf);
-+                      if (ret) {
-+                              return ret;
-+                      }
-+              }
-+      }
-+
-+      /*
-+       * Write the VLAN table
-+       */
-+      txbuf = vid;
-+      ret = bcm539x_write_16(bd, PAGE_VTBL, REG_VTBL_INDX_5395, txbuf);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      txbuf = 0;
-+      ret = bcm539x_write_32(bd, PAGE_VTBL, REG_VTBL_ENTRY_5395, txbuf);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      txbuf = (1 << 7) | (0);
-+      ret = bcm539x_write_8(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395, txbuf);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      /*
-+       * Wait for completion
-+       */
-+      for (j = 0; j < BCM539X_SPI_RETRIES; j++) {
-+              ret = bcm539x_read_bytes(bd, PAGE_VTBL, REG_VTBL_ACCESS_5395,
-+                                       &rxbuf8, 1);
-+              if (ret) {
-+                      return ret;
-+              }
-+              if (!(rxbuf8 & (1 << 7))) {
-+                      break;
-+              }
-+      }
-+
-+      if (j == BCM539X_SPI_RETRIES) {
-+              return -EIO;
-+      }
-+
-+      return switch_remove_vlan_dir(dev, vid);
-+}
-+
-+/*
-+ * bcm539x_handle_vlan_create_write
-+ */
-+static int bcm539x_handle_vlan_create_write(struct switch_device *dev,
-+                                          char *buf, int inst)
-+{
-+      int vid;
-+
-+      vid = simple_strtoul(buf, NULL, 0);
-+      if (!vid) {
-+              return -EINVAL;
-+      }
-+
-+      return switch_create_vlan_dir(dev, vid,
-+                                    bcm539x_switch_handlers_vlan_dir);
-+}
-+
-+/*
-+ * bcm539x_handle_enable_read
-+ */
-+static int bcm539x_handle_enable_read(struct switch_device *dev,
-+                                    char *buf, int inst)
-+{
-+      struct bcm539x_data *bd =
-+              (struct bcm539x_data *)switch_get_drvdata(dev);
-+      u8_t rxbuf;
-+      int ret;
-+
-+      ret = bcm539x_read_8(bd, PAGE_PORT_TC, REG_CTRL_MODE, &rxbuf);
-+      if (ret) {
-+              return ret;
-+      }
-+      rxbuf = (rxbuf & (1 << 1)) ? 1 : 0;
-+
-+      return sprintf(buf, "%d\n", rxbuf);
-+}
-+
-+/*
-+ * bcm539x_handle_enable_write
-+ */
-+static int bcm539x_handle_enable_write(struct switch_device *dev,
-+                                     char *buf, int inst)
-+{
-+      struct bcm539x_data *bd =
-+              (struct bcm539x_data *)switch_get_drvdata(dev);
-+
-+      return bcm539x_set_mode(bd, buf[0] == '1');
-+}
-+
-+/*
-+ * bcm539x_handle_enable_vlan_read
-+ */
-+static int bcm539x_handle_enable_vlan_read(struct switch_device *dev,
-+                                         char *buf, int inst)
-+{
-+      struct bcm539x_data *bd =
-+              (struct bcm539x_data *)switch_get_drvdata(dev);
-+      u8_t rxbuf;
-+      int ret;
-+
-+      ret = bcm539x_read_8(bd, PAGE_VLAN, REG_VLAN_CTRL0, &rxbuf);
-+      if (ret) {
-+              return ret;
-+      }
-+      rxbuf = (rxbuf & (1 << 7)) ? 1 : 0;
-+
-+      return sprintf(buf, "%d\n", rxbuf);
-+}
-+
-+/*
-+ * bcm539x_handle_enable_vlan_write
-+ */
-+static int bcm539x_handle_enable_vlan_write(struct switch_device *dev,
-+                                          char *buf, int inst)
-+{
-+      struct bcm539x_data *bd =
-+              (struct bcm539x_data *)switch_get_drvdata(dev);
-+      int ret;
-+
-+      /*
-+       * disable 802.1Q VLANs
-+       */
-+      if (buf[0] != '1') {
-+              ret = bcm539x_write_8(bd, PAGE_VLAN, REG_VLAN_CTRL0, 0);
-+              return ret;
-+      }
-+
-+      /*
-+       * enable 802.1Q VLANs
-+       *
-+       * Enable 802.1Q | IVL learning
-+       */
-+      ret = bcm539x_write_8(bd, PAGE_VLAN, REG_VLAN_CTRL0,
-+                            (1 << 7) | (3 << 5));
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      /*
-+       * RSV multicast fwd | RSV multicast chk
-+       */
-+      ret = bcm539x_write_8(bd, PAGE_VLAN, REG_VLAN_CTRL1,
-+                            (1 << 2) | (1 << 3));
-+      if (ret) {
-+              return ret;
-+      }
-+#if 0
-+      /*
-+       * Drop invalid VID
-+       */
-+      ret = bcm539x_write_16(bd, PAGE_VLAN, REG_VLAN_CTRL3, 0x00FF);
-+      if (ret) {
-+              return ret;
-+      }
-+#endif
-+      return 0;
-+}
-+
-+/*
-+ * bcm539x_handle_port_enable_read
-+ */
-+static int bcm539x_handle_port_enable_read(struct switch_device *dev,
-+                                         char *buf, int inst)
-+{
-+      return sprintf(buf, "%d\n", 1);
-+}
-+
-+/*
-+ * bcm539x_handle_port_enable_write
-+ */
-+static int bcm539x_handle_port_enable_write(struct switch_device *dev,
-+                                          char *buf, int inst)
-+{
-+      /*
-+       * validate port
-+       */
-+      if (!(dev->port_mask[0] & (1 << inst))) {
-+              return -EIO;
-+      }
-+
-+      if (buf[0] != '1') {
-+              printk(KERN_WARNING "switch port[%d] disabling is not supported\n", inst);
-+      }
-+      return 0;
-+}
-+
-+/*
-+ * bcm539x_handle_port_state_read
-+ */
-+static int bcm539x_handle_port_state_read(struct switch_device *dev,
-+                                         char *buf, int inst)
-+{
-+      struct bcm539x_data *bd =
-+              (struct bcm539x_data *)switch_get_drvdata(dev);
-+      int ret;
-+      u16_t link;
-+
-+      /*
-+       * validate port
-+       */
-+      if (!(dev->port_mask[0] & (1 << inst))) {
-+              return -EIO;
-+      }
-+
-+      /*
-+       * check PHY link state - CPU port (port 8) is always up
-+       */
-+      ret = bcm539x_read_16(bd, PAGE_STATUS, REG_LINK_STATUS, &link);
-+      if (ret) {
-+              return ret;
-+      }
-+      link |= (1 << 8);
-+
-+      return sprintf(buf, "%d\n", (link & (1 << inst)) ? 1 : 0);
-+}
-+
-+/*
-+ * bcm539x_handle_port_media_read
-+ */
-+static int bcm539x_handle_port_media_read(struct switch_device *dev,
-+                                         char *buf, int inst)
-+{
-+      struct bcm539x_data *bd =
-+              (struct bcm539x_data *)switch_get_drvdata(dev);
-+      int ret;
-+      u16_t link, duplex;
-+      u32_t speed;
-+
-+      /*
-+       * validate port
-+       */
-+      if (!(dev->port_mask[0] & (1 << inst))) {
-+              return -EIO;
-+      }
-+
-+      /*
-+       * check PHY link state first - CPU port (port 8) is always up
-+       */
-+      ret = bcm539x_read_16(bd, PAGE_STATUS, REG_LINK_STATUS, &link);
-+      if (ret) {
-+              return ret;
-+      }
-+      link |= (1 << 8);
-+
-+      if (!(link & (1 << inst))) {
-+              return sprintf(buf, "UNKNOWN\n");
-+      }
-+
-+      /*
-+       * get link speeda dn duplex - CPU port (port 8) is 1000/full
-+       */
-+      ret = bcm539x_read_32(bd, PAGE_STATUS, 4, &speed);
-+      if (ret) {
-+              return ret;
-+      }
-+      speed |= (2 << 16);
-+      speed = (speed >> (2 * inst)) & 3;
-+
-+      ret = bcm539x_read_16(bd, PAGE_STATUS, 8, &duplex);
-+      if (ret) {
-+              return ret;
-+      }
-+      duplex |= (1 << 8);
-+      duplex = (duplex >> inst) & 1;
-+
-+      return sprintf(buf, "%d%cD\n",
-+              (speed == 0) ? 10 : ((speed == 1) ? 100 : 1000),
-+              duplex ? 'F' : 'H');
-+}
-+
-+/*
-+ * bcm539x_handle_port_meida_write
-+ */
-+static int bcm539x_handle_port_meida_write(struct switch_device *dev,
-+                                          char *buf, int inst)
-+{
-+      struct bcm539x_data *bd =
-+              (struct bcm539x_data *)switch_get_drvdata(dev);
-+      int ret;
-+      u16_t ctrl_word, local_cap, local_giga_cap;
-+
-+      /*
-+       * validate port (not for CPU port)
-+       */
-+      if (!(dev->port_mask[0] & (1 << inst) & ~(1 << 8))) {
-+              return -EIO;
-+      }
-+
-+      /*
-+       * Get the maximum capability from status
-+       *      SPI reg[0x00] = PHY[0x0] --- MII control
-+       *      SPI reg[0x08] = PHY[0x4] --- MII local capability
-+       *      SPI reg[0x12] = PHY[0x9] --- GMII control
-+       */
-+      ret = bcm539x_read_16(bd, REG_MII_PAGE + inst, (MII_ADVERTISE << 1), &local_cap);
-+      if (ret) {
-+              return ret;
-+      }
-+      ret = bcm539x_read_16(bd, REG_MII_PAGE + inst, (MII_CTRL1000 << 1), &local_giga_cap);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      /* Configure to the requested speed */
-+      if (strncmp(buf, "1000FD", 6) == 0) {
-+              /* speed */
-+              local_cap &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL);
-+              local_cap &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL);
-+              local_giga_cap |= (ADVERTISE_1000HALF | ADVERTISE_1000FULL);
-+              /* duplex */
-+      } else if (strncmp(buf, "100FD", 5) == 0) {
-+              /* speed */
-+              local_cap &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL);
-+              local_cap |= (ADVERTISE_100HALF | ADVERTISE_100FULL);
-+              local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
-+              /* duplex */
-+              local_cap &= ~(ADVERTISE_100HALF);
-+      } else if (strncmp(buf, "100HD", 5) == 0) {
-+              /* speed */
-+              local_cap &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL);
-+              local_cap |= (ADVERTISE_100HALF | ADVERTISE_100FULL);
-+              local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
-+              /* duplex */
-+              local_cap &= ~(ADVERTISE_100FULL);
-+      } else if (strncmp(buf, "10FD", 4) == 0) {
-+              /* speed */
-+              local_cap |= (ADVERTISE_10HALF | ADVERTISE_10FULL);
-+              local_cap &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL);
-+              local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
-+              /* duplex */
-+              local_cap &= ~(ADVERTISE_10HALF);
-+      } else if (strncmp(buf, "10HD", 4) == 0) {
-+              /* speed */
-+              local_cap |= (ADVERTISE_10HALF | ADVERTISE_10FULL);
-+              local_cap &= ~(ADVERTISE_100HALF | ADVERTISE_100FULL);
-+              local_giga_cap &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
-+              /* duplex */
-+              local_cap &= ~(ADVERTISE_10FULL);
-+      } else if (strncmp(buf, "AUTO", 4) == 0) {
-+              /* speed */
-+              local_cap |= (ADVERTISE_10HALF | ADVERTISE_10FULL);
-+              local_cap |= (ADVERTISE_100HALF | ADVERTISE_100FULL);
-+              local_giga_cap |= (ADVERTISE_1000HALF | ADVERTISE_1000FULL);
-+      } else {
-+              return -EINVAL;
-+      }
-+
-+      /* Active PHY with the requested speed for auto-negotiation */
-+      ret = bcm539x_write_16(bd, REG_MII_PAGE + inst, (MII_ADVERTISE << 1), local_cap);
-+      if (ret) {
-+              return ret;
-+      }
-+      ret = bcm539x_write_16(bd, REG_MII_PAGE + inst, (MII_CTRL1000 << 1), local_giga_cap);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      ret = bcm539x_read_16(bd, REG_MII_PAGE + inst, (MII_BMCR << 1), &ctrl_word);
-+      if (ret) {
-+              return ret;
-+      }
-+      ctrl_word |= (BMCR_ANENABLE | BMCR_ANRESTART);
-+      ret = bcm539x_write_16(bd, REG_MII_PAGE + inst, (MII_BMCR << 1), ctrl_word);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * proc_fs entries for this switch
-+ */
-+static const struct switch_handler bcm539x_switch_handlers[] = {
-+      {
-+              .name   = "enable",
-+              .read   = bcm539x_handle_enable_read,
-+              .write  = bcm539x_handle_enable_write,
-+      },
-+      {
-+              .name   = "enable_vlan",
-+              .read   = bcm539x_handle_enable_vlan_read,
-+              .write  = bcm539x_handle_enable_vlan_write,
-+      },
-+      {
-+              .name   = "reset",
-+              .write  = bcm539x_handle_reset,
-+      },
-+      {
-+      },
-+};
-+
-+/*
-+ * Handlers for <this_driver>/vlan
-+ */
-+static const struct switch_handler bcm539x_switch_handlers_vlan[] = {
-+      {
-+              .name   = "delete",
-+              .write  = bcm539x_handle_vlan_delete_write,
-+      },
-+      {
-+              .name   = "create",
-+              .write  = bcm539x_handle_vlan_create_write,
-+      },
-+      {
-+      },
-+};
-+
-+/*
-+ * Handlers for <this_driver>/port/<port number>
-+ */
-+static const struct switch_handler bcm539x_switch_handlers_port[] = {
-+      {
-+              .name   = "enable",
-+              .read   = bcm539x_handle_port_enable_read,
-+              .write  = bcm539x_handle_port_enable_write,
-+      },
-+      {
-+              .name   = "state",
-+              .read   = bcm539x_handle_port_state_read,
-+      },
-+      {
-+              .name   = "media",
-+              .read   = bcm539x_handle_port_media_read,
-+              .write  = bcm539x_handle_port_meida_write,
-+      },
-+      {
-+      },
-+};
-+
-+/*
-+ * bcm539x_probe
-+ */
-+static int __devinit bcm539x_probe(struct spi_device *spi)
-+{
-+      struct bcm539x_data *bd;
-+      struct switch_core_platform_data *pdata;
-+      struct switch_device *switch_dev = NULL;
-+      int i, ret;
-+      u8_t txbuf[2];
-+
-+      pdata = spi->dev.platform_data;
-+      if (!pdata) {
-+              return -EINVAL;
-+      }
-+
-+      ret = spi_setup(spi);
-+      if (ret < 0) {
-+              return ret;
-+      }
-+
-+      /*
-+       * Reset the chip if requested
-+       */
-+      if (pdata->flags & SWITCH_DEV_FLAG_HW_RESET) {
-+              ret = gpio_request(pdata->pin_reset, "switch-bcm539x-reset");
-+              if (ret) {
-+                      printk(KERN_WARNING "Could not request reset\n");
-+                      return -EINVAL;
-+              }
-+
-+              gpio_direction_output(pdata->pin_reset, 0);
-+              udelay(10);
-+              gpio_set_value(pdata->pin_reset, 1);
-+              udelay(20);
-+      }
-+
-+      /*
-+       * Allocate our private data structure
-+       */
-+      bd = kzalloc(sizeof(struct bcm539x_data), GFP_KERNEL);
-+      if (!bd) {
-+              return -ENOMEM;
-+      }
-+
-+      dev_set_drvdata(&spi->dev, bd);
-+      bd->pdata = pdata;
-+      bd->spi = spi;
-+      bd->last_page = 0xFF;
-+
-+      /*
-+       * First perform SW reset if needed
-+       */
-+      if (pdata->flags & SWITCH_DEV_FLAG_SW_RESET) {
-+              txbuf[0] = (1 << 7) | (1 << 4);
-+              ret = bcm539x_write_bytes(bd, PAGE_PORT_TC,
-+                                        REG_CTRL_SRST, txbuf, 1);
-+              if (ret) {
-+                      goto fail;
-+              }
-+
-+              udelay(20);
-+
-+              txbuf[0] = 0;
-+              ret = bcm539x_write_bytes(bd, PAGE_PORT_TC,
-+                                        REG_CTRL_SRST, txbuf, 1);
-+              if (ret) {
-+                      goto fail;
-+              }
-+      }
-+
-+      /*
-+       * See if we can see the chip
-+       */
-+      for (i = 0; i < 10; i++) {
-+              ret = bcm539x_read_bytes(bd, PAGE_MMR, REG_DEVICE_ID,
-+                                       &bd->device_id, 1);
-+              if (!ret) {
-+                      break;
-+              }
-+      }
-+      if (ret) {
-+              goto fail;
-+      }
-+
-+      /*
-+       * We only support 5395, 5397, 5398
-+       */
-+      if ((bd->device_id != 0x95) && (bd->device_id != 0x97) &&
-+          (bd->device_id != 0x98)) {
-+              ret = -ENODEV;
-+              goto fail;
-+      }
-+
-+      /*
-+       *  Override CPU port config: fixed link @1000 with flow control
-+       */
-+      ret = bcm539x_read_8(bd, PAGE_PORT_TC, REG_CTRL_MIIPO, txbuf);
-+      bcm539x_write_8(bd, PAGE_PORT_TC, REG_CTRL_MIIPO, 0xbb);        // Override IMP port config
-+      printk("Broadcom SW CPU port setting: 0x%x -> 0xbb\n", txbuf[0]);
-+
-+      /*
-+       * Setup the switch driver structure
-+       */
-+      switch_dev = switch_alloc();
-+      if (!switch_dev) {
-+              ret = -ENOMEM;
-+              goto fail;
-+      }
-+      switch_dev->name = pdata->name;
-+
-+      switch_dev->ports = (bd->device_id == 0x98) ? 9 : 6;
-+      switch_dev->port_mask[0] = (bd->device_id == 0x98) ? 0x1FF : 0x11F;
-+      switch_dev->driver_handlers = bcm539x_switch_handlers;
-+      switch_dev->reg_handlers = NULL;
-+      switch_dev->vlan_handlers = bcm539x_switch_handlers_vlan;
-+      switch_dev->port_handlers = bcm539x_switch_handlers_port;
-+
-+      bd->switch_dev = switch_dev;
-+      switch_set_drvdata(switch_dev, (void *)bd);
-+
-+      ret = switch_register(bd->switch_dev);
-+      if (ret < 0) {
-+              goto fail;
-+      }
-+
-+      printk(KERN_INFO "bcm53%02x switch chip initialized\n", bd->device_id);
-+
-+      return ret;
-+
-+fail:
-+      if (switch_dev) {
-+              switch_release(switch_dev);
-+      }
-+      dev_set_drvdata(&spi->dev, NULL);
-+      kfree(bd);
-+      return ret;
-+}
-+
-+static int __attribute__((unused)) bcm539x_remove(struct spi_device *spi)
-+{
-+      struct bcm539x_data *bd;
-+
-+      bd = dev_get_drvdata(&spi->dev);
-+
-+      if (bd->pdata->flags & SWITCH_DEV_FLAG_HW_RESET) {
-+              gpio_free(bd->pdata->pin_reset);
-+      }
-+
-+      if (bd->switch_dev) {
-+              switch_unregister(bd->switch_dev);
-+              switch_release(bd->switch_dev);
-+      }
-+
-+      dev_set_drvdata(&spi->dev, NULL);
-+
-+      kfree(bd);
-+
-+      return 0;
-+}
-+
-+static struct spi_driver bcm539x_driver = {
-+      .driver = {
-+              .name           = DRIVER_NAME,
-+              .owner          = THIS_MODULE,
-+      },
-+      .probe          = bcm539x_probe,
-+      .remove         = __devexit_p(bcm539x_remove),
-+};
-+
-+static int __init bcm539x_init(void)
-+{
-+      return spi_register_driver(&bcm539x_driver);
-+}
-+
-+module_init(bcm539x_init);
-+
-+static void __exit bcm539x_exit(void)
-+{
-+      spi_unregister_driver(&bcm539x_driver);
-+}
-+module_exit(bcm539x_exit);
-+
-+MODULE_AUTHOR("Pat Tjin");
-+MODULE_LICENSE("GPL v2");
-+MODULE_DESCRIPTION("bcm539x SPI switch chip driver");
---- /dev/null
-+++ b/arch/ubicom32/mach-common/switch-bcm539x-reg.h
-@@ -0,0 +1,221 @@
-+/*
-+ * arch/ubicom32/mach-common/switch-bcm539x-reg.h
-+ *   Broadcom switch definitions for Ubicom32 architecture.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+/*
-+ * Broadcom 53xx RoboSwitch device driver.
-+ *
-+ * Copyright 2007, Broadcom Corporation
-+ * All Rights Reserved.
-+ *
-+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
-+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
-+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
-+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
-+ *
-+ * $Id$
-+ */
-+
-+#ifndef _SWITCH_BCM539X_REG_H_
-+#define _SWITCH_BCM539X_REG_H_
-+
-+#define       BCM539X_CMD_READ                0x60
-+#define       BCM539X_CMD_WRITE               0x61
-+
-+#define       BCM539X_GLOBAL_SPI_DATA0        0xf0
-+
-+#define       BCM539X_GLOBAL_SPI_STATUS       0xfe
-+#define       BCM539X_GLOBAL_SPI_ST_SPIF      (1<<7)
-+#define       BCM539X_GLOBAL_SPI_ST_RACK      (1<<5)
-+
-+#define       BCM539X_GLOBAL_PAGE             0xff
-+
-+#define PAGE_PORT_TC                  0x00            // Port Traffic Control Register
-+
-+#define PAGE_QOS_CTL                  0x30            // QoS Global Control Register
-+#define PAGE_QOS_TAG                  0x34            // Default IEEE 802.1Q TAG Register
-+
-+#define PAGE_MII_CTL_PORT0            0x10            // Internal PHY MII Register
-+#define PAGE_MII_CTL_PORT1            0x11
-+#define PAGE_MII_CTL_PORT2            0x12
-+#define PAGE_MII_CTL_PORT3            0x13
-+#define PAGE_MII_CTL_PORT4            0x14
-+
-+#define PAGE_STATUS                   0x01            // Status Register Page
-+#define PAGE_RATE_CONTROL             0x41            // Broadcast Storm Suppression Register
-+
-+#define REG_GRATE_CONTROL             0x00
-+
-+#define REG_LED_POWER                 0x12
-+
-+// Ingress Rate Control
-+#define REG_IRATE_CONTROLP0           0x10
-+#define REG_IRATE_CONTROLP1           0x14
-+#define REG_IRATE_CONTROLP2           0x18
-+#define REG_IRATE_CONTROLP3           0x1C
-+#define REG_IRATE_CONTROLP4           0x20
-+#define REG_IRATE_CONTROLP7           0x2C
-+#define REG_IRATE_CONTROLPI           0x30
-+
-+// Egress Rate Control
-+#define REG_ERATE_CONTROLP0           0x80
-+#define REG_ERATE_CONTROLP1           0x82
-+#define REG_ERATE_CONTROLP2           0x84
-+#define REG_ERATE_CONTROLP3           0x86
-+#define REG_ERATE_CONTROLP4           0x88
-+#define REG_ERATE_CONTROLP5           0x8A
-+#define REG_ERATE_CONTROLP6           0x8C
-+#define REG_ERATE_CONTROLP7           0x8E
-+#define REG_ERATE_CONTROLPI           0x90
-+
-+#define REG_LINK_STATUS                       0x00
-+
-+#define REG_TC_PORT0                  0x00
-+#define REG_TC_PORT1                  0x01
-+#define REG_TC_PORT2                  0x02
-+#define REG_TC_PORT3                  0x03
-+#define REG_TC_PORT4                  0x04
-+#define REG_TC_PORT5                  0x05
-+
-+#define REG_SPEED_CTL                 0x00
-+#define REG_SPEED_ADV100              0x08
-+#define REG_SPEED_ADV1000             0x12
-+
-+#define REG_QOS_EN                    0x00
-+#define REG_QOS_TAG_PORT1             0x12            // Default IEEE 802.1Q TAG, PORT 1
-+#define REG_QOS_TAG_PORT2             0x14            // Default IEEE 802.1Q TAG, PORT 2
-+#define REG_QOS_TAG_PORT3             0x16            // Default IEEE 802.1Q TAG, PORT 3
-+#define REG_QOS_TAG_PORT4             0x18            // Default IEEE 802.1Q TAG, PORT 4
-+#define REG_QOS_PID_PORT1             0x52            // Ingress Port Priority ID MAP, PORT 1
-+#define REG_QOS_PID_PORT2             0x54            // Ingress Port Priority ID MAP, PORT 2
-+#define REG_QOS_PID_PORT3             0x56            // Ingress Port Priority ID MAP, PORT 3
-+#define REG_QOS_PID_PORT4             0x58            // Ingress Port Priority ID MAP, PORT 4
-+#define REG_QOS_TXQ_CTL                       0x80            // Tx Queue Control Register
-+#define REG_QOS_TXQ_WHTQ0             0x81            // Tx Queue Weight Register Queue 0
-+#define REG_QOS_TXQ_WHTQ1             0x82            // Tx Queue Weight Register Queue 1
-+#define REG_QOS_TXQ_WHTQ2             0x83            // Tx Queue Weight Register Queue 2
-+#define REG_QOS_TXQ_WHTQ3             0x84            // Tx Queue Weight Register Queue 3
-+
-+#define REG_CTRL_PPSEL                0x24            /* 5397: Protected port select register */
-+
-+#define RATE_CONTROL_ENABLED          (1 << 22)
-+#define RATE_CONTROL_BSIZE            ((1 << 10) | (1 << 9) | (1 << 8))
-+
-+#define RATE_CONTROL_HIGH             ((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4))
-+#define RATE_CONTROL_HIGH_N           ~((1 << 3) | (1 << 2) | (1 << 1) | (1 << 0))
-+
-+#define RATE_CONTROL_MEDIUM           ((1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0))
-+#define RATE_CONTROL_MEDIUM_N         ~((1 << 7))
-+
-+#define RATE_CONTROL_NORMAL           ((1 << 5) | (1 << 2) | (1 << 0))
-+#define RATE_CONTROL_NORMAL_N         ~((1 << 7) | (1 << 6) | (1 << 4) | (1 << 3) | (1 << 1))
-+
-+#define RATE_CONTROL_LOW              ((1 << 4) | (1 << 3) | (1 << 0))
-+#define RATE_CONTROL_LOW_N            ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2) | (1 << 1))
-+
-+// --- Gemtek, Configure the switch to support Ethernet Port QoS
-+
-+/* MII access registers */
-+#define PSEUDO_PHYAD                  0x1E    /* MII Pseudo PHY address */
-+#define REG_MII_PAGE                  0x10    /* MII Page register */
-+#define REG_MII_ADDR                  0x11    /* MII Address register */
-+#define REG_MII_DATA0                 0x18    /* MII Data register 0 */
-+#define REG_MII_DATA1                 0x19    /* MII Data register 1 */
-+#define REG_MII_DATA2                 0x1a    /* MII Data register 2 */
-+#define REG_MII_DATA3                 0x1b    /* MII Data register 3 */
-+
-+/* Page numbers */
-+#define PAGE_CTRL                     0x00    /* Control page */
-+#define PAGE_MMR                      0x02    /* 5397 Management/Mirroring page */
-+#define PAGE_VTBL                     0x05    /* ARL/VLAN Table access page */
-+#define PAGE_VLAN                     0x34    /* VLAN page */
-+
-+/* Control page registers */
-+#define REG_CTRL_PORT0                        0x00    /* Port 0 traffic control register */
-+#define REG_CTRL_PORT1                        0x01    /* Port 1 traffic control register */
-+#define REG_CTRL_PORT2                        0x02    /* Port 2 traffic control register */
-+#define REG_CTRL_PORT3                        0x03    /* Port 3 traffic control register */
-+#define REG_CTRL_PORT4                        0x04    /* Port 4 traffic control register */
-+#define REG_CTRL_PORT5                        0x05    /* Port 5 traffic control register */
-+#define REG_CTRL_PORT6                        0x06    /* Port 6 traffic control register */
-+#define REG_CTRL_PORT7                        0x07    /* Port 7 traffic control register */
-+#define REG_CTRL_MODE                 0x0B    /* Switch Mode register */
-+#define REG_CTRL_MIIPO                        0x0E    /* 5325: MII Port Override register */
-+#define REG_CTRL_SRST                 0x79    /* Software reset control register */
-+
-+#define REG_DEVICE_ID                 0x30    /* 539x Device id: */
-+#define       DEVID5395                       0x95    /*  5395 */
-+#define       DEVID5397                       0x97    /*  5397 */
-+#define       DEVID5398                       0x98    /*  5398 */
-+#define REG_REVISION_ID                       0x40    /* 539x Revision id: */
-+
-+/* VLAN page registers */
-+#define REG_VLAN_CTRL0                        0x00    /* VLAN Control 0 register */
-+#define REG_VLAN_CTRL1                        0x01    /* VLAN Control 1 register */
-+#define REG_VLAN_CTRL2                        0x02    /* VLAN Control 2 register */
-+#define REG_VLAN_CTRL3                        0x03    /* VLAN Control 3 register */
-+#define REG_VLAN_CTRL4                        0x04    /* VLAN Control 4 register */
-+#define REG_VLAN_CTRL5                        0x05    /* VLAN Control 5 register */
-+#define REG_VLAN_ACCESS                       0x06    /* VLAN Table Access register */
-+#define REG_VLAN_WRITE                        0x08    /* VLAN Write register */
-+#define REG_VLAN_READ                 0x0C    /* VLAN Read register */
-+#define REG_VLAN_PTAG0                        0x10    /* VLAN Default Port Tag register - port 0 */
-+#define REG_VLAN_PTAG1                        0x12    /* VLAN Default Port Tag register - port 1 */
-+#define REG_VLAN_PTAG2                        0x14    /* VLAN Default Port Tag register - port 2 */
-+#define REG_VLAN_PTAG3                        0x16    /* VLAN Default Port Tag register - port 3 */
-+#define REG_VLAN_PTAG4                        0x18    /* VLAN Default Port Tag register - port 4 */
-+#define REG_VLAN_PTAG5                        0x1a    /* VLAN Default Port Tag register - port 5 */
-+#define REG_VLAN_PTAG6                        0x1c    /* VLAN Default Port Tag register - port 6 */
-+#define REG_VLAN_PTAG7                        0x1e    /* VLAN Default Port Tag register - port 7 */
-+#define REG_VLAN_PTAG8                        0x20    /* 539x: VLAN Default Port Tag register - IMP port */
-+#define REG_VLAN_PMAP                 0x20    /* 5325: VLAN Priority Re-map register */
-+
-+/* ARL/VLAN Table Access page registers */
-+#define REG_VTBL_CTRL                 0x00    /* ARL Read/Write Control */
-+#define REG_VTBL_MINDX                        0x02    /* MAC Address Index */
-+#define REG_VTBL_VINDX                        0x08    /* VID Table Index */
-+#define REG_VTBL_ARL_E0                       0x10    /* ARL Entry 0 */
-+#define REG_VTBL_ARL_E1                       0x18    /* ARL Entry 1 */
-+#define REG_VTBL_DAT_E0                       0x18    /* ARL Table Data Entry 0 */
-+#define REG_VTBL_SCTRL                        0x20    /* ARL Search Control */
-+#define REG_VTBL_SADDR                        0x22    /* ARL Search Address */
-+#define REG_VTBL_SRES                 0x24    /* ARL Search Result */
-+#define REG_VTBL_SREXT                        0x2c    /* ARL Search Result */
-+#define REG_VTBL_VID_E0                       0x30    /* VID Entry 0 */
-+#define REG_VTBL_VID_E1                       0x32    /* VID Entry 1 */
-+#define REG_VTBL_PREG                 0xFF    /* Page Register */
-+#define REG_VTBL_ACCESS                       0x60    /* VLAN table access register */
-+#define REG_VTBL_INDX                 0x61    /* VLAN table address index register */
-+#define REG_VTBL_ENTRY                        0x63    /* VLAN table entry register */
-+#define REG_VTBL_ACCESS_5395          0x80    /* VLAN table access register */
-+#define REG_VTBL_INDX_5395            0x81    /* VLAN table address index register */
-+#define REG_VTBL_ENTRY_5395           0x83    /* VLAN table entry register */
-+
-+/* SPI registers */
-+#define REG_SPI_PAGE                  0xff    /* SPI Page register */
-+
-+#endif
---- /dev/null
-+++ b/arch/ubicom32/mach-common/switch-core.c
-@@ -0,0 +1,737 @@
-+/*
-+ * arch/ubicom32/mach-common/switch-core.c
-+ *   Ubicom32 architecture switch and /proc/switch/... implementation.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 2005 Felix Fietkau <openwrt@nbd.name>
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *
-+ * Basic doc of driver's /proc interface:
-+ * /proc/switch/<interface>/
-+ *   registers:              read-only
-+ *   counters:               read-only
-+ *   reset:                  write causes hardware reset
-+ *   enable:                 "0", "1"
-+ *   enable_vlan:            "0", "1"
-+ *   port/<port-number>/
-+ *     enabled:              "0", "1"
-+ *     link state:           read-only
-+ *     media:                "AUTO", "1000FD", "100FD", "100HD", "10FD", "10HD"
-+ *   vlan/<port-number>/
-+ *     ports: same syntax as for nvram's vlan*ports (eg. "1 2 3 4 5*")
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/uaccess.h>
-+#include <linux/ctype.h>
-+#include <linux/proc_fs.h>
-+#include <linux/list.h>
-+#include <linux/rwsem.h>
-+#include <linux/device.h>
-+
-+#include "switch-core.h"
-+
-+/*
-+ * Pointer to the root of our filesystem
-+ */
-+static struct proc_dir_entry *switch_root;
-+
-+/*
-+ * Lock used to manage access to the switch list
-+ */
-+DECLARE_RWSEM(switch_list_lock);
-+EXPORT_SYMBOL_GPL(switch_list_lock);
-+
-+/*
-+ * List of switches we are managing
-+ */
-+LIST_HEAD(switch_list);
-+EXPORT_SYMBOL_GPL(switch_list);
-+
-+/*
-+ * List of handlers we have
-+ */
-+LIST_HEAD(switch_handler_list);
-+EXPORT_SYMBOL_GPL(switch_handler_list);
-+
-+/*
-+ * Keep track of all the handlers we added
-+ */
-+struct switch_handler_entry {
-+      struct list_head                node;
-+      struct proc_dir_entry           *parent;
-+      struct switch_device            *dev;
-+      const struct switch_handler     *handler;
-+      int                             inst;
-+};
-+
-+/*
-+ * Keep track of all VLAN dirs we created
-+ */
-+struct switch_vlan_entry {
-+      struct list_head                node;
-+      struct proc_dir_entry           *pde;
-+      int                             vlan_id;
-+      const struct switch_handler     *handlers;
-+};
-+
-+/*
-+ * switch_parse_vlan_ports
-+ *    Parse the vlan properties written to <driver>/vlan/<vlan_id>/ports
-+ */
-+void switch_parse_vlan_ports(struct switch_device *switch_dev,
-+                           char *buf, u32_t *untag,
-+                           u32_t *ports, u32_t *def)
-+{
-+      u32_t tag = 0;
-+      *untag = 0;
-+      *ports = 0;
-+      *def = 0;
-+
-+
-+      /*
-+       * Skip any leading spaces
-+       */
-+      while (isspace(*buf)) {
-+              buf++;
-+      }
-+
-+      /*
-+       * Parse out the string
-+       */
-+      while (*buf) {
-+              u32_t port = simple_strtoul(buf, &buf, 10);
-+              u32_t mask = (1 << port);
-+
-+              /*
-+               * Parse out any flags
-+               */
-+              while (*buf && !isspace(*buf)) {
-+                      switch (*buf++) {
-+                      case 't':
-+                              tag |= mask;
-+                              break;
-+                      case '*':
-+                              *def |= mask;
-+                              break;
-+                      }
-+              }
-+              *ports |= mask;
-+
-+              /*
-+               * Skip any spaces
-+               */
-+              while (isspace(*buf)) {
-+                      buf++;
-+              }
-+      }
-+
-+      *untag = ~tag & *ports;
-+}
-+
-+/*
-+ * switch_proc_read
-+ *    Handle reads from the procfs, dispatches the driver specific handler
-+ */
-+static ssize_t switch_proc_read(struct file *file, char *buf, size_t count,
-+                              loff_t *ppos)
-+{
-+      struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
-+      char *page;
-+      int len = 0;
-+
-+      page = kmalloc(SWITCH_MAX_BUFSZ, GFP_KERNEL);
-+      if (!page) {
-+              return -ENOBUFS;
-+      }
-+
-+      if (pde->data != NULL) {
-+              struct switch_handler_entry *she =
-+                      (struct switch_handler_entry *)pde->data;
-+              if (she->handler->read) {
-+                      len += she->handler->read(she->dev, page + len,
-+                                                she->inst);
-+              }
-+      }
-+      len += 1;
-+
-+      if (*ppos < len) {
-+              len = min_t(int, len - *ppos, count);
-+              if (copy_to_user(buf, (page + *ppos), len)) {
-+                      kfree(page);
-+                      return -EFAULT;
-+              }
-+              *ppos += len;
-+      } else {
-+              len = 0;
-+      }
-+
-+      kfree(page);
-+
-+      return len;
-+}
-+
-+/*
-+ * switch_proc_write
-+ *    Handle writes from the procfs, dispatches the driver specific handler
-+ */
-+static ssize_t switch_proc_write(struct file *file, const char *buf,
-+                               size_t count, loff_t *data)
-+{
-+      struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
-+      char *page;
-+      int ret = -EINVAL;
-+
-+      page = kmalloc(count + 1, GFP_KERNEL);
-+      if (page == NULL)
-+              return -ENOBUFS;
-+
-+      if (copy_from_user(page, buf, count)) {
-+              kfree(page);
-+              return -EINVAL;
-+      }
-+      page[count] = 0;
-+
-+      if (pde->data != NULL) {
-+              struct switch_handler_entry *she =
-+                      (struct switch_handler_entry *)pde->data;
-+              if (she->handler->write) {
-+                      ret = she->handler->write(she->dev, page, she->inst);
-+                      if (ret >= 0) {
-+                              ret = count;
-+                      }
-+              }
-+      }
-+
-+      kfree(page);
-+      return ret;
-+}
-+
-+/*
-+ * File operations for the proc_fs, we must cast here since proc_fs' definitions
-+ * differ from file_operations definitions.
-+ */
-+static struct file_operations switch_proc_fops = {
-+      .read = (ssize_t (*) (struct file *, char __user *,
-+                            size_t, loff_t *))switch_proc_read,
-+      .write = (ssize_t (*) (struct file *, const char __user *,
-+                             size_t, loff_t *))switch_proc_write,
-+};
-+
-+/*
-+ * switch_add_handler
-+ */
-+static int switch_add_handler(struct switch_device *switch_dev,
-+                            struct proc_dir_entry *parent,
-+                            const struct switch_handler *handler,
-+                            int inst)
-+{
-+      struct switch_handler_entry *she;
-+      struct proc_dir_entry *pde;
-+      int mode;
-+
-+      she = (struct switch_handler_entry *)
-+              kzalloc(sizeof(struct switch_handler_entry), GFP_KERNEL);
-+      if (!she) {
-+              return -ENOMEM;
-+      }
-+
-+      INIT_LIST_HEAD(&she->node);
-+      she->parent = parent;
-+      she->dev = switch_dev;
-+      she->inst = inst;
-+      she->handler = handler;
-+      list_add(&she->node, &switch_dev->handlers);
-+
-+      mode = 0;
-+      if (handler->read != NULL) {
-+              mode |= S_IRUSR;
-+      }
-+      if (handler->write != NULL) {
-+              mode |= S_IWUSR;
-+      }
-+
-+      pde = create_proc_entry(handler->name, mode, parent);
-+      if (!pde) {
-+              kfree(she);
-+              printk("Failed to create node '%s' in parent %p\n",
-+                     handler->name, parent);
-+              return -ENOMEM;
-+      }
-+      pde->data = (void *)she;
-+      pde->proc_fops = &switch_proc_fops;
-+
-+      return 0;
-+}
-+
-+/*
-+ * switch_add_handlers
-+ */
-+static int switch_add_handlers(struct switch_device *switch_dev,
-+                             struct proc_dir_entry *parent,
-+                             const struct switch_handler *handlers,
-+                             int inst)
-+{
-+      while (handlers->name) {
-+              int ret = switch_add_handler(switch_dev,
-+                                           parent, handlers, inst);
-+              if (ret) {
-+                      return ret;
-+              }
-+              handlers++;
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * switch_remove_vlan_dirs
-+ *    Removes all vlan directories
-+ *
-+ * Assumes all vlan directories are empty, should be called after
-+ * switch_remove_handlers
-+ */
-+static void switch_remove_vlan_dirs(struct switch_device *switch_dev)
-+{
-+      struct list_head *pos;
-+      struct list_head *tmp;
-+      struct switch_vlan_entry *sve;
-+
-+      list_for_each_safe(pos, tmp, &switch_dev->vlan_dirs) {
-+              sve = list_entry(pos, struct switch_vlan_entry, node);
-+              list_del(pos);
-+              remove_proc_entry(sve->pde->name, switch_dev->vlan_dir);
-+              kfree(sve);
-+      }
-+}
-+
-+/*
-+ * switch_remove_handlers
-+ *    Removes all handlers registered to the given switch_device
-+ */
-+static void switch_remove_handlers(struct switch_device *switch_dev)
-+{
-+      struct list_head *pos;
-+      struct list_head *tmp;
-+      struct switch_handler_entry *she;
-+
-+      list_for_each_safe(pos, tmp, &switch_dev->handlers) {
-+              she = list_entry(pos, struct switch_handler_entry, node);
-+              list_del(pos);
-+              remove_proc_entry(she->handler->name, she->parent);
-+              kfree(she);
-+      }
-+}
-+
-+/*
-+ * switch_unregister_proc_nodes
-+ *    Unregisters all proc nodes related to switch_dev
-+ */
-+void switch_unregister_proc_nodes(struct switch_device *switch_dev)
-+{
-+      switch_remove_handlers(switch_dev);
-+
-+      if (switch_dev->port_dirs) {
-+              int i;
-+
-+              for (i = 0; i < switch_dev->ports; i++) {
-+                      if (switch_dev->port_dirs[i]) {
-+                              remove_proc_entry(
-+                                      switch_dev->port_dirs[i]->name,
-+                                      switch_dev->port_dir);
-+                      }
-+              }
-+      }
-+
-+      if (switch_dev->port_dir) {
-+              remove_proc_entry("port", switch_dev->driver_dir);
-+              switch_dev->port_dir = NULL;
-+      }
-+
-+      if (switch_dev->reg_dir) {
-+              remove_proc_entry("reg", switch_dev->reg_dir);
-+              switch_dev->reg_dir = NULL;
-+      }
-+
-+      if (switch_dev->vlan_dir) {
-+              switch_remove_vlan_dirs(switch_dev);
-+              remove_proc_entry("vlan", switch_dev->driver_dir);
-+              switch_dev->vlan_dir = NULL;
-+      }
-+
-+      if (switch_dev->driver_dir) {
-+              remove_proc_entry(switch_dev->name, switch_root);
-+              switch_dev->driver_dir = NULL;
-+      }
-+}
-+
-+/*
-+ * switch_remove_vlan_dir
-+ *    Removes vlan dir in switch/<switch_driver>/vlan/<vlan_id>
-+ */
-+int switch_remove_vlan_dir(struct switch_device *switch_dev, int vlan_id)
-+{
-+      struct list_head *pos;
-+      struct switch_vlan_entry *sve = NULL;
-+
-+      list_for_each(pos, &switch_dev->vlan_dirs) {
-+              struct switch_vlan_entry *tmp =
-+                      list_entry(pos, struct switch_vlan_entry, node);
-+              if (tmp->vlan_id == vlan_id) {
-+                      sve = tmp;
-+                      break;
-+              }
-+      }
-+
-+      if (!sve) {
-+              return -ENOENT;
-+      }
-+
-+      /*
-+       * Remove it from the list
-+       */
-+      list_del(pos);
-+
-+      /*
-+       * Remove the handlers
-+       */
-+      while (sve->handlers->name) {
-+              remove_proc_entry(sve->handlers->name, sve->pde);
-+              sve->handlers++;
-+      }
-+
-+      /*
-+       * Remove the proc entry for the <vlan_id> dir
-+       */
-+      remove_proc_entry(sve->pde->name, switch_dev->vlan_dir);
-+
-+      kfree(sve);
-+
-+      return 0;
-+}
-+
-+/*
-+ * switch_create_vlan_dir
-+ *    Creates vlan dir in switch/<switch_driver>/vlan/<vlan_id>
-+ */
-+int switch_create_vlan_dir(struct switch_device *switch_dev,
-+                         int vlan_id, const struct switch_handler *handlers)
-+{
-+      char s[14];
-+      struct proc_dir_entry *pde = NULL;
-+      struct switch_vlan_entry *sve = NULL;
-+      int ret;
-+      struct list_head *pos;
-+
-+      /*
-+       * Check to see if it exists already
-+       */
-+      list_for_each(pos, &switch_dev->vlan_dirs) {
-+              sve = list_entry(pos, struct switch_vlan_entry, node);
-+              if (sve->vlan_id == vlan_id) {
-+                      return -EEXIST;
-+              }
-+      }
-+      sve = NULL;
-+
-+      /*
-+       * Create the vlan directory if we didn't have it before
-+       */
-+      if (!switch_dev->vlan_dir) {
-+              switch_dev->vlan_dir = proc_mkdir("vlan",
-+                                                switch_dev->driver_dir);
-+              if (!switch_dev->vlan_dir) {
-+                      goto fail;
-+              }
-+              if (switch_dev->vlan_handlers) {
-+                      ret = switch_add_handlers(switch_dev,
-+                                                switch_dev->vlan_dir,
-+                                                switch_dev->vlan_handlers, 0);
-+                      if (ret) {
-+                              goto fail;
-+                      }
-+              }
-+      }
-+
-+      /*
-+       * Create the vlan_id directory
-+       */
-+      snprintf(s, 14, "%d", vlan_id);
-+      pde = proc_mkdir(s, switch_dev->vlan_dir);
-+      if (!pde) {
-+              goto fail;
-+      }
-+
-+      /*
-+       * Create the handlers for this vlan
-+       */
-+      if (handlers) {
-+              ret = switch_add_handlers(switch_dev, pde, handlers, vlan_id);
-+              if (ret) {
-+                      goto fail;
-+              }
-+      }
-+
-+      /*
-+       * Keep track of all the switch vlan entries created
-+       */
-+      sve = (struct switch_vlan_entry *)
-+              kzalloc(sizeof(struct switch_vlan_entry), GFP_KERNEL);
-+      if (!sve) {
-+              goto fail;
-+      }
-+      INIT_LIST_HEAD(&sve->node);
-+      sve->handlers = handlers;
-+      sve->vlan_id = vlan_id;
-+      sve->pde = pde;
-+      list_add(&sve->node, &switch_dev->vlan_dirs);
-+
-+      return 0;
-+
-+fail:
-+      if (sve) {
-+              kfree(sve);
-+      }
-+
-+      if (pde) {
-+              /*
-+               * Remove any proc entries we might have created
-+               */
-+              while (handlers->name) {
-+                      remove_proc_entry(handlers->name, pde);
-+                      handlers++;
-+              }
-+
-+              remove_proc_entry(s, switch_dev->driver_dir);
-+      }
-+
-+      return -ENOMEM;
-+}
-+
-+/*
-+ * switch_register_proc_nodes
-+ */
-+int switch_register_proc_nodes(struct switch_device *switch_dev)
-+{
-+      int i;
-+      int n;
-+
-+      switch_dev->port_dirs = kzalloc(switch_dev->ports *
-+                                      sizeof(struct proc_dir_entry *),
-+                                      GFP_KERNEL);
-+      if (!switch_dev->port_dirs) {
-+              return -ENOMEM;
-+      }
-+
-+      /*
-+       * Create a new proc entry for this switch
-+       */
-+      switch_dev->driver_dir = proc_mkdir(switch_dev->name, switch_root);
-+      if (!switch_dev->driver_dir) {
-+              goto fail;
-+      }
-+      if (switch_dev->driver_handlers) {
-+              switch_add_handlers(switch_dev,
-+                                  switch_dev->driver_dir,
-+                                  switch_dev->driver_handlers,
-+                                  0);
-+      }
-+
-+      /*
-+       * Create the ports
-+       */
-+      switch_dev->port_dir = proc_mkdir("port", switch_dev->driver_dir);
-+      if (!switch_dev->port_dir) {
-+              goto fail;
-+      }
-+      for (n = 0, i = 0; i < (SWITCH_PORT_MASK_SIZE * 32); i++) {
-+              if (switch_dev->port_mask[i / 32] & (1 << i % 32)) {
-+                      char s[14];
-+
-+                      snprintf(s, 14, "%d", i);
-+                      switch_dev->port_dirs[n] =
-+                              proc_mkdir(s, switch_dev->port_dir);
-+                      if (!switch_dev->port_dirs[n]) {
-+                              goto fail;
-+                      }
-+                      if (switch_dev->port_handlers) {
-+                              switch_add_handlers(switch_dev,
-+                                                  switch_dev->port_dirs[n],
-+                                                  switch_dev->port_handlers,
-+                                                  i);
-+                      }
-+                      n++;
-+              }
-+      }
-+
-+      /*
-+       * Create the register directory for switch register access.
-+       */
-+      if (switch_dev->reg_handlers) {
-+              switch_dev->reg_dir = proc_mkdir("reg", switch_dev->driver_dir);
-+              if (!switch_dev->reg_dir) {
-+                      goto fail;
-+              }
-+
-+              switch_add_handlers(switch_dev,
-+                                  switch_dev->reg_dir,
-+                                  switch_dev->reg_handlers,
-+                                  0);
-+      }
-+
-+      /*
-+       * Create the vlan directory
-+       */
-+      if (switch_dev->vlan_handlers) {
-+              switch_dev->vlan_dir = proc_mkdir("vlan",
-+                                                switch_dev->driver_dir);
-+              if (!switch_dev->vlan_dir) {
-+                      goto fail;
-+              }
-+              if (switch_dev->vlan_handlers) {
-+                      switch_add_handlers(switch_dev,
-+                                          switch_dev->vlan_dir,
-+                                          switch_dev->vlan_handlers,
-+                                          0);
-+              }
-+      }
-+
-+      return 0;
-+
-+fail:
-+      switch_unregister_proc_nodes(switch_dev);
-+      return -ENOMEM;
-+}
-+
-+/*
-+ * switch_release
-+ */
-+void switch_release(struct switch_device *switch_dev)
-+{
-+      kfree(switch_dev);
-+}
-+
-+/*
-+ * switch_alloc
-+ */
-+struct switch_device *switch_alloc(void)
-+{
-+      struct switch_device *switch_dev =
-+              kzalloc(sizeof(struct switch_device),
-+                                              GFP_KERNEL);
-+      INIT_LIST_HEAD(&switch_dev->node);
-+      INIT_LIST_HEAD(&switch_dev->vlan_dirs);
-+      INIT_LIST_HEAD(&switch_dev->handlers);
-+      return switch_dev;
-+}
-+
-+/*
-+ * switch_register
-+ */
-+int switch_register(struct switch_device *switch_dev)
-+{
-+      int ret;
-+      int i;
-+
-+      /*
-+       * Make sure that the number of ports and the port mask make sense
-+       */
-+      for (ret = 0, i = 0; i < (SWITCH_PORT_MASK_SIZE * 32); i++) {
-+              if (switch_dev->port_mask[i / 32] & (1 << i % 32)) {
-+                      ret++;
-+              }
-+      }
-+      if (ret > switch_dev->ports) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Create the /proc entries
-+       */
-+      ret = switch_register_proc_nodes(switch_dev);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      /*
-+       * Add it to the list of switches
-+       */
-+      down_write(&switch_list_lock);
-+      list_add_tail(&switch_dev->node, &switch_list);
-+      up_write(&switch_list_lock);
-+
-+      printk(KERN_INFO "Registered switch device: %s\n", switch_dev->name);
-+
-+      return 0;
-+}
-+EXPORT_SYMBOL_GPL(switch_register);
-+
-+/*
-+ * switch_unregister
-+ *    Unregisters a previously registered switch_device object
-+ */
-+void switch_unregister(struct switch_device *switch_dev)
-+{
-+      /*
-+       * remove the proc entries
-+       */
-+      switch_unregister_proc_nodes(switch_dev);
-+
-+      /*
-+       * Remove it from the list of switches
-+       */
-+      down_write(&switch_list_lock);
-+      list_del(&switch_dev->node);
-+      up_write(&switch_list_lock);
-+
-+      printk(KERN_INFO "Unregistered switch device: %s\n", switch_dev->name);
-+}
-+EXPORT_SYMBOL_GPL(switch_unregister);
-+
-+/*
-+ * switch_init
-+ */
-+static int __init switch_init(void)
-+{
-+      switch_root = proc_mkdir("switch", NULL);
-+      if (!switch_root) {
-+              printk(KERN_WARNING "Failed to make root switch node\n");
-+              return -ENODEV;
-+      }
-+      return 0;
-+}
-+module_init(switch_init);
-+
-+/*
-+ * switch_exit
-+ */
-+static void __exit switch_exit(void)
-+{
-+      remove_proc_entry("switch", NULL);
-+}
-+module_exit(switch_exit);
-+
-+MODULE_AUTHOR("Patrick Tjin");
-+MODULE_LICENSE("GPL");
-+MODULE_DESCRIPTION("Ethernet Switch Class Interface");
---- /dev/null
-+++ b/arch/ubicom32/mach-common/switch-core.h
-@@ -0,0 +1,92 @@
-+/*
-+ * arch/ubicom32/mach-common/switch-core.h
-+ *   Private data for the switch module
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _SWITCH_CORE_H_
-+#define _SWITCH_CORE_H_
-+
-+struct switch_handler_entry;
-+struct switch_vlan_entry;
-+
-+#define SWITCH_PORT_MASK_SIZE 2
-+
-+struct switch_device {
-+      struct list_head                node;
-+
-+      const char                      *name;
-+      void                            *drvdata;
-+
-+      u8_t                            ports;
-+
-+      struct proc_dir_entry           *driver_dir;
-+      const struct switch_handler     *driver_handlers;
-+
-+      struct proc_dir_entry           *port_dir;
-+      struct proc_dir_entry           **port_dirs;
-+      const struct switch_handler     *port_handlers;
-+
-+      struct proc_dir_entry           *reg_dir;
-+      const struct switch_handler     *reg_handlers;
-+
-+      struct proc_dir_entry           *vlan_dir;
-+      const struct switch_handler     *vlan_handlers;
-+      struct list_head                vlan_dirs;
-+
-+      struct list_head                handlers;
-+
-+      u32_t                           port_mask[SWITCH_PORT_MASK_SIZE];
-+};
-+
-+typedef int (*switch_handler_fn)(struct switch_device *, char *buf, int nr);
-+struct switch_handler {
-+      const char              *name;
-+
-+      switch_handler_fn       read;
-+      switch_handler_fn       write;
-+};
-+
-+#define SWITCH_MAX_BUFSZ      4096
-+
-+static inline void switch_set_drvdata(struct switch_device *switch_dev, void *drvdata)
-+{
-+      switch_dev->drvdata = drvdata;
-+}
-+
-+static inline void *switch_get_drvdata(struct switch_device *switch_dev)
-+{
-+      return switch_dev->drvdata;
-+}
-+
-+extern int switch_create_vlan_dir(struct switch_device *switch_dev, int vlan_id, const struct switch_handler *handlers);
-+extern int switch_remove_vlan_dir(struct switch_device *switch_dev, int vlan_id);
-+extern void switch_parse_vlan_ports(struct switch_device *switch_dev, char *buf, u32_t *untag, u32_t *ports, u32_t *def);
-+
-+extern void switch_release(struct switch_device *switch_dev);
-+extern struct switch_device *switch_alloc(void);
-+extern int switch_register(struct switch_device *switch_dev);
-+extern void switch_unregister(struct switch_device *switch_dev);
-+
-+#endif
---- /dev/null
-+++ b/arch/ubicom32/mach-common/ubi32-gpio.c
-@@ -0,0 +1,411 @@
-+/*
-+ * arch/ubicom32/mach-common/ubi32-gpio.c
-+ *   Ubicom gpio driver
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/kernel.h>
-+#include <linux/io.h>
-+#include <linux/gpio.h>
-+#include <linux/irq.h>
-+#include <linux/version.h>
-+
-+#if defined(CONFIG_PROC_FS)
-+#include <linux/proc_fs.h>
-+#endif
-+
-+#include <linux/io.h>
-+#include <asm/ip5000.h>
-+#include <linux/gpio.h>
-+
-+#define UBI_GPIO_CHECK_RANGE     0  /* !0 enables range checking */
-+
-+
-+/*
-+ * Each I/O port can be configured to operate in one of several
-+ * functional modes. One of these modes is GPIO, which causes the
-+ * entire port to function as a GPIO port.  Since the various port
-+ * registers serve the system with other important functions, such as
-+ * ethernet, serial, USB, etc., it isn't advantageous to set any of
-+ * the ports to be entirely dedicated for GPIO use.  The processor
-+ * alternatively allows individual bits of a port to be assigned to be
-+ * used as GPIO independently from the overall port function.  This
-+ * bit-by-bit assignment is selected by setting the corresponding bit
-+ * in the port's gpio_mask register.  When set, the selected bit is
-+ * then enabled as a GPIO.  If the corresponding bit is set in the
-+ * gpio_ctl register of the port, the bit is configured as a GPIO
-+ * output.  Otherwise, it is an input.
-+ *
-+ * NOTE: This driver uses the bit-by-bit GPIO function assignment
-+ * exclusively and *never* sets the port function registers to the
-+ * GPIO function.
-+ *
-+ * GPIO is not the main function of any of the I/O ports.  The port
-+ * bit widths are variable from one port to the next, determined by
-+ * the more common I/O functions of the ports.  For simplicity, this
-+ * driver assumes all the ports are 32 bits wide regardless of the
-+ * real bit width of the port.  GPIO bits are numbered from zero to
-+ * MAX_UBICOM_GPIOS.  Within a port, the least significant bit is
-+ * numbered bit zero, the most significant is bit 31.  Since the ports
-+ * are considered logically contiguous, GPIO #32 is the zeroth bit in
-+ * port #1, and so on.  Due to the hardware definition, there are
-+ * large gaps in the GPIO numbers representing real pins.
-+ *
-+ * NOTE: It is up to the programmer to refer to the processor data
-+ * sheet to determine which bits in which ports can be accessed and
-+ * used for GPIO.
-+ *
-+ */
-+
-+
-+/* There are 9 ports, A through I. Not all 32 bits in each
-+ * port can be a GPIO, but we pretend they are.  Its up to the
-+ * programmer to refer to the processor data sheet.
-+ */
-+#define MAX_UBICOM_GPIOS   (9 * 32) /* ARCH_NR_GPIOS */
-+#define NUM_GPIO_PORTS     (gpio_bank(MAX_UBICOM_GPIOS))
-+
-+
-+/* GPIO reservation bit map array */
-+static int reserved_gpio_map[NUM_GPIO_PORTS];
-+
-+
-+/* Array of hardware io_port addresses */
-+static struct ubicom32_io_port *gpio_bank_addr[NUM_GPIO_PORTS] =
-+{
-+      UBICOM32_IO_PORT(RA),
-+      UBICOM32_IO_PORT(RB),
-+      UBICOM32_IO_PORT(RC),
-+      UBICOM32_IO_PORT(RD),
-+      UBICOM32_IO_PORT(RE),
-+      UBICOM32_IO_PORT(RF),
-+      UBICOM32_IO_PORT(RG),
-+      UBICOM32_IO_PORT(RH),
-+      UBICOM32_IO_PORT(RI)
-+};
-+
-+
-+struct ubi_gpio_chip {
-+      /*
-+       * Right now, nothing else lives here.
-+       */
-+      struct gpio_chip gpio_chip;
-+};
-+
-+
-+#if UBI_GPIO_CHECK_RANGE
-+inline int check_gpio(unsigned gpio)
-+{
-+      if (gpio >= MAX_UBICOM_GPIOS)
-+              return -EINVAL;
-+      return 0;
-+}
-+#else
-+#define check_gpio(n)   (0)
-+#endif
-+
-+/*
-+ * ubi_gpio_get_port
-+ *    Get the IO port associated with a certain gpio
-+ */
-+struct ubicom32_io_port *ubi_gpio_get_port(unsigned gpio)
-+{
-+      if (gpio_bank(gpio) > NUM_GPIO_PORTS) {
-+              return NULL;
-+      }
-+      return gpio_bank_addr[gpio_bank(gpio)];
-+}
-+
-+/*
-+ * ubi_gpio_error()
-+ */
-+static void ubi_gpio_error(unsigned gpio)
-+{
-+      printk(KERN_ERR "ubicom-gpio: GPIO %d wasn't requested!\n", gpio);
-+}
-+
-+/*
-+ * ubi_port_setup()
-+ */
-+static void ubi_port_setup(unsigned gpio, unsigned short usage)
-+{
-+      if (!check_gpio(gpio)) {
-+              if (usage) {
-+                      UBICOM32_GPIO_ENABLE(gpio);
-+              } else {
-+                      UBICOM32_GPIO_DISABLE(gpio);
-+              }
-+      }
-+}
-+
-+/*
-+ * ubi_gpio_request()
-+ */
-+static int ubi_gpio_request(struct gpio_chip *chip, unsigned gpio)
-+{
-+      unsigned long flags;
-+
-+      if (check_gpio(gpio) < 0)
-+              return -EINVAL;
-+
-+      local_irq_save(flags);
-+
-+      if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
-+              printk(KERN_ERR "ubi-gpio: GPIO %d is already reserved!\n",
-+                     gpio);
-+              local_irq_restore(flags);
-+              return -EBUSY;
-+      }
-+
-+      reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio);
-+
-+      ubi_port_setup(gpio, 1);
-+
-+      local_irq_restore(flags);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubi_gpio_free()
-+ */
-+static void ubi_gpio_free(struct gpio_chip *chip, unsigned gpio)
-+{
-+      unsigned long flags;
-+
-+      if (check_gpio(gpio) < 0)
-+              return;
-+
-+      local_irq_save(flags);
-+
-+      if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
-+              ubi_gpio_error(gpio);
-+              local_irq_restore(flags);
-+              return;
-+      }
-+
-+      /* Assert the pin is no longer claimed */
-+      reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
-+
-+      /* Revert port bit to use specified by port->function */
-+      ubi_port_setup(gpio, 0);
-+
-+      local_irq_restore(flags);
-+}
-+
-+/*
-+ * ubi_gpio_direction_input()
-+ */
-+static int ubi_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
-+{
-+      unsigned long flags;
-+
-+      if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
-+              ubi_gpio_error(gpio);
-+              return -EINVAL;
-+      }
-+
-+      local_irq_save(flags);
-+
-+      /* Configure pin as gpio */
-+      ubi_port_setup(gpio, 1);
-+
-+      /* Assert pin is an input */
-+      UBICOM32_GPIO_SET_PIN_INPUT(gpio);
-+
-+      local_irq_restore(flags);
-+
-+      return 0;
-+}
-+
-+
-+/*
-+ * ubi_gpio_direction_output()
-+ */
-+static int ubi_gpio_direction_output(struct gpio_chip *chip,
-+                                   unsigned gpio, int value)
-+{
-+      unsigned long flags;
-+
-+      if (!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
-+              ubi_gpio_error(gpio);
-+              return -EINVAL;
-+      }
-+
-+      local_irq_save(flags);
-+
-+      /* Configure pin as gpio and set initial value in gpio_out register
-+       * so that when we enable it as an output, it will have the correct
-+       * initial value.
-+       */
-+      ubi_port_setup(gpio, 1);
-+      if (value) {
-+              UBICOM32_GPIO_SET_PIN_HIGH(gpio);
-+      } else {
-+              UBICOM32_GPIO_SET_PIN_LOW(gpio);
-+      }
-+
-+      /* Enable the pin as an output */
-+      UBICOM32_GPIO_SET_PIN_OUTPUT(gpio);
-+
-+      local_irq_restore(flags);
-+
-+      return 0;
-+}
-+
-+
-+/*
-+ * ubi_gpio_get_value()
-+ */
-+static int ubi_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
-+{
-+      return 0 != (gpio_bank_addr[gpio_bank(gpio)]->gpio_in & gpio_bit(gpio));
-+}
-+
-+
-+/*
-+ * ubi_gpio_set_value()
-+ */
-+static void ubi_gpio_set_value(struct gpio_chip *chip, unsigned gpio,
-+                             int arg)
-+{
-+      unsigned long flags;
-+      local_irq_save(flags);
-+
-+      if (arg) {
-+              UBICOM32_GPIO_SET_PIN_HIGH(gpio);
-+      } else {
-+              UBICOM32_GPIO_SET_PIN_LOW(gpio);
-+      }
-+
-+      local_irq_restore(flags);
-+}
-+
-+
-+/*
-+ * ubi_gpio_to_irq()
-+ */
-+static int ubi_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
-+{
-+      return gpio_to_irq(gpio);
-+}
-+
-+
-+/*
-+ * ubi_gpio_init()
-+ */
-+int __init ubi_gpio_init(void)
-+{
-+      int k;
-+      int status;
-+      struct ubi_gpio_chip *chip;
-+      struct gpio_chip *gc;
-+
-+      printk(KERN_INFO "Ubicom GPIO Controller\n");
-+
-+      chip = kzalloc(sizeof(struct ubi_gpio_chip), GFP_KERNEL);
-+      if (chip == NULL)
-+              return -ENOMEM;
-+
-+      gc = &chip->gpio_chip;
-+      gc->request          = ubi_gpio_request;
-+      gc->free             = ubi_gpio_free;
-+      gc->to_irq           = ubi_gpio_to_irq;
-+      gc->direction_input  = ubi_gpio_direction_input;
-+      gc->direction_output = ubi_gpio_direction_output;
-+      gc->get              = ubi_gpio_get_value;
-+      gc->set              = ubi_gpio_set_value;
-+      gc->can_sleep        = 0;
-+      gc->base             = 0;
-+      gc->ngpio            = MAX_UBICOM_GPIOS; /* ARCH_NR_GPIOS - 1 */
-+      gc->label            = "ubi_gpio";
-+
-+      status = gpiochip_add(gc);
-+      if (status != 0) {
-+              kfree(chip);
-+              return status;
-+      }
-+
-+      /* Assert all pins are free */
-+      for (k = 0; k < NUM_GPIO_PORTS; k++) {
-+              reserved_gpio_map[k] = 0;
-+      }
-+
-+      return 0;
-+}
-+
-+#if defined(CONFIG_PROC_FS)
-+/*
-+ * ubi_get_gpio_dir()
-+ */
-+static int ubi_get_gpio_dir(unsigned gpio)
-+{
-+      if (gpio_bank_addr[gpio_bank(gpio)]->gpio_ctl & gpio_bit(gpio))
-+              return 1;
-+      else
-+              return 0;
-+}
-+
-+/*
-+ * gpio_proc_read()
-+ */
-+static int ubi_gpio_proc_read(char *buf, char **start, off_t offset,
-+                        int len, int *unused_i, void *unused_v)
-+{
-+      int c, outlen = 0;
-+
-+      for (c = 0; c < MAX_UBICOM_GPIOS; c++) {
-+              if (!check_gpio(c) &&
-+                  (reserved_gpio_map[gpio_bank(c)] & gpio_bit(c))) {
-+                      len = sprintf(buf, "GPIO_%d:\t\tGPIO %s\n", c,
-+                                    ubi_get_gpio_dir(c) ? "OUTPUT" : "INPUT");
-+              } else {
-+                      continue;
-+              }
-+
-+              buf += len;
-+              outlen += len;
-+      }
-+      return outlen;
-+}
-+
-+/*
-+ * ubi_gpio_register_proc()
-+ */
-+static __init int ubi_gpio_register_proc(void)
-+{
-+      struct proc_dir_entry *proc_gpio;
-+
-+      proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL);
-+      if (proc_gpio)
-+              proc_gpio->read_proc = ubi_gpio_proc_read;
-+
-+      return proc_gpio != NULL;
-+}
-+device_initcall(ubi_gpio_register_proc);
-+#endif
---- /dev/null
-+++ b/arch/ubicom32/mach-common/ubicom32hid.c
-@@ -0,0 +1,557 @@
-+/*
-+ * arch/ubicom32/mach-common/ubicom32hid.c
-+ *   I2C driver for HID coprocessor found on some DPF implementations.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/gpio.h>
-+#include <linux/delay.h>
-+#include <linux/platform_device.h>
-+#include <linux/i2c.h>
-+#include <linux/backlight.h>
-+#include <linux/fb.h>
-+#include <linux/input.h>
-+#include <linux/input-polldev.h>
-+
-+#include <asm/ubicom32hid.h>
-+
-+#define DRIVER_NAME "ubicom32hid"
-+
-+#ifdef DEBUG
-+static int ubicom32hid_debug;
-+#endif
-+
-+static const struct i2c_device_id ubicom32hid_id[] = {
-+      { DRIVER_NAME, },
-+      { }
-+};
-+MODULE_DEVICE_TABLE(i2c, ubicom32hid_id);
-+
-+/*
-+ * Define this to make IR checking strict, in general, it's not needed
-+ */
-+#undef UBICOM32HID_STRICT_IR_CHECK
-+
-+#define UBICOM32HID_CMD_SET_PWM               0x01
-+#define UBICOM32HID_CMD_SET_BL_EN     0x02
-+#define UBICOM32HID_BL_EN_LOW         0x00
-+#define UBICOM32HID_BL_EN_HIZ         0x01
-+#define UBICOM32HID_BL_EN_HI          0x02
-+#define UBICOM32HID_CMD_FLUSH         0x99
-+#define UBICOM32HID_CMD_RESET         0x99
-+#define UBICOM32HID_CMD_GET_IR_SWITCH 0xC0
-+#define UBICOM32HID_CMD_GET_REVISION  0xfd
-+#define UBICOM32HID_CMD_GET_DEVICE_ID 0xfe
-+#define UBICOM32HID_CMD_GET_VERSION   0xff
-+#define UBICOM32HID_DEVICE_ID         0x49
-+
-+#define UBICOM32HID_MAX_BRIGHTNESS_PWM        255
-+
-+/*
-+ * Data structure returned by the HID device
-+ */
-+struct ubicom32hid_input_data {
-+      uint32_t        ircmd;
-+      uint8_t         sw_state;
-+      uint8_t         sw_changed;
-+};
-+
-+/*
-+ * Our private data
-+ */
-+struct ubicom32hid_data {
-+      /*
-+       * Pointer to the platform data structure, we need the settings.
-+       */
-+      const struct ubicom32hid_platform_data  *pdata;
-+
-+      /*
-+       * Backlight device
-+       */
-+      struct backlight_device                 *bldev;
-+
-+      /*
-+       * I2C client, for sending messages to the HID device
-+       */
-+      struct i2c_client                       *client;
-+
-+      /*
-+       * Current intensity, used for get_intensity.
-+       */
-+      int                                     cur_intensity;
-+
-+      /*
-+       * Input subsystem
-+       *      We won't register an input subsystem if there are no mappings.
-+       */
-+      struct input_polled_dev                 *poll_dev;
-+};
-+
-+
-+/*
-+ * ubicom32hid_set_intensity
-+ */
-+static int ubicom32hid_set_intensity(struct backlight_device *bd)
-+{
-+      struct ubicom32hid_data *ud =
-+              (struct ubicom32hid_data *)bl_get_data(bd);
-+      int intensity = bd->props.brightness;
-+      int reg;
-+      u8_t val;
-+      int ret;
-+
-+      /*
-+       * If we're blanked the the intensity doesn't matter.
-+       */
-+      if ((bd->props.power != FB_BLANK_UNBLANK) ||
-+          (bd->props.fb_blank != FB_BLANK_UNBLANK)) {
-+              intensity = 0;
-+      }
-+
-+      /*
-+       * Set the brightness based on the type of backlight
-+       */
-+      if (ud->pdata->type == UBICOM32HID_BL_TYPE_BINARY) {
-+              reg = UBICOM32HID_CMD_SET_BL_EN;
-+              if (intensity) {
-+                      val = ud->pdata->invert
-+                              ? UBICOM32HID_BL_EN_LOW : UBICOM32HID_BL_EN_HI;
-+              } else {
-+                      val = ud->pdata->invert
-+                              ? UBICOM32HID_BL_EN_HI : UBICOM32HID_BL_EN_LOW;
-+              }
-+      } else {
-+              reg = UBICOM32HID_CMD_SET_PWM;
-+              val = ud->pdata->invert
-+                      ? (UBICOM32HID_MAX_BRIGHTNESS_PWM - intensity) :
-+                      intensity;
-+      }
-+
-+      /*
-+       * Send the command
-+       */
-+      ret = i2c_smbus_write_byte_data(ud->client, reg, val);
-+      if (ret < 0) {
-+              dev_warn(&ud->client->dev, "Unable to write backlight err=%d\n",
-+                       ret);
-+              return ret;
-+      }
-+
-+      ud->cur_intensity = intensity;
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32hid_get_intensity
-+ *    Return the current intensity of the backlight.
-+ */
-+static int ubicom32hid_get_intensity(struct backlight_device *bd)
-+{
-+      struct ubicom32hid_data *ud =
-+              (struct ubicom32hid_data *)bl_get_data(bd);
-+
-+      return ud->cur_intensity;
-+}
-+
-+/*
-+ * ubicom32hid_verify_data
-+ *    Verify the data to see if there is any action to be taken
-+ *
-+ * Returns 0 if no action is to be taken, non-zero otherwise
-+ */
-+static int ubicom32hid_verify_data(struct ubicom32hid_data *ud,
-+                                 struct ubicom32hid_input_data *data)
-+{
-+      uint8_t *ircmd = (uint8_t *)&(data->ircmd);
-+
-+      /*
-+       * ircmd == DEADBEEF means ir queue is empty.  Since this is a
-+       * meaningful code, that means the rest of the message is most likely
-+       * correct, so only process the data if the switch state has changed.
-+       */
-+      if (data->ircmd == 0xDEADBEEF) {
-+              return data->sw_changed != 0;
-+      }
-+
-+      /*
-+       * We have an ircmd which is not empty:
-+       *      Data[1] should be the complement of Data[0]
-+       */
-+      if (ircmd[0] != (u8_t)~ircmd[1]) {
-+              return 0;
-+      }
-+
-+#ifdef UBICOM32HID_STRICT_IR_CHECK
-+      /*
-+       * It seems that some remote controls don't follow the NEC protocol
-+       * properly, so only do this check if the remote does indeed follow the
-+       * spec.  Data[3] should be the complement of Data[2]
-+       */
-+      if (ircmd[2] == (u8_t)~ircmd[3]) {
-+              return 1;
-+      }
-+
-+      /*
-+       * For non-compliant remotes, check the system code according to what
-+       * they send.
-+       */
-+      if ((ircmd[2] != UBICOM32HID_IR_SYSTEM_CODE_CHECK) ||
-+          (ircmd[3] != UBICOM32HID_IR_SYSTEM_CODE)) {
-+              return 0;
-+      }
-+#endif
-+
-+      /*
-+       * Data checks out, process
-+       */
-+      return 1;
-+}
-+
-+/*
-+ * ubicom32hid_poll_input
-+ *    Poll the input from the HID device.
-+ */
-+static void ubicom32hid_poll_input(struct input_polled_dev *dev)
-+{
-+      struct ubicom32hid_data *ud = (struct ubicom32hid_data *)dev->private;
-+      const struct ubicom32hid_platform_data *pdata = ud->pdata;
-+      struct ubicom32hid_input_data data;
-+      struct input_dev *id = dev->input;
-+      int i;
-+      int sync_needed = 0;
-+      uint8_t cmd;
-+      int ret;
-+
-+      /*
-+       * Flush the queue
-+       */
-+      cmd = UBICOM32HID_CMD_FLUSH;
-+      ret = i2c_master_send(ud->client, &cmd, 1);
-+      if (ret < 0) {
-+              return;
-+      }
-+
-+      ret = i2c_smbus_read_i2c_block_data(
-+              ud->client, UBICOM32HID_CMD_GET_IR_SWITCH, 6, (void *)&data);
-+      if (ret < 0) {
-+              return;
-+      }
-+
-+      /*
-+       * Verify the data to see if there is any action to be taken
-+       */
-+      if (!ubicom32hid_verify_data(ud, &data)) {
-+              return;
-+      }
-+
-+#ifdef DEBUG
-+      if (ubicom32hid_debug) {
-+              printk("Polled ircmd=%8x swstate=%2x swchanged=%2x\n",
-+                     data.ircmd, data.sw_state, data.sw_changed);
-+      }
-+#endif
-+
-+      /*
-+       * Process changed switches
-+       */
-+      if (data.sw_changed) {
-+              const struct ubicom32hid_button *ub = pdata->buttons;
-+              for (i = 0; i < pdata->nbuttons; i++, ub++) {
-+                      uint8_t mask = (1 << ub->bit);
-+                      if (!(data.sw_changed & mask)) {
-+                              continue;
-+                      }
-+
-+                      sync_needed = 1;
-+                      input_event(id, ub->type, ub->code,
-+                                  (data.sw_state & mask) ? 1 : 0);
-+              }
-+      }
-+      if (sync_needed) {
-+              input_sync(id);
-+      }
-+
-+      /*
-+       * Process ir codes
-+       */
-+      if (data.ircmd != 0xDEADBEEF) {
-+              const struct ubicom32hid_ir *ui = pdata->ircodes;
-+              for (i = 0; i < pdata->nircodes; i++, ui++) {
-+                      if (ui->ir_code == data.ircmd) {
-+                              /*
-+                               * Simulate a up/down event
-+                               */
-+                              input_event(id, ui->type, ui->code, 1);
-+                              input_sync(id);
-+                              input_event(id, ui->type, ui->code, 0);
-+                              input_sync(id);
-+                      }
-+              }
-+      }
-+}
-+
-+
-+/*
-+ * Backlight ops
-+ */
-+static struct backlight_ops ubicom32hid_blops = {
-+      .get_brightness = ubicom32hid_get_intensity,
-+      .update_status  = ubicom32hid_set_intensity,
-+};
-+
-+/*
-+ * ubicom32hid_probe
-+ */
-+static int ubicom32hid_probe(struct i2c_client *client,
-+                           const struct i2c_device_id *id)
-+{
-+      struct ubicom32hid_platform_data *pdata;
-+      struct ubicom32hid_data *ud;
-+      int ret;
-+      int i;
-+      u8 version[2];
-+      char buf[1];
-+
-+      pdata = client->dev.platform_data;
-+      if (pdata == NULL) {
-+              return -ENODEV;
-+      }
-+
-+      /*
-+       * See if we even have a device available before allocating memory.
-+       *
-+       * Hard reset the device
-+       */
-+      ret = gpio_request(pdata->gpio_reset, "ubicom32hid-reset");
-+      if (ret < 0) {
-+              return ret;
-+      }
-+      gpio_direction_output(pdata->gpio_reset, pdata->gpio_reset_polarity);
-+      udelay(100);
-+      gpio_set_value(pdata->gpio_reset, !pdata->gpio_reset_polarity);
-+      udelay(100);
-+
-+      /*
-+       * soft reset the device.  It sometimes takes a while to do this.
-+       */
-+      for (i = 0; i < 50; i++) {
-+              buf[0] = UBICOM32HID_CMD_RESET;
-+              ret = i2c_master_send(client, buf, 1);
-+              if (ret > 0) {
-+                      break;
-+              }
-+              udelay(10000);
-+      }
-+      if (i == 50) {
-+              dev_warn(&client->dev, "Unable to reset device\n");
-+              goto fail;
-+      }
-+
-+      ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_DEVICE_ID);
-+      if (ret != UBICOM32HID_DEVICE_ID) {
-+              dev_warn(&client->dev, "Incorrect device id %02x\n", buf[0]);
-+              ret = -ENODEV;
-+              goto fail;
-+      }
-+
-+      ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_VERSION);
-+      if (ret < 0) {
-+              dev_warn(&client->dev, "Unable to get version\n");
-+              goto fail;
-+      }
-+      version[0] = ret;
-+
-+      ret = i2c_smbus_read_byte_data(client, UBICOM32HID_CMD_GET_REVISION);
-+      if (ret < 0) {
-+              dev_warn(&client->dev, "Unable to get revision\n");
-+              goto fail;
-+      }
-+      version[1] = ret;
-+
-+      /*
-+       * Allocate our private data
-+       */
-+      ud = kzalloc(sizeof(struct ubicom32hid_data), GFP_KERNEL);
-+      if (!ud) {
-+              ret = -ENOMEM;
-+              goto fail;
-+      }
-+      ud->pdata = pdata;
-+      ud->client = client;
-+
-+      /*
-+       * Register our backlight device
-+       */
-+      ud->bldev = backlight_device_register(DRIVER_NAME, &client->dev,
-+                                            ud, &ubicom32hid_blops);
-+      if (IS_ERR(ud->bldev)) {
-+              ret = PTR_ERR(ud->bldev);
-+              goto fail2;
-+      }
-+      platform_set_drvdata(client, ud);
-+
-+      /*
-+       * Start up the backlight with the requested intensity
-+       */
-+      ud->bldev->props.power = FB_BLANK_UNBLANK;
-+      ud->bldev->props.max_brightness =
-+              (pdata->type == UBICOM32HID_BL_TYPE_PWM) ?
-+              UBICOM32HID_MAX_BRIGHTNESS_PWM : 1;
-+      if (pdata->default_intensity < ud->bldev->props.max_brightness) {
-+              ud->bldev->props.brightness = pdata->default_intensity;
-+      } else {
-+              dev_warn(&client->dev, "Default brightness out of range, "
-+                       "setting to max\n");
-+              ud->bldev->props.brightness = ud->bldev->props.max_brightness;
-+      }
-+
-+      ubicom32hid_set_intensity(ud->bldev);
-+
-+      /*
-+       * Check to see if we have any inputs
-+       */
-+      if (!pdata->nbuttons && !pdata->nircodes) {
-+              goto done;
-+      }
-+
-+      /*
-+       * We have buttons or codes, we must register an input device
-+       */
-+      ud->poll_dev = input_allocate_polled_device();
-+      if (!ud->poll_dev) {
-+              ret = -ENOMEM;
-+              goto fail3;
-+      }
-+
-+      /*
-+       * Setup the polling to default to 100ms
-+       */
-+      ud->poll_dev->poll = ubicom32hid_poll_input;
-+      ud->poll_dev->poll_interval =
-+              pdata->poll_interval ? pdata->poll_interval : 100;
-+      ud->poll_dev->private = ud;
-+
-+      ud->poll_dev->input->name =
-+              pdata->input_name ? pdata->input_name : "Ubicom32HID";
-+      ud->poll_dev->input->phys = "ubicom32hid/input0";
-+      ud->poll_dev->input->dev.parent = &client->dev;
-+      ud->poll_dev->input->id.bustype = BUS_I2C;
-+
-+      /*
-+       * Set the capabilities by running through the buttons and ir codes
-+       */
-+      for (i = 0; i < pdata->nbuttons; i++) {
-+              const struct ubicom32hid_button *ub = &pdata->buttons[i];
-+
-+              input_set_capability(ud->poll_dev->input,
-+                                   ub->type ? ub->type : EV_KEY, ub->code);
-+      }
-+
-+      for (i = 0; i < pdata->nircodes; i++) {
-+              const struct ubicom32hid_ir *ui = &pdata->ircodes[i];
-+
-+              input_set_capability(ud->poll_dev->input,
-+                                   ui->type ? ui->type : EV_KEY, ui->code);
-+      }
-+
-+      ret = input_register_polled_device(ud->poll_dev);
-+      if (ret) {
-+              goto fail3;
-+      }
-+
-+done:
-+      printk(KERN_INFO DRIVER_NAME ": enabled, version=%02x.%02x\n",
-+             version[0], version[1]);
-+
-+      return 0;
-+
-+fail3:
-+      gpio_free(ud->pdata->gpio_reset);
-+      backlight_device_unregister(ud->bldev);
-+fail2:
-+      kfree(ud);
-+fail:
-+      gpio_free(pdata->gpio_reset);
-+      return ret;
-+}
-+
-+/*
-+ * ubicom32hid_remove
-+ */
-+static int ubicom32hid_remove(struct i2c_client *client)
-+{
-+      struct ubicom32hid_data *ud =
-+              (struct ubicom32hid_data *)platform_get_drvdata(client);
-+
-+      gpio_free(ud->pdata->gpio_reset);
-+
-+      backlight_device_unregister(ud->bldev);
-+
-+      if (ud->poll_dev) {
-+              input_unregister_polled_device(ud->poll_dev);
-+              input_free_polled_device(ud->poll_dev);
-+      }
-+
-+      platform_set_drvdata(client, NULL);
-+
-+      kfree(ud);
-+
-+      return 0;
-+}
-+
-+static struct i2c_driver ubicom32hid_driver = {
-+      .driver = {
-+              .name   = DRIVER_NAME,
-+              .owner  = THIS_MODULE,
-+      },
-+      .probe          = ubicom32hid_probe,
-+      .remove         = __exit_p(ubicom32hid_remove),
-+      .id_table       = ubicom32hid_id,
-+};
-+
-+/*
-+ * ubicom32hid_init
-+ */
-+static int __init ubicom32hid_init(void)
-+{
-+      return i2c_add_driver(&ubicom32hid_driver);
-+}
-+module_init(ubicom32hid_init);
-+
-+/*
-+ * ubicom32hid_exit
-+ */
-+static void __exit ubicom32hid_exit(void)
-+{
-+      i2c_del_driver(&ubicom32hid_driver);
-+}
-+module_exit(ubicom32hid_exit);
-+
-+MODULE_AUTHOR("Pat Tjin <@ubicom.com>")
-+MODULE_DESCRIPTION("Ubicom HID driver");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/arch/ubicom32/mach-common/ubicom32input.c
-@@ -0,0 +1,265 @@
-+/*
-+ * arch/ubicom32/mach-common/ubicom32input.c
-+ *   Ubicom32 Input driver
-+ *
-+ *   based on gpio-keys
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ *
-+ *
-+ * TODO: add groups for inputs which can be sampled together (i.e. I2C)
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/input.h>
-+#include <linux/input-polldev.h>
-+#include <linux/delay.h>
-+#include <linux/gpio.h>
-+
-+#include <asm/ubicom32input.h>
-+
-+struct ubicom32input_data {
-+      struct ubicom32input_platform_data      *pdata;
-+
-+      struct input_polled_dev                 *poll_dev;
-+
-+      /*
-+       * collection of previous states for buttons
-+       */
-+      u8                                      prev_state[0];
-+};
-+
-+/*
-+ * ubicom32input_poll
-+ */
-+static void ubicom32input_poll(struct input_polled_dev *dev)
-+{
-+      struct ubicom32input_data *ud =
-+              (struct ubicom32input_data *)dev->private;
-+      struct ubicom32input_platform_data *pdata = ud->pdata;
-+      struct input_dev *id = dev->input;
-+      int i;
-+      int sync_needed = 0;
-+
-+      for (i = 0; i < pdata->nbuttons; i++) {
-+              const struct ubicom32input_button *ub = &pdata->buttons[i];
-+              int state = 0;
-+
-+              int val = gpio_get_value(ub->gpio);
-+
-+              /*
-+               * Check to see if the state changed from the last time we
-+               * looked
-+               */
-+              if (val == ud->prev_state[i]) {
-+                      continue;
-+              }
-+
-+              /*
-+               * The state has changed, determine if we are "up" or "down"
-+               */
-+              ud->prev_state[i] = val;
-+
-+              if ((!val && ub->active_low) || (val && !ub->active_low)) {
-+                      state = 1;
-+              }
-+
-+              input_event(id, ub->type, ub->code, state);
-+              sync_needed = 1;
-+      }
-+
-+      if (sync_needed) {
-+              input_sync(id);
-+      }
-+}
-+
-+/*
-+ * ubicom32input_probe
-+ */
-+static int __devinit ubicom32input_probe(struct platform_device *pdev)
-+{
-+      int i;
-+      struct ubicom32input_data *ud;
-+      struct input_polled_dev *poll_dev;
-+      struct input_dev *input_dev;
-+      struct ubicom32input_platform_data *pdata;
-+      int ret;
-+
-+      pdata = pdev->dev.platform_data;
-+      if (!pdata) {
-+              return -EINVAL;
-+      }
-+
-+      ud = kzalloc(sizeof(struct ubicom32input_data) +
-+                   pdata->nbuttons, GFP_KERNEL);
-+      if (!ud) {
-+              return -ENOMEM;
-+      }
-+      ud->pdata = pdata;
-+
-+      poll_dev = input_allocate_polled_device();
-+      if (!poll_dev) {
-+              ret = -ENOMEM;
-+              goto fail;
-+      }
-+
-+      platform_set_drvdata(pdev, ud);
-+
-+      ud->poll_dev = poll_dev;
-+      poll_dev->private = ud;
-+      poll_dev->poll = ubicom32input_poll;
-+
-+      /*
-+       * Set the poll interval requested, default to 50 msec
-+       */
-+      if (pdata->poll_interval) {
-+              poll_dev->poll_interval = pdata->poll_interval;
-+      } else {
-+              poll_dev->poll_interval = 50;
-+      }
-+
-+      /*
-+       * Setup the input device
-+       */
-+      input_dev = poll_dev->input;
-+      input_dev->name = pdata->name ? pdata->name : "Ubicom32 Input";
-+      input_dev->phys = "ubicom32input/input0";
-+      input_dev->dev.parent = &pdev->dev;
-+      input_dev->id.bustype = BUS_HOST;
-+
-+      /*
-+       * Reserve the GPIOs
-+       */
-+      for (i = 0; i < pdata->nbuttons; i++) {
-+              const struct ubicom32input_button *ub = &pdata->buttons[i];
-+
-+              ret = gpio_request(ub->gpio,
-+                                 ub->desc ? ub->desc : "ubicom32input");
-+              if (ret < 0) {
-+                      pr_err("ubicom32input: failed to request "
-+                             "GPIO %d ret=%d\n", ub->gpio, ret);
-+                      goto fail2;
-+              }
-+
-+              ret = gpio_direction_input(ub->gpio);
-+              if (ret < 0) {
-+                      pr_err("ubicom32input: failed to set "
-+                             "GPIO %d to input ret=%d\n", ub->gpio, ret);
-+                      goto fail2;
-+              }
-+
-+              /*
-+               * Set the previous state to the non-active stae
-+               */
-+              ud->prev_state[i] = ub->active_low;
-+
-+              input_set_capability(input_dev,
-+                                   ub->type ? ub->type : EV_KEY, ub->code);
-+      }
-+
-+      /*
-+       * Register
-+       */
-+      ret = input_register_polled_device(ud->poll_dev);
-+      if (ret) {
-+              goto fail2;
-+      }
-+
-+      return 0;
-+
-+fail2:
-+      /*
-+       * release the GPIOs we have already requested.
-+       */
-+      while (--i >= 0) {
-+              gpio_free(pdata->buttons[i].gpio);
-+      }
-+
-+fail:
-+      printk(KERN_ERR "Ubicom32Input: Failed to register driver %d", ret);
-+      platform_set_drvdata(pdev, NULL);
-+      input_free_polled_device(poll_dev);
-+      kfree(ud);
-+      return ret;
-+}
-+
-+/*
-+ * ubicom32input_remove
-+ */
-+static int __devexit ubicom32input_remove(struct platform_device *dev)
-+{
-+      struct ubicom32input_data *ud =
-+              (struct ubicom32input_data *)platform_get_drvdata(dev);
-+      int i;
-+
-+      /*
-+       * Free the GPIOs
-+       */
-+      for (i = 0; i < ud->pdata->nbuttons; i++) {
-+              gpio_free(ud->pdata->buttons[i].gpio);
-+      }
-+
-+      platform_set_drvdata(dev, NULL);
-+      input_unregister_polled_device(ud->poll_dev);
-+      input_free_polled_device(ud->poll_dev);
-+
-+      kfree(ud);
-+
-+      return 0;
-+}
-+
-+static struct platform_driver ubicom32input_driver = {
-+      .driver         = {
-+              .name   = "ubicom32input",
-+              .owner  = THIS_MODULE,
-+      },
-+      .probe          = ubicom32input_probe,
-+      .remove         = __devexit_p(ubicom32input_remove),
-+};
-+
-+/*
-+ * ubicom32input_init
-+ */
-+static int __devinit ubicom32input_init(void)
-+{
-+      return platform_driver_register(&ubicom32input_driver);
-+}
-+
-+/*
-+ * ubicom32input_exit
-+ */
-+static void __exit ubicom32input_exit(void)
-+{
-+      platform_driver_unregister(&ubicom32input_driver);
-+}
-+
-+module_init(ubicom32input_init);
-+module_exit(ubicom32input_exit);
-+
-+MODULE_AUTHOR("Pat Tjin <pattjin@ubicom.com>");
-+MODULE_DESCRIPTION("Ubicom32 Input Driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:ubicom32-input");
---- /dev/null
-+++ b/arch/ubicom32/mach-common/ubicom32input_i2c.c
-@@ -0,0 +1,325 @@
-+/*
-+ * arch/ubicom32/mach-common/ubicom32input_i2c.c
-+ *   Ubicom32 Input driver for I2C
-+ *      Supports PCA953x and family
-+ *
-+ *   We hog the I2C device, turning it all to input.
-+ *
-+ *   Based on gpio-keys, pca953x
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/input.h>
-+#include <linux/input-polldev.h>
-+#include <linux/i2c.h>
-+
-+#include <asm/ubicom32input_i2c.h>
-+
-+#define UBICOM32INPUT_I2C_REG_INPUT   0
-+#define UBICOM32INPUT_I2C_REG_OUTPUT  1
-+#define UBICOM32INPUT_I2C_REG_INVERT  2
-+#define UBICOM32INPUT_I2C_REG_DIRECTION       3
-+
-+static const struct i2c_device_id ubicom32input_i2c_id[] = {
-+      { "ubicom32in_pca9534", 8, },
-+      { "ubicom32in_pca9535", 16, },
-+      { "ubicom32in_pca9536", 4, },
-+      { "ubicom32in_pca9537", 4, },
-+      { "ubicom32in_pca9538", 8, },
-+      { "ubicom32in_pca9539", 16, },
-+      { "ubicom32in_pca9554", 8, },
-+      { "ubicom32in_pca9555", 16, },
-+      { "ubicom32in_pca9557", 8, },
-+      { "ubicom32in_max7310", 8, },
-+      { }
-+};
-+MODULE_DEVICE_TABLE(i2c, ubicom32input_i2c_id);
-+
-+struct ubicom32input_i2c_data {
-+      struct ubicom32input_i2c_platform_data  *pdata;
-+
-+      struct i2c_client                       *client;
-+
-+      struct input_polled_dev                 *poll_dev;
-+
-+      /*
-+       * collection of previous states for buttons
-+       */
-+      uint16_t                                prev_state;
-+
-+      uint8_t                                 ngpios;
-+};
-+
-+/*
-+ * ubicom32input_i2c_write_reg
-+ *    writes a register to the I2C device.
-+ */
-+static int ubicom32input_i2c_write_reg(struct ubicom32input_i2c_data *ud,
-+                                     int reg, uint16_t val)
-+{
-+      int ret;
-+
-+      if (ud->ngpios <= 8) {
-+              ret = i2c_smbus_write_byte_data(ud->client, reg, val);
-+      } else {
-+              ret = i2c_smbus_write_word_data(ud->client, reg << 1, val);
-+      }
-+
-+      if (ret < 0) {
-+              return ret;
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32input_i2c_read_reg
-+ *    reads a register from the I2C device.
-+ */
-+static int ubicom32input_i2c_read_reg(struct ubicom32input_i2c_data *ud,
-+                                    int reg, uint16_t *val)
-+{
-+      int ret;
-+
-+      if (ud->ngpios <= 8) {
-+              ret = i2c_smbus_read_byte_data(ud->client, reg);
-+      } else {
-+              ret = i2c_smbus_read_word_data(ud->client, reg);
-+      }
-+
-+      if (ret < 0) {
-+              return ret;
-+      }
-+
-+      *val = (uint16_t)ret;
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32input_i2c_poll
-+ */
-+static void ubicom32input_i2c_poll(struct input_polled_dev *dev)
-+{
-+      struct ubicom32input_i2c_data *ud =
-+              (struct ubicom32input_i2c_data *)dev->private;
-+      struct ubicom32input_i2c_platform_data *pdata = ud->pdata;
-+      struct input_dev *id = dev->input;
-+      int i;
-+      int sync_needed = 0;
-+      uint16_t val;
-+      uint16_t change_mask;
-+
-+      /*
-+       * Try to get the input status, if we fail, bail out, maybe we can do it
-+       * next time.
-+       */
-+      if (ubicom32input_i2c_read_reg(ud, UBICOM32INPUT_I2C_REG_INPUT, &val)) {
-+              return;
-+      }
-+
-+      /*
-+       * see if anything changed by using XOR
-+       */
-+      change_mask = ud->prev_state ^ val;
-+      ud->prev_state = val;
-+
-+      for (i = 0; i < pdata->nbuttons; i++) {
-+              const struct ubicom32input_i2c_button *ub = &pdata->buttons[i];
-+              uint16_t mask = 1 << ub->bit;
-+              int state = val & mask;
-+
-+              /*
-+               * Check to see if the state changed from the last time we
-+               * looked
-+               */
-+              if (!(change_mask & mask)) {
-+                      continue;
-+              }
-+              input_event(id, ub->type, ub->code, state);
-+              sync_needed = 1;
-+      }
-+
-+      if (sync_needed) {
-+              input_sync(id);
-+      }
-+}
-+
-+/*
-+ * ubicom32input_i2c_probe
-+ */
-+static int __devinit ubicom32input_i2c_probe(struct i2c_client *client,
-+                                           const struct i2c_device_id *id)
-+{
-+      int i;
-+      struct ubicom32input_i2c_data *ud;
-+      struct input_polled_dev *poll_dev;
-+      struct input_dev *input_dev;
-+      struct ubicom32input_i2c_platform_data *pdata;
-+      int ret;
-+      uint16_t invert_mask = 0;
-+
-+      pdata = client->dev.platform_data;
-+      if (!pdata) {
-+              return -EINVAL;
-+      }
-+
-+      ud = kzalloc(sizeof(struct ubicom32input_i2c_data), GFP_KERNEL);
-+      if (!ud) {
-+              return -ENOMEM;
-+      }
-+      ud->pdata = pdata;
-+      ud->client = client;
-+      ud->ngpios = id->driver_data;
-+
-+      poll_dev = input_allocate_polled_device();
-+      if (!poll_dev) {
-+              ret = -ENOMEM;
-+              goto fail;
-+      }
-+
-+      ud->poll_dev = poll_dev;
-+      poll_dev->private = ud;
-+      poll_dev->poll = ubicom32input_i2c_poll;
-+
-+      /*
-+       * Set the poll interval requested, default to 100 msec
-+       */
-+      if (pdata->poll_interval) {
-+              poll_dev->poll_interval = pdata->poll_interval;
-+      } else {
-+              poll_dev->poll_interval = 100;
-+      }
-+
-+      /*
-+       * Setup the input device
-+       */
-+      input_dev = poll_dev->input;
-+      input_dev->name = pdata->name ? pdata->name : "Ubicom32 Input I2C";
-+      input_dev->phys = "ubicom32input_i2c/input0";
-+      input_dev->dev.parent = &client->dev;
-+      input_dev->id.bustype = BUS_I2C;
-+
-+      /*
-+       * Set the capabilities
-+       */
-+      for (i = 0; i < pdata->nbuttons; i++) {
-+              const struct ubicom32input_i2c_button *ub = &pdata->buttons[i];
-+
-+              if (ub->active_low) {
-+                      invert_mask |= (1 << ub->bit);
-+              }
-+
-+              input_set_capability(input_dev,
-+                                   ub->type ? ub->type : EV_KEY, ub->code);
-+      }
-+
-+      /*
-+       * Setup the device (all inputs)
-+       */
-+      ret = ubicom32input_i2c_write_reg(ud, UBICOM32INPUT_I2C_REG_DIRECTION,
-+                                        0xFFFF);
-+      if (ret < 0) {
-+              goto fail;
-+      }
-+
-+      ret = ubicom32input_i2c_write_reg(ud, UBICOM32INPUT_I2C_REG_INVERT,
-+                                        invert_mask);
-+      if (ret < 0) {
-+              goto fail;
-+      }
-+
-+      /*
-+       * Register
-+       */
-+      ret = input_register_polled_device(ud->poll_dev);
-+      if (ret) {
-+              goto fail;
-+      }
-+
-+      i2c_set_clientdata(client, ud);
-+
-+      return 0;
-+
-+fail:
-+      printk(KERN_ERR "ubicom32input_i2c: Failed to register driver %d\n",
-+             ret);
-+      input_free_polled_device(poll_dev);
-+      kfree(ud);
-+      return ret;
-+}
-+
-+/*
-+ * ubicom32input_i2c_remove
-+ */
-+static int __devexit ubicom32input_i2c_remove(struct i2c_client *client)
-+{
-+      struct ubicom32input_i2c_data *ud =
-+              (struct ubicom32input_i2c_data *)i2c_get_clientdata(client);
-+
-+      i2c_set_clientdata(client, NULL);
-+      input_unregister_polled_device(ud->poll_dev);
-+      input_free_polled_device(ud->poll_dev);
-+
-+      kfree(ud);
-+
-+      return 0;
-+}
-+
-+static struct i2c_driver ubicom32input_i2c_driver = {
-+      .driver         = {
-+              .name   = "ubicom32input_i2c",
-+              .owner  = THIS_MODULE,
-+      },
-+      .remove         = __devexit_p(ubicom32input_i2c_remove),
-+      .id_table       = ubicom32input_i2c_id,
-+      .probe          = ubicom32input_i2c_probe,
-+};
-+
-+/*
-+ * ubicom32input_i2c_init
-+ */
-+static int __devinit ubicom32input_i2c_init(void)
-+{
-+      return i2c_add_driver(&ubicom32input_i2c_driver);
-+}
-+
-+/*
-+ * ubicom32input_i2c_exit
-+ */
-+static void __exit ubicom32input_i2c_exit(void)
-+{
-+      i2c_del_driver(&ubicom32input_i2c_driver);
-+}
-+
-+module_init(ubicom32input_i2c_init);
-+module_exit(ubicom32input_i2c_exit);
-+
-+MODULE_AUTHOR("Pat Tjin <pattjin@ubicom.com>");
-+MODULE_DESCRIPTION("Ubicom32 Input Driver I2C");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS("platform:ubicom32-input");
---- /dev/null
-+++ b/arch/ubicom32/mach-common/usb.c
-@@ -0,0 +1,132 @@
-+/*
-+ * arch/ubicom32/mach-common/ip5k_usb.c
-+ *   Ubicom32 architecture usb support.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
-+ * Author: Kevin Hilman
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/delay.h>
-+#include <linux/platform_device.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/usb/musb.h>
-+#include <asm/devtree.h>
-+#include <asm/ip5000.h>
-+#include "usb_tio.h"
-+
-+struct usbtionode *unode = NULL;
-+
-+static struct resource usb_resources[] = {
-+      [0] = {
-+              .start  = RJ + 0x800,
-+              .end    = RJ + 0x1000,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+      [1] = { /* general IRQ */
-+              .start  = 1, /* this is a dummy value, the real irq number is passed from kernel_setup_param */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+};
-+
-+
-+static struct musb_hdrc_eps_bits musb_eps[] = {
-+      { "ep1_tx", 4, },
-+      { "ep1_rx", 4, },
-+      { "ep2_tx", 10, },
-+      { "ep2_rx", 10, },
-+      { "ep3_tx", 9, },
-+      { "ep3_rx", 9, },
-+      { "ep4_tx", 9, },
-+      { "ep4_rx", 9, },
-+      { "ep5_tx", 6, },
-+      { "ep5_rx", 6, },
-+};
-+
-+static struct musb_hdrc_config musb_config = {
-+      .multipoint     = true,
-+      .dyn_fifo       = false,
-+      .soft_con       = true,
-+      .dma            = false,
-+
-+      .num_eps        = 6,
-+      .dma_channels   = 0,
-+      .ram_bits       = 0,
-+      .eps_bits       = musb_eps,
-+};
-+
-+static struct musb_hdrc_platform_data usb_data = {
-+#ifdef CONFIG_USB_MUSB_OTG
-+      .mode           = MUSB_OTG,
-+#else
-+#ifdef CONFIG_USB_MUSB_HDRC_HCD
-+      .mode           = MUSB_HOST,
-+#else
-+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
-+      .mode           = MUSB_PERIPHERAL,
-+#endif
-+#endif
-+#endif
-+      .clock          = NULL,
-+      .set_clock      = NULL,
-+      .config         = &musb_config,
-+};
-+
-+static struct platform_device musb_device = {
-+      .name           = "musb_hdrc",
-+      .id             = 0,
-+      .dev = {
-+              .platform_data          = &usb_data,
-+              .dma_mask               = NULL,
-+              .coherent_dma_mask      = 0,
-+      },
-+      .resource       = usb_resources,
-+      .num_resources  = ARRAY_SIZE(usb_resources),
-+};
-+
-+struct usbtio_node *usb_node = NULL;
-+void ubi32_usb_init(void)
-+{
-+      /*
-+       * See if the usbtio is in the device tree.
-+       */
-+      usb_node = (struct usbtio_node *)devtree_find_node("usbtio");
-+      if (!usb_node) {
-+              printk(KERN_WARNING "usb init failed\n");
-+              return;
-+      }
-+
-+      usb_resources[1].start = usb_node->dn.recvirq;
-+      if (platform_device_register(&musb_device) < 0) {
-+              printk(KERN_ERR "Unable to register HS-USB (MUSB) device\n");
-+              return;
-+      }
-+}
-+
-+void ubi32_usb_int_clr(void)
-+{
-+        UBICOM32_IO_PORT(RJ)->int_clr = (1 << 3);
-+}
---- /dev/null
-+++ b/arch/ubicom32/mach-common/usb_tio.c
-@@ -0,0 +1,356 @@
-+/*
-+ * arch/ubicom32/mach-common/usb_tio.c
-+ *  Linux side Ubicom USB TIO driver
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/module.h>
-+#include <linux/spinlock.h>
-+#include <linux/slab.h>
-+#include <asm/devtree.h>
-+#include "usb_tio.h"
-+
-+#ifdef CONFIG_SMP
-+static DEFINE_SPINLOCK(tio_lock);
-+#define USB_TIO_LOCK(lock, flag) spin_lock_irqsave(lock, flag)
-+#define USB_TIO_UNLOCK(lock, flag) spin_unlock_irqrestore(lock, flag)
-+#define USB_TIO_LOCK_ISLOCKED(lock) spin_try_lock(lock)
-+#else
-+#define USB_TIO_LOCK(lock, flag) local_irq_save(flag)
-+#define USB_TIO_UNLOCK(lock, flag) local_irq_restore(flag)
-+#endif
-+
-+spinlock_t usb_tio_lock;
-+
-+/*
-+ * usb_tio_set_hrt_interrupt()
-+ */
-+static inline void usb_tio_set_hrt_interrupt(void)
-+{
-+      ubicom32_set_interrupt(usb_node->dn.sendirq);
-+}
-+
-+static inline void usb_tio_wait_hrt(void)
-+{
-+      while (unlikely(usb_node->pdesc));
-+}
-+
-+#if defined(USB_TIO_DEBUG)
-+static void usb_tio_request_verify_magic(volatile struct usb_tio_request *req)
-+{
-+      BUG_ON(req->magic != USB_TIO_REQUEST_MAGIC2);
-+}
-+
-+static void usb_tio_request_clear_magic(volatile struct usb_tio_request *req)
-+{
-+      req->magic = 0;
-+}
-+#endif
-+
-+static void usb_tio_request_set_magic(volatile struct usb_tio_request *req)
-+{
-+      req->magic = USB_TIO_REQUEST_MAGIC1;
-+}
-+
-+/*
-+ * usb_tio_commit_request()
-+ */
-+static inline void usb_tio_commit_request(volatile struct usb_tio_request *request)
-+{
-+      wmb();
-+      usb_node->pdesc = request;
-+
-+      /*
-+       * next thing to do is alway checking if (usb_node->pdesc == NULL)
-+       * to see if the request is done, so add a mb() here
-+       */
-+      mb();
-+      usb_tio_set_hrt_interrupt();
-+}
-+
-+/*
-+ * usb_tio_read_u16()
-+ *    Synchronously read 16 bits.
-+ */
-+u8_t usb_tio_read_u16(u32_t address, u16_t *data)
-+{
-+      volatile struct usb_tio_request *tio_req = &usb_node->request;
-+      unsigned long flag;
-+
-+      /*
-+       * Wait for any previous request to complete and then make this request.
-+       */
-+      USB_TIO_LOCK(&tio_lock, flag);
-+      usb_tio_wait_hrt();
-+
-+      /*
-+       * Fill in the request.
-+       */
-+      tio_req->address = address;
-+      tio_req->cmd = USB_TIO_READ16_SYNC;
-+      USB_TIO_REQUEST_SET_MAGIC(tio_req);
-+      usb_tio_commit_request(tio_req);
-+
-+      /*
-+       * Wait for the result to show up.
-+       */
-+      usb_tio_wait_hrt();
-+      USB_TIO_REQUEST_VERIFY_MAGIC(tio_req);
-+      *data = (u16_t)tio_req->data;
-+      USB_TIO_REQUEST_CLEAR_MAGIC(tio_req);
-+      USB_TIO_UNLOCK(&tio_lock, flag);
-+      return USB_TIO_OK;
-+}
-+
-+/*
-+ * usb_tio_read_u8()
-+ *    Synchronously read 16 bits.
-+ */
-+u8_t usb_tio_read_u8(u32_t address, u8_t *data)
-+{
-+      volatile struct usb_tio_request *tio_req = &usb_node->request;
-+      unsigned long flag;
-+
-+      /*
-+       * Wait for any previous request to complete and then make this request.
-+       */
-+      USB_TIO_LOCK(&tio_lock, flag);
-+      usb_tio_wait_hrt();
-+
-+      /*
-+       * Fill in the request.
-+       */
-+      tio_req->address = address;
-+      tio_req->cmd = USB_TIO_READ8_SYNC;
-+      USB_TIO_REQUEST_SET_MAGIC(tio_req);
-+
-+      /*
-+       * commit the request
-+       */
-+      usb_tio_commit_request(tio_req);
-+
-+      /*
-+       * Wait for the result to show up.
-+       */
-+      usb_tio_wait_hrt();
-+      USB_TIO_REQUEST_VERIFY_MAGIC(tio_req);
-+      *data = (u8_t)tio_req->data;
-+      USB_TIO_REQUEST_CLEAR_MAGIC(tio_req);
-+      USB_TIO_UNLOCK(&tio_lock, flag);
-+      return USB_TIO_OK;
-+}
-+
-+/*
-+ * usb_tio_write_u16()
-+ *    Asynchronously  write 16 bits.
-+ */
-+u8_t usb_tio_write_u16(u32_t address, u16_t data)
-+{
-+      volatile struct usb_tio_request *tio_req = &usb_node->request;
-+      unsigned long flag;
-+
-+      /*
-+       * Wait for any previous write or pending read to complete.
-+       */
-+      USB_TIO_LOCK(&tio_lock, flag);
-+      usb_tio_wait_hrt();
-+
-+      tio_req->address = address;
-+      tio_req->data = data;
-+      tio_req->cmd = USB_TIO_WRITE16_ASYNC;
-+      USB_TIO_REQUEST_SET_MAGIC(tio_req);
-+
-+      /*
-+       * commit the request
-+       */
-+      usb_tio_commit_request(tio_req);
-+      USB_TIO_UNLOCK(&tio_lock, flag);
-+      return USB_TIO_OK;
-+}
-+
-+/*
-+ * usb_tio_write_u8()
-+ *    Asynchronously  write 8 bits.
-+ */
-+u8_t usb_tio_write_u8(u32_t address, u8_t data)
-+{
-+      volatile struct usb_tio_request *tio_req = &usb_node->request;
-+      unsigned long flag;
-+
-+      /*
-+       * Wait for any previous write or pending read to complete.
-+       */
-+      USB_TIO_LOCK(&tio_lock, flag);
-+      usb_tio_wait_hrt();
-+
-+      tio_req->address = address;
-+      tio_req->data = data;
-+      tio_req->cmd = USB_TIO_WRITE8_ASYNC;
-+      USB_TIO_REQUEST_SET_MAGIC(tio_req);
-+
-+      /*
-+       * commit the request
-+       */
-+      usb_tio_commit_request(tio_req);
-+      USB_TIO_UNLOCK(&tio_lock, flag);
-+      return USB_TIO_OK;
-+}
-+
-+/*
-+ * usb_tio_read_fifo()
-+ *    Synchronously read FIFO.
-+ */
-+u8_t usb_tio_read_fifo(u32_t address, u32_t buffer, u32_t bytes)
-+{
-+      volatile struct usb_tio_request *tio_req = &usb_node->request;
-+      unsigned long flag;
-+
-+      /*
-+       * Wait for any previous request to complete and then make this request.
-+       */
-+      USB_TIO_LOCK(&tio_lock, flag);
-+      usb_tio_wait_hrt();
-+
-+      /*
-+       * Fill in the request.
-+       */
-+      tio_req->address = address;
-+      tio_req->cmd = USB_TIO_READ_FIFO_SYNC;
-+      tio_req->buffer = buffer;
-+      tio_req->transfer_length = bytes;
-+      USB_TIO_REQUEST_SET_MAGIC(tio_req);
-+
-+      /*
-+       * commit the request
-+       */
-+      usb_tio_commit_request(tio_req);
-+
-+       /*
-+       * Wait for the result to show up.
-+       */
-+      usb_tio_wait_hrt();
-+      USB_TIO_REQUEST_VERIFY_MAGIC(tio_req);
-+      USB_TIO_REQUEST_CLEAR_MAGIC(tio_req);
-+      USB_TIO_UNLOCK(&tio_lock, flag);
-+      return USB_TIO_OK;
-+}
-+
-+/*
-+ * usb_tio_write_fifo()
-+ *    Synchronously  write 32 bits.
-+ */
-+u8_t usb_tio_write_fifo(u32_t address, u32_t buffer, u32_t bytes)
-+{
-+      volatile struct usb_tio_request *tio_req = &usb_node->request;
-+      unsigned long flag;
-+
-+      USB_TIO_LOCK(&tio_lock, flag);
-+      usb_tio_wait_hrt();
-+
-+      tio_req->address = address;
-+      tio_req->buffer = buffer;
-+      tio_req->cmd = USB_TIO_WRITE_FIFO_SYNC;
-+      tio_req->transfer_length = bytes;
-+      USB_TIO_REQUEST_SET_MAGIC(tio_req);
-+      /*
-+       * commit the request
-+       */
-+      usb_tio_commit_request(tio_req);
-+
-+      /*
-+       * Wait for the result to show up.
-+       */
-+      usb_tio_wait_hrt();
-+      USB_TIO_REQUEST_VERIFY_MAGIC(tio_req);
-+      USB_TIO_REQUEST_CLEAR_MAGIC(tio_req);
-+      USB_TIO_UNLOCK(&tio_lock, flag);
-+      return USB_TIO_OK;
-+}
-+
-+/*
-+ * usb_tio_write_fifo_async()
-+ *    Asynchronously write 32 bits.
-+ */
-+u8_t usb_tio_write_fifo_async(u32_t address, u32_t buffer, u32_t bytes)
-+{
-+      volatile struct usb_tio_request *tio_req = &usb_node->request;
-+      unsigned long flag;
-+
-+      USB_TIO_LOCK(&tio_lock, flag);
-+      usb_tio_wait_hrt();
-+
-+      tio_req->address = address;
-+
-+      /*
-+       * Is it necessary to make a local copy of the buffer? Any chance the URB is aborted before TIO finished the FIFO write?
-+       */
-+      tio_req->buffer = buffer;
-+      tio_req->cmd = USB_TIO_WRITE_FIFO_SYNC;
-+      tio_req->transfer_length = bytes;
-+      USB_TIO_REQUEST_SET_MAGIC(tio_req);
-+      /*
-+       * commit the request
-+       */
-+      usb_tio_commit_request(tio_req);
-+      USB_TIO_UNLOCK(&tio_lock, flag);
-+      return USB_TIO_OK;
-+}
-+
-+/*
-+ * usb_tio_read_int_status()
-+ *    read and clear the interrupt status registers
-+ */
-+void usb_tio_read_int_status(u8_t *int_usb, u16_t *int_tx, u16_t *int_rx)
-+{
-+
-+      /*
-+       * clear the interrupt must be syncronized with the TIO thread to prevent the racing condiiton
-+       * that TIO thread try to set it at same time
-+       */
-+      asm volatile (
-+      "1:     bset (%0), (%0), #0     \n\t" \
-+      "       jmpne.f 1b              \n\t" \
-+              :
-+              : "a" (&usb_node->usb_vp_control)
-+              : "memory", "cc"
-+      );
-+
-+      *int_usb = usb_node->usb_vp_hw_int_usb;
-+      *int_tx  = cpu_to_le16(usb_node->usb_vp_hw_int_tx);
-+      *int_rx  = cpu_to_le16(usb_node->usb_vp_hw_int_rx);
-+
-+      //printk(KERN_INFO "int read %x, %x, %x\n", *int_usb, *int_tx, *int_rx);
-+
-+      /*
-+       * The interrupt status register is read-clean, so clear it now
-+       */
-+      usb_node->usb_vp_hw_int_usb = 0;
-+      usb_node->usb_vp_hw_int_tx = 0;
-+      usb_node->usb_vp_hw_int_rx = 0;
-+
-+      /*
-+       * release the lock bit
-+       */
-+      usb_node->usb_vp_control &= 0xfffe;
-+}
---- /dev/null
-+++ b/arch/ubicom32/mach-common/usb_tio.h
-@@ -0,0 +1,111 @@
-+/*
-+ * arch/ubicom32/mach-common/usb_tio.h
-+ *   Definitions for usb_tio.c
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/errno.h>
-+#include <linux/err.h>
-+#include <asm/devtree.h>
-+#include <asm/ip5000.h>
-+
-+#ifndef _USB_TIO_H
-+#define _USB_TIO_H
-+
-+#undef  USB_TIO_DEBUG
-+
-+#define USB_TIO_REQUEST_MAGIC1        0x2307
-+#define USB_TIO_REQUEST_MAGIC2        0x0789
-+#if defined(USB_TIO_DEBUG)
-+#define USB_TIO_REQUEST_VERIFY_MAGIC(req)     usb_tio_request_verify_magic(req)
-+#define USB_TIO_REQUEST_SET_MAGIC(req)          usb_tio_request_set_magic(req)
-+#define USB_TIO_REQUEST_CLEAR_MAGIC(req)      usb_tio_request_clear_magic(req)
-+#else
-+#define USB_TIO_REQUEST_VERIFY_MAGIC(req)
-+#define USB_TIO_REQUEST_SET_MAGIC(req)          usb_tio_request_set_magic(req)
-+#define USB_TIO_REQUEST_CLEAR_MAGIC(req)
-+#endif
-+
-+enum USB_TIO_status {
-+      USB_TIO_OK,
-+      USB_TIO_ERROR,
-+      USB_TIO_ERROR_COMMIT,
-+};
-+
-+enum USB_TIO_cmds {
-+      USB_TIO_READ16_SYNC,
-+      USB_TIO_READ8_SYNC,
-+      USB_TIO_READ_FIFO_SYNC,
-+
-+      USB_TIO_WRITE16_ASYNC,
-+      USB_TIO_WRITE8_ASYNC,
-+      USB_TIO_WRITE_FIFO_ASYNC,
-+
-+      USB_TIO_WRITE16_SYNC,
-+      USB_TIO_WRITE8_SYNC,
-+      USB_TIO_WRITE_FIFO_SYNC,
-+
-+};
-+
-+enum USB_TIO_state {
-+      USB_TIO_NORMAL,
-+      USB_TIO_DMA_SETUP,
-+};
-+
-+struct usb_tio_request {
-+      volatile u32_t address;
-+      union {
-+              volatile u32_t data;
-+              volatile u32_t buffer;
-+      };
-+      volatile u16_t cmd;
-+      const volatile u16_t status;
-+      volatile u32_t transfer_length;
-+      volatile u32_t thread_mask;
-+      volatile u16_t magic;
-+};
-+
-+struct usbtio_node {
-+      struct devtree_node dn;
-+      volatile struct usb_tio_request * volatile pdesc;
-+      struct usb_tio_request  request;
-+      volatile u32_t usb_vp_config;
-+      volatile u32_t usb_vp_control;
-+      const volatile u32_t usb_vp_status;
-+      volatile u16_t usb_vp_hw_int_tx;
-+      volatile u16_t usb_vp_hw_int_rx;
-+      volatile u8_t  usb_vp_hw_int_usb;
-+      volatile u8_t usb_vp_hw_int_mask_usb;
-+        volatile u16_t usb_vp_hw_int_mask_tx;
-+        volatile u16_t usb_vp_hw_int_mask_rx;
-+
-+};
-+
-+extern struct usbtio_node *usb_node;
-+extern void ubi32_usb_init(void);
-+#endif
---- /dev/null
-+++ b/arch/ubicom32/mach-common/vdc_tio.c
-@@ -0,0 +1,111 @@
-+/*
-+ * arch/ubicom32/mach-common/vdc_tio.c
-+ *   Generic initialization for VDC
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/platform_device.h>
-+#include <linux/types.h>
-+
-+#include <asm/devtree.h>
-+#include <asm/vdc_tio.h>
-+
-+/*
-+ * Resources that this driver uses
-+ */
-+static struct resource vdc_tio_resources[] = {
-+      /*
-+       * Send IRQ
-+       */
-+      [0] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Receive IRQ (optional)
-+       */
-+      [1] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Memory Mapped Registers
-+       */
-+      [2] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_MEM,
-+      },
-+};
-+
-+/*
-+ * The platform_device structure which is passed to the driver
-+ */
-+static struct platform_device vdc_tio_platform_device = {
-+      .name           = "ubicom32fb",
-+      .id             = -1,
-+      .resource       = vdc_tio_resources,
-+      .num_resources  = ARRAY_SIZE(vdc_tio_resources),
-+};
-+
-+/*
-+ * vdc_tio_init
-+ *    Checks the device tree and instantiates the driver if found
-+ */
-+void __init vdc_tio_init(void)
-+{
-+      /*
-+       * Check the device tree for the vdc_tio
-+       */
-+      struct vdc_tio_node *vdc_node =
-+              (struct vdc_tio_node *)devtree_find_node("vdctio");
-+      if (!vdc_node) {
-+              printk(KERN_WARNING "No vdc_tio found\n");
-+              return;
-+      }
-+
-+      /*
-+       * Fill in the resources and platform data from devtree information
-+       */
-+      vdc_tio_resources[0].start = vdc_node->dn.sendirq;
-+      vdc_tio_resources[1].start = vdc_node->dn.recvirq;
-+      vdc_tio_resources[2].start = (u32_t)vdc_node->regs;
-+      vdc_tio_resources[2].end = (u32_t)vdc_node->regs +
-+              sizeof(struct vdc_tio_vp_regs);
-+
-+      /*
-+       * Try to get the device registered
-+       */
-+      if (platform_device_register(&vdc_tio_platform_device) < 0) {
-+              printk(KERN_WARNING "VDC failed to register\n");
-+      }
-+}
---- /dev/null
-+++ b/arch/ubicom32/mach-ip5k/board-ip5160dev.c
-@@ -0,0 +1,109 @@
-+/*
-+ * arch/ubicom32/mach-ip5k/board-ip5160dev.c
-+ *   Platform initialization for ip5160dev board.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/gpio.h>
-+
-+#include <asm/board.h>
-+#include <asm/machdep.h>
-+#ifdef CONFIG_SERIAL_UBI32_SERDES
-+#include <asm/ubicom32suart.h>
-+#endif
-+
-+/*
-+ * Factory Default Button on the board at PXn
-+ * TODO: This is just a placeholder and it needs to include proper header files
-+ */
-+struct ubicom32fdb_platform_data {
-+      int             fdb_gpio;
-+      bool            fdb_polarity;
-+};
-+
-+static struct ubicom32fdb_platform_data ip5160dev_fdb_data = {
-+      .fdb_gpio               = 0,
-+      .fdb_polarity           = true,
-+};
-+
-+static struct platform_device ip5160dev_fdb_device = {
-+      .name   = "ubicom32fdb",
-+      .id     = -1,
-+      .dev    = {
-+              .platform_data = &ip5160dev_fdb_data,
-+      },
-+};
-+
-+#ifdef CONFIG_SERIAL_UBI32_SERDES
-+static struct resource ip5160dev_ubicom32_suart_resources[] = {
-+        {
-+              .start  = RD,
-+              .end    = RD,
-+              .flags  = IORESOURCE_MEM,
-+        },
-+        {
-+              .start  = PORT_OTHER_INT(RD),
-+              .end    = PORT_OTHER_INT(RD),
-+              .flags  = IORESOURCE_IRQ,
-+        },
-+        {
-+              .start  = 240000000,
-+              .end    = 240000000,
-+              .flags  = UBICOM32_SUART_IORESOURCE_CLOCK,
-+        },
-+};
-+
-+static struct platform_device ip5160dev_ubicom32_suart_device = {
-+      .name           = "ubicom32suart",
-+      .id             = -1,
-+        .num_resources  = ARRAY_SIZE(ip5160dev_ubicom32_suart_resources),
-+        .resource       = ip5160dev_ubicom32_suart_resources,
-+};
-+#endif
-+
-+/*
-+ * List of all devices in our system
-+ */
-+static struct platform_device *ip5160dev_devices[] __initdata = {
-+#ifdef CONFIG_SERIAL_UBI32_SERDES
-+      &ip5160dev_ubicom32_suart_device,
-+#endif
-+      &ip5160dev_fdb_device,
-+};
-+
-+/*
-+ * ip5160dev_init
-+ *    Called to add the devices which we have on this board
-+ */
-+static int __init ip5160dev_init(void)
-+{
-+      ubi_gpio_init();
-+      printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
-+      platform_add_devices(ip5160dev_devices, ARRAY_SIZE(ip5160dev_devices));
-+      return 0;
-+}
-+
-+arch_initcall(ip5160dev_init);
---- /dev/null
-+++ b/arch/ubicom32/mach-ip5k/board-ip5160rgw.c
-@@ -0,0 +1,75 @@
-+/*
-+ * arch/ubicom32/mach-ip5k/board-ip5160rgw.c
-+ *   Platform initialization for ip5160rgw board.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/gpio.h>
-+#include <asm/board.h>
-+#include <asm/machdep.h>
-+
-+/*
-+ * Factory Default Button on the board at PXn
-+ * TODO: This is just a placeholder and it needs to include proper header files
-+ */
-+struct ubicom32fdb_platform_data {
-+      int             fdb_gpio;
-+      bool            fdb_polarity;
-+};
-+
-+static struct ubicom32fdb_platform_data ip5160rgw_fdb_data = {
-+      .fdb_gpio               = 0,
-+      .fdb_polarity           = true,
-+};
-+
-+static struct platform_device ip5160rgw_fdb_device = {
-+      .name   = "ubicom32fdb",
-+      .id     = -1,
-+      .dev    = {
-+              .platform_data = &ip5160rgw_fdb_data,
-+      },
-+};
-+
-+/*
-+ * List of all devices in our system
-+ */
-+static struct platform_device *ip5160rgw_devices[] __initdata = {
-+      &ip5160rgw_fdb_device,
-+};
-+
-+/*
-+ * ip5160rgw_init
-+ *    Called to add the devices which we have on this board
-+ */
-+static int __init ip5160rgw_init(void)
-+{
-+      ubi_gpio_init();
-+      printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
-+      platform_add_devices(ip5160rgw_devices, ARRAY_SIZE(ip5160rgw_devices));
-+      return 0;
-+}
-+
-+arch_initcall(ip5160rgw_init);
---- /dev/null
-+++ b/arch/ubicom32/mach-ip5k/board-ip5170dpf.c
-@@ -0,0 +1,279 @@
-+/*
-+ * arch/ubicom32/mach-ip5k/board-ip5170dpf.c
-+ *   Platform initialization for ip5160dpf board.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/gpio.h>
-+#include <linux/leds.h>
-+
-+#include <linux/i2c.h>
-+#include <linux/i2c-gpio.h>
-+
-+#include <linux/input.h>
-+#include <asm/board.h>
-+#include <asm/machdep.h>
-+#include <asm/ubicom32hid.h>
-+#include <asm/vdc_tio.h>
-+
-+/*
-+ * LEDs
-+ *
-+ * WLAN                       PD9     (Note this is shared with MISO, but we don't use it)
-+ * WPS                        PD8
-+ *
-+ * TODO: check triggers, are they generic?
-+ */
-+static struct gpio_led ip5170dpf_gpio_leds[] = {
-+      {
-+              .name                   = "d31:green:WLAN1",
-+              .default_trigger        = "WLAN1",
-+              .gpio                   = GPIO_RD_9,
-+              .active_low             = 1,
-+      },
-+      {
-+              .name                   = "d30:green:WPS",
-+              .default_trigger        = "WPS",
-+              .gpio                   = GPIO_RD_8,
-+              .active_low             = 1,
-+      },
-+};
-+
-+static struct gpio_led_platform_data ip5170dpf_gpio_led_platform_data = {
-+      .num_leds       = 2,
-+      .leds           = ip5170dpf_gpio_leds,
-+};
-+
-+static struct platform_device ip5170dpf_gpio_leds_device = {
-+      .name           = "leds-gpio",
-+      .id             = -1,
-+      .dev = {
-+              .platform_data = &ip5170dpf_gpio_led_platform_data,
-+      },
-+};
-+
-+/*
-+ * Backlight on the board PD0, hardware PWM
-+ */
-+static const struct ubicom32hid_button ip5170dpf_ubicom32hid_buttons[] = {
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_UP,
-+              .bit    = 0,
-+      },
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_LEFT,
-+              .bit    = 1,
-+      },
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_RIGHT,
-+              .bit    = 2,
-+      },
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_DOWN,
-+              .bit    = 3,
-+      },
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_ENTER,
-+              .bit    = 4,
-+      },
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_MENU,
-+              .bit    = 5,
-+      },
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_ESC,
-+              .bit    = 7,
-+      },
-+};
-+
-+static const struct ubicom32hid_ir ip5170dpf_ubicom32hid_ircodes[] = {
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_UP,
-+              .ir_code        = 0xF807916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_DOWN,
-+              .ir_code        = 0xF20D916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_LEFT,
-+              .ir_code        = 0xF609916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_RIGHT,
-+              .ir_code        = 0xF40B916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_ENTER,
-+              .ir_code        = 0xF50A916E
-+      },
-+      {       /* rotate */
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F1,
-+              .ir_code        = 0xF906916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_MENU,
-+              .ir_code        = 0xF708916E
-+      },
-+      {       /* font size */
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F2,
-+              .ir_code        = 0xF30C916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_ESC,
-+              .ir_code        = 0xF10E916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_VOLUMEUP,
-+              .ir_code        = 0xF00F916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_VOLUMEDOWN,
-+              .ir_code        = 0xED12916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_MUTE,
-+              .ir_code        = 0xEA15916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_INFO,
-+              .ir_code        = 0xEF10916E
-+      },
-+      {       /* Like */
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F3,
-+              .ir_code        = 0xEE11916E
-+      },
-+      {       /* Dislike */
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F4,
-+              .ir_code        = 0xEB14916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_POWER,
-+              .ir_code        = 0xFD02916E
-+      },
-+};
-+
-+static struct ubicom32hid_platform_data ip5170dpf_ubicom32hid_platform_data = {
-+      .gpio_reset             = GPIO_RA_4,
-+      .gpio_reset_polarity    = 0,
-+      .type                   = UBICOM32HID_BL_TYPE_BINARY,
-+      .invert                 = 0,
-+      .default_intensity      = 1,
-+      .buttons                = ip5170dpf_ubicom32hid_buttons,
-+      .nbuttons               = ARRAY_SIZE(ip5170dpf_ubicom32hid_buttons),
-+      .ircodes                = ip5170dpf_ubicom32hid_ircodes,
-+      .nircodes               = ARRAY_SIZE(ip5170dpf_ubicom32hid_ircodes),
-+};
-+
-+/*
-+ * Devices on the I2C bus
-+ */
-+static struct i2c_board_info __initdata ip5170dpf_i2c_board_info[] = {
-+      /*
-+       * U24, ubicom32hid
-+       */
-+      {
-+              .type           = "ubicom32hid",
-+              .addr           = 0x08,
-+              .platform_data  = &ip5170dpf_ubicom32hid_platform_data,
-+      },
-+
-+      /*
-+       * U14, CS4350 DAC, address 0x4B
-+       */
-+};
-+
-+/*
-+ * I2C bus on the board, SDA PF13, SCL PF14
-+ */
-+static struct i2c_gpio_platform_data ip5170dpf_i2c_data = {
-+      .sda_pin                = GPIO_RF_13,
-+      .scl_pin                = GPIO_RF_14,
-+      .sda_is_open_drain      = 0,
-+      .scl_is_open_drain      = 0,
-+      .scl_is_output_only     = 1,
-+      .udelay                 = 5,
-+};
-+
-+static struct platform_device ip5170dpf_i2c_device = {
-+      .name   = "i2c-gpio",
-+      .id     = 0,
-+      .dev    = {
-+              .platform_data = &ip5170dpf_i2c_data,
-+      },
-+};
-+
-+/*
-+ * List of all devices in our system
-+ */
-+static struct platform_device *ip5170dpf_devices[] __initdata = {
-+      &ip5170dpf_i2c_device,
-+      &ip5170dpf_gpio_leds_device,
-+};
-+
-+/*
-+ * ip5170dpf_init
-+ *    Called to add the devices which we have on this board
-+ */
-+static int __init ip5170dpf_init(void)
-+{
-+      ubi_gpio_init();
-+
-+      vdc_tio_init();
-+
-+      printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
-+      platform_add_devices(ip5170dpf_devices, ARRAY_SIZE(ip5170dpf_devices));
-+
-+      printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
-+      i2c_register_board_info(0, ip5170dpf_i2c_board_info, ARRAY_SIZE(ip5170dpf_i2c_board_info));
-+
-+      return 0;
-+}
-+
-+arch_initcall(ip5170dpf_init);
---- /dev/null
-+++ b/arch/ubicom32/mach-ip5k/Kconfig
-@@ -0,0 +1,28 @@
-+
-+config IP5170DPF
-+      bool "IP5170DPF"
-+      select UBICOM32_V3
-+      select I2C
-+      select I2C_GPIO
-+      select FB
-+      select FB_UBICOM32
-+      select BACKLIGHT_LCD_SUPPORT
-+      select BACKLIGHT_CLASS_DEVICE
-+      select UBICOM_HID
-+      select NEW_LEDS
-+      select LEDS_CLASS
-+      select LEDS_GPIO
-+      help
-+              IP5170 Digital Picture Frame board, 8005-1113, IP5K-BEV-0011-13 v1.3
-+
-+config IP5160DEV
-+      bool "IP5160Dev_Ver1Dot1"
-+      select UBICOM32_V3
-+      help
-+              Ubicom StreamEngine 5000 Development Board, IP5K-BDV-0004-11 v1.1
-+
-+config IP5160EVAL
-+      bool "IP5160RGWEval_Ver2Rev2"
-+      select UBICOM32_V3
-+      help
-+              Ubicom StreamEngine 5000 RGW Evaluation Board, IP5K-RGW-0004-11 v2.2
---- /dev/null
-+++ b/arch/ubicom32/mach-ip5k/Makefile
-@@ -0,0 +1,31 @@
-+#
-+# arch/ubicom32/mach-ip5k/Makefile
-+#     Makefile for boards which have an ip5k on them.
-+#
-+# (C) Copyright 2009, Ubicom, Inc.
-+#
-+# This file is part of the Ubicom32 Linux Kernel Port.
-+#
-+# The Ubicom32 Linux Kernel Port 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.
-+#
-+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+# see <http://www.gnu.org/licenses/>.
-+#
-+# Ubicom32 implementation derived from (with many thanks):
-+#   arch/m68knommu
-+#   arch/blackfin
-+#   arch/parisc
-+#
-+
-+obj-$(CONFIG_IP5170DPF)               += board-ip5170dpf.o
-+obj-$(CONFIG_IP5160DEV)               += board-ip5160dev.o
-+obj-$(CONFIG_IP5160EVAL)      += board-ip5160rgw.o
---- /dev/null
-+++ b/arch/ubicom32/mach-ip7k/board-ip7145dpf.c
-@@ -0,0 +1,715 @@
-+/*
-+ * arch/ubicom32/mach-ip7k/board-ip7145dpf.c
-+ *   Board file for IP7145DPF, rev 1.0, P/N 8007-0410
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/gpio.h>
-+
-+#include <linux/input.h>
-+
-+#include <linux/i2c.h>
-+#include <linux/i2c-gpio.h>
-+#include <linux/i2c/pca953x.h>
-+
-+#include <asm/board.h>
-+#include <asm/machdep.h>
-+#include <asm/ubicom32input.h>
-+#include <asm/ubicom32input_i2c.h>
-+#include <asm/ubicom32bl.h>
-+#include <asm/ubicom32lcdpower.h>
-+#include <asm/vdc_tio.h>
-+
-+#include <asm/ubicom32sd.h>
-+#include <asm/sd_tio.h>
-+#include <asm/devtree.h>
-+#include <asm/audio.h>
-+
-+#include <asm/ring_tio.h>
-+
-+/******************************************************************************
-+ * SD/IO Port F (Slot 1) platform data
-+ */
-+static struct resource ip7145dpf_portf_sd_resources[] = {
-+      /*
-+       * Send IRQ
-+       */
-+      [0] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Receive IRQ
-+       */
-+      [1] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Memory Mapped Registers
-+       */
-+      [2] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_MEM,
-+      },
-+};
-+
-+static struct ubicom32sd_card ip7145dpf_portf_sd_cards[] = {
-+      [0] = {
-+              .pin_wp         = IP7145DPF_IOB0,
-+              .wp_polarity    = 1,
-+              .pin_pwr        = IP7145DPF_IOB4,
-+              .pin_cd         = GPIO_RA_4,
-+      },
-+      [1] = {
-+              .pin_wp         = IP7145DPF_IOB1,
-+              .wp_polarity    = 1,
-+              .pin_pwr        = IP7145DPF_IOB5,
-+              .pin_cd         = GPIO_RA_6,
-+      },
-+};
-+
-+static struct ubicom32sd_platform_data ip7145dpf_portf_sd_platform_data = {
-+      .ncards         = 2,
-+      .cards          = ip7145dpf_portf_sd_cards,
-+};
-+
-+static struct platform_device ip7145dpf_portf_sd_device = {
-+      .name           = "ubicom32sd",
-+      .id             = 0,
-+      .resource       = ip7145dpf_portf_sd_resources,
-+      .num_resources  = ARRAY_SIZE(ip7145dpf_portf_sd_resources),
-+      .dev            = {
-+                      .platform_data = &ip7145dpf_portf_sd_platform_data,
-+      },
-+
-+};
-+
-+/*
-+ * ip7145dpf_portf_sd_init
-+ */
-+static void ip7145dpf_portf_sd_init(void)
-+{
-+      /*
-+       * Check the device tree for the sd_tio
-+       */
-+      struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portf_sd");
-+      if (!sd_node) {
-+              printk(KERN_INFO "PortF SDTIO not found\n");
-+              return;
-+      }
-+
-+      /*
-+       * Fill in the resources and platform data from devtree information
-+       */
-+      ip7145dpf_portf_sd_resources[0].start = sd_node->dn.sendirq;
-+      ip7145dpf_portf_sd_resources[1].start = sd_node->dn.recvirq;
-+      ip7145dpf_portf_sd_resources[2].start = (u32_t)&(sd_node->regs);
-+      ip7145dpf_portf_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs);
-+
-+      platform_device_register(&ip7145dpf_portf_sd_device);
-+}
-+
-+/******************************************************************************
-+ * SD/IO Port B (Slot 2) platform data
-+ */
-+static struct resource ip7145dpf_portb_sd_resources[] = {
-+      /*
-+       * Send IRQ
-+       */
-+      [0] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Receive IRQ
-+       */
-+      [1] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Memory Mapped Registers
-+       */
-+      [2] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_MEM,
-+      },
-+};
-+
-+static struct ubicom32sd_card ip7145dpf_portb_sd_cards[] = {
-+      [0] = {
-+              .pin_wp         = IP7145DPF_IOB2,
-+              .wp_polarity    = 1,
-+              .pin_pwr        = IP7145DPF_IOB6,
-+              .pin_cd         = IP7145DPF_IOB3,
-+      },
-+};
-+
-+static struct ubicom32sd_platform_data ip7145dpf_portb_sd_platform_data = {
-+      .ncards         = 1,
-+      .cards          = ip7145dpf_portb_sd_cards,
-+};
-+
-+static struct platform_device ip7145dpf_portb_sd_device = {
-+      .name           = "ubicom32sd",
-+      .id             = 1,
-+      .resource       = ip7145dpf_portb_sd_resources,
-+      .num_resources  = ARRAY_SIZE(ip7145dpf_portb_sd_resources),
-+      .dev            = {
-+                      .platform_data = &ip7145dpf_portb_sd_platform_data,
-+      },
-+
-+};
-+
-+/*
-+ * ip7145dpf_portb_sd_init
-+ */
-+static void ip7145dpf_portb_sd_init(void)
-+{
-+      /*
-+       * Check the device tree for the sd_tio
-+       */
-+      struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portb_sd");
-+      if (!sd_node) {
-+              printk(KERN_INFO "PortB SDTIO not found\n");
-+              return;
-+      }
-+
-+      /*
-+       * Fill in the resources and platform data from devtree information
-+       */
-+      ip7145dpf_portb_sd_resources[0].start = sd_node->dn.sendirq;
-+      ip7145dpf_portb_sd_resources[1].start = sd_node->dn.recvirq;
-+      ip7145dpf_portb_sd_resources[2].start = (u32_t)&(sd_node->regs);
-+      ip7145dpf_portb_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs);
-+
-+      platform_device_register(&ip7145dpf_portb_sd_device);
-+}
-+
-+
-+#ifdef IP7145DPF_USE_MMC_SPI
-+/******************************************************************************
-+ * SPI over GPIO (MMC_SPI)
-+ */
-+#include <linux/spi/spi.h>
-+#include <linux/spi/mmc_spi.h>
-+#include <linux/mmc/host.h>
-+#include <asm/ubicom32-spi-gpio.h>
-+
-+#define MMC_CS        GPIO_RF_5       // PF5 D3
-+#define MMC_CD        GPIO_RA_4       // PA4 CD
-+#define MMC_WP        IP7145DPF_IOB0  // IOB0 WP
-+#define MMC_PWR       IP7145DPF_IOB4  // IOB4 PWR
-+
-+/*
-+ * SPI bus over GPIO (for SD card)
-+ */
-+static struct ubicom32_spi_gpio_platform_data ip7145dpf_spi_gpio_data = {
-+      .pin_mosi       = GPIO_RF_0,    // PF0 CMD
-+      .pin_miso       = GPIO_RF_2,    // PF2 D0
-+      .pin_clk        = GPIO_RF_1,    // PF1 CLK
-+      .bus_num        = 0,            // We'll call this SPI bus 0
-+      .num_chipselect = 1,            // only one device on this SPI bus
-+};
-+
-+static struct platform_device ip7145dpf_spi_gpio_device = {
-+      .name   = "ubicom32-spi-gpio",
-+      .id     = 0,
-+      .dev    = {
-+              .platform_data = &ip7145dpf_spi_gpio_data,
-+      },
-+};
-+
-+/*
-+ * ip7145dpf_mmc_spi_setpower_slot_a
-+ *    Set the power state for slot A
-+ */
-+static void ip7145dpf_mmc_spi_setpower_slot_a(struct device *dev, unsigned int vdd)
-+{
-+      struct mmc_spi_platform_data *pd = dev->platform_data;
-+
-+      /*
-+       * Power is inverted, we could tell the IOB to do it, but it's cleaner this way.
-+       */
-+      if ((1 << vdd) & pd->ocr_mask) {
-+              gpio_set_value(MMC_PWR, 0);
-+              return;
-+      }
-+      gpio_set_value(MMC_PWR, 1);
-+}
-+
-+/*
-+ * ip7145dpf_mmc_spi_get_cd_slot_a
-+ *    Get the CD bit for slot A
-+ */
-+static int ip7145dpf_mmc_spi_get_cd_slot_a(struct device *dev)
-+{
-+      /*
-+       * Note that the sense of the GPIO is inverted
-+       */
-+      return !gpio_get_value(MMC_CD);
-+}
-+
-+/*
-+ * ip7145dpf_mmc_spi_get_ro_slot_a
-+ *    Get the WP bit for slot A
-+ */
-+static int ip7145dpf_mmc_spi_get_ro_slot_a(struct device *dev)
-+{
-+      /*
-+       * Note that the sense of the GPIO is inverted, we could tell the IOB to do it, but
-+       * it's clearer this way.
-+       */
-+      return !gpio_get_value(MMC_WP);
-+}
-+
-+/*
-+ * ip7145dpf_mmc_spi_exit_slot_a
-+ *    Free the appropriate GPIOs for slot A SD slot.
-+ */
-+static void ip7145dpf_mmc_spi_exit_slot_a(struct device *dev, void *appdata)
-+{
-+      gpio_free(MMC_CD);
-+      gpio_free(MMC_CS);
-+      gpio_free(MMC_WP);
-+      gpio_free(MMC_PWR);
-+      platform_device_unregister(&ip7145dpf_spi_gpio_device);
-+}
-+
-+/*
-+ * ip7145dpf_mmc_spi_init_slot_a
-+ *    Allocate the appropriate GPIOs for slot A SD slot.
-+ *    WP is on IOB0, CD is PA4, CS is on PF5
-+ *    TODO: make CD an interrupt
-+ */
-+static int ip7145dpf_mmc_spi_init_slot_a(void)
-+{
-+      int ret = gpio_request(MMC_CD, "mmc-a-cd");
-+      if (ret) {
-+              printk(KERN_ERR "%s: could not request mmc-a-cd pin\n", __FUNCTION__);
-+              return -ENOSYS;
-+      }
-+      gpio_direction_input(MMC_CD);
-+
-+      ret = gpio_request(MMC_CS, "mmc-a-cs");
-+      if (ret) {
-+              printk(KERN_ERR "%s: could not request mmc-a-cs pin\n", __FUNCTION__);
-+              goto no_cs;
-+      }
-+      gpio_direction_output(MMC_CS, 0);
-+
-+      ret = gpio_request(MMC_WP, "mmc-a-wp");
-+      if (ret) {
-+              printk(KERN_ERR "%s: could not request mmc-a-wp pin\n", __FUNCTION__);
-+              goto no_wp;
-+      }
-+      gpio_direction_input(MMC_WP);
-+
-+      /*
-+       * Start off with power off
-+       */
-+      ret = gpio_request(MMC_PWR, "mmc-a-pwr");
-+      if (ret) {
-+              printk(KERN_ERR "%s: could not request mmc-a-pwr pin\n", __FUNCTION__);
-+              goto no_pwr;
-+      }
-+      ret = gpio_direction_output(MMC_PWR, 1);
-+
-+      return 0;
-+
-+no_pwr:
-+      gpio_free(MMC_WP);
-+
-+no_wp:
-+      gpio_free(MMC_CS);
-+
-+no_cs:
-+      gpio_free(MMC_CD);
-+      return -ENOSYS;
-+}
-+
-+/*
-+ * MMC_SPI driver (currently bitbang)
-+ */
-+static struct mmc_spi_platform_data ip7145dpf_mmc_platform_data = {
-+      .ocr_mask       = MMC_VDD_33_34,
-+      .exit           = ip7145dpf_mmc_spi_exit_slot_a,
-+      .get_ro         = ip7145dpf_mmc_spi_get_ro_slot_a,
-+      .get_cd         = ip7145dpf_mmc_spi_get_cd_slot_a,
-+
-+      .setpower       = ip7145dpf_mmc_spi_setpower_slot_a,
-+      .powerup_msecs  = 500,
-+
-+      .detect_delay   = 100,
-+
-+      .caps           = MMC_CAP_NEEDS_POLL,
-+};
-+
-+static struct ubicom32_spi_gpio_controller_data ip7145dpf_mmc_controller_data = {
-+      .pin_cs =  MMC_CS,
-+};
-+
-+static struct spi_board_info ip7145dpf_spi_board_info[] = {
-+      {
-+              .modalias = "mmc_spi",
-+              .bus_num = 0,
-+              .chip_select = 0,
-+              .max_speed_hz = 2000000,
-+              .platform_data = &ip7145dpf_mmc_platform_data,
-+              .controller_data = &ip7145dpf_mmc_controller_data,
-+      }
-+};
-+#endif /* IP7145DPF_USE_MMC_SPI */
-+
-+/*
-+ * ip7145dpf_u72_setup
-+ *    Called by I2C to tell us that u72 is setup.
-+ *
-+ * This function is called by I2C to tell us that u72 has been setup.  All
-+ * devices which rely on this chip being initialized (or even present) need to
-+ * be initialized in this function otherwise they may get initialized too early.
-+ *
-+ * Currently the only device depending on u72 is the SPI
-+ */
-+static int __init ip7145dpf_u72_setup(struct i2c_client *client, unsigned gpio, unsigned ngpio, void *context)
-+{
-+#ifdef IP7145DPF_USE_MMC_SPI
-+      if (ip7145dpf_mmc_spi_init_slot_a()) {
-+              printk(KERN_ERR "%s: could not request mmc resources\n", __FUNCTION__);
-+      } else {
-+              printk(KERN_INFO "%s: registering SPI resources\n", __FUNCTION__);
-+              spi_register_board_info(ip7145dpf_spi_board_info, ARRAY_SIZE(ip7145dpf_spi_board_info));
-+              platform_device_register(&ip7145dpf_spi_gpio_device);
-+      }
-+#else
-+      /*
-+       * Initialize the Port F/Port B SD slots
-+       */
-+      ip7145dpf_portf_sd_init();
-+      ip7145dpf_portb_sd_init();
-+#endif
-+      return 0;
-+}
-+
-+/******************************************************************************
-+ * LCD VGH on the board at PE6
-+ */
-+static struct ubicom32lcdpower_platform_data ip7145dpf_lcdpower_data = {
-+      .vgh_gpio               = GPIO_RE_6,
-+      .vgh_polarity           = true,
-+};
-+
-+static struct platform_device ip7145dpf_lcdpower_device = {
-+      .name   = "ubicom32lcdpower",
-+      .id     = -1,
-+      .dev    = {
-+              .platform_data = &ip7145dpf_lcdpower_data,
-+      },
-+};
-+
-+/******************************************************************************
-+ * Backlight on the board PD0, hardware PWM
-+ */
-+static struct ubicom32bl_platform_data ip7145dpf_backlight_data = {
-+      .type                   = UBICOM32BL_TYPE_PWM,
-+      .pwm_channel            = 2,
-+      .pwm_prescale           = 15,
-+      .pwm_period             = 60,
-+      .default_intensity      = 0x80,
-+};
-+
-+static struct platform_device ip7145dpf_backlight_device = {
-+      .name   = "ubicom32bl",
-+      .id     = -1,
-+      .dev    = {
-+              .platform_data = &ip7145dpf_backlight_data,
-+      },
-+};
-+
-+/******************************************************************************
-+ * Ubicom32Input on I2C, U48 MAX7310, address 0x18, 8 bits
-+ */
-+static struct ubicom32input_i2c_button ip7145dpf_ubicom32input_i2c_u48_buttons[] = {
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_UP,
-+              .bit            = 0,
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_LEFT,
-+              .bit            = 1,
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_RIGHT,
-+              .bit            = 2,
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_DOWN,
-+              .bit            = 3,
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_ENTER,
-+              .bit            = 4,
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_MENU,
-+              .bit            = 5,
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_ESC,
-+              .bit            = 6,
-+              .active_low     = 1,
-+      },
-+};
-+
-+static struct ubicom32input_i2c_platform_data ip7145dpf_ubicom32input_i2c_u48_platform_data = {
-+      .buttons        = ip7145dpf_ubicom32input_i2c_u48_buttons,
-+      .nbuttons       = ARRAY_SIZE(ip7145dpf_ubicom32input_i2c_u48_buttons),
-+      .name           = "Ubicom32 Input I2C U48",
-+};
-+
-+/******************************************************************************
-+ * Additional GPIO chips
-+ */
-+static struct pca953x_platform_data ip7145dpf_gpio_u72_platform_data = {
-+      .gpio_base = IP7145DPF_U72_BASE,
-+      .setup = ip7145dpf_u72_setup,
-+};
-+
-+/******************************************************************************
-+ * Devices on the I2C bus
-+ */
-+static struct i2c_board_info __initdata ip7145dpf_i2c_board_info[] = {
-+      /*
-+       * U51, S35390A RTC, address 0x30
-+       */
-+      {
-+              .type           = "s35390a",
-+              .addr           = 0x30,
-+      },
-+
-+      /*
-+       * U48, MAX7310 IO expander, 8 bits, address 0x18
-+       */
-+      {
-+              .type           = "ubicom32in_max7310",
-+              .addr           = 0x18,
-+              .platform_data  = &ip7145dpf_ubicom32input_i2c_u48_platform_data,
-+      },
-+
-+      /*
-+       * U72, MAX7310 IOB expander, 8 bits, address 0x19
-+       */
-+      {
-+              .type           = "max7310",
-+              .addr           = 0x19,
-+              .platform_data  = &ip7145dpf_gpio_u72_platform_data,
-+      },
-+};
-+
-+/*
-+ * I2C bus on the board, SDA PE1, SCL PE2
-+ */
-+static struct i2c_gpio_platform_data ip7145dpf_i2c_data = {
-+      .sda_pin                = GPIO_RE_1,
-+      .scl_pin                = GPIO_RE_2,
-+      .sda_is_open_drain      = 0,
-+      .scl_is_open_drain      = 0,
-+};
-+
-+static struct platform_device ip7145dpf_i2c_device = {
-+      .name   = "i2c-gpio",
-+      .id     = 0,
-+      .dev    = {
-+              .platform_data = &ip7145dpf_i2c_data,
-+      },
-+};
-+
-+/******************************************************************************
-+ * Use ubicom32input driver to monitor the various pushbuttons on this board.
-+ *
-+ * WPS                        PF12
-+ * FACT_DEFAULT               PF13
-+ * POWER              PE4
-+ *
-+ * Not sutable for the keypad buttons since those run on I2C GPIO.  The polling
-+ * of ubicom32input would seem to be excessive for this.
-+ *
-+ * TODO: pick some ubicom understood EV_xxx define for WPS and Fact Default
-+ */
-+static struct ubicom32input_button ip7145dpf_ubicom32input_buttons[] = {
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F1,
-+              .gpio           = GPIO_RF_12,
-+              .desc           = "WPS",
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F2,
-+              .gpio           = GPIO_RF_13,
-+              .desc           = "Factory Default",
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_POWER,
-+              .gpio           = GPIO_RE_4,
-+              .desc           = "Power",
-+              .active_low     = 1,
-+      },
-+};
-+
-+static struct ubicom32input_platform_data ip7145dpf_ubicom32input_data = {
-+      .buttons        = ip7145dpf_ubicom32input_buttons,
-+      .nbuttons       = ARRAY_SIZE(ip7145dpf_ubicom32input_buttons),
-+};
-+
-+static struct platform_device ip7145dpf_ubicom32input_device = {
-+      .name   = "ubicom32input",
-+      .id     = -1,
-+      .dev    = {
-+              .platform_data = &ip7145dpf_ubicom32input_data,
-+      },
-+};
-+
-+/*
-+ * List of all devices in our system
-+ */
-+static struct platform_device *ip7145dpf_devices[] __initdata = {
-+      &ip7145dpf_i2c_device,
-+      &ip7145dpf_lcdpower_device,
-+      &ip7145dpf_backlight_device,
-+      &ip7145dpf_ubicom32input_device,
-+};
-+
-+/*
-+ * ip7145dpf_power_off
-+ *    Called to turn the power off for this board
-+ */
-+static void ip7145dpf_power_off(void)
-+{
-+      gpio_set_value(GPIO_RE_5, 0);
-+}
-+
-+/*
-+ * ip7145dpf_init
-+ *    Called to add the devices which we have on this board
-+ */
-+static int __init ip7145dpf_init(void)
-+{
-+      int ret;
-+      struct platform_device *audio_dev;
-+
-+      ubi_gpio_init();
-+
-+#ifdef CONFIG_UIO_UBICOM32RING
-+      ring_tio_init("decoder_ring");
-+#endif
-+
-+      /*
-+       * Start up the video driver first
-+       */
-+      vdc_tio_init();
-+
-+      /*
-+       * Take over holding of the power from the system
-+       */
-+      ret = gpio_request(GPIO_RE_5, "power_hold");
-+      if (ret) {
-+              printk(KERN_ERR "%s: could not request power hold GPIO\n", __FUNCTION__);
-+      }
-+      gpio_direction_output(GPIO_RE_5, 1);
-+      mach_power_off = ip7145dpf_power_off;
-+
-+      /*
-+       * USB SEL_HOST_USB line
-+       */
-+      ret = gpio_request(GPIO_RF_11, "SEL_HOST_USB");
-+      if (ret) {
-+              printk(KERN_ERR "%s: could not request SEL_HOST_USB GPIO\n", __FUNCTION__);
-+      }
-+      gpio_direction_output(GPIO_RF_11, 0);
-+
-+      /*
-+       * Setup audio
-+       */
-+      audio_dev = audio_device_alloc("snd-ubi32-generic", "audio", "audio-i2sout", 0);
-+      if (audio_dev) {
-+              platform_device_register(audio_dev);
-+      }
-+
-+      /*
-+       * Register all of the devices we have on this board
-+       */
-+      printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
-+      platform_add_devices(ip7145dpf_devices, ARRAY_SIZE(ip7145dpf_devices));
-+
-+      /*
-+       * Register all of the devices which sit on the I2C bus
-+       */
-+      printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
-+      i2c_register_board_info(0, ip7145dpf_i2c_board_info, ARRAY_SIZE(ip7145dpf_i2c_board_info));
-+
-+      /*
-+       * We have to initialize the SPI after the I2C IOB gets setup. SPI is initialized in
-+       * ip7145dpf_u72_setup
-+       */
-+
-+      return 0;
-+}
-+
-+arch_initcall(ip7145dpf_init);
---- /dev/null
-+++ b/arch/ubicom32/mach-ip7k/board-ip7160bringup.c
-@@ -0,0 +1,134 @@
-+/*
-+ * arch/ubicom32/mach-ip7k/board-ip7160bringup.c
-+ *   Support for the IP7160 bringup board.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/gpio.h>
-+#include <linux/leds.h>
-+#include <linux/delay.h>
-+#include <linux/input.h>
-+
-+#include <asm/board.h>
-+#include <asm/machdep.h>
-+#include <asm/ubicom32input.h>
-+
-+#ifdef CONFIG_SERIAL_UBI32_SERDES
-+#include <asm/ubicom32suart.h>
-+#endif
-+
-+/*
-+ * Use ubicom32input driver to monitor the various pushbuttons on this board.
-+ *
-+ * WPS                        PD5
-+ * FACT_DEFAULT               PD6
-+ *
-+ * TODO: pick some ubicom understood EV_xxx define for WPS and Fact Default
-+ */
-+static struct ubicom32input_button ip7160bringup_ubicom32input_buttons[] = {
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F1,
-+              .gpio           = GPIO_RD_5,
-+              .desc           = "WPS",
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F2,
-+              .gpio           = GPIO_RD_6,
-+              .desc           = "Factory Default",
-+              .active_low     = 1,
-+      },
-+};
-+
-+static struct ubicom32input_platform_data ip7160bringup_ubicom32input_data = {
-+      .buttons        = ip7160bringup_ubicom32input_buttons,
-+      .nbuttons       = ARRAY_SIZE(ip7160bringup_ubicom32input_buttons),
-+};
-+
-+static struct platform_device ip7160bringup_ubicom32input_device = {
-+      .name   = "ubicom32input",
-+      .id     = -1,
-+      .dev    = {
-+              .platform_data = &ip7160bringup_ubicom32input_data,
-+      },
-+};
-+
-+#ifdef CONFIG_SERIAL_UBI32_SERDES
-+static struct resource ip7160bringup_ubicom32_suart_resources[] = {
-+      {
-+              .start  = RE,
-+              .end    = RE,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+      {
-+              .start  = PORT_OTHER_INT(RE),
-+              .end    = PORT_OTHER_INT(RE),
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+      {
-+              .start  = 250000000,
-+              .end    = 250000000,
-+              .flags  = UBICOM32_SUART_IORESOURCE_CLOCK,
-+      },
-+};
-+
-+static struct platform_device ip7160bringup_ubicom32_suart_device = {
-+      .name           = "ubicom32suart",
-+      .id             = -1,
-+      .num_resources  = ARRAY_SIZE(ip7160bringup_ubicom32_suart_resources),
-+      .resource       = ip7160bringup_ubicom32_suart_resources,
-+};
-+#endif
-+
-+/*
-+ * List of all devices in our system
-+ */
-+static struct platform_device *ip7160bringup_devices[] __initdata = {
-+#ifdef CONFIG_SERIAL_UBI32_SERDES
-+      &ip7160bringup_ubicom32_suart_device,
-+#endif
-+      &ip7160bringup_ubicom32input_device,
-+};
-+
-+/*
-+ * ip7160bringup_init
-+ *    Called to add the devices which we have on this board
-+ */
-+static int __init ip7160bringup_init(void)
-+{
-+      board_init();
-+
-+      ubi_gpio_init();
-+
-+      printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
-+      platform_add_devices(ip7160bringup_devices, ARRAY_SIZE(ip7160bringup_devices));
-+
-+      return 0;
-+}
-+
-+arch_initcall(ip7160bringup_init);
---- /dev/null
-+++ b/arch/ubicom32/mach-ip7k/board-ip7160dpf.c
-@@ -0,0 +1,326 @@
-+/*
-+ * arch/ubicom32/mach-ip7k/board-ip7160dpf.c
-+ *   Platform initialization for ip7160dpf board.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/delay.h>
-+#include <linux/gpio.h>
-+
-+#include <linux/i2c.h>
-+#include <linux/i2c-gpio.h>
-+
-+#include <linux/input.h>
-+
-+#include <asm/board.h>
-+#include <asm/machdep.h>
-+#include <asm/ubicom32hid.h>
-+#include <asm/vdc_tio.h>
-+#include <asm/audio.h>
-+
-+/*
-+ * Backlight on the board PD0, hardware PWM
-+ */
-+static const struct ubicom32hid_button ip7160dpf_ubicom32hid_buttons[] = {
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_UP,
-+              .bit    = 0,
-+      },
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_LEFT,
-+              .bit    = 1,
-+      },
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_RIGHT,
-+              .bit    = 2,
-+      },
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_DOWN,
-+              .bit    = 3,
-+      },
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_ENTER,
-+              .bit    = 4,
-+      },
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_MENU,
-+              .bit    = 5,
-+      },
-+      {
-+              .type   = EV_KEY,
-+              .code   = KEY_ESC,
-+              .bit    = 7,
-+      },
-+};
-+
-+static const struct ubicom32hid_ir ip7160dpf_ubicom32hid_ircodes[] = {
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_UP,
-+              .ir_code        = 0xF807916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_DOWN,
-+              .ir_code        = 0xF20D916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_LEFT,
-+              .ir_code        = 0xF609916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_RIGHT,
-+              .ir_code        = 0xF40B916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_ENTER,
-+              .ir_code        = 0xF50A916E
-+      },
-+      {       /* rotate */
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F1,
-+              .ir_code        = 0xF906916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_MENU,
-+              .ir_code        = 0xF708916E
-+      },
-+      {       /* font size */
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F2,
-+              .ir_code        = 0xF30C916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_ESC,
-+              .ir_code        = 0xF10E916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_VOLUMEUP,
-+              .ir_code        = 0xF00F916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_VOLUMEDOWN,
-+              .ir_code        = 0xED12916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_MUTE,
-+              .ir_code        = 0xEA15916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_INFO,
-+              .ir_code        = 0xEF10916E
-+      },
-+      {       /* Like */
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F3,
-+              .ir_code        = 0xEE11916E
-+      },
-+      {       /* Dislike */
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F4,
-+              .ir_code        = 0xEB14916E
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_POWER,
-+              .ir_code        = 0xFD02916E
-+      },
-+};
-+
-+static struct ubicom32hid_platform_data ip7160dpf_ubicom32hid_platform_data = {
-+      .gpio_reset             = GPIO_RI_5,
-+      .gpio_reset_polarity    = 0,
-+      .type                   = UBICOM32HID_BL_TYPE_PWM,
-+      .invert                 = 0,
-+      .default_intensity      = 128,
-+      .buttons                = ip7160dpf_ubicom32hid_buttons,
-+      .nbuttons               = ARRAY_SIZE(ip7160dpf_ubicom32hid_buttons),
-+      .ircodes                = ip7160dpf_ubicom32hid_ircodes,
-+      .nircodes               = ARRAY_SIZE(ip7160dpf_ubicom32hid_ircodes),
-+};
-+
-+/*
-+ * Devices on the I2C bus
-+ *    This board has a "bus 2" which is isolated from the main bus by U47
-+ *    and pin RI0.  It should be safe to always enable bus 2 by setting
-+ *    RI0 to low, however, it should be noted that on all existing configurations
-+ *    of this board, U49 and U51 are not populated.
-+ */
-+static struct i2c_board_info __initdata ip7160dpf_i2c_board_info[] = {
-+      /*
-+       * U37, CS4350 DAC, address 0x4B, bus 2
-+       *      THIS ENTRY MUST BE FIRST
-+       */
-+      {
-+              .type           = "cs4350",
-+              .addr           = 0x4B,
-+      }
-+
-+      /*
-+       * U24, ubicom32hid
-+       */
-+      {
-+              .type           = "ubicom32hid",
-+              .addr           = 0x08,
-+              .platform_data  = &ip7160dpf_ubicom32hid_platform_data,
-+      },
-+
-+      /*
-+       * U49, ISL29001 Ambient Light Sensor, address 0x44, bus 2 (may not be stuffed)
-+       */
-+
-+      /*
-+       * U51, S35390A RTC, address 0x30, bus 2 (may not be stuffed)
-+       */
-+#ifdef CONFIG_RTC_DRV_S35390A
-+      {
-+              .type           = "s35390a",
-+              .addr           = 0x30,
-+      },
-+#endif
-+};
-+
-+/*
-+ * I2C bus on the board, SDA PI1, SCL PI2
-+ */
-+static struct i2c_gpio_platform_data ip7160dpf_i2c_data = {
-+      .sda_pin                = GPIO_RI_1,
-+      .scl_pin                = GPIO_RI_2,
-+      .sda_is_open_drain      = 0,
-+      .scl_is_open_drain      = 0,
-+      .scl_is_output_only     = 1,
-+      .udelay                 = 6,
-+};
-+
-+static struct platform_device ip7160dpf_i2c_device = {
-+      .name   = "i2c-gpio",
-+      .id     = 0,
-+      .dev    = {
-+              .platform_data = &ip7160dpf_i2c_data,
-+      },
-+};
-+
-+/*
-+ * List of all devices in our system
-+ */
-+static struct platform_device *ip7160dpf_devices[] __initdata = {
-+      &ip7160dpf_i2c_device,
-+};
-+
-+/*
-+ * ip7160dpf_power_off
-+ *    Called to turn the power off for this board
-+ */
-+static void ip7160dpf_power_off(void)
-+{
-+      gpio_set_value(GPIO_RF_14, 0);
-+}
-+
-+/*
-+ * ip7160dpf_init
-+ *    Called to add the devices which we have on this board
-+ */
-+static int __init ip7160dpf_init(void)
-+{
-+      int ret;
-+      struct platform_device *audio_dev;
-+
-+      ubi_gpio_init();
-+
-+      /*
-+       * Hold the POWER_HOLD line
-+       */
-+      ret = gpio_request(GPIO_RF_14, "POWER_HOLD");
-+      if (ret) {
-+              printk(KERN_ERR "%s: could not request POWER_HOLD GPIO\n", __FUNCTION__);
-+      }
-+      gpio_direction_output(GPIO_RF_14, 1);
-+      mach_power_off = ip7160dpf_power_off;
-+
-+      /*
-+       * USB SEL_HOST_USB line
-+       */
-+      ret = gpio_request(GPIO_RI_13, "SEL_HOST_USB");
-+      if (ret) {
-+              printk(KERN_ERR "%s: could not request SEL_HOST_USB GPIO\n", __FUNCTION__);
-+      }
-+      gpio_direction_output(GPIO_RI_13, 0);
-+
-+      /*
-+       * USB/DAC nRESET line
-+       */
-+      ret = gpio_request(GPIO_RI_3, "USB_DAC_nRESET");
-+      if (ret) {
-+              printk(KERN_ERR "%s: could not request USB_DAC_nRESET GPIO\n", __FUNCTION__);
-+      }
-+      gpio_direction_output(GPIO_RI_3, 0);
-+      udelay(1);
-+      gpio_direction_output(GPIO_RI_3, 1);
-+
-+      /*
-+       * I2C BUS2 Disable line
-+       */
-+      ret = gpio_request(GPIO_RI_0, "DISABLE_BUS2");
-+      if (ret) {
-+              printk(KERN_ERR "%s: could not request DISABLE_BUS2 GPIO\n", __FUNCTION__);
-+      }
-+      gpio_direction_output(GPIO_RI_0, 0);
-+
-+      vdc_tio_init();
-+
-+      printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
-+      platform_add_devices(ip7160dpf_devices, ARRAY_SIZE(ip7160dpf_devices));
-+
-+      /*
-+       * Allocate the audio driver if we can
-+       */
-+      audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio-i2sout", 0);
-+      if (audio_dev) {
-+              ip7160dpf_i2c_board_info[0].platform_data = audio_dev;
-+      }
-+
-+      printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
-+      i2c_register_board_info(0, ip7160dpf_i2c_board_info, ARRAY_SIZE(ip7160dpf_i2c_board_info));
-+
-+      return 0;
-+}
-+
-+arch_initcall(ip7160dpf_init);
---- /dev/null
-+++ b/arch/ubicom32/mach-ip7k/board-ip7160rgw.c
-@@ -0,0 +1,355 @@
-+/*
-+ * arch/ubicom32/mach-ip7k/board-ip7160rgw.c
-+ *   Platform initialization for ip7160rgw board.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/gpio.h>
-+#include <linux/leds.h>
-+#include <linux/delay.h>
-+#include <linux/input.h>
-+#include <linux/spi/spi.h>
-+
-+#include <asm/board.h>
-+#include <asm/machdep.h>
-+#include <asm/ubicom32input.h>
-+
-+#ifdef CONFIG_SERIAL_UBI32_SERDES
-+#include <asm/ubicom32suart.h>
-+#endif
-+
-+#include <asm/ubicom32-spi-gpio.h>
-+#include <asm/switch-dev.h>
-+
-+#ifdef CONFIG_IP7160RGWLCD
-+#include <linux/i2c.h>
-+#include <linux/i2c-gpio.h>
-+/*
-+ * LCD Adapter board 8007-092x support
-+ *
-+ * Touch controller
-+ *
-+ * Connected via I2C bus, interrupt on PA6
-+ */
-+#include <linux/i2c/tsc2007.h>
-+
-+/*
-+ * ip7160rgwlcd_tsc2007_exit_platform_hw
-+ */
-+static void ip7160rgwlcd_tsc2007_exit_platform_hw(void)
-+{
-+      UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 17);
-+      gpio_free(GPIO_RA_5);
-+}
-+
-+/*
-+ * ip7160rgwlcd_tsc2007_init_platform_hw
-+ */
-+static int ip7160rgwlcd_tsc2007_init_platform_hw(void)
-+{
-+      int res = gpio_request(GPIO_RA_5, "TSC2007_IRQ");
-+      if (res) {
-+              return res;
-+      }
-+
-+      UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 17);
-+      UBICOM32_IO_PORT(RA)->ctl0 |= (0x02 << 17);
-+      return 0;
-+}
-+
-+/*
-+ * ip7160rgwlcd_tsc2007_get_pendown_state
-+ */
-+static int ip7160rgwlcd_tsc2007_get_pendown_state(void)
-+{
-+      return !gpio_get_value(GPIO_RA_5);
-+}
-+
-+static struct tsc2007_platform_data ip7160rgwlcd_tsc2007_data = {
-+      .model                  = 2007,
-+      .x_plate_ohms           = 350,
-+      .get_pendown_state      = ip7160rgwlcd_tsc2007_get_pendown_state,
-+      .init_platform_hw       = ip7160rgwlcd_tsc2007_init_platform_hw,
-+      .exit_platform_hw       = ip7160rgwlcd_tsc2007_exit_platform_hw,
-+};
-+
-+/******************************************************************************
-+ * I2C bus on the board, SDA PI14, SCL PI13
-+ */
-+static struct i2c_gpio_platform_data ip7160rgwlcd_i2c_data = {
-+      .sda_pin                = GPIO_RI_14,
-+      .scl_pin                = GPIO_RI_13,
-+      .sda_is_open_drain      = 0,
-+      .scl_is_open_drain      = 0,
-+      .udelay                 = 50,
-+};
-+
-+static struct platform_device ip7160rgwlcd_i2c_device = {
-+      .name   = "i2c-gpio",
-+      .id     = 0,
-+      .dev    = {
-+              .platform_data = &ip7160rgwlcd_i2c_data,
-+      },
-+};
-+
-+static struct i2c_board_info __initdata ip7160rgwlcd_i2c_board_info[] = {
-+      {
-+              .type = "tsc2007",
-+              .addr = 0x48,
-+              .irq = 45, // RA5
-+              .platform_data = &ip7160rgwlcd_tsc2007_data,
-+      },
-+};
-+
-+#endif
-+
-+/*
-+ * SPI bus over GPIO for Gigabit Ethernet Switch
-+ *    U58:
-+ *            MOSI    PE0
-+ *            MISO    PE1
-+ *            CLK     PE3
-+ *            CS      PE2
-+ */
-+static struct ubicom32_spi_gpio_platform_data ip7160rgw_spi_gpio_data = {
-+      .pin_mosi       = GPIO_RE_0,
-+      .pin_miso       = GPIO_RE_1,
-+      .pin_clk        = GPIO_RE_3,
-+      .bus_num        = 0,            // We'll call this SPI bus 0
-+      .num_chipselect = 1,            // only one device on this SPI bus
-+      .clk_default    = 1,
-+};
-+
-+static struct platform_device ip7160rgw_spi_gpio_device = {
-+      .name   = "ubicom32-spi-gpio",
-+      .id     = 0,
-+      .dev    = {
-+              .platform_data = &ip7160rgw_spi_gpio_data,
-+      },
-+};
-+
-+static struct ubicom32_spi_gpio_controller_data ip7160rgw_bcm539x_controller_data = {
-+      .pin_cs = GPIO_RE_2,
-+};
-+
-+static struct switch_core_platform_data ip7160rgw_bcm539x_platform_data = {
-+      .flags          = SWITCH_DEV_FLAG_HW_RESET,
-+      .pin_reset      = GPIO_RE_4,
-+      .name           = "bcm539x",
-+};
-+
-+static struct spi_board_info ip7160rgw_spi_board_info[] = {
-+      {
-+              .modalias               = "bcm539x-spi",
-+              .bus_num                = 0,
-+              .chip_select            = 0,
-+              .max_speed_hz           = 2000000,
-+              .platform_data          = &ip7160rgw_bcm539x_platform_data,
-+              .controller_data        = &ip7160rgw_bcm539x_controller_data,
-+              .mode                   = SPI_MODE_3,
-+      }
-+};
-+
-+/*
-+ * LEDs
-+ *
-+ * WLAN1              PD0     (PWM capable)
-+ * WLAN2              PD1
-+ * USB2.0             PD2
-+ * Status             PD3
-+ * WPS                        PD4
-+ *
-+ * TODO: check triggers, are they generic?
-+ */
-+static struct gpio_led ip7160rgw_gpio_leds[] = {
-+      {
-+              .name                   = "d53:green:WLAN1",
-+              .default_trigger        = "WLAN1",
-+              .gpio                   = GPIO_RD_0,
-+              .active_low             = 1,
-+      },
-+      {
-+              .name                   = "d54:green:WLAN2",
-+              .default_trigger        = "WLAN2",
-+              .gpio                   = GPIO_RD_1,
-+              .active_low             = 1,
-+      },
-+      {
-+              .name                   = "d55:green:USB",
-+              .default_trigger        = "USB",
-+              .gpio                   = GPIO_RD_2,
-+              .active_low             = 1,
-+      },
-+      {
-+              .name                   = "d56:green:Status",
-+              .default_trigger        = "Status",
-+              .gpio                   = GPIO_RD_3,
-+              .active_low             = 1,
-+      },
-+      {
-+              .name                   = "d57:green:WPS",
-+              .default_trigger        = "WPS",
-+              .gpio                   = GPIO_RD_4,
-+              .active_low             = 1,
-+      },
-+};
-+
-+static struct gpio_led_platform_data ip7160rgw_gpio_led_platform_data = {
-+      .num_leds       = 5,
-+      .leds           = ip7160rgw_gpio_leds,
-+};
-+
-+static struct platform_device ip7160rgw_gpio_leds_device = {
-+      .name           = "leds-gpio",
-+      .id             = -1,
-+      .dev = {
-+              .platform_data = &ip7160rgw_gpio_led_platform_data,
-+      },
-+};
-+
-+/*
-+ * Use ubicom32input driver to monitor the various pushbuttons on this board.
-+ *
-+ * WPS                        PD5
-+ * FACT_DEFAULT               PD6
-+ *
-+ * TODO: pick some ubicom understood EV_xxx define for WPS and Fact Default
-+ */
-+static struct ubicom32input_button ip7160rgw_ubicom32input_buttons[] = {
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F1,
-+              .gpio           = GPIO_RD_5,
-+              .desc           = "WPS",
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_FN_F2,
-+              .gpio           = GPIO_RD_6,
-+              .desc           = "Factory Default",
-+              .active_low     = 1,
-+      },
-+};
-+
-+static struct ubicom32input_platform_data ip7160rgw_ubicom32input_data = {
-+      .buttons        = ip7160rgw_ubicom32input_buttons,
-+      .nbuttons       = ARRAY_SIZE(ip7160rgw_ubicom32input_buttons),
-+};
-+
-+static struct platform_device ip7160rgw_ubicom32input_device = {
-+      .name   = "ubicom32input",
-+      .id     = -1,
-+      .dev    = {
-+              .platform_data = &ip7160rgw_ubicom32input_data,
-+      },
-+};
-+
-+#ifdef CONFIG_SERIAL_UBI32_SERDES
-+static struct resource ip7160rgw_ubicom32_suart_resources[] = {
-+      {
-+              .start  = RE,
-+              .end    = RE,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+      {
-+              .start  = PORT_OTHER_INT(RE),
-+              .end    = PORT_OTHER_INT(RE),
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+      {
-+              .start  = 250000000,
-+              .end    = 250000000,
-+              .flags  = UBICOM32_SUART_IORESOURCE_CLOCK,
-+      },
-+};
-+
-+static struct platform_device ip7160rgw_ubicom32_suart_device = {
-+      .name           = "ubicom32suart",
-+      .id             = -1,
-+      .num_resources  = ARRAY_SIZE(ip7160rgw_ubicom32_suart_resources),
-+      .resource       = ip7160rgw_ubicom32_suart_resources,
-+};
-+#endif
-+
-+/*
-+ * List of all devices in our system
-+ */
-+static struct platform_device *ip7160rgw_devices[] __initdata = {
-+#ifdef CONFIG_SERIAL_UBI32_SERDES
-+      &ip7160rgw_ubicom32_suart_device,
-+#endif
-+      &ip7160rgw_ubicom32input_device,
-+      &ip7160rgw_gpio_leds_device,
-+      &ip7160rgw_spi_gpio_device,
-+#ifdef CONFIG_IP7160RGWLCD
-+      &ip7160rgwlcd_i2c_device,
-+#endif
-+};
-+
-+/*
-+ * ip7160rgw_init
-+ *    Called to add the devices which we have on this board
-+ */
-+static int __init ip7160rgw_init(void)
-+{
-+      board_init();
-+
-+      /*
-+       * Rev 1.2 boards have spi in a different place than 1.1/1.0
-+       */
-+      if (strcmp(board_get_revision(), "1.2") == 0) {
-+              ip7160rgw_spi_gpio_data.pin_mosi = GPIO_RD_7;
-+      }
-+
-+      ubi_gpio_init();
-+
-+      /*
-+       * Reserve switch SPI CS on behalf on switch driver
-+       */
-+      if (gpio_request(ip7160rgw_bcm539x_controller_data.pin_cs, "switch-bcm539x-cs")) {
-+              printk(KERN_WARNING "Could not request cs of switch SPI I/F\n");
-+              return -EIO;
-+      }
-+      gpio_direction_output(ip7160rgw_bcm539x_controller_data.pin_cs, 1);
-+
-+      printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
-+      platform_add_devices(ip7160rgw_devices, ARRAY_SIZE(ip7160rgw_devices));
-+
-+      printk(KERN_INFO "%s: registering SPI resources\n", __FUNCTION__);
-+      spi_register_board_info(ip7160rgw_spi_board_info, ARRAY_SIZE(ip7160rgw_spi_board_info));
-+
-+#ifdef CONFIG_IP7160RGWLCD
-+      printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
-+      i2c_register_board_info(0, ip7160rgwlcd_i2c_board_info, ARRAY_SIZE(ip7160rgwlcd_i2c_board_info));
-+      printk(KERN_INFO "IP7160 RGW + LCD\n");
-+#else
-+      printk(KERN_INFO "IP7160 RGW\n");
-+#endif
-+      return 0;
-+}
-+
-+arch_initcall(ip7160rgw_init);
---- /dev/null
-+++ b/arch/ubicom32/mach-ip7k/board-ip7500av.c
-@@ -0,0 +1,273 @@
-+/*
-+ * arch/ubicom32/mach-ip7k/board-ip7500av.c
-+ *   Support for IP7500 Audio Video Board + CPU module board.
-+ *
-+ * This file supports the IP7500 Audio Video Board:
-+ *    8007-0810  Rev 1.0
-+ * with one of the following CPU module boards:
-+ *    8007-0510  Rev 1.0
-+ *    8007-0510A Rev 1.0 (with ethernet)
-+ *
-+ * DIP Switch SW2 configuration: (*) default
-+ *    POS 1: on(*) = PCI enabled, off = PCI disabled
-+ *    POS 2: on(*) = TTYX => PA6, off = TTYX => PF12
-+ *    POS 3: on(*) = TTYY => PA7, off = TTYY => PF15
-+ *    POS 4: unused
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/platform_device.h>
-+#include <linux/device.h>
-+#include <linux/gpio.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-gpio.h>
-+#include <linux/delay.h>
-+#include <asm/board.h>
-+#include <asm/machdep.h>
-+#include <asm/ring_tio.h>
-+#include <asm/vdc_tio.h>
-+#include <asm/audio.h>
-+#include <asm/ubi32-pcm.h>
-+#include <asm/ubi32-cs4384.h>
-+
-+/******************************************************************************
-+ * Devices on the I2C bus
-+ *
-+ * BEWARE of changing the order of things in this array as we depend on
-+ * certain things to be in certain places.
-+ */
-+static struct i2c_board_info __initdata ip7500av_i2c_board_info[] = {
-+      /*
-+       * U6, CS4384 DAC, address 0x19
-+       */
-+      {
-+              .type           = "cs4384",
-+              .addr           = 0x19,
-+      },
-+};
-+
-+/*
-+ * I2C bus on the board, SDA PD1, SCL PD2
-+ */
-+static struct i2c_gpio_platform_data ip7500av_i2c_data = {
-+      .sda_pin                = GPIO_RD_6,
-+      .scl_pin                = GPIO_RD_3,
-+      .sda_is_open_drain      = 0,
-+      .scl_is_open_drain      = 0,
-+      .udelay                 = 50,
-+};
-+
-+static struct platform_device ip7500av_i2c_device = {
-+      .name   = "i2c-gpio",
-+      .id     = 0,
-+      .dev    = {
-+              .platform_data = &ip7500av_i2c_data,
-+      },
-+};
-+
-+/*
-+ * List of possible mclks we can generate.  This depends on the CPU frequency.
-+ */
-+static struct ubi32_cs4384_mclk_entry ip7500av_cs4384_mclk_entries[] = {
-+      {
-+              .rate   =       12288000,
-+              .div    =       44,
-+      },
-+      {
-+              .rate   =       11289600,
-+              .div    =       48,
-+      },
-+};
-+
-+/*
-+ * List of all devices in our system
-+ */
-+static struct platform_device *ip7500av_devices[] __initdata = {
-+      &ip7500av_i2c_device,
-+};
-+
-+/*
-+ * ip7500av_vdac_write
-+ */
-+static int __init ip7500av_vdac_write(int reg, int val)
-+{
-+      struct i2c_adapter *adap;
-+      struct i2c_msg msg[1];
-+      unsigned char data[2];
-+      int err;
-+
-+      adap = i2c_get_adapter(0);
-+      if (!adap) {
-+              printk(KERN_WARNING "%s: failed to get i2c adapter\n", __FUNCTION__);
-+              return -ENODEV;
-+      }
-+      msg->addr = 0x2B;
-+      msg->flags = 0;
-+      msg->len = 2;
-+      msg->buf = data;
-+      data[0] = reg;
-+      data[1] = val;
-+      err = i2c_transfer(adap, msg, 1);
-+      i2c_put_adapter(adap);
-+      if (err >= 0) {
-+              return 0;
-+      }
-+      return err;
-+}
-+
-+/*
-+ * ip7500av_vdac_init
-+ *    Initializes the video DAC via I2C
-+ *
-+ * Equivalent mode line: 720x480p = 27 Mhz, 720 736 800 858 480 484 492 525
-+ */
-+static int __init ip7500av_vdac_init(void)
-+{
-+      int err;
-+
-+      printk(KERN_INFO "Initializing ADV7393 DAC\n");
-+
-+      /*
-+       * Reset the VDAC
-+       */
-+      if (gpio_request(GPIO_RF_6, "VDAC Reset")) {
-+              printk(KERN_WARNING "%s: failed to allocate VDAC Reset\n", __FUNCTION__);
-+              return -EBUSY;
-+      }
-+      gpio_direction_output(GPIO_RF_6, 0);
-+      udelay(1);
-+      gpio_set_value(GPIO_RF_6, 1);
-+
-+      /*
-+       * See table 100 of ADV7393 data sheet: 16-bit 525p YCrCb In, YPbPr Out
-+       */
-+      err = ip7500av_vdac_write(0x17, 0x02);
-+      if (err) {
-+              printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__);
-+              return err;
-+      }
-+      err = ip7500av_vdac_write(0x00, 0x1c);
-+      if (err) {
-+              printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__);
-+              return err;
-+      }
-+      err = ip7500av_vdac_write(0x01, 0x10);
-+      if (err) {
-+              printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__);
-+              return err;
-+      }
-+      err = ip7500av_vdac_write(0x31, 0x01);
-+      if (err) {
-+              printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__);
-+              return err;
-+      }
-+#ifdef IP7500AV_VDAC_SWAP_PBPR
-+      err = ip7500av_vdac_write(0x35, 0x08);
-+      if (err) {
-+              printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__);
-+              return err;
-+      }
-+#endif
-+#ifdef IP7500AV_VDAC_FULL_RANGE
-+      err = ip7500av_vdac_write(0x30, 0x02);
-+      if (err) {
-+              printk(KERN_WARNING "%s: failed to write VDAC\n", __FUNCTION__);
-+              return err;
-+      }
-+#endif
-+      return 0;
-+}
-+late_initcall(ip7500av_vdac_init);
-+
-+/*
-+ * ip7500av_init
-+ *    Called to add the devices which we have on this board
-+ */
-+static int __init ip7500av_init(void)
-+{
-+      struct platform_device *audio_dev;
-+      struct platform_device *audio_dev2;
-+      struct ubi32_cs4384_platform_data *cs4384_pd;
-+
-+      board_init();
-+
-+      ubi_gpio_init();
-+
-+      vdc_tio_init();
-+
-+      printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
-+      platform_add_devices(ip7500av_devices, ARRAY_SIZE(ip7500av_devices));
-+
-+      /*
-+       * CS4384 DAC
-+       */
-+      audio_dev = audio_device_alloc("snd-ubi32-cs4384", "audio", "audio-i2sout",
-+                      sizeof(struct ubi32_cs4384_platform_data));
-+      if (audio_dev) {
-+              /*
-+               * Attempt to figure out a good divisor.  This will only work
-+               * assuming the core frequency is compatible.
-+               */
-+              int i;
-+              unsigned int freq = processor_frequency();
-+              for (i = 0; i < ARRAY_SIZE(ip7500av_cs4384_mclk_entries); i++) {
-+                      unsigned int div;
-+                      unsigned int rate = ip7500av_cs4384_mclk_entries[i].rate / 1000;
-+                      div = ((freq / rate) + 500) / 1000;
-+                      ip7500av_cs4384_mclk_entries[i].div = div;
-+                      printk("CS4384 mclk %d rate %u000Hz div %u act %u\n", i, rate, div, freq / div);
-+              }
-+
-+              cs4384_pd = audio_device_priv(audio_dev);
-+              cs4384_pd->mclk_src = UBI32_CS4384_MCLK_PWM_0;
-+              cs4384_pd->n_mclk = ARRAY_SIZE(ip7500av_cs4384_mclk_entries);
-+              cs4384_pd->mclk_entries = ip7500av_cs4384_mclk_entries;
-+              ip7500av_i2c_board_info[0].platform_data = audio_dev;
-+
-+              /*
-+               * Reset the DAC
-+               */
-+              if (gpio_request(GPIO_RF_4, "DAC Reset") == 0) {
-+                      gpio_direction_output(GPIO_RF_4, 0);
-+                      udelay(1);
-+                      gpio_direction_output(GPIO_RF_4, 1);
-+              } else {
-+                      printk("Unable to request DAC reset GPIO\n");
-+              }
-+      }
-+
-+      /*
-+       * SPDIF port
-+       */
-+      audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0);
-+      if (audio_dev2) {
-+              platform_device_register(audio_dev2);
-+      }
-+
-+      /*
-+       * Register all of the devices which sit on the I2C bus
-+       */
-+      printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
-+      i2c_register_board_info(0, ip7500av_i2c_board_info, ARRAY_SIZE(ip7500av_i2c_board_info));
-+
-+      printk(KERN_INFO "IP7500 Audio/Video Board\n");
-+      return 0;
-+}
-+arch_initcall(ip7500av_init);
---- /dev/null
-+++ b/arch/ubicom32/mach-ip7k/board-ip7500iap.c
-@@ -0,0 +1,414 @@
-+/*
-+ * arch/ubicom32/mach-ip7k/board-ip7500iap.c
-+ *   Support for IP7500 Internet Audio Player
-+ *
-+ * This file supports the IP7500 Internet Audio Player:
-+ *    8007-1110  Rev 1.0
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+#include <linux/device.h>
-+#include <linux/gpio.h>
-+#include <asm/board.h>
-+
-+#include <linux/delay.h>
-+
-+#include <linux/platform_device.h>
-+#include <asm/audio.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-gpio.h>
-+
-+#include <asm/ubicom32sd.h>
-+#include <asm/sd_tio.h>
-+
-+#include <asm/ubicom32bl.h>
-+
-+#include <asm/machdep.h>
-+
-+/******************************************************************************
-+ * SD/IO Port F (Slot 1) platform data
-+ */
-+static struct resource ip7500iap_portf_sd_resources[] = {
-+      /*
-+       * Send IRQ
-+       */
-+      [0] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Receive IRQ
-+       */
-+      [1] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Memory Mapped Registers
-+       */
-+      [2] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_MEM,
-+      },
-+};
-+
-+static struct ubicom32sd_card ip7500iap_portf_sd_cards[] = {
-+      [0] = {
-+              .pin_wp         = GPIO_RF_7,
-+              .wp_polarity    = 1,
-+              .pin_pwr        = GPIO_RF_8,
-+              .pin_cd         = GPIO_RF_6,
-+      },
-+};
-+
-+static struct ubicom32sd_platform_data ip7500iap_portf_sd_platform_data = {
-+      .ncards         = 1,
-+      .cards          = ip7500iap_portf_sd_cards,
-+};
-+
-+static struct platform_device ip7500iap_portf_sd_device = {
-+      .name           = "ubicom32sd",
-+      .id             = 0,
-+      .resource       = ip7500iap_portf_sd_resources,
-+      .num_resources  = ARRAY_SIZE(ip7500iap_portf_sd_resources),
-+      .dev            = {
-+                      .platform_data = &ip7500iap_portf_sd_platform_data,
-+      },
-+
-+};
-+
-+/*
-+ * ip7500iap_portf_sd_init
-+ */
-+static void ip7500iap_portf_sd_init(void)
-+{
-+      /*
-+       * Check the device tree for the sd_tio
-+       */
-+      struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portf_sd");
-+      if (!sd_node) {
-+              printk(KERN_INFO "PortF SDTIO not found\n");
-+              return;
-+      }
-+
-+      /*
-+       * Fill in the resources and platform data from devtree information
-+       */
-+      ip7500iap_portf_sd_resources[0].start = sd_node->dn.sendirq;
-+      ip7500iap_portf_sd_resources[1].start = sd_node->dn.recvirq;
-+      ip7500iap_portf_sd_resources[2].start = (u32_t)&(sd_node->regs);
-+      ip7500iap_portf_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs);
-+
-+      platform_device_register(&ip7500iap_portf_sd_device);
-+}
-+
-+/******************************************************************************
-+ * SD/IO Port B (Slot 2) platform data
-+ */
-+static struct resource ip7500iap_portb_sd_resources[] = {
-+      /*
-+       * Send IRQ
-+       */
-+      [0] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Receive IRQ
-+       */
-+      [1] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Memory Mapped Registers
-+       */
-+      [2] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_MEM,
-+      },
-+};
-+
-+static struct ubicom32sd_card ip7500iap_portb_sd_cards[] = {
-+      [0] = {
-+              .pin_wp         = GPIO_RB_13,
-+              .wp_polarity    = 1,
-+              .pin_pwr        = GPIO_RB_11,
-+              .pin_cd         = GPIO_RB_12,
-+      },
-+};
-+
-+static struct ubicom32sd_platform_data ip7500iap_portb_sd_platform_data = {
-+      .ncards         = 1,
-+      .cards          = ip7500iap_portb_sd_cards,
-+};
-+
-+static struct platform_device ip7500iap_portb_sd_device = {
-+      .name           = "ubicom32sd",
-+      .id             = 1,
-+      .resource       = ip7500iap_portb_sd_resources,
-+      .num_resources  = ARRAY_SIZE(ip7500iap_portb_sd_resources),
-+      .dev            = {
-+                      .platform_data = &ip7500iap_portb_sd_platform_data,
-+      },
-+
-+};
-+
-+/*
-+ * ip7500iap_portb_sd_init
-+ */
-+static void ip7500iap_portb_sd_init(void)
-+{
-+      /*
-+       * Check the device tree for the sd_tio
-+       */
-+      struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portb_sd");
-+      if (!sd_node) {
-+              printk(KERN_INFO "PortB SDTIO not found\n");
-+              return;
-+      }
-+
-+      /*
-+       * Fill in the resources and platform data from devtree information
-+       */
-+      ip7500iap_portb_sd_resources[0].start = sd_node->dn.sendirq;
-+      ip7500iap_portb_sd_resources[1].start = sd_node->dn.recvirq;
-+      ip7500iap_portb_sd_resources[2].start = (u32_t)&(sd_node->regs);
-+      ip7500iap_portb_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs);
-+
-+      platform_device_register(&ip7500iap_portb_sd_device);
-+}
-+
-+/******************************************************************************
-+ * Touch controller
-+ *
-+ * Connected via I2C bus, interrupt on PA6
-+ */
-+#include <linux/i2c/tsc2007.h>
-+
-+/*
-+ * ip7500iap_tsc2007_exit_platform_hw
-+ */
-+static void ip7500iap_tsc2007_exit_platform_hw(void)
-+{
-+      UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 19);
-+      gpio_free(GPIO_RA_6);
-+}
-+
-+/*
-+ * ip7500iap_tsc2007_init_platform_hw
-+ */
-+static int ip7500iap_tsc2007_init_platform_hw(void)
-+{
-+      int res = gpio_request(GPIO_RA_6, "TSC2007_IRQ");
-+      if (res) {
-+              return res;
-+      }
-+
-+      UBICOM32_IO_PORT(RA)->ctl0 &= ~(0x03 << 19);
-+      UBICOM32_IO_PORT(RA)->ctl0 |= (0x02 << 19);
-+      return 0;
-+}
-+
-+/*
-+ * ip7500iap_tsc2007_get_pendown_state
-+ */
-+static int ip7500iap_tsc2007_get_pendown_state(void)
-+{
-+      return !gpio_get_value(GPIO_RA_6);
-+}
-+
-+static struct tsc2007_platform_data ip7500iap_tsc2007_data = {
-+      .model                  = 2007,
-+      .x_plate_ohms           = 350,
-+      .get_pendown_state      = ip7500iap_tsc2007_get_pendown_state,
-+      .init_platform_hw       = ip7500iap_tsc2007_init_platform_hw,
-+      .exit_platform_hw       = ip7500iap_tsc2007_exit_platform_hw,
-+};
-+
-+/******************************************************************************
-+ * i2c devices
-+ *
-+ * DO NOT CHANGE THE ORDER HERE unless you know how this works.  There
-+ * are hardcoded indicies which refer to the order of drivers listed here.
-+ */
-+static struct i2c_board_info __initdata ip7500iap_i2c_board_info[] = {
-+      /*
-+       * U6, CS4350 DAC, address 0x4B
-+       */
-+      {
-+              .type           = "cs4350",
-+              .addr           = 0x4B,
-+      },
-+
-+      /*
-+       * U20, S35390A RTC, address 0x30
-+       */
-+      {
-+              .type           = "s35390a",
-+              .addr           = 0x30,
-+      },
-+
-+      /*
-+       * U9, TSC2007 Touch screen controller, address 0x49, irq RA6
-+       */
-+      {
-+              .type           = "tsc2007",
-+              .addr           = 0x49,
-+              .irq            = 46,
-+              .platform_data  = &ip7500iap_tsc2007_data,
-+      },
-+};
-+
-+/*
-+ * I2C bus on the board, SDA PE4, SCL PE5
-+ */
-+static struct i2c_gpio_platform_data ip7500iap_i2c_data = {
-+      .sda_pin                = GPIO_RF_14,
-+      .scl_pin                = GPIO_RF_13,
-+      .sda_is_open_drain      = 0,
-+      .scl_is_open_drain      = 0,
-+      .udelay                 = 50,
-+};
-+
-+static struct platform_device ip7500iap_i2c_device = {
-+      .name   = "i2c-gpio",
-+      .id     = 0,
-+      .dev    = {
-+              .platform_data = &ip7500iap_i2c_data,
-+      },
-+};
-+
-+/******************************************************************************
-+ * Backlight on the board PD0, hardware PWM
-+ */
-+static struct ubicom32bl_platform_data ip7500iap_backlight_data = {
-+      .type                   = UBICOM32BL_TYPE_PWM,
-+      .pwm_channel            = 2,
-+      .pwm_prescale           = 15,
-+      .pwm_period             = 60,
-+      .default_intensity      = 0x80,
-+};
-+
-+static struct platform_device ip7500iap_backlight_device = {
-+      .name   = "ubicom32bl",
-+      .id     = -1,
-+      .dev    = {
-+              .platform_data = &ip7500iap_backlight_data,
-+      },
-+};
-+
-+/******************************************************************************
-+ * Devices on this board
-+ */
-+static struct platform_device *ip7500iap_devices[] __initdata = {
-+      &ip7500iap_i2c_device,
-+      &ip7500iap_backlight_device,
-+};
-+
-+/*
-+ * ip7500iap_power_off
-+ *    Called to turn the power off for this board
-+ */
-+static void ip7500iap_power_off(void)
-+{
-+      gpio_set_value(GPIO_RF_11, 0);
-+}
-+
-+/*
-+ * ip7500iap_init
-+ *    Called to add the devices which we have on this board
-+ */
-+static int __init ip7500iap_init(void)
-+{
-+      struct platform_device *audio_dev;
-+      struct platform_device *audio_dev2;
-+      int ret;
-+
-+      board_init();
-+
-+      ubi_gpio_init();
-+
-+      /*
-+       * Hold the POWER_HOLD line
-+       */
-+      ret = gpio_request(GPIO_RF_11, "POWER_HOLD");
-+      if (ret) {
-+              printk(KERN_ERR "%s: could not request POWER_HOLD GPIO\n", __FUNCTION__);
-+      }
-+      gpio_direction_output(GPIO_RF_11, 1);
-+      mach_power_off = ip7500iap_power_off;
-+
-+      /*
-+       * DAC nRESET line
-+       */
-+      ret = gpio_request(GPIO_RE_7, "DAC_nRESET");
-+      if (ret) {
-+              printk(KERN_ERR "%s: could not request DAC_nRESET GPIO\n", __FUNCTION__);
-+      }
-+      gpio_direction_output(GPIO_RE_7, 0);
-+      udelay(1);
-+      gpio_set_value(GPIO_RE_7, 1);
-+
-+      /*
-+       * Bring up any SDIO slots
-+       */
-+      ip7500iap_portb_sd_init();
-+      ip7500iap_portf_sd_init();
-+
-+      /*
-+       * Bring up audio devices
-+       */
-+      platform_add_devices(ip7500iap_devices, ARRAY_SIZE(ip7500iap_devices));
-+
-+      audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio", "audio-i2sout", 0);
-+      if (audio_dev) {
-+              ip7500iap_i2c_board_info[0].platform_data = audio_dev;
-+      }
-+
-+      audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0);
-+      if (audio_dev2) {
-+              platform_device_register(audio_dev2);
-+      }
-+
-+      printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
-+      i2c_register_board_info(0, ip7500iap_i2c_board_info, ARRAY_SIZE(ip7500iap_i2c_board_info));
-+
-+      printk(KERN_INFO "IP7500 Internet Audio Player\n");
-+
-+      return 0;
-+}
-+
-+arch_initcall(ip7500iap_init);
---- /dev/null
-+++ b/arch/ubicom32/mach-ip7k/board-ip7500media.c
-@@ -0,0 +1,732 @@
-+/*
-+ * arch/ubicom32/mach-ip7k/board-ip7500media.c
-+ *   Board file for IP7500 media board.
-+ *
-+ * Supports the following configuration
-+ *    CPU Module:
-+ *            P/N 8007-0510 rev 1.0 NOPHY
-+ *            P/N 8007-0511 rev 1.1 NOPHY
-+ *                    DIP Switch SW2 configuration:
-+ *                            POS 1: on  = PCI enabled
-+ *                            POS 2: off = TTYX => PF12
-+ *                            POS 3: off = TTYY => PF15
-+ *                            POS 4: unused
-+ *    Media Board:
-+ *            P/N 8007-0610 rev 1.0
-+ *
-+ *    LCD Adapter Board: (optional)
-+ *            P/N 8007-0920 rev 2.0
-+ *            P/N 8007-0921 rev 2.1
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/gpio.h>
-+
-+#include <linux/input.h>
-+
-+#include <linux/i2c.h>
-+#include <linux/i2c-gpio.h>
-+#include <linux/i2c/pca953x.h>
-+
-+#include <asm/board.h>
-+#include <asm/machdep.h>
-+#include <asm/ubicom32input_i2c.h>
-+#include <asm/ubicom32bl.h>
-+#include <asm/ubicom32lcdpower.h>
-+#include <asm/vdc_tio.h>
-+
-+#include <asm/ubicom32sd.h>
-+#include <asm/sd_tio.h>
-+#include <asm/devtree.h>
-+#include <asm/audio.h>
-+
-+#include <asm/ring_tio.h>
-+
-+/******************************************************************************
-+ * SD/IO Port F (Slot 1) platform data
-+ */
-+static struct resource ip7500media_portf_sd_resources[] = {
-+      /*
-+       * Send IRQ
-+       */
-+      [0] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Receive IRQ
-+       */
-+      [1] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Memory Mapped Registers
-+       */
-+      [2] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_MEM,
-+      },
-+};
-+
-+static struct ubicom32sd_card ip7500media_portf_sd_cards[] = {
-+      [0] = {
-+              .pin_wp         = IP7500MEDIA_IO16,
-+              .wp_polarity    = 1,
-+              .pin_pwr        = IP7500MEDIA_IO20,
-+              .pin_cd         = IP7500MEDIA_IO23,
-+      },
-+      [1] = {
-+              .pin_wp         = IP7500MEDIA_IO17,
-+              .wp_polarity    = 1,
-+              .pin_pwr        = IP7500MEDIA_IO21,
-+              .pin_cd         = IP7500MEDIA_IO24,
-+      },
-+};
-+
-+static struct ubicom32sd_platform_data ip7500media_portf_sd_platform_data = {
-+      .ncards         = 2,
-+      .cards          = ip7500media_portf_sd_cards,
-+};
-+
-+static struct platform_device ip7500media_portf_sd_device = {
-+      .name           = "ubicom32sd",
-+      .id             = 0,
-+      .resource       = ip7500media_portf_sd_resources,
-+      .num_resources  = ARRAY_SIZE(ip7500media_portf_sd_resources),
-+      .dev            = {
-+                      .platform_data = &ip7500media_portf_sd_platform_data,
-+      },
-+
-+};
-+
-+/*
-+ * ip7500media_portf_sd_init
-+ */
-+static void ip7500media_portf_sd_init(void)
-+{
-+      /*
-+       * Check the device tree for the sd_tio
-+       */
-+      struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portf_sd");
-+      if (!sd_node) {
-+              printk(KERN_INFO "PortF SDTIO not found\n");
-+              return;
-+      }
-+
-+      /*
-+       * Fill in the resources and platform data from devtree information
-+       */
-+      ip7500media_portf_sd_resources[0].start = sd_node->dn.sendirq;
-+      ip7500media_portf_sd_resources[1].start = sd_node->dn.recvirq;
-+      ip7500media_portf_sd_resources[2].start = (u32_t)&(sd_node->regs);
-+      ip7500media_portf_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs);
-+
-+      platform_device_register(&ip7500media_portf_sd_device);
-+}
-+
-+/******************************************************************************
-+ * SD/IO Port B (Slot 2) platform data
-+ */
-+static struct resource ip7500media_portb_sd_resources[] = {
-+      /*
-+       * Send IRQ
-+       */
-+      [0] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Receive IRQ
-+       */
-+      [1] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_IRQ,
-+      },
-+
-+      /*
-+       * Memory Mapped Registers
-+       */
-+      [2] = {
-+              /*
-+               * The init routine will query the devtree and fill this in
-+               */
-+              .flags  = IORESOURCE_MEM,
-+      },
-+};
-+
-+static struct ubicom32sd_card ip7500media_portb_sd_cards[] = {
-+      [0] = {
-+              .pin_wp         = IP7500MEDIA_IO19,
-+              .wp_polarity    = 1,
-+              .pin_pwr        = IP7500MEDIA_IO22,
-+              .pin_cd         = IP7500MEDIA_IO18,
-+      },
-+};
-+
-+static struct ubicom32sd_platform_data ip7500media_portb_sd_platform_data = {
-+      .ncards         = 1,
-+      .cards          = ip7500media_portb_sd_cards,
-+};
-+
-+static struct platform_device ip7500media_portb_sd_device = {
-+      .name           = "ubicom32sd",
-+      .id             = 1,
-+      .resource       = ip7500media_portb_sd_resources,
-+      .num_resources  = ARRAY_SIZE(ip7500media_portb_sd_resources),
-+      .dev            = {
-+                      .platform_data = &ip7500media_portb_sd_platform_data,
-+      },
-+
-+};
-+
-+/*
-+ * ip7500media_portb_sd_init
-+ */
-+static void ip7500media_portb_sd_init(void)
-+{
-+      /*
-+       * Check the device tree for the sd_tio
-+       */
-+      struct sd_tio_node *sd_node = (struct sd_tio_node *)devtree_find_node("portb_sd");
-+      if (!sd_node) {
-+              printk(KERN_INFO "PortB SDTIO not found\n");
-+              return;
-+      }
-+
-+      /*
-+       * Fill in the resources and platform data from devtree information
-+       */
-+      ip7500media_portb_sd_resources[0].start = sd_node->dn.sendirq;
-+      ip7500media_portb_sd_resources[1].start = sd_node->dn.recvirq;
-+      ip7500media_portb_sd_resources[2].start = (u32_t)&(sd_node->regs);
-+      ip7500media_portb_sd_resources[2].end = (u32_t)&(sd_node->regs) + sizeof(sd_node->regs);
-+
-+      platform_device_register(&ip7500media_portb_sd_device);
-+}
-+
-+/*
-+ * ip7500media_u17_setup
-+ *    Called by I2C to tell us that u17 is setup.
-+ *
-+ * This function is called by I2C to tell us that u17 has been setup.  All
-+ * devices which rely on this chip being initialized (or even present) need to
-+ * be initialized in this function otherwise they may get initialized too early.
-+ *
-+ * Currently the only device depending on u17 is the SDIO
-+ */
-+static int __init ip7500media_u17_setup(struct i2c_client *client, unsigned gpio, unsigned ngpio, void *context)
-+{
-+      /*
-+       * Initialize the Port F/Port B SD slots (only the enabled ports will init)
-+       */
-+      ip7500media_portf_sd_init();
-+      ip7500media_portb_sd_init();
-+
-+      return 0;
-+}
-+
-+/******************************************************************************
-+ * LCD VGH on the board at PE6
-+ */
-+static struct ubicom32lcdpower_platform_data ip7500media_lcdpower_data = {
-+      .vgh_gpio               = GPIO_RE_7,
-+      .vgh_polarity           = true,
-+};
-+
-+static struct platform_device ip7500media_lcdpower_device = {
-+      .name   = "ubicom32lcdpower",
-+      .id     = -1,
-+      .dev    = {
-+              .platform_data = &ip7500media_lcdpower_data,
-+      },
-+};
-+
-+/******************************************************************************
-+ * Backlight on the board PD0, hardware PWM
-+ */
-+static struct ubicom32bl_platform_data ip7500media_backlight_data = {
-+      .type                   = UBICOM32BL_TYPE_PWM,
-+      .pwm_channel            = 2,
-+      .pwm_prescale           = 15,
-+      .pwm_period             = 60,
-+      .default_intensity      = 0x80,
-+};
-+
-+static struct platform_device ip7500media_backlight_device = {
-+      .name   = "ubicom32bl",
-+      .id     = -1,
-+      .dev    = {
-+              .platform_data = &ip7500media_backlight_data,
-+      },
-+};
-+
-+/******************************************************************************
-+ * Ubicom32Input on I2C, U15 MAX7310, address 0x18, 8 bits
-+ */
-+static struct ubicom32input_i2c_button ip7500media_ubicom32input_i2c_u15_buttons[] = {
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_LEFT,
-+              .bit            = 0,
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_RIGHT,
-+              .bit            = 1,
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_UP,
-+              .bit            = 2,
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_DOWN,
-+              .bit            = 3,
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_ENTER,
-+              .bit            = 4,
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_MENU,
-+              .bit            = 5,
-+              .active_low     = 1,
-+      },
-+      {
-+              .type           = EV_KEY,
-+              .code           = KEY_ESC,
-+              .bit            = 6,
-+              .active_low     = 1,
-+      },
-+};
-+
-+static struct ubicom32input_i2c_platform_data ip7500media_ubicom32input_i2c_u15_platform_data = {
-+      .buttons        = ip7500media_ubicom32input_i2c_u15_buttons,
-+      .nbuttons       = ARRAY_SIZE(ip7500media_ubicom32input_i2c_u15_buttons),
-+      .name           = "Ubicom32 Input I2C U15",
-+};
-+
-+/******************************************************************************
-+ * Additional GPIO chips
-+ */
-+static struct pca953x_platform_data ip7500media_gpio_u16_platform_data = {
-+      .gpio_base = IP7500MEDIA_U16_BASE,
-+};
-+
-+static struct pca953x_platform_data ip7500media_gpio_u17_platform_data = {
-+      .gpio_base = IP7500MEDIA_U17_BASE,
-+      .setup = ip7500media_u17_setup,
-+};
-+
-+static struct pca953x_platform_data ip7500media_gpio_u18_platform_data = {
-+      .gpio_base = IP7500MEDIA_U18_BASE,
-+};
-+
-+
-+/******************************************************************************
-+ * Touch controller present on LCD Adapter board
-+ *
-+ * Connected via I2C bus, interrupt on PD1
-+ */
-+#include <linux/i2c/tsc2007.h>
-+
-+/*
-+ * ip7500media_tsc2007_exit_platform_hw
-+ */
-+static void ip7500media_tsc2007_exit_platform_hw(void)
-+{
-+      UBICOM32_IO_PORT(RD)->int_mask &= ~(1 << 11);
-+      UBICOM32_IO_PORT(RD)->ctl2 &= ~(0x03 << 16);
-+      gpio_free(GPIO_RD_1);
-+}
-+
-+/*
-+ * ip7500media_tsc2007_init_platform_hw
-+ */
-+static int ip7500media_tsc2007_init_platform_hw(void)
-+{
-+      int res = gpio_request(GPIO_RD_1, "TSC2007_IRQ");
-+      if (res) {
-+              return res;
-+      }
-+      UBICOM32_IO_PORT(RD)->function = 0;
-+      UBICOM32_IO_PORT(RD)->int_mask = (1 << 11);
-+      UBICOM32_IO_PORT(RD)->ctl2 &= ~(0x03 << 16);
-+      UBICOM32_IO_PORT(RD)->ctl2 |= (0x02 << 16);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ip7500media_tsc2007_clear_penirq
-+ */
-+static void ip7500media_tsc2007_clear_penirq(void)
-+{
-+      UBICOM32_IO_PORT(RD)->int_clr = (1 << 11);
-+}
-+
-+/*
-+ * ip7500media_tsc2007_get_pendown_state
-+ */
-+static int ip7500media_tsc2007_get_pendown_state(void)
-+{
-+      return !gpio_get_value(GPIO_RD_1);
-+}
-+
-+static struct tsc2007_platform_data ip7500media_tsc2007_data = {
-+      .model                  = 2007,
-+      .x_plate_ohms           = 350,
-+      .get_pendown_state      = ip7500media_tsc2007_get_pendown_state,
-+      .init_platform_hw       = ip7500media_tsc2007_init_platform_hw,
-+      .exit_platform_hw       = ip7500media_tsc2007_exit_platform_hw,
-+      .clear_penirq           = ip7500media_tsc2007_clear_penirq,
-+};
-+
-+/******************************************************************************
-+ * Devices on the I2C bus
-+ *
-+ * BEWARE of changing the order of things in this array as we depend on
-+ * certain things to be in certain places.
-+ */
-+static struct i2c_board_info __initdata ip7500media_i2c_board_info[] = {
-+      /*
-+       * U6, CS4350 DAC, address 0x4B
-+       */
-+      {
-+              .type           = "cs4350",
-+              .addr           = 0x4B,
-+      },
-+
-+      /*
-+       * U14, S35390A RTC, address 0x30
-+       */
-+      {
-+              .type           = "s35390a",
-+              .addr           = 0x30,
-+      },
-+
-+      /*
-+       * U15, MAX7310 IO expander, 8 bits, address 0x18
-+       *      IO0: User I/O (J16-1) (Left)    IO4: User I/O (J16-5) (Enter)
-+       *      IO1: User I/O (J16-2) (Right)   IO5: User I/O (J16-6) (Menu)
-+       *      IO2: User I/O (J16-3) (Up)      IO6: User I/O (J16-7) (Back)
-+       *      IO3: User I/O (J16-4) (Down)    IO7: User I/O (J16-8)
-+       */
-+      {
-+              .type           = "ubicom32in_max7310",
-+              .addr           = 0x18,
-+              .platform_data  = &ip7500media_ubicom32input_i2c_u15_platform_data,
-+      },
-+
-+      /*
-+       * U16, MAX7310 IO expander, 8 bits, address 0x1C
-+       *      IO8 : User I/O (J16-9)          IO12: User I/O (J16-17)
-+       *      IO9 : User I/O (J16-10)         IO13: User I/O (J16-18)
-+       *      IO10: User I/O (J16-15)         IO14: User I/O (J16-19)
-+       *      IO11: User I/O (J16-16)         IO15: User I/O (J16-20)
-+       */
-+      {
-+              .type           = "max7310",
-+              .addr           = 0x1C,
-+              .platform_data  = &ip7500media_gpio_u16_platform_data,
-+      },
-+
-+      /*
-+       * U17, MAX7310 IO expander, 8 bits, address 0x1A
-+       *      IO16: SDIO1A_WP                 IO20: SD1A_PWREN
-+       *      IO17: SDIO1B_WP                 IO21: SD1B_PWREN
-+       *      IO18: SDIO2_CD                  IO22: SD2_PWREN
-+       *      IO19: SDIO2_WP                  IO23: SDIO1A_CD
-+       *
-+       */
-+      {
-+              .type           = "max7310",
-+              .addr           = 0x1A,
-+              .platform_data  = &ip7500media_gpio_u17_platform_data,
-+      },
-+
-+      /*
-+       * U18, MAX7310 IOB expander, 8 bits, address 0x1E
-+       *      IO24: SDIO1B_CD                 IO28: User I/O TP6
-+       *      IO25: User I/O TP9              IO29: User I/O TP5
-+       *      IO26: User I/O TP8              IO30: User I/O TP4
-+       *      IO27: User I/O TP7              IO31: User I/O TP3
-+       */
-+      {
-+              .type           = "max7310",
-+              .addr           = 0x1E,
-+              .platform_data  = &ip7500media_gpio_u18_platform_data,
-+      },
-+};
-+
-+/*
-+ * Additional I2C devices to add when a LCD adapter board is present
-+ */
-+static struct i2c_board_info __initdata ip7500media_lcd_adapter_i2c_board_info[] = {
-+      {
-+              I2C_BOARD_INFO("tsc2007", 0x48),
-+              .irq = PORT_OTHER_INT(RD),
-+              .platform_data = &ip7500media_tsc2007_data,
-+      },
-+};
-+
-+/*
-+ * I2C bus on the board, SDA PE4, SCL PE5
-+ */
-+static struct i2c_gpio_platform_data ip7500media_i2c_data = {
-+      .sda_pin                = GPIO_RE_4,
-+      .scl_pin                = GPIO_RE_5,
-+      .sda_is_open_drain      = 0,
-+      .scl_is_open_drain      = 0,
-+      .udelay                 = 50,
-+};
-+
-+static struct platform_device ip7500media_i2c_device = {
-+      .name   = "i2c-gpio",
-+      .id     = 0,
-+      .dev    = {
-+              .platform_data = &ip7500media_i2c_data,
-+      },
-+};
-+
-+/*
-+ * Virtual Frame Buffer device for use with LCD Adapter
-+ */
-+static struct platform_device ip7500media_vfb_device = {
-+      .name   = "ubicom32vfb",
-+      .id     = -1,
-+};
-+
-+/*
-+ * vdc_override:
-+ *    0: no override (auto-detect)
-+ *    1: force vdc usage
-+ *    2: force lcd adapter usage
-+ */
-+static int __initdata vdc_override = 0;
-+
-+/*
-+ * ip7500media_set_forcevdc
-+ *    Called when forcevdc is present on the kernel boot line
-+ */
-+static int __init ip7500media_set_forcevdc(char *str)
-+{
-+      if (str[0] == '1') {
-+              vdc_override = 1;
-+      } else {
-+              vdc_override = 2;
-+      }
-+      return 1;
-+}
-+
-+/*
-+ * ip7500media_video_init
-+ *    Called late to determine what kind of video we have on this board
-+ */
-+static int __init ip7500media_video_init(void)
-+{
-+      struct i2c_adapter *adap;
-+      struct i2c_msg msg[1];
-+      unsigned char *data;
-+      unsigned char checksum;
-+      int err;
-+      int i;
-+
-+      if (vdc_override == 1) {
-+              printk(KERN_INFO "Force VDCTIO mode\n");
-+              goto no_adapter;
-+      }
-+      if (vdc_override == 2) {
-+              printk(KERN_INFO "Force LCD Adapter Board mode\n");
-+              return 0;
-+      }
-+
-+      /*
-+       * Check to see if there is an EEPROM out there.  If we see an
-+       * EEPROM then we will assume a LCD Adapter Board (8007-092x)
-+       * exists.
-+       */
-+      data = kmalloc(256, GFP_KERNEL);
-+      if (!data) {
-+              printk(KERN_WARNING "%s: Failed to allocate memory\n", __FUNCTION__);
-+              return -ENOMEM;
-+      }
-+
-+      adap = i2c_get_adapter(0);
-+      if (!adap) {
-+              printk(KERN_WARNING "%s: Failed to get i2c adapter\n", __FUNCTION__);
-+              kfree(data);
-+              return -ENODEV;
-+      }
-+      data[0] = 0;
-+      msg->addr = 0x50;
-+      msg->flags = 0;
-+      msg->len = 1;
-+      msg->buf = data;
-+      err = i2c_transfer(adap, msg, 1);
-+      if (err < 0) {
-+              goto no_adapter;
-+      }
-+
-+      msg->addr = 0x50;
-+      msg->flags = I2C_M_RD;
-+      msg->len = 256;
-+      msg->buf = data;
-+      err = i2c_transfer(adap, msg, 1);
-+      if (err < 0) {
-+              goto no_adapter;
-+      }
-+
-+      i2c_put_adapter(adap);
-+
-+      /*
-+       * Verify the checksum
-+       */
-+      checksum = 0xff;
-+      for (i = 0; i < 255; i++) {
-+              checksum ^= data[i];
-+      }
-+      if (checksum != data[255]) {
-+              printk(KERN_WARNING "%s: Checksum mismatch\n", __FUNCTION__);
-+      }
-+
-+      kfree(data);
-+
-+      /*
-+       * Bring up VFB
-+       */
-+      platform_device_register(&ip7500media_vfb_device);
-+
-+      /*
-+       * Add the i2c devices on the LCD Adapter board.  (We have to use i2c_new_device
-+       * since it's late in the boot process.)
-+       */
-+      printk(KERN_INFO "%s: registering LCD Adapter board i2c resources\n", __FUNCTION__);
-+      for (i = 0; i < ARRAY_SIZE(ip7500media_lcd_adapter_i2c_board_info); i++) {
-+              i2c_new_device(adap, &ip7500media_lcd_adapter_i2c_board_info[i]);
-+      }
-+
-+      i2c_put_adapter(adap);
-+
-+      return 0;
-+
-+      /*
-+       * No LCD Adapter board, bring up VDC
-+       */
-+no_adapter:
-+      vdc_tio_init();
-+      return 0;
-+}
-+late_initcall(ip7500media_video_init);
-+__setup("forcevdc=", ip7500media_set_forcevdc);
-+
-+/*
-+ * ip7500media_init
-+ *    Called to add the devices which we have on this board
-+ */
-+static int __init ip7500media_init(void)
-+{
-+      struct platform_device *audio_dev;
-+      int have_ethernet = (devtree_find_node("eth_lan") != 0);
-+
-+      board_init();
-+
-+      ubi_gpio_init();
-+
-+#ifdef CONFIG_UIO_UBICOM32RING
-+      ring_tio_init("decoder_ring");
-+#endif
-+
-+      /*
-+       * Register all of the devices we have on this board
-+       */
-+      printk(KERN_INFO "%s: registering device resources\n", __FUNCTION__);
-+      platform_device_register(&ip7500media_i2c_device);
-+      platform_device_register(&ip7500media_backlight_device);
-+
-+      /*
-+       * If ethernet doesn't exist then we can init the lcdpower
-+       */
-+      if (!have_ethernet) {
-+              platform_device_register(&ip7500media_lcdpower_device);
-+      }
-+
-+      /*
-+       * Allocate the audio drivers.  SPDIF not supported on boards with ethernet.
-+       */
-+      audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio", "audio-i2sout", 0);
-+      if (audio_dev) {
-+              ip7500media_i2c_board_info[0].platform_data = audio_dev;
-+      }
-+
-+      if (!have_ethernet) {
-+              struct platform_device *audio_dev2;
-+
-+              audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0);
-+              if (audio_dev2) {
-+                      platform_device_register(audio_dev2);
-+              }
-+      }
-+
-+      /*
-+       * Register all of the devices which sit on the I2C bus
-+       */
-+      printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
-+      i2c_register_board_info(0, ip7500media_i2c_board_info, ARRAY_SIZE(ip7500media_i2c_board_info));
-+
-+      /*
-+       * We have to initialize the SDIO after the I2C IOB gets setup.  SDIO is initialized in
-+       * ip7500media_u17_setup
-+       */
-+
-+      printk("IP7500 Media Board\n");
-+
-+      return 0;
-+}
-+
-+arch_initcall(ip7500media_init);
---- /dev/null
-+++ b/arch/ubicom32/mach-ip7k/board-ip7500module.c
-@@ -0,0 +1,55 @@
-+/*
-+ * arch/ubicom32/mach-ip7k/board-ip7500module.c
-+ *   Support for IP7500 CPU module board.
-+ *
-+ * This file supports the IP7500 CPU module board:
-+ *    8007-0510  Rev 1.0
-+ *    8007-0510A Rev 1.0 (with ethernet)
-+ *
-+ * DIP Switch SW2 configuration: (*) default
-+ *    POS 1: on(*) = PCI enabled, off = PCI disabled
-+ *    POS 2: on(*) = TTYX => PA6, off = TTYX => PF12
-+ *    POS 3: on(*) = TTYY => PA7, off = TTYY => PF15
-+ *    POS 4: unused
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/device.h>
-+#include <linux/gpio.h>
-+#include <asm/board.h>
-+
-+/*
-+ * ip7500module_init
-+ *    Called to add the devices which we have on this board
-+ */
-+static int __init ip7500module_init(void)
-+{
-+      board_init();
-+
-+      ubi_gpio_init();
-+
-+      return 0;
-+}
-+
-+arch_initcall(ip7500module_init);
---- /dev/null
-+++ b/arch/ubicom32/mach-ip7k/board-ip7500wspkr.c
-@@ -0,0 +1,101 @@
-+/*
-+ * arch/ubicom32/mach-ip7k/board-ip7500wspkr.c
-+ *   Support for IP7500 Wireless Speaker board.
-+ *
-+ * This file supports the IP7500 Wireless Speaker board:
-+ *    8007-1210  Rev 1.0
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+#include <linux/device.h>
-+#include <linux/gpio.h>
-+#include <asm/board.h>
-+
-+#include <linux/platform_device.h>
-+#include <asm/audio.h>
-+#include <linux/i2c.h>
-+#include <linux/i2c-gpio.h>
-+
-+static struct i2c_board_info __initdata ip7500wspkr_i2c_board_info[] = {
-+      /*
-+       * U6, CS4350 DAC, address 0x4B
-+       */
-+      {
-+              .type           = "cs4350",
-+              .addr           = 0x4B,
-+      },
-+};
-+
-+/*
-+ * I2C bus on the board, SDA PE4, SCL PE5
-+ */
-+static struct i2c_gpio_platform_data ip7500wspkr_i2c_data = {
-+      .sda_pin                = GPIO_RD_5,
-+      .scl_pin                = GPIO_RD_6,
-+      .sda_is_open_drain      = 0,
-+      .scl_is_open_drain      = 0,
-+      .udelay                 = 50,
-+};
-+
-+static struct platform_device ip7500wspkr_i2c_device = {
-+      .name   = "i2c-gpio",
-+      .id     = 0,
-+      .dev    = {
-+              .platform_data = &ip7500wspkr_i2c_data,
-+      },
-+};
-+
-+static struct platform_device *ip7500wspkr_devices[] __initdata = {
-+      &ip7500wspkr_i2c_device,
-+};
-+
-+/*
-+ * ip7500wspkr_init
-+ *    Called to add the devices which we have on this board
-+ */
-+static int __init ip7500wspkr_init(void)
-+{
-+      struct platform_device *audio_dev;
-+      struct platform_device *audio_dev2;
-+
-+      board_init();
-+
-+      ubi_gpio_init();
-+
-+      platform_add_devices(ip7500wspkr_devices, ARRAY_SIZE(ip7500wspkr_devices));
-+
-+      audio_dev = audio_device_alloc("snd-ubi32-cs4350", "audio", "audio-i2sout", 0);
-+      if (audio_dev) {
-+              ip7500wspkr_i2c_board_info[0].platform_data = audio_dev;
-+      }
-+
-+      audio_dev2 = audio_device_alloc("snd-ubi32-generic", "audio", "audio-spdifout", 0);
-+      if (audio_dev2) {
-+              platform_device_register(audio_dev2);
-+      }
-+
-+      printk(KERN_INFO "%s: registering i2c resources\n", __FUNCTION__);
-+      i2c_register_board_info(0, ip7500wspkr_i2c_board_info, ARRAY_SIZE(ip7500wspkr_i2c_board_info));
-+
-+      printk(KERN_INFO "IP7500 Wireless Speaker Board\n");
-+
-+      return 0;
-+}
-+
-+arch_initcall(ip7500wspkr_init);
---- /dev/null
-+++ b/arch/ubicom32/mach-ip7k/Kconfig
-@@ -0,0 +1,205 @@
-+config IP7145DPF
-+      bool "IP7145DPF"
-+      select UBICOM32_V4
-+      select UBICOM_INPUT
-+      select UBICOM_INPUT_I2C
-+      select RTC_CLASS
-+      select RTC_DRV_S35390A
-+      select I2C
-+      select I2C_GPIO
-+      select GPIO_PCA953X
-+      select FB
-+      select FB_UBICOM32
-+      select LCD_CLASS_DEVICE
-+      select LCD_UBICOM32POWER
-+      select BACKLIGHT_LCD_SUPPORT
-+      select BACKLIGHT_CLASS_DEVICE
-+      select BACKLIGHT_UBICOM32
-+      select SND_UBI32
-+      select MMC_UBICOM32
-+      select MMC
-+      select MMC_BLOCK
-+      help
-+              IP7145 Digital Picture Frame reference design, supports:
-+                      8007-0410 v1.0
-+
-+config IP7160RGW
-+      bool "IP7160RGW"
-+      select UBICOM32_V4
-+      select UBICOM_INPUT
-+      select NEW_LEDS
-+      select LEDS_CLASS
-+      select LEDS_GPIO
-+      select SPI
-+      select SPI_UBICOM32_GPIO
-+      select VLAN_8021Q
-+      select UBICOM_SWITCH
-+      select UBICOM_SWITCH_BCM539X
-+      help
-+              Ubicom IP7160 RGW Eval, supports:
-+                      8007-0110 v1.0
-+                      8007-0111 v1.1
-+                      8007-0112 v1.2
-+
-+config IP7160RGWLCD
-+      bool "IP7160RGWLCD"
-+      select UBICOM32_V4
-+      select UBICOM_INPUT
-+      select NEW_LEDS
-+      select LEDS_CLASS
-+      select LEDS_GPIO
-+      select SPI
-+      select SPI_UBICOM32_GPIO
-+      select VLAN_8021Q
-+      select UBICOM_SWITCH
-+      select UBICOM_SWITCH_BCM539X
-+      select INPUT_TOUCHSCREEN
-+      select TOUCHSCREEN_TSC2007
-+      select FB
-+      select FB_UBICOM32_VIRTUAL
-+      select I2C
-+      select I2C_GPIO
-+      help
-+              Ubicom IP7160 RGW Eval, supports:
-+                      8007-0112 v1.2 + 8007-1410 v1.0
-+
-+              With Ubicom LCD Adapter
-+                      8007-0920 v2.0
-+                      8007-0921 v2.1
-+
-+
-+config IP7160BRINGUP
-+      bool "IP7160BRINGUP"
-+      select UBICOM32_V4
-+      select NEW_LEDS
-+      select LEDS_CLASS
-+      select LEDS_GPIO
-+      help
-+              Ubicom IP7160 Bringup, supports:
-+                      8007-0010 v1.0
-+
-+config IP7160DPF
-+      bool "IP7160DPF"
-+      select UBICOM32_V4
-+      select I2C
-+      select I2C_GPIO
-+      select FB
-+      select FB_UBICOM32
-+      select BACKLIGHT_LCD_SUPPORT
-+      select BACKLIGHT_CLASS_DEVICE
-+      select SND_UBI32
-+      select SND_UBI32_AUDIO_CS4350
-+      select UBICOM_HID
-+      help
-+              IP7160 Digital Picture Frame board, supports:
-+                      8007-0211 Rev 1.1
-+
-+config IP7500MODULE
-+      bool "IP7500MODULE"
-+      select UBICOM32_V4
-+      help
-+              Ubicom IP7500 CPU Module board, supports:
-+                      8007-0510  v1.0
-+                      8007-0510A v1.0
-+
-+              Please see ip7500module.c for more details.
-+
-+config IP7500AV
-+      bool "IP7500AV"
-+      select UBICOM32_V4
-+      select I2C
-+      select I2C_GPIO
-+      select SND_UBI32
-+      select SND_UBI32_AUDIO_CS4384
-+      select FB
-+      select FB_UBICOM32
-+      help
-+              Ubicom IP7500 Audio Video board, supports:
-+                      8007-0810  v1.0
-+
-+              With Ubicom IP7500 CPU Module board:
-+                      8007-0510  v1.0 -or-
-+                      8007-0510A v1.0
-+
-+              Please see ip7500av.c for more details.
-+
-+config IP7500MEDIA
-+      bool "IP7500MEDIA"
-+      select UBICOM32_V4
-+      select UBICOM_INPUT_I2C
-+      select RTC_CLASS
-+      select RTC_DRV_S35390A
-+      select I2C
-+      select I2C_GPIO
-+      select GPIO_PCA953X
-+      select FB
-+      select FB_UBICOM32
-+      select FB_UBICOM32_VIRTUAL
-+      select FB_UBICOM32_VIRTUAL_NOAUTO
-+      select LCD_CLASS_DEVICE
-+      select LCD_UBICOM32POWER
-+      select BACKLIGHT_LCD_SUPPORT
-+      select BACKLIGHT_CLASS_DEVICE
-+      select BACKLIGHT_UBICOM32
-+      select INPUT_TOUCHSCREEN
-+      select TOUCHSCREEN_TSC2007
-+      select SOUND
-+      select SND
-+      select SND_UBI32
-+      select SND_UBI32_AUDIO_CS4350
-+      select MMC_UBICOM32
-+      select MMC
-+      select MMC_BLOCK
-+      help
-+              IP7500 Media Board w/ IP7500 CPU Module board, supports:
-+                      8007-0610 v1.0 w/ 8007-0510 v1.0
-+                      8007-0610 v1.0 w/ 8007-0510 v1.0 NOPHY
-+                      8007-0610 v1.0 w/ 8007-0511 v1.1 NOPHY
-+
-+              Also supports optional LCD Adapter board:
-+                      8006-0920 v2.0
-+                      8006-0921 v2.1
-+
-+              Please see ip7500media.c for more details.
-+
-+config IP7500WSPKR
-+      bool "IP7500WSPKR"
-+      select UBICOM32_V4
-+      select I2C
-+      select I2C_GPIO
-+      select SOUND
-+      select SND
-+      select SND_UBI32
-+      select SND_UBI32_AUDIO_CS4350
-+      help
-+              IP7500 Wireless Speaker Board, supports:
-+                      8007-1210 v1.0
-+
-+              Please see ip7500wspkr.c for more details.
-+
-+config IP7500IAP
-+      bool "IP7500IAP"
-+      select UBICOM32_V4
-+      select I2C
-+      select I2C_GPIO
-+      select FB
-+      select FB_UBICOM32_VIRTUAL
-+      select SOUND
-+      select SND
-+      select SND_UBI32
-+      select SND_UBI32_AUDIO_CS4350
-+      select RTC_CLASS
-+      select RTC_DRV_S35390A
-+      select INPUT_TOUCHSCREEN
-+      select TOUCHSCREEN_TSC2007
-+      select BACKLIGHT_LCD_SUPPORT
-+      select BACKLIGHT_CLASS_DEVICE
-+      select BACKLIGHT_UBICOM32
-+      help
-+              IP7500 Internet Audio Player, supports:
-+                      8007-1110 v1.0
-+
-+              Please see ip7500iap.c for more details.
-+
-+
-+              Please see ip7500media.c for more details.
---- /dev/null
-+++ b/arch/ubicom32/mach-ip7k/Makefile
-@@ -0,0 +1,38 @@
-+#
-+# arch/ubicom32/mach-ip7k/Makefile
-+#     Makefile for ip7k based boards.
-+#
-+# (C) Copyright 2009, Ubicom, Inc.
-+#
-+# This file is part of the Ubicom32 Linux Kernel Port.
-+#
-+# The Ubicom32 Linux Kernel Port 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.
-+#
-+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+# see <http://www.gnu.org/licenses/>.
-+#
-+# Ubicom32 implementation derived from (with many thanks):
-+#   arch/m68knommu
-+#   arch/blackfin
-+#   arch/parisc
-+#
-+
-+obj-$(CONFIG_IP7145DPF)               += board-ip7145dpf.o
-+obj-$(CONFIG_IP7160RGW)               += board-ip7160rgw.o
-+obj-$(CONFIG_IP7160RGWLCD)    += board-ip7160rgw.o
-+obj-$(CONFIG_IP7160BRINGUP)   += board-ip7160bringup.o
-+obj-$(CONFIG_IP7160DPF)               += board-ip7160dpf.o
-+obj-$(CONFIG_IP7500MODULE)    += board-ip7500module.o
-+obj-$(CONFIG_IP7500MEDIA)     += board-ip7500media.o
-+obj-$(CONFIG_IP7500AV)                += board-ip7500av.o
-+obj-$(CONFIG_IP7500WSPKR)     += board-ip7500wspkr.o
-+obj-$(CONFIG_IP7500IAP)               += board-ip7500iap.o
---- /dev/null
-+++ b/arch/ubicom32/Makefile
-@@ -0,0 +1,104 @@
-+#
-+# arch/ubicom32/Makefile
-+#     <TODO: Replace with short file description>
-+#
-+# (C) Copyright 2009, Ubicom, Inc.
-+#
-+# This file is part of the Ubicom32 Linux Kernel Port.
-+#
-+# The Ubicom32 Linux Kernel Port 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.
-+#
-+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+# see <http://www.gnu.org/licenses/>.
-+#
-+# Ubicom32 implementation derived from (with many thanks):
-+#   arch/m68knommu
-+#   arch/blackfin
-+#   arch/parisc
-+#
-+
-+KBUILD_DEFCONFIG :=
-+
-+# setup the machine name and machine dependent settings
-+machine-$(CONFIG_UBICOM32_V3) := ip5k
-+machine-$(CONFIG_UBICOM32_V4) := ip7k
-+MACHINE := $(machine-y)
-+export MACHINE
-+
-+model-$(CONFIG_RAMKERNEL)     := ram
-+model-$(CONFIG_ROMKERNEL)     := rom
-+MODEL := $(model-y)
-+export MODEL
-+
-+CPUCLASS := $(cpuclass-y)
-+
-+export CPUCLASS
-+
-+#
-+# We want the core kernel built using the fastcall ABI but modules need
-+# to be built using the slower calling convention because they could be
-+# loaded out of range for fast calls.
-+#
-+CFLAGS_KERNEL    += -mfastcall
-+CFLAGS_MODULE    += -mno-fastcall
-+
-+#
-+# Some CFLAG additions based on specific CPU type.
-+#
-+cflags-$(CONFIG_UBICOM32_V3)          := -march=ubicom32v3 -DIP5000
-+cflags-$(CONFIG_UBICOM32_V4)          := -march=ubicom32v4 -DIP7000
-+
-+ldflags-$(CONFIG_LINKER_RELAXATION)   := --relax
-+LDFLAGS_vmlinux := $(ldflags-y)
-+
-+GCCLIBDIR := $(dir $(shell $(CC) $(cflags-y) -print-libgcc-file-name))
-+GCC_LIBS := $(GCCLIBDIR)/libgcc.a
-+
-+KBUILD_CFLAGS += $(cflags-y) -ffunction-sections
-+KBUILD_AFLAGS += $(cflags-y)
-+
-+KBUILD_CFLAGS += -D__linux__ -Dlinux
-+KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\"
-+
-+# include any machine specific directory
-+ifneq ($(machine-y),)
-+core-y += arch/$(ARCH)/mach-$(MACHINE)/
-+endif
-+
-+head-y := arch/$(ARCH)/kernel/head.o
-+
-+core-y        += arch/$(ARCH)/kernel/ \
-+         arch/$(ARCH)/mm/ \
-+         arch/$(ARCH)/crypto/ \
-+         arch/$(ARCH)/mach-common/
-+
-+drivers-$(CONFIG_OPROFILE)    += arch/ubicom32/oprofile/
-+
-+libs-y        += arch/$(ARCH)/lib/
-+libs-y        += $(GCC_LIBS)
-+
-+archclean:
-+
-+# make sure developer has selected a valid board
-+ifeq ($(CONFIG_NOBOARD),y)
-+# $(error have to select a valid board file $(CONFIG_NOBOARD), please run kernel config again)
-+_all: config_board_error
-+endif
-+
-+config_board_error:
-+      @echo "*************************************************"
-+      @echo "You have not selected a proper board."
-+      @echo "Please run menuconfig (or config) against your"
-+      @echo "kernel and choose your board under Processor"
-+      @echo "options"
-+      @echo "*************************************************"
-+      @exit 1
---- /dev/null
-+++ b/arch/ubicom32/mm/fault.c
-@@ -0,0 +1,80 @@
-+/*
-+ * arch/ubicom32/mm/fault.c
-+ *   Ubicom32 architecture page fault implementation.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
-+ *  Copyright (C) 2000  Lineo, Inc.  (www.lineo.com)
-+ *
-+ *  Based on:
-+ *
-+ *  linux/arch/m68k/mm/fault.c
-+ *
-+ *  Copyright (C) 1995  Hamish Macdonald
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/mman.h>
-+#include <linux/mm.h>
-+#include <linux/kernel.h>
-+#include <linux/ptrace.h>
-+
-+#include <asm/system.h>
-+#include <asm/pgtable.h>
-+
-+extern void die_if_kernel(char *, struct pt_regs *, long);
-+
-+/*
-+ * This routine handles page faults.  It determines the problem, and
-+ * then passes it off to one of the appropriate routines.
-+ *
-+ * error_code:
-+ *    bit 0 == 0 means no page found, 1 means protection fault
-+ *    bit 1 == 0 means read, 1 means write
-+ *
-+ * If this routine detects a bad access, it returns 1, otherwise it
-+ * returns 0.
-+ */
-+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
-+                            unsigned long error_code)
-+{
-+#ifdef DEBUG
-+      printk (KERN_DEBUG "regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld\n",
-+              regs->sr, regs->pc, address, error_code);
-+#endif
-+
-+      /*
-+       * Oops. The kernel tried to access some bad page. We'll have to
-+       * terminate things with extreme prejudice.
-+       */
-+      if ((unsigned long) address < PAGE_SIZE) {
-+              printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-+      } else
-+              printk(KERN_ALERT "Unable to handle kernel access");
-+      printk(KERN_ALERT " at virtual address %08lx\n",address);
-+      die_if_kernel("Oops", regs, error_code);
-+      do_exit(SIGKILL);
-+
-+      return 1;
-+}
---- /dev/null
-+++ b/arch/ubicom32/mm/init.c
-@@ -0,0 +1,262 @@
-+/*
-+ * arch/ubicom32/mm/init.c
-+ *   Ubicom32 architecture virtual memory initialization.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
-+ *                      Kenneth Albanowski <kjahds@kjahds.com>,
-+ *  Copyright (C) 2000  Lineo, Inc.  (www.lineo.com)
-+ *
-+ *  Based on:
-+ *
-+ *  linux/arch/m68k/mm/init.c
-+ *
-+ *  Copyright (C) 1995  Hamish Macdonald
-+ *
-+ *  JAN/1999 -- hacked to support ColdFire (gerg@snapgear.com)
-+ *  DEC/2000 -- linux 2.4 support <davidm@snapgear.com>
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/signal.h>
-+#include <linux/sched.h>
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include <linux/ptrace.h>
-+#include <linux/mman.h>
-+#include <linux/mm.h>
-+#include <linux/swap.h>
-+#include <linux/init.h>
-+#include <linux/highmem.h>
-+#include <linux/pagemap.h>
-+#include <linux/bootmem.h>
-+#include <linux/slab.h>
-+
-+#include <asm/setup.h>
-+#include <asm/segment.h>
-+#include <asm/page.h>
-+#include <asm/pgtable.h>
-+#include <asm/system.h>
-+#include <asm/machdep.h>
-+#include <asm/ocm-alloc.h>
-+#include <asm/processor.h>
-+
-+#undef DEBUG
-+
-+extern void die_if_kernel(char *,struct pt_regs *,long);
-+extern void free_initmem(void);
-+
-+/*
-+ * BAD_PAGE is the page that is used for page faults when linux
-+ * is out-of-memory. Older versions of linux just did a
-+ * do_exit(), but using this instead means there is less risk
-+ * for a process dying in kernel mode, possibly leaving a inode
-+ * unused etc..
-+ *
-+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
-+ * to point to BAD_PAGE entries.
-+ *
-+ * ZERO_PAGE is a special page that is used for zero-initialized
-+ * data and COW.
-+ */
-+static unsigned long empty_bad_page_table;
-+
-+static unsigned long empty_bad_page;
-+
-+unsigned long empty_zero_page;
-+
-+void show_mem(void)
-+{
-+    unsigned long i;
-+    int free = 0, total = 0, reserved = 0, shared = 0;
-+    int cached = 0;
-+
-+    printk(KERN_INFO "\nMem-info:\n");
-+    show_free_areas();
-+    i = max_mapnr;
-+    while (i-- > 0) {
-+      total++;
-+      if (PageReserved(mem_map+i))
-+          reserved++;
-+      else if (PageSwapCache(mem_map+i))
-+          cached++;
-+      else if (!page_count(mem_map+i))
-+          free++;
-+      else
-+          shared += page_count(mem_map+i) - 1;
-+    }
-+    printk(KERN_INFO "%d pages of RAM\n",total);
-+    printk(KERN_INFO "%d free pages\n",free);
-+    printk(KERN_INFO "%d reserved pages\n",reserved);
-+    printk(KERN_INFO "%d pages shared\n",shared);
-+    printk(KERN_INFO "%d pages swap cached\n",cached);
-+}
-+
-+extern unsigned long memory_start;
-+extern unsigned long memory_end;
-+extern char __ocm_free_begin;
-+extern char __ocm_free_end;
-+
-+/*
-+ * paging_init() continues the virtual memory environment setup which
-+ * was begun by the code in arch/head.S.
-+ * The parameters are pointers to where to stick the starting and ending
-+ * addresses of available kernel virtual memory.
-+ */
-+void __init paging_init(void)
-+{
-+      /*
-+       * Make sure start_mem is page aligned, otherwise bootmem and
-+       * page_alloc get different views of the world.
-+       */
-+#ifdef DEBUG
-+      unsigned long start_mem = PAGE_ALIGN(memory_start);
-+#endif
-+      unsigned long end_mem   = memory_end & PAGE_MASK;
-+
-+#ifdef DEBUG
-+      printk (KERN_DEBUG "start_mem is %#lx\nvirtual_end is %#lx\n",
-+              start_mem, end_mem);
-+#endif
-+
-+      /*
-+       * Initialize the bad page table and bad page to point
-+       * to a couple of allocated pages.
-+       */
-+      empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
-+      empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
-+      empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
-+      memset((void *)empty_zero_page, 0, PAGE_SIZE);
-+
-+      /*
-+       * TODO: enable setting up for user memory management interface.
-+       */
-+
-+#ifdef DEBUG
-+      printk (KERN_DEBUG "before free_area_init\n");
-+
-+      printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n",
-+              start_mem, end_mem);
-+#endif
-+
-+      {
-+              unsigned long zones_size[MAX_NR_ZONES] = {0, };
-+#ifdef CONFIG_ZONE_DMA
-+              zones_size[ZONE_DMA] = OCMSIZE >> PAGE_SHIFT;
-+#endif
-+              zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
-+#ifdef CONFIG_HIGHMEM
-+              zones_size[ZONE_HIGHMEM] = 0;
-+#endif
-+              free_area_init(zones_size);
-+      }
-+}
-+
-+void __init mem_init(void)
-+{
-+      int codek = 0, datak = 0, initk = 0;
-+      unsigned long tmp, ram_start, ram_end, len;
-+      extern char _etext, _stext, _sdata, _ebss, __init_begin, __init_end;
-+
-+      unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */
-+      unsigned long end_mem   = memory_end; /* DAVIDM - this must not include kernel stack at top */
-+      processor_dram(&ram_start, &ram_end);
-+      len = (ram_end - ram_start) + OCMSIZE;
-+#ifdef DEBUG
-+      printk(KERN_DEBUG "Mem_init: start=%lx, end=%lx\n", start_mem, end_mem);
-+#endif
-+
-+      end_mem &= PAGE_MASK;
-+      high_memory = (void *) end_mem;
-+
-+      start_mem = PAGE_ALIGN(start_mem);
-+      max_mapnr = num_physpages = (((unsigned long) high_memory) - PAGE_OFFSET) >> PAGE_SHIFT;
-+
-+      /* this will put all memory onto the freelists */
-+#ifdef CONFIG_ZONE_DMA
-+      {
-+              unsigned long ocm_free_begin = (unsigned long)&__ocm_free_begin;
-+              unsigned long ocm_free_end = (unsigned long)&__ocm_free_end;
-+              unsigned long zone_dma_begin = (ocm_free_begin + PAGE_SIZE - 1) & PAGE_MASK;
-+              unsigned long zone_dma_end = ocm_free_end & PAGE_MASK;
-+              if (zone_dma_end > zone_dma_begin)
-+                      free_bootmem(zone_dma_begin, zone_dma_end-zone_dma_begin);
-+      }
-+#endif
-+      totalram_pages = free_all_bootmem();
-+
-+      codek = (&_etext - &_stext) >> 10;
-+      datak = (&_ebss - &_sdata) >> 10;
-+      initk = (&__init_begin - &__init_end) >> 10;
-+
-+      tmp = nr_free_pages() << PAGE_SHIFT;
-+      printk(KERN_INFO "Memory available: %luk/%luk RAM, (%dk kernel code, %dk data)\n",
-+             tmp >> 10,
-+             len >> 10,
-+             codek,
-+             datak
-+             );
-+
-+}
-+
-+#ifdef CONFIG_BLK_DEV_INITRD
-+void free_initrd_mem(unsigned long start, unsigned long end)
-+{
-+      int pages = 0;
-+      for (; start < end; start += PAGE_SIZE) {
-+              ClearPageReserved(virt_to_page(start));
-+              init_page_count(virt_to_page(start));
-+              free_page(start);
-+              totalram_pages++;
-+              pages++;
-+      }
-+      printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages);
-+}
-+#endif
-+
-+void
-+free_initmem()
-+{
-+#ifdef CONFIG_RAMKERNEL
-+      unsigned long addr;
-+      extern char __init_begin, __init_end;
-+      /*
-+       * The following code should be cool even if these sections
-+       * are not page aligned.
-+       */
-+      addr = PAGE_ALIGN((unsigned long)(&__init_begin));
-+      /* next to check that the page we free is not a partial page */
-+      for (; addr + PAGE_SIZE < (unsigned long)(&__init_end); addr +=PAGE_SIZE) {
-+              ClearPageReserved(virt_to_page(addr));
-+              init_page_count(virt_to_page(addr));
-+              free_page(addr);
-+              totalram_pages++;
-+      }
-+      printk(KERN_NOTICE "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n",
-+                      (addr - PAGE_ALIGN((long) &__init_begin)) >> 10,
-+                      (int)(PAGE_ALIGN((unsigned long)(&__init_begin))),
-+                      (int)(addr - PAGE_SIZE));
-+#endif
-+}
---- /dev/null
-+++ b/arch/ubicom32/mm/kmap.c
-@@ -0,0 +1,79 @@
-+/*
-+ * arch/ubicom32/mm/kmap.c
-+ *   Ubicom32 architecture non-mmu ioremap and friends implementation.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 2000 Lineo, <davidm@snapgear.com>
-+ * Copyright (C) 2000-2002 David McCullough <davidm@snapgear.com>
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/mm.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include <linux/slab.h>
-+#include <linux/vmalloc.h>
-+
-+#include <asm/setup.h>
-+#include <asm/segment.h>
-+#include <asm/page.h>
-+#include <asm/pgalloc.h>
-+#include <asm/io.h>
-+#include <asm/system.h>
-+
-+#undef DEBUG
-+
-+/*
-+ * Map some physical address range into the kernel address space.
-+ */
-+void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
-+{
-+      return (void *)physaddr;
-+}
-+
-+/*
-+ * Unmap a ioremap()ed region again.
-+ */
-+void iounmap(void *addr)
-+{
-+}
-+
-+/*
-+ * __iounmap unmaps nearly everything, so be careful
-+ * it doesn't free currently pointer/page tables anymore but it
-+ * wans't used anyway and might be added later.
-+ */
-+void __iounmap(void *addr, unsigned long size)
-+{
-+}
-+
-+/*
-+ * Set new cache mode for some kernel address space.
-+ * The caller must push data for that range itself, if such data may already
-+ * be in the cache.
-+ */
-+void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
-+{
-+}
---- /dev/null
-+++ b/arch/ubicom32/mm/Makefile
-@@ -0,0 +1,32 @@
-+#
-+# arch/ubicom32/mm/Makefile
-+#     <TODO: Replace with short file description>
-+#
-+# (C) Copyright 2009, Ubicom, Inc.
-+#
-+# This file is part of the Ubicom32 Linux Kernel Port.
-+#
-+# The Ubicom32 Linux Kernel Port 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.
-+#
-+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+# see <http://www.gnu.org/licenses/>.
-+#
-+# Ubicom32 implementation derived from (with many thanks):
-+#   arch/m68knommu
-+#   arch/blackfin
-+#   arch/parisc
-+#
-+#
-+# Makefile for the linux m68knommu specific parts of the memory manager.
-+#
-+
-+obj-y += init.o fault.o memory.o kmap.o ocm-alloc.o
---- /dev/null
-+++ b/arch/ubicom32/mm/memory.c
-@@ -0,0 +1,58 @@
-+/*
-+ * arch/ubicom32/mm/memory.c
-+ *   Ubicom32 architecture kernel_map() implementation.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *  Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
-+ *  Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
-+ *
-+ *  Based on:
-+ *
-+ *  linux/arch/m68k/mm/memory.c
-+ *
-+ *  Copyright (C) 1995  Hamish Macdonald
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/mm.h>
-+#include <linux/kernel.h>
-+#include <linux/string.h>
-+#include <linux/types.h>
-+#include <linux/slab.h>
-+
-+#include <asm/segment.h>
-+#include <asm/page.h>
-+#include <asm/pgtable.h>
-+#include <asm/system.h>
-+
-+/*
-+ * Map some physical address range into the kernel address space.
-+ * The code is copied and adapted from map_chunk().
-+ */
-+
-+unsigned long kernel_map(unsigned long paddr, unsigned long size,
-+                       int nocacheflag, unsigned long *memavailp )
-+{
-+      return paddr;
-+}
---- /dev/null
-+++ b/arch/ubicom32/mm/ocm-alloc.c
-@@ -0,0 +1,487 @@
-+/*
-+ * arch/ubicom32/mm/ocm-alloc.c
-+ *    OCM allocator for Uibcom32 On-Chip memory
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *  Copyright 2004-2008 Analog Devices Inc.
-+ *
-+ *  Based on:
-+ *
-+ *  arch/blackfin/mm/sram-alloc.c
-+ *
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/types.h>
-+#include <linux/miscdevice.h>
-+#include <linux/ioport.h>
-+#include <linux/fcntl.h>
-+#include <linux/init.h>
-+#include <linux/poll.h>
-+#include <linux/proc_fs.h>
-+#include <linux/mutex.h>
-+#include <linux/rtc.h>
-+#include <asm/ocm-alloc.h>
-+
-+#if 0
-+#define DEBUGP printk
-+#else
-+#define DEBUGP(fmt, a...)
-+#endif
-+/*
-+ * the data structure for OCM heap pieces
-+ */
-+struct ocm_piece {
-+      void *paddr;
-+      int size;
-+      pid_t pid;
-+      struct ocm_piece *next;
-+};
-+
-+/*
-+ * struct ocm_heap
-+ */
-+struct ocm_heap {
-+      struct ocm_piece free_head;
-+      struct ocm_piece used_head;
-+      struct mutex lock;
-+};
-+
-+static struct ocm_heap ocm_inst_heap;
-+int ubi32_ocm_skbuf_max = 21, ubi32_ocm_skbuf, ubi32_ddr_skbuf;
-+
-+/*
-+ * OCM area for storing code
-+ */
-+extern asmlinkage void *__ocm_free_begin;
-+extern asmlinkage void *__ocm_free_end;
-+extern asmlinkage void *__ocm_inst_heap_begin;
-+extern asmlinkage void *__ocm_inst_heap_end;
-+#define OCM_INST_HEAP_BEGIN ((unsigned int)&__ocm_inst_heap_begin)
-+#define OCM_INST_HEAP_END ((unsigned int)&__ocm_inst_heap_end)
-+#define OCM_INST_HEAP_LENGTH (OCM_INST_HEAP_END - OCM_INST_HEAP_BEGIN)
-+
-+static struct kmem_cache *ocm_piece_cache;
-+
-+/*
-+ * _ocm_heap_init()
-+ */
-+static int __init _ocm_heap_init(struct ocm_heap *ocmh,
-+                                unsigned int start,
-+                                unsigned int size)
-+{
-+      ocmh->free_head.next = kmem_cache_alloc(ocm_piece_cache, GFP_KERNEL);
-+
-+      if (!ocmh->free_head.next)
-+              return -1;
-+
-+      ocmh->free_head.next->paddr = (void *)start;
-+      ocmh->free_head.next->size = size;
-+      ocmh->free_head.next->pid = 0;
-+      ocmh->free_head.next->next = 0;
-+
-+      ocmh->used_head.next = NULL;
-+
-+      /* mutex initialize */
-+      mutex_init(&ocmh->lock);
-+
-+      return 0;
-+}
-+
-+/*
-+ * _ocm_alloc_init()
-+ *
-+ * starts the ocm heap(s)
-+ */
-+static int __init _ocm_alloc_init(void)
-+{
-+      if (OCM_INST_HEAP_LENGTH) {
-+              ocm_piece_cache = kmem_cache_create("ocm_piece_cache",
-+                                                  sizeof(struct ocm_piece),
-+                                                  0, SLAB_PANIC, NULL);
-+
-+              if (_ocm_heap_init(&ocm_inst_heap,
-+                                 OCM_INST_HEAP_BEGIN,
-+                                 OCM_INST_HEAP_LENGTH) == 0)
-+                      printk(KERN_INFO "OCM Instruction Heap %d KB\n",
-+                             OCM_INST_HEAP_LENGTH >> 10);
-+              else
-+                      printk(KERN_INFO "Failed to initialize OCM "
-+                             "Instruction Heap\n");
-+
-+      } else
-+              printk(KERN_INFO "No space available for OCM "
-+                     "Instruction Heap\n");
-+
-+      return 0;
-+}
-+pure_initcall(_ocm_alloc_init);
-+
-+/*
-+ * _ocm_alloc()
-+ *    generic alloc a block in the ocm heap, if successful
-+ *    returns the pointer.
-+ */
-+static void *_ocm_alloc(size_t size, pid_t pid, struct ocm_heap *ocmheap)
-+{
-+      struct ocm_piece *pslot, *plast, *pavail;
-+      struct ocm_piece *pfree_head = &ocmheap->free_head;
-+      struct ocm_piece *pused_head = &ocmheap->used_head;
-+
-+      if (size <= 0 || !pfree_head || !pused_head)
-+              return NULL;
-+
-+      /* Align the size */
-+      size = (size + 3) & ~3;
-+
-+      pslot = pfree_head->next;
-+      plast = pfree_head;
-+
-+      /*
-+       * search an available piece slot
-+       */
-+      while (pslot != NULL && size > pslot->size) {
-+              plast = pslot;
-+              pslot = pslot->next;
-+      }
-+
-+      if (!pslot)
-+              return NULL;
-+
-+      if (pslot->size == size) {
-+              /*
-+               * Unlink this block from the list
-+               */
-+              plast->next = pslot->next;
-+              pavail = pslot;
-+      } else {
-+              /*
-+               * Split this block in two.
-+               */
-+              pavail = kmem_cache_alloc(ocm_piece_cache, GFP_KERNEL);
-+
-+              if (!pavail)
-+                      return NULL;
-+
-+              pavail->paddr = pslot->paddr;
-+              pavail->size = size;
-+              pslot->paddr += size;
-+              pslot->size -= size;
-+      }
-+
-+      pavail->pid = pid;
-+
-+      pslot = pused_head->next;
-+      plast = pused_head;
-+
-+      /*
-+       * insert new piece into used piece list !!!
-+       */
-+      while (pslot != NULL && pavail->paddr < pslot->paddr) {
-+              plast = pslot;
-+              pslot = pslot->next;
-+      }
-+
-+      pavail->next = pslot;
-+      plast->next = pavail;
-+
-+      DEBUGP("_ocm_alloc %d bytes at %p from in %p",
-+             size, pavail->paddr, ocmheap);
-+
-+      return pavail->paddr;
-+}
-+
-+#if 0
-+/* Allocate the largest available block.  */
-+static void *_ocm_alloc_max(struct ocm_heap *ocmheap,
-+                           unsigned long *psize)
-+{
-+      struct ocm_piece *pfree_head = &ocmheap->free_head;
-+      struct ocm_piece *pslot, *pmax;
-+
-+      pmax = pslot = pfree_head->next;
-+
-+      /* search an available piece slot */
-+      while (pslot != NULL) {
-+              if (pslot->size > pmax->size)
-+                      pmax = pslot;
-+              pslot = pslot->next;
-+      }
-+
-+      if (!pmax)
-+              return NULL;
-+
-+      *psize = pmax->size;
-+
-+      return _ocm_alloc(*psize, ocmheap);
-+}
-+#endif
-+
-+/*
-+ * _ocm_free()
-+ *    generic free a block in the ocm heap, if successful
-+ */
-+static int _ocm_free(const void *addr,
-+                   struct ocm_heap *ocmheap)
-+{
-+      struct ocm_piece *pslot, *plast, *pavail;
-+      struct ocm_piece *pfree_head = &ocmheap->free_head;
-+      struct ocm_piece *pused_head = &ocmheap->used_head;
-+
-+      /* search the relevant memory slot */
-+      pslot = pused_head->next;
-+      plast = pused_head;
-+
-+      /* search an available piece slot */
-+      while (pslot != NULL && pslot->paddr != addr) {
-+              plast = pslot;
-+              pslot = pslot->next;
-+      }
-+
-+      if (!pslot) {
-+              DEBUGP("_ocm_free %p  not found in %p", addr, ocmheap);
-+              return -1;
-+      }
-+      DEBUGP("_ocm_free %p from in %p", addr, ocmheap);
-+
-+      plast->next = pslot->next;
-+      pavail = pslot;
-+      pavail->pid = 0;
-+
-+      /* insert free pieces back to the free list */
-+      pslot = pfree_head->next;
-+      plast = pfree_head;
-+
-+      while (pslot != NULL && addr > pslot->paddr) {
-+              plast = pslot;
-+              pslot = pslot->next;
-+      }
-+
-+      if (plast != pfree_head &&
-+          plast->paddr + plast->size == pavail->paddr) {
-+              plast->size += pavail->size;
-+              kmem_cache_free(ocm_piece_cache, pavail);
-+      } else {
-+              pavail->next = plast->next;
-+              plast->next = pavail;
-+              plast = pavail;
-+      }
-+
-+      if (pslot && plast->paddr + plast->size == pslot->paddr) {
-+              plast->size += pslot->size;
-+              plast->next = pslot->next;
-+              kmem_cache_free(ocm_piece_cache, pslot);
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * ocm_inst_alloc()
-+ *
-+ *    allocates a block of size in the ocm instrction heap, if
-+ *    successful returns address allocated.
-+ */
-+void *ocm_inst_alloc(size_t size, pid_t pid)
-+{
-+      void *addr;
-+
-+      if (!OCM_INST_HEAP_LENGTH)
-+              return NULL;
-+
-+
-+      mutex_lock(&ocm_inst_heap.lock);
-+
-+      addr = _ocm_alloc(size, pid, &ocm_inst_heap);
-+
-+      mutex_unlock(&ocm_inst_heap.lock);
-+
-+      return addr;
-+}
-+EXPORT_SYMBOL(ocm_inst_alloc);
-+
-+/*
-+ * ocm_inst_free()
-+ *    free a block in the ocm instrction heap, returns 0 if successful.
-+ */
-+int ocm_inst_free(const void *addr)
-+{
-+      int ret;
-+
-+      if (!OCM_INST_HEAP_LENGTH)
-+              return -1;
-+
-+      mutex_lock(&ocm_inst_heap.lock);
-+
-+      ret = _ocm_free(addr, &ocm_inst_heap);
-+
-+      mutex_unlock(&ocm_inst_heap.lock);
-+
-+      return ret;
-+}
-+EXPORT_SYMBOL(ocm_inst_free);
-+
-+/*
-+ * ocm_free()
-+ *    free a block in one of the ocm heaps, returns 0 if successful.
-+ */
-+int ocm_free(const void *addr)
-+{
-+      if (addr >= (void *)OCM_INST_HEAP_BEGIN
-+               && addr < (void *)(OCM_INST_HEAP_END))
-+              return ocm_inst_free(addr);
-+      else
-+              return -1;
-+}
-+EXPORT_SYMBOL(ocm_free);
-+
-+
-+#ifdef CONFIG_PROC_FS
-+/* Need to keep line of output the same.  Currently, that is 46 bytes
-+ * (including newline).
-+ */
-+static int _ocm_proc_read(char *buf, int *len, int count, const char *desc,
-+                         struct ocm_heap *ocmheap)
-+{
-+      struct ocm_piece *pslot;
-+      struct ocm_piece *pfree_head = &ocmheap->free_head;
-+      struct ocm_piece *pused_head = &ocmheap->used_head;
-+
-+      /* The format is the following
-+       * --- OCM 123456789012345 Size   PID State     \n
-+       * 12345678-12345678 1234567890 12345 1234567890\n
-+       */
-+      int l;
-+      l = sprintf(&buf[*len], "--- OCM %-15s Size   PID State     \n",
-+                  desc);
-+
-+      *len += l;
-+      count -= l;
-+
-+      mutex_lock(&ocm_inst_heap.lock);
-+
-+      /*
-+       * search the relevant memory slot
-+       */
-+      pslot = pused_head->next;
-+
-+      while (pslot != NULL && count > 46) {
-+              l = sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
-+                           pslot->paddr, pslot->paddr + pslot->size,
-+                           pslot->size, pslot->pid, "ALLOCATED");
-+
-+              *len += l;
-+              count -= l;
-+              pslot = pslot->next;
-+      }
-+
-+      pslot = pfree_head->next;
-+
-+      while (pslot != NULL && count > 46) {
-+              l = sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
-+                          pslot->paddr, pslot->paddr + pslot->size,
-+                          pslot->size, pslot->pid, "FREE");
-+
-+              *len += l;
-+              count -= l;
-+              pslot = pslot->next;
-+      }
-+
-+      mutex_unlock(&ocm_inst_heap.lock);
-+
-+      return 0;
-+}
-+
-+static int ocm_proc_read(char *buf, char **start, off_t offset, int count,
-+              int *eof, void *data)
-+{
-+      int len = 0;
-+
-+      len = sprintf(&buf[len], "--- OCM SKB usage (max RX buf %d)\n"
-+                      "(SKB in OCM) %d - (SKB in DDR) %d\n",
-+                      ubi32_ocm_skbuf_max,
-+                      ubi32_ocm_skbuf,
-+                      ubi32_ddr_skbuf);
-+
-+      len += sprintf(&buf[len], "--- OCM Data Heap       Size\n"
-+                      "%p-%p %10i\n",
-+                      ((void *)&__ocm_free_begin),
-+                      ((void *)&__ocm_free_end),
-+                      ((unsigned int)&__ocm_free_end) -
-+                      ((unsigned int)&__ocm_free_begin));
-+
-+      if (_ocm_proc_read(buf, &len, count - len, "Inst Heap",
-+                          &ocm_inst_heap))
-+              goto not_done;
-+      *eof = 1;
-+ not_done:
-+      return len;
-+}
-+
-+static int ocm_proc_write(struct file *file, const char __user *buffer,
-+                           unsigned long count, void *data)
-+{
-+      int n, v;
-+      char in[8];
-+
-+      if (count > sizeof(in))
-+              return -EINVAL;
-+
-+      if (copy_from_user(in, buffer, count))
-+              return -EFAULT;
-+      in[count-1] = 0;
-+
-+      printk(KERN_INFO "OCM skb alloc max = %s\n", in);
-+
-+      n = 0;
-+      v = 0;
-+      while ((in[n] >= '0') && (in[n] <= '9')) {
-+              v = v * 10 + (int)(in[n] - '0');
-+              n++;
-+      }
-+
-+      if (v == 0)
-+              return -EINVAL;
-+
-+      ubi32_ocm_skbuf_max = v;
-+      ubi32_ocm_skbuf = ubi32_ddr_skbuf = 0;
-+
-+      return count;
-+}
-+
-+static int __init sram_proc_init(void)
-+{
-+      struct proc_dir_entry *ptr;
-+      ptr = create_proc_entry("ocm", S_IFREG | S_IRUGO, NULL);
-+      if (!ptr) {
-+              printk(KERN_WARNING "unable to create /proc/ocm\n");
-+              return -1;
-+      }
-+      ptr->read_proc = ocm_proc_read;
-+      ptr->write_proc = ocm_proc_write;
-+      return 0;
-+}
-+late_initcall(sram_proc_init);
-+#endif
---- /dev/null
-+++ b/arch/ubicom32/oprofile/ipProf.h
-@@ -0,0 +1,39 @@
-+#ifndef __IP_PROF_H__
-+#define __IP_PROF_H__
-+
-+/* This number MUST match what is used in the ultra configuration! */
-+#define IPPROFILETIO_MAX_SAMPLES      600
-+
-+/* Move to .h file used in both; avoid special types  */
-+struct profile_sample {
-+      unsigned int    pc;             /* PC value */
-+      unsigned int    parent;         /* a5 contents, to find the caller */
-+      unsigned char   cond_codes;     /* for branch prediction */
-+      unsigned char   thread;         /* I-blocked, D-blocked,
-+                                         4-bit thread number */
-+      unsigned short  active;         /* which threads are active -
-+                                         for accurate counting */
-+      unsigned short  blocked;        /* which threads are blocked due to
-+                                         I or D cache misses */
-+      unsigned int    latency;        /* CPU clocks since the last message
-+                                         dispatch in this thread
-+                                         (thread 0 only for now) */
-+};
-+
-+
-+struct profilenode {
-+      struct devtree_node dn;
-+      volatile unsigned char enabled; /* Is the tio enabled to
-+                                         take samples? */
-+      volatile unsigned char busy;    /* set when the samples
-+                                         are being read */
-+      volatile unsigned int mask;     /* Threads that change the MT_EN flag */
-+      volatile unsigned short rate;   /* What is the sampling rate? */
-+      volatile unsigned short head;   /* sample taker puts samples here */
-+      volatile unsigned short tail;   /* packet filler takes samples here */
-+      volatile unsigned short count;  /* number of valid samples */
-+      volatile unsigned short total;  /* Total samples */
-+      struct profile_sample samples[IPPROFILETIO_MAX_SAMPLES];
-+};
-+
-+#endif
---- /dev/null
-+++ b/arch/ubicom32/oprofile/Makefile
-@@ -0,0 +1,37 @@
-+#
-+# arch/ubicom32/Makefile
-+#       Makefile for Oprofile support on Ubicom32
-+#
-+# (C) Copyright 2009, Ubicom, Inc.
-+#
-+# This file is part of the Ubicom32 Linux Kernel Port.
-+#
-+# The Ubicom32 Linux Kernel Port 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.
-+#
-+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+# see <http://www.gnu.org/licenses/>.
-+#
-+# Ubicom32 implementation derived from (with many thanks):
-+#   arch/m68knommu
-+#   arch/blackfin
-+#   arch/parisc
-+#
-+
-+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) profile.o
---- /dev/null
-+++ b/arch/ubicom32/oprofile/profile.c
-@@ -0,0 +1,221 @@
-+/*
-+ * arch/ubicom32/oprofile/profile.c
-+ *    Oprofile support for arch Ubicom32
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not, see
-+ * <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+/**
-+ * @file profile.c
-+ *
-+ * @remark Copyright 2002 OProfile authors
-+ * @remark Read the file COPYING
-+ *
-+ * @author Hunyue Yau <hy@hy-research.com>
-+ */
-+
-+#include <linux/oprofile.h>
-+#include <linux/init.h>
-+#include <linux/errno.h>
-+#include <linux/interrupt.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+
-+#include <asm/devtree.h>
-+#include <asm/thread.h>
-+
-+/* For identifying userland vs kernel address */
-+#include <asm/stacktrace.h>
-+#include "ipProf.h"
-+
-+/* For communications with the backend */
-+static struct profilenode *profile_node;
-+
-+/* Bitmask containing all Linux threads - as seen by the ROSR reg */
-+static unsigned long th_all_mask;
-+
-+/* Lookup table to translate a hardware thread into a CPU identifier
-+ * Table is indexed by the ROSR value which is assumed to be
-+ * relatively small (0...15).
-+ */
-+unsigned int cpu_map[THREAD_ARCHITECTURAL_MAX];
-+
-+static struct pt_regs regs;
-+
-+/*
-+ * For each sample returned, checked to see if they are relevant to
-+ * us. This is necessary as the ubicom32 architecture has other software
-+ * running outside of Linux. Only then, put the sample into the relevant
-+ * cpu bins.
-+ *
-+ * To minimize overhead, a global mask with all possible threads of in
-+ * interest to us is used as a first check. Then a second mask identifying
-+ * the thread is used to obtain an identifier for that "CPU".
-+ */
-+
-+/*
-+ * ubicom32_build_cpu_th_mask()
-+ *
-+ * Build a lookup table for translation between hardware thread
-+ * "ROSR" values and Linux CPU ids
-+ *
-+ * *** This gets executed on all CPUs at once! ***
-+ */
-+static void ubicom32_build_cpu_th_mask(void *mask)
-+{
-+      thread_t self = thread_get_self();
-+      unsigned long *th_m = mask;
-+
-+      BUG_ON(self <= 0 || self >= THREAD_ARCHITECTURAL_MAX);
-+      cpu_map[self] = smp_processor_id();
-+
-+      set_bit(self, th_m);
-+}
-+
-+/*
-+ * profile_interrupt()
-+ *
-+ * Process samples returned from the profiler backend. The backend
-+ * may return samples that are irrelevant to us or may even return
-+ * multiple samples for the same CPU. Note that the sames may be
-+ * for ANY cpu. At this time, this is unique and to support this requires
-+ * Oprofile to expose an interface to accept the CPU that the same came
-+ * frome.
-+ */
-+static irqreturn_t profile_interrupt(int irq, void *arg)
-+{
-+      int i, buf_entry;
-+      int is_kernel;
-+      unsigned int bit_th;
-+      unsigned int th;
-+
-+      if (!(profile_node->enabled) || profile_node->count < 0) {
-+              printk(KERN_WARNING
-+                      "Unexpected interrupt, no samples or not enabled!\n");
-+              return IRQ_HANDLED;
-+      }
-+
-+      profile_node->busy = 1;         /* Keep backend out */
-+
-+      for (i = 0; i < profile_node->count; i++) {
-+              buf_entry = profile_node->tail;
-+              profile_node->tail++;
-+              profile_node->tail %= IPPROFILETIO_MAX_SAMPLES;
-+
-+              /* Note - the "thread" ID is only the lower 4 bits */
-+              th = (0x0f & profile_node->samples[buf_entry].thread);
-+              bit_th = (1 << th);
-+
-+              if ((bit_th & th_all_mask) == 0)
-+                      continue;
-+
-+              regs.pc = profile_node->samples[buf_entry].pc;
-+
-+              is_kernel = ubicom32_is_kernel(regs.pc);
-+
-+              oprofile_add_ext_sample_cpu(regs.pc, &regs, 0, is_kernel,
-+                                          cpu_map[th]);
-+      }
-+      profile_node->count = 0;
-+      profile_node->busy = 0;
-+
-+      return IRQ_HANDLED;
-+}
-+
-+/*
-+ * profile_start()
-+ *
-+ * Notification from oprofile to start the profiler
-+ */
-+static int profile_start(void)
-+{
-+      if (!profile_node)
-+              return -1;
-+
-+      profile_node->enabled = 1;
-+
-+      return 0;
-+}
-+
-+/*
-+ * profile_stop()
-+ *
-+ * Notification from oprofile to stop the profiler
-+ */
-+static void profile_stop(void)
-+{
-+      if (profile_node)
-+              profile_node->enabled = 0;
-+}
-+
-+/*
-+ * oprofile_arch_init()
-+ *
-+ * Attach to Oprofile after qualify the availability of the backend
-+ * profiler support.
-+ */
-+int __init oprofile_arch_init(struct oprofile_operations *ops)
-+{
-+      int r = -ENODEV;
-+
-+      profile_node = (struct profilenode *)devtree_find_node("profiler");
-+
-+      if (profile_node == NULL) {
-+              printk(KERN_WARNING "Cannot find profiler node\n");
-+              return r;
-+      }
-+
-+      r = request_irq(profile_node->dn.recvirq, profile_interrupt,
-+                      IRQF_DISABLED, "profiler", NULL);
-+
-+      if (r < 0) {
-+              profile_node = NULL;
-+              printk(KERN_WARNING "Cannot get profiler IRQ\n");
-+              return r;
-+      }
-+
-+      ops->start = profile_start;
-+      ops->stop = profile_stop;
-+      ops->cpu_type = "timer";
-+
-+      memset(cpu_map, 0, sizeof(cpu_map));
-+
-+      on_each_cpu(ubicom32_build_cpu_th_mask, &th_all_mask, 1);
-+
-+      memset(&regs, 0, sizeof(regs));
-+
-+      return r;
-+}
-+
-+/*
-+ * oprofile_arch_exit()
-+ *
-+ * External call to take outselves out.
-+ * Make sure backend is not running.
-+ */
-+void oprofile_arch_exit(void)
-+{
-+      BUG_ON(profile_node->enabled);
-+}
---- a/drivers/char/hw_random/Kconfig
-+++ b/drivers/char/hw_random/Kconfig
-@@ -148,3 +148,16 @@ config HW_RANDOM_VIRTIO
-         To compile this driver as a module, choose M here: the
-         module will be called virtio-rng.  If unsure, say N.
-+
-+config HW_RANDOM_UBICOM32
-+      tristate "Ubicom32 HW Random Number Generator support"
-+      depends on HW_RANDOM && UBICOM32
-+      default HW_RANDOM
-+      ---help---
-+        This driver provides kernel-side support for the Random Number
-+        Generator hardware found on Ubicom32 processors.
-+
-+        To compile this driver as a module, choose M here: the
-+        module will be called pasemi-rng.
-+
-+        If unsure, say Y.
---- a/drivers/char/hw_random/Makefile
-+++ b/drivers/char/hw_random/Makefile
-@@ -15,3 +15,4 @@ obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx
- obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
- obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
- obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
-+obj-$(CONFIG_HW_RANDOM_UBICOM32) += ubicom32-rng.o
---- /dev/null
-+++ b/drivers/char/hw_random/ubicom32-rng.c
-@@ -0,0 +1,105 @@
-+/*
-+ * drivers/net/ubi32-eth.c
-+ *   Ubicom32 hardware random number generator driver.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/hw_random.h>
-+#include <linux/delay.h>
-+#include <asm/io.h>
-+#include <asm/ip5000.h>
-+
-+#define MODULE_NAME "ubicom32_rng"
-+
-+static int ubicom32_rng_data_present(struct hwrng *rng, int wait)
-+{
-+      int data, i;
-+
-+      for (i = 0; i < 20; i++) {
-+              data = *(int *)(TIMER_BASE + TIMER_TRN);
-+              if (data || !wait)
-+                      break;
-+              udelay(10);
-+      }
-+      return data;
-+}
-+
-+static int ubicom32_rng_data_read(struct hwrng *rng, u32 *data)
-+{
-+      *data = *(int *)(TIMER_BASE + TIMER_TRN);
-+      return 4;
-+}
-+
-+static int ubicom32_rng_init(struct hwrng *rng)
-+{
-+      printk(KERN_INFO "ubicom32 rng init\n");
-+      *(int *)(TIMER_BASE + TIMER_TRN_CFG) = TIMER_TRN_CFG_ENABLE_OSC;
-+      return 0;
-+}
-+
-+static void ubicom32_rng_cleanup(struct hwrng *rng)
-+{
-+      printk(KERN_INFO "ubicom32 rng cleanup\n");
-+      *(int *)(TIMER_BASE + TIMER_TRN_CFG) = 0;
-+}
-+
-+static struct hwrng ubicom32_rng = {
-+      .name           = MODULE_NAME,
-+      .init           = ubicom32_rng_init,
-+      .cleanup        = ubicom32_rng_cleanup,
-+      .data_present   = ubicom32_rng_data_present,
-+      .data_read      = ubicom32_rng_data_read,
-+      .priv           = 0,
-+};
-+
-+static int __init mod_init(void)
-+{
-+      int err;
-+
-+      printk(KERN_INFO "ubicom32 rng started\n");
-+      err = hwrng_register(&ubicom32_rng);
-+      if (err) {
-+              printk(KERN_ERR "ubicom32 rng register failed (%d)\n",
-+                      err);
-+      }
-+
-+      return err;
-+}
-+
-+static void __exit mod_exit(void)
-+{
-+      printk(KERN_INFO "ubicom32 rng stopped\n");
-+      hwrng_unregister(&ubicom32_rng);
-+}
-+
-+module_init(mod_init);
-+module_exit(mod_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Ubicom, Inc.");
-+MODULE_DESCRIPTION("H/W rng driver for ubicom32 processor");
-+MODULE_VERSION("1:1.0.a");
---- a/drivers/crypto/Kconfig
-+++ b/drivers/crypto/Kconfig
-@@ -61,6 +61,40 @@ config CRYPTO_DEV_GEODE
-         To compile this driver as a module, choose M here: the module
-         will be called geode-aes.
-+config CRYPTO_UBICOM32
-+        bool "Ubicom32 Security Module"
-+        depends on UBICOM32
-+        help
-+          This is the ubicom32 hardware acceleration common code.
-+
-+config CRYPTO_AES_UBICOM32
-+        tristate "Ubicom32 AES implementation"
-+        depends on CRYPTO_UBICOM32
-+        select CRYPTO_ALGAPI
-+        help
-+          This is the ubicom32 hardware AES implementation.
-+
-+config CRYPTO_DES_UBICOM32
-+        tristate "Ubicom32 DES implementation"
-+        depends on CRYPTO_UBICOM32
-+        select CRYPTO_ALGAPI
-+        help
-+          This is the ubicom32 hardware DES and 3DES implementation.
-+
-+config CRYPTO_SHA1_UBICOM32
-+        tristate "Ubicom32 SHA1 implementation"
-+        depends on CRYPTO_UBICOM32
-+        select CRYPTO_ALGAPI
-+        help
-+          This is the ubicom32 hardware SHA1 implementation.
-+
-+config CRYPTO_MD5_UBICOM32
-+        tristate "Ubicom32 MD5 implementation"
-+        depends on CRYPTO_UBICOM32
-+        select CRYPTO_ALGAPI
-+        help
-+          This is the ubicom32 hardware MD5 implementation.
-+
- config ZCRYPT
-       tristate "Support for PCI-attached cryptographic adapters"
-       depends on S390
---- a/drivers/mmc/host/Kconfig
-+++ b/drivers/mmc/host/Kconfig
-@@ -266,3 +266,10 @@ config GPIOMMC_CONFIGFS
-       help
-         This option automatically enables configfs support for gpiommc
-         if configfs is available.
-+
-+config MMC_UBICOM32
-+      tristate "Ubicom32 MMC/SD host controller"
-+      depends on UBICOM32
-+      help
-+        This provides support for the SD/MMC hardware found on Ubicom32
-+        IP7K processors
---- a/drivers/mmc/host/Makefile
-+++ b/drivers/mmc/host/Makefile
-@@ -30,4 +30,5 @@ obj-$(CONFIG_MMC_S3C)        += s3cmci.o
- obj-$(CONFIG_MMC_SDRICOH_CS)  += sdricoh_cs.o
- obj-$(CONFIG_MMC_TMIO)                += tmio_mmc.o
- obj-$(CONFIG_GPIOMMC)         += gpiommc.o
-+obj-$(CONFIG_MMC_UBICOM32)    += ubicom32sd.o
---- /dev/null
-+++ b/drivers/mmc/host/ubicom32sd.c
-@@ -0,0 +1,773 @@
-+/*
-+ * drivers/mmc/host/ubicom32sd.c
-+ *    Ubicom32 Secure Digital Host Controller Interface driver
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/delay.h>
-+#include <linux/scatterlist.h>
-+#include <linux/leds.h>
-+#include <linux/gpio.h>
-+#include <linux/mmc/host.h>
-+
-+#include <asm/ubicom32sd.h>
-+
-+#define DRIVER_NAME "ubicom32sd"
-+
-+#define sd_printk(...)
-+//#define sd_printk printk
-+
-+#define SDTIO_VP_VERSION      3
-+
-+#define SDTIO_MAX_SG_BLOCKS   16
-+
-+enum sdtio_commands {
-+      SDTIO_COMMAND_NOP,
-+      SDTIO_COMMAND_SETUP,
-+      SDTIO_COMMAND_SETUP_SDIO,
-+      SDTIO_COMMAND_EXECUTE,
-+      SDTIO_COMMAND_RESET,
-+};
-+
-+#define SDTIO_COMMAND_SHIFT                   24
-+#define SDTIO_COMMAND_FLAG_STOP_RSP_CRC               (1 << 10)
-+#define SDTIO_COMMAND_FLAG_STOP_RSP_136               (1 << 9)
-+#define SDTIO_COMMAND_FLAG_STOP_RSP           (1 << 8)
-+#define SDTIO_COMMAND_FLAG_STOP_CMD           (1 << 7)
-+#define SDTIO_COMMAND_FLAG_DATA_STREAM                (1 << 6)
-+#define SDTIO_COMMAND_FLAG_DATA_RD            (1 << 5)
-+#define SDTIO_COMMAND_FLAG_DATA_WR            (1 << 4)
-+#define SDTIO_COMMAND_FLAG_CMD_RSP_CRC                (1 << 3)
-+#define SDTIO_COMMAND_FLAG_CMD_RSP_136                (1 << 2)
-+#define SDTIO_COMMAND_FLAG_CMD_RSP            (1 << 1)
-+#define SDTIO_COMMAND_FLAG_CMD                        (1 << 0)
-+
-+/*
-+ * SDTIO_COMMAND_SETUP_SDIO
-+ */
-+#define SDTIO_COMMAND_FLAG_SDIO_INT_EN                (1 << 0)
-+
-+/*
-+ * SDTIO_COMMAND_SETUP
-+ *      clock speed in arg
-+ */
-+#define SDTIO_COMMAND_FLAG_4BIT                 (1 << 3)
-+#define SDTIO_COMMAND_FLAG_1BIT                 (1 << 2)
-+#define SDTIO_COMMAND_FLAG_SET_CLOCK            (1 << 1)
-+#define SDTIO_COMMAND_FLAG_SET_WIDTH            (1 << 0)
-+
-+#define SDTIO_COMMAND_FLAG_CMD_RSP_MASK               (SDTIO_COMMAND_FLAG_CMD_RSP | SDTIO_COMMAND_FLAG_CMD_RSP_136)
-+#define SDTIO_COMMAND_FLAG_STOP_RSP_MASK      (SDTIO_COMMAND_FLAG_STOP_RSP | SDTIO_COMMAND_FLAG_STOP_RSP_136)
-+#define SDTIO_COMMAND_FLAG_RSP_MASK           (SDTIO_COMMAND_FLAG_CMD_RSP_MASK | SDTIO_COMMAND_FLAG_STOP_RSP_MASK)
-+
-+struct sdtio_vp_sg {
-+      volatile void           *addr;
-+      volatile u32_t          len;
-+};
-+
-+#define SDTIO_VP_INT_STATUS_DONE              (1 << 31)
-+#define SDTIO_VP_INT_STATUS_SDIO_INT          (1 << 10)
-+#define SDTIO_VP_INT_STATUS_DATA_CRC_ERR      (1 << 9)
-+#define SDTIO_VP_INT_STATUS_DATA_PROG_ERR     (1 << 8)
-+#define SDTIO_VP_INT_STATUS_DATA_TIMEOUT      (1 << 7)
-+#define SDTIO_VP_INT_STATUS_STOP_RSP_CRC      (1 << 6)
-+#define SDTIO_VP_INT_STATUS_STOP_RSP_TIMEOUT  (1 << 5)
-+#define SDTIO_VP_INT_STATUS_CMD_RSP_CRC               (1 << 4)
-+#define SDTIO_VP_INT_STATUS_CMD_RSP_TIMEOUT   (1 << 3)
-+#define SDTIO_VP_INT_STATUS_CMD_TIMEOUT               (1 << 2)
-+#define SDTIO_VP_INT_STATUS_CARD1_INSERT      (1 << 1)
-+#define SDTIO_VP_INT_STATUS_CARD0_INSERT      (1 << 0)
-+
-+struct sdtio_vp_regs {
-+      u32_t                           version;
-+      u32_t                           f_max;
-+      u32_t                           f_min;
-+
-+      volatile u32_t                  int_status;
-+
-+      volatile u32_t                  command;
-+      volatile u32_t                  arg;
-+
-+      volatile u32_t                  cmd_opcode;
-+      volatile u32_t                  cmd_arg;
-+      volatile u32_t                  cmd_rsp0;
-+      volatile u32_t                  cmd_rsp1;
-+      volatile u32_t                  cmd_rsp2;
-+      volatile u32_t                  cmd_rsp3;
-+
-+      volatile u32_t                  stop_opcode;
-+      volatile u32_t                  stop_arg;
-+      volatile u32_t                  stop_rsp0;
-+      volatile u32_t                  stop_rsp1;
-+      volatile u32_t                  stop_rsp2;
-+      volatile u32_t                  stop_rsp3;
-+
-+      volatile u32_t                  data_timeout_ns;
-+      volatile u16_t                  data_blksz;
-+      volatile u16_t                  data_blkct;
-+      volatile u32_t                  data_bytes_transferred;
-+      volatile u32_t                  sg_len;
-+      struct sdtio_vp_sg              sg[SDTIO_MAX_SG_BLOCKS];
-+};
-+
-+struct ubicom32sd_data {
-+      const struct ubicom32sd_platform_data   *pdata;
-+
-+      struct mmc_host                         *mmc;
-+
-+      /*
-+       * Lock used to protect the data structure
-+      spinlock_t                              lock;
-+       */
-+      int     int_en;
-+      int     int_pend;
-+
-+      /*
-+       * Receive and transmit interrupts used for communicating
-+       * with hardware
-+       */
-+      int                                     irq_tx;
-+      int                                     irq_rx;
-+
-+      /*
-+       * Current outstanding mmc request
-+       */
-+      struct mmc_request                      *mrq;
-+
-+      /*
-+       * Hardware registers
-+       */
-+      struct sdtio_vp_regs                    *regs;
-+};
-+
-+/*****************************************************************************\
-+ *                                                                           *
-+ * Suspend/resume                                                            *
-+ *                                                                           *
-+\*****************************************************************************/
-+
-+#if 0//def CONFIG_PM
-+
-+int ubicom32sd_suspend_host(struct ubicom32sd_host *host, pm_message_t state)
-+{
-+      int ret;
-+
-+      ret = mmc_suspend_host(host->mmc, state);
-+      if (ret)
-+              return ret;
-+
-+      free_irq(host->irq, host);
-+
-+      return 0;
-+}
-+
-+EXPORT_SYMBOL_GPL(ubicom32sd_suspend_host);
-+
-+int ubicom32sd_resume_host(struct ubicom32sd_host *host)
-+{
-+      int ret;
-+
-+      if (host->flags & UBICOM32SD_USE_DMA) {
-+              if (host->ops->enable_dma)
-+                      host->ops->enable_dma(host);
-+      }
-+
-+      ret = request_irq(host->irq, ubicom32sd_irq, IRQF_SHARED,
-+                        mmc_hostname(host->mmc), host);
-+      if (ret)
-+              return ret;
-+
-+      ubicom32sd_init(host);
-+      mmiowb();
-+
-+      ret = mmc_resume_host(host->mmc);
-+      if (ret)
-+              return ret;
-+
-+      return 0;
-+}
-+
-+EXPORT_SYMBOL_GPL(ubicom32sd_resume_host);
-+
-+#endif /* CONFIG_PM */
-+
-+/*
-+ * ubicom32sd_send_command_sync
-+ */
-+static void ubicom32sd_send_command_sync(struct ubicom32sd_data *ud, u32_t command, u32_t arg)
-+{
-+      ud->regs->command = command;
-+      ud->regs->arg = arg;
-+      ubicom32_set_interrupt(ud->irq_tx);
-+      while (ud->regs->command) {
-+              ndelay(100);
-+      }
-+}
-+
-+/*
-+ * ubicom32sd_send_command
-+ */
-+static void ubicom32sd_send_command(struct ubicom32sd_data *ud, u32_t command, u32_t arg)
-+{
-+      ud->regs->command = command;
-+      ud->regs->arg = arg;
-+      ubicom32_set_interrupt(ud->irq_tx);
-+}
-+
-+/*
-+ * ubicom32sd_reset
-+ */
-+static void ubicom32sd_reset(struct ubicom32sd_data *ud)
-+{
-+      ubicom32sd_send_command_sync(ud, SDTIO_COMMAND_RESET << SDTIO_COMMAND_SHIFT, 0);
-+      ud->regs->int_status = 0;
-+}
-+
-+/*
-+ * ubicom32sd_mmc_request
-+ */
-+static void ubicom32sd_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
-+{
-+      struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc);
-+      u32_t command = SDTIO_COMMAND_EXECUTE << SDTIO_COMMAND_SHIFT;
-+      int ret = 0;
-+
-+      WARN(ud->mrq != NULL, "ud->mrq still set to %p\n", ud->mrq);
-+      //pr_debug("send cmd %08x arg %08x flags %08x\n", cmd->opcode, cmd->arg, cmd->flags);
-+
-+      if (mrq->cmd) {
-+              struct mmc_command *cmd = mrq->cmd;
-+
-+              sd_printk("%s:\t\t\tsetup cmd %02d arg %08x flags %08x\n", mmc_hostname(mmc), cmd->opcode, cmd->arg, cmd->flags);
-+
-+              ud->regs->cmd_opcode = cmd->opcode;
-+              ud->regs->cmd_arg = cmd->arg;
-+
-+              command |= SDTIO_COMMAND_FLAG_CMD;
-+
-+              if (cmd->flags & MMC_RSP_PRESENT) {
-+                      command |= SDTIO_COMMAND_FLAG_CMD_RSP;
-+              }
-+
-+              if (cmd->flags & MMC_RSP_136) {
-+                      command |= SDTIO_COMMAND_FLAG_CMD_RSP_136;
-+              }
-+
-+              if (cmd->flags & MMC_RSP_CRC) {
-+                      command |= SDTIO_COMMAND_FLAG_CMD_RSP_CRC;
-+              }
-+      }
-+
-+      if (mrq->data) {
-+              struct mmc_data *data = mrq->data;
-+              struct scatterlist *sg = data->sg;
-+              int i;
-+
-+printk("%s:\t\t\tsetup data blksz %d num %d sglen=%d fl=%08x Tns=%u\n", mmc_hostname(mmc), data->blksz, data->blocks, data->sg_len, data->flags, data->timeout_ns);
-+
-+              sd_printk("%s:\t\t\tsetup data blksz %d num %d sglen=%d fl=%08x Tns=%u\n",
-+                        mmc_hostname(mmc), data->blksz, data->blocks, data->sg_len,
-+                        data->flags, data->timeout_ns);
-+
-+              if (data->sg_len > SDTIO_MAX_SG_BLOCKS) {
-+                      ret = -EINVAL;
-+                      data->error = -EINVAL;
-+                      goto fail;
-+              }
-+
-+              ud->regs->data_timeout_ns = data->timeout_ns;
-+              ud->regs->data_blksz = data->blksz;
-+              ud->regs->data_blkct = data->blocks;
-+              ud->regs->sg_len = data->sg_len;
-+
-+              /*
-+               * Load all of our sg list into the driver sg buffer
-+               */
-+              for (i = 0; i < data->sg_len; i++) {
-+                      sd_printk("%s: sg %d = %p %d\n", mmc_hostname(mmc), i, sg_virt(sg), sg->length);
-+                      ud->regs->sg[i].addr = sg_virt(sg);
-+                      ud->regs->sg[i].len = sg->length;
-+                      if (((u32_t)ud->regs->sg[i].addr & 0x03) || (sg->length & 0x03)) {
-+                              sd_printk("%s: Need aligned buffers\n", mmc_hostname(mmc));
-+                              ret = -EINVAL;
-+                              data->error = -EINVAL;
-+                              goto fail;
-+                      }
-+                      sg++;
-+              }
-+              if (data->flags & MMC_DATA_READ) {
-+                      command |= SDTIO_COMMAND_FLAG_DATA_RD;
-+              } else if (data->flags & MMC_DATA_WRITE) {
-+                      command |= SDTIO_COMMAND_FLAG_DATA_WR;
-+              } else if (data->flags & MMC_DATA_STREAM) {
-+                      command |= SDTIO_COMMAND_FLAG_DATA_STREAM;
-+              }
-+      }
-+
-+      if (mrq->stop) {
-+              struct mmc_command *stop = mrq->stop;
-+              sd_printk("%s: \t\t\tsetup stop %02d arg %08x flags %08x\n", mmc_hostname(mmc), stop->opcode, stop->arg, stop->flags);
-+
-+              ud->regs->stop_opcode = stop->opcode;
-+              ud->regs->stop_arg = stop->arg;
-+
-+              command |= SDTIO_COMMAND_FLAG_STOP_CMD;
-+
-+              if (stop->flags & MMC_RSP_PRESENT) {
-+                      command |= SDTIO_COMMAND_FLAG_STOP_RSP;
-+              }
-+
-+              if (stop->flags & MMC_RSP_136) {
-+                      command |= SDTIO_COMMAND_FLAG_STOP_RSP_136;
-+              }
-+
-+              if (stop->flags & MMC_RSP_CRC) {
-+                      command |= SDTIO_COMMAND_FLAG_STOP_RSP_CRC;
-+              }
-+      }
-+
-+      ud->mrq = mrq;
-+
-+      sd_printk("%s: Sending command %08x\n", mmc_hostname(mmc), command);
-+
-+      ubicom32sd_send_command(ud, command, 0);
-+
-+      return;
-+fail:
-+      sd_printk("%s: mmcreq ret = %d\n", mmc_hostname(mmc), ret);
-+      mrq->cmd->error = ret;
-+      mmc_request_done(mmc, mrq);
-+}
-+
-+/*
-+ * ubicom32sd_mmc_set_ios
-+ */
-+static void ubicom32sd_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-+{
-+      struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc);
-+      u32_t command = SDTIO_COMMAND_SETUP << SDTIO_COMMAND_SHIFT;
-+      u32_t arg = 0;
-+      sd_printk("%s: ios call bw:%u pm:%u clk:%u\n", mmc_hostname(mmc), 1 << ios->bus_width, ios->power_mode, ios->clock);
-+
-+      switch (ios->bus_width) {
-+      case MMC_BUS_WIDTH_1:
-+              command |= SDTIO_COMMAND_FLAG_SET_WIDTH | SDTIO_COMMAND_FLAG_1BIT;
-+              break;
-+
-+      case MMC_BUS_WIDTH_4:
-+              command |= SDTIO_COMMAND_FLAG_SET_WIDTH | SDTIO_COMMAND_FLAG_4BIT;
-+              break;
-+      }
-+
-+      if (ios->clock) {
-+              arg = ios->clock;
-+              command |= SDTIO_COMMAND_FLAG_SET_CLOCK;
-+      }
-+
-+      switch (ios->power_mode) {
-+
-+      /*
-+       * Turn off the SD bus (power + clock)
-+       */
-+      case MMC_POWER_OFF:
-+              gpio_set_value(ud->pdata->cards[0].pin_pwr, !ud->pdata->cards[0].pwr_polarity);
-+              command |= SDTIO_COMMAND_FLAG_SET_CLOCK;
-+              break;
-+
-+      /*
-+       * Turn on the power to the SD bus
-+       */
-+      case MMC_POWER_ON:
-+              gpio_set_value(ud->pdata->cards[0].pin_pwr, ud->pdata->cards[0].pwr_polarity);
-+              break;
-+
-+      /*
-+       * Turn on the clock to the SD bus
-+       */
-+      case MMC_POWER_UP:
-+              /*
-+               * Done above
-+               */
-+              break;
-+      }
-+
-+      ubicom32sd_send_command_sync(ud, command, arg);
-+
-+      /*
-+       * Let the power settle down
-+       */
-+      udelay(500);
-+}
-+
-+/*
-+ * ubicom32sd_mmc_get_cd
-+ */
-+static int ubicom32sd_mmc_get_cd(struct mmc_host *mmc)
-+{
-+      struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc);
-+      sd_printk("%s: get cd %u %u\n", mmc_hostname(mmc), ud->pdata->cards[0].pin_cd, gpio_get_value(ud->pdata->cards[0].pin_cd));
-+
-+      return gpio_get_value(ud->pdata->cards[0].pin_cd) ?
-+                              ud->pdata->cards[0].cd_polarity :
-+                              !ud->pdata->cards[0].cd_polarity;
-+}
-+
-+/*
-+ * ubicom32sd_mmc_get_ro
-+ */
-+static int ubicom32sd_mmc_get_ro(struct mmc_host *mmc)
-+{
-+      struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc);
-+      sd_printk("%s: get ro %u %u\n", mmc_hostname(mmc), ud->pdata->cards[0].pin_wp, gpio_get_value(ud->pdata->cards[0].pin_wp));
-+
-+      return gpio_get_value(ud->pdata->cards[0].pin_wp) ?
-+                              ud->pdata->cards[0].wp_polarity :
-+                              !ud->pdata->cards[0].wp_polarity;
-+}
-+
-+/*
-+ * ubicom32sd_mmc_enable_sdio_irq
-+ */
-+static void ubicom32sd_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
-+{
-+      struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc);
-+
-+      ud->int_en = enable;
-+      if (enable && ud->int_pend) {
-+              ud->int_pend = 0;
-+              mmc_signal_sdio_irq(mmc);
-+      }
-+}
-+
-+/*
-+ * ubicom32sd_interrupt
-+ */
-+static irqreturn_t ubicom32sd_interrupt(int irq, void *dev)
-+{
-+      struct mmc_host *mmc = (struct mmc_host *)dev;
-+      struct mmc_request *mrq;
-+      struct ubicom32sd_data *ud;
-+      u32_t int_status;
-+
-+      if (!mmc) {
-+              return IRQ_HANDLED;
-+      }
-+
-+      ud = (struct ubicom32sd_data *)mmc_priv(mmc);
-+      if (!ud) {
-+              return IRQ_HANDLED;
-+      }
-+
-+      int_status = ud->regs->int_status;
-+      ud->regs->int_status &= ~int_status;
-+
-+      if (int_status & SDTIO_VP_INT_STATUS_SDIO_INT) {
-+              if (ud->int_en) {
-+                      ud->int_pend = 0;
-+                      mmc_signal_sdio_irq(mmc);
-+              } else {
-+                      ud->int_pend++;
-+              }
-+      }
-+
-+      if (!(int_status & SDTIO_VP_INT_STATUS_DONE)) {
-+              return IRQ_HANDLED;
-+      }
-+
-+      mrq = ud->mrq;
-+      if (!mrq) {
-+              sd_printk("%s: Spurious interrupt", mmc_hostname(mmc));
-+              return IRQ_HANDLED;
-+      }
-+      ud->mrq = NULL;
-+
-+      /*
-+       * SDTIO_VP_INT_DONE
-+       */
-+      if (mrq->cmd->flags & MMC_RSP_PRESENT) {
-+              struct mmc_command *cmd = mrq->cmd;
-+              cmd->error = 0;
-+
-+              if ((cmd->flags & MMC_RSP_CRC) && (int_status & SDTIO_VP_INT_STATUS_CMD_RSP_CRC)) {
-+                      cmd->error = -EILSEQ;
-+              } else if (int_status & SDTIO_VP_INT_STATUS_CMD_RSP_TIMEOUT) {
-+                      cmd->error = -ETIMEDOUT;
-+                      goto done;
-+              } else if (cmd->flags & MMC_RSP_136) {
-+                      cmd->resp[0] = ud->regs->cmd_rsp0;
-+                      cmd->resp[1] = ud->regs->cmd_rsp1;
-+                      cmd->resp[2] = ud->regs->cmd_rsp2;
-+                      cmd->resp[3] = ud->regs->cmd_rsp3;
-+              } else {
-+                      cmd->resp[0] = ud->regs->cmd_rsp0;
-+              }
-+              sd_printk("%s:\t\t\tResponse %08x %08x %08x %08x err=%d\n", mmc_hostname(mmc), cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error);
-+      }
-+
-+      if (mrq->data) {
-+              struct mmc_data *data = mrq->data;
-+
-+              if (int_status & SDTIO_VP_INT_STATUS_DATA_TIMEOUT) {
-+                      data->error = -ETIMEDOUT;
-+                      sd_printk("%s:\t\t\tData Timeout\n", mmc_hostname(mmc));
-+                      goto done;
-+              } else if (int_status & SDTIO_VP_INT_STATUS_DATA_CRC_ERR) {
-+                      data->error = -EILSEQ;
-+                      sd_printk("%s:\t\t\tData CRC\n", mmc_hostname(mmc));
-+                      goto done;
-+              } else if (int_status & SDTIO_VP_INT_STATUS_DATA_PROG_ERR) {
-+                      data->error = -EILSEQ;
-+                      sd_printk("%s:\t\t\tData Program Error\n", mmc_hostname(mmc));
-+                      goto done;
-+              } else {
-+                      data->error = 0;
-+                      data->bytes_xfered = ud->regs->data_bytes_transferred;
-+              }
-+      }
-+
-+      if (mrq->stop && (mrq->stop->flags & MMC_RSP_PRESENT)) {
-+              struct mmc_command *stop = mrq->stop;
-+              stop->error = 0;
-+
-+              if ((stop->flags & MMC_RSP_CRC) && (int_status & SDTIO_VP_INT_STATUS_STOP_RSP_CRC)) {
-+                      stop->error = -EILSEQ;
-+              } else if (int_status & SDTIO_VP_INT_STATUS_STOP_RSP_TIMEOUT) {
-+                      stop->error = -ETIMEDOUT;
-+                      goto done;
-+              } else if (stop->flags & MMC_RSP_136) {
-+                      stop->resp[0] = ud->regs->stop_rsp0;
-+                      stop->resp[1] = ud->regs->stop_rsp1;
-+                      stop->resp[2] = ud->regs->stop_rsp2;
-+                      stop->resp[3] = ud->regs->stop_rsp3;
-+              } else {
-+                      stop->resp[0] = ud->regs->stop_rsp0;
-+              }
-+              sd_printk("%s:\t\t\tStop Response %08x %08x %08x %08x err=%d\n", mmc_hostname(mmc), stop->resp[0], stop->resp[1], stop->resp[2], stop->resp[3], stop->error);
-+      }
-+
-+done:
-+      mmc_request_done(mmc, mrq);
-+
-+      return IRQ_HANDLED;
-+}
-+
-+static struct mmc_host_ops ubicom32sd_ops = {
-+      .request                = ubicom32sd_mmc_request,
-+      .set_ios                = ubicom32sd_mmc_set_ios,
-+      .get_ro                 = ubicom32sd_mmc_get_ro,
-+      .get_cd                 = ubicom32sd_mmc_get_cd,
-+      .enable_sdio_irq        = ubicom32sd_mmc_enable_sdio_irq,
-+};
-+
-+/*
-+ * ubicom32sd_probe
-+ */
-+static int __devinit ubicom32sd_probe(struct platform_device *pdev)
-+{
-+      struct ubicom32sd_platform_data *pdata = (struct ubicom32sd_platform_data *)pdev->dev.platform_data;
-+      struct mmc_host *mmc;
-+      struct ubicom32sd_data *ud;
-+      struct resource *res_regs;
-+      struct resource *res_irq_tx;
-+      struct resource *res_irq_rx;
-+      int ret;
-+
-+      /*
-+       * Get our resources, regs is the hardware driver base address
-+       * and the tx and rx irqs are used to communicate with the
-+       * hardware driver.
-+       */
-+      res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      res_irq_tx = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-+      res_irq_rx = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
-+      if (!res_regs || !res_irq_tx || !res_irq_rx) {
-+              ret = -EINVAL;
-+              goto fail;
-+      }
-+
-+      /*
-+       * Reserve any gpios we need
-+       */
-+      ret = gpio_request(pdata->cards[0].pin_wp, "sd-wp");
-+      if (ret) {
-+              goto fail;
-+      }
-+      gpio_direction_input(pdata->cards[0].pin_wp);
-+
-+      ret = gpio_request(pdata->cards[0].pin_cd, "sd-cd");
-+      if (ret) {
-+              goto fail_cd;
-+      }
-+      gpio_direction_input(pdata->cards[0].pin_cd);
-+
-+      /*
-+       * HACK: for the dual port controller on port F, we don't support the second port right now
-+       */
-+      if (pdata->ncards > 1) {
-+              ret = gpio_request(pdata->cards[1].pin_pwr, "sd-pwr");
-+              gpio_direction_output(pdata->cards[1].pin_pwr, !pdata->cards[1].pwr_polarity);
-+              gpio_direction_output(pdata->cards[1].pin_pwr, pdata->cards[1].pwr_polarity);
-+      }
-+
-+      ret = gpio_request(pdata->cards[0].pin_pwr, "sd-pwr");
-+      if (ret) {
-+              goto fail_pwr;
-+      }
-+      gpio_direction_output(pdata->cards[0].pin_pwr, !pdata->cards[0].pwr_polarity);
-+
-+      /*
-+       * Allocate the MMC driver, it includes memory for our data.
-+       */
-+      mmc = mmc_alloc_host(sizeof(struct ubicom32sd_data), &pdev->dev);
-+      if (!mmc) {
-+              ret = -ENOMEM;
-+              goto fail_mmc;
-+      }
-+      ud = (struct ubicom32sd_data *)mmc_priv(mmc);
-+      ud->mmc = mmc;
-+      ud->pdata = pdata;
-+      ud->regs = (struct sdtio_vp_regs *)res_regs->start;
-+      ud->irq_tx = res_irq_tx->start;
-+      ud->irq_rx = res_irq_rx->start;
-+      platform_set_drvdata(pdev, mmc);
-+
-+      ret = request_irq(ud->irq_rx, ubicom32sd_interrupt, IRQF_DISABLED, mmc_hostname(mmc), mmc);
-+      if (ret) {
-+              goto fail_mmc;
-+      }
-+
-+      /*
-+       * Fill in the mmc structure
-+       */
-+      mmc->ops = &ubicom32sd_ops;
-+      mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NEEDS_POLL | MMC_CAP_SDIO_IRQ |
-+                  MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
-+
-+      mmc->f_min = ud->regs->f_min;
-+      mmc->f_max = ud->regs->f_max;
-+      mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-+
-+      /*
-+       * Setup some restrictions on transfers
-+       *
-+       * We allow up to SDTIO_MAX_SG_BLOCKS of data to DMA into, there are
-+       * not really any "max_seg_size", "max_req_size", or "max_blk_count"
-+       * restrictions (must be less than U32_MAX though), pick
-+       * something large?!...
-+       *
-+       * The hardware can do up to 4095 bytes per block, since the spec
-+       * only requires 2048, we'll set it to that and not worry about
-+       * potential weird blk lengths.
-+       */
-+      mmc->max_hw_segs = SDTIO_MAX_SG_BLOCKS;
-+      mmc->max_phys_segs = SDTIO_MAX_SG_BLOCKS;
-+      mmc->max_seg_size = 1024 * 1024;
-+      mmc->max_req_size = 1024 * 1024;
-+      mmc->max_blk_count = 1024;
-+
-+      mmc->max_blk_size = 2048;
-+
-+      ubicom32sd_reset(ud);
-+
-+      /*
-+       * enable interrupts
-+       */
-+      ud->int_en = 0;
-+      ubicom32sd_send_command_sync(ud, SDTIO_COMMAND_SETUP_SDIO << SDTIO_COMMAND_SHIFT | SDTIO_COMMAND_FLAG_SDIO_INT_EN, 0);
-+
-+      mmc_add_host(mmc);
-+
-+      printk(KERN_INFO "%s at %p, irq %d/%d\n", mmc_hostname(mmc),
-+                      ud->regs, ud->irq_tx, ud->irq_rx);
-+      return 0;
-+
-+fail_mmc:
-+      gpio_free(pdata->cards[0].pin_pwr);
-+fail_pwr:
-+      gpio_free(pdata->cards[0].pin_cd);
-+fail_cd:
-+      gpio_free(pdata->cards[0].pin_wp);
-+fail:
-+      return ret;
-+}
-+
-+/*
-+ * ubicom32sd_remove
-+ */
-+static int __devexit ubicom32sd_remove(struct platform_device *pdev)
-+{
-+      struct mmc_host *mmc = platform_get_drvdata(pdev);
-+
-+      platform_set_drvdata(pdev, NULL);
-+
-+      if (mmc) {
-+              struct ubicom32sd_data *ud = (struct ubicom32sd_data *)mmc_priv(mmc);
-+
-+              gpio_free(ud->pdata->cards[0].pin_pwr);
-+              gpio_free(ud->pdata->cards[0].pin_cd);
-+              gpio_free(ud->pdata->cards[0].pin_wp);
-+
-+              mmc_remove_host(mmc);
-+              mmc_free_host(mmc);
-+      }
-+
-+      /*
-+       * Note that our data is allocated as part of the mmc structure
-+       * so we don't need to free it.
-+       */
-+      return 0;
-+}
-+
-+static struct platform_driver ubicom32sd_driver = {
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+      .probe = ubicom32sd_probe,
-+      .remove = __devexit_p(ubicom32sd_remove),
-+#if 0
-+      .suspend = ubicom32sd_suspend,
-+      .resume = ubicom32sd_resume,
-+#endif
-+};
-+
-+/*
-+ * ubicom32sd_init
-+ */
-+static int __init ubicom32sd_init(void)
-+{
-+      return platform_driver_register(&ubicom32sd_driver);
-+}
-+module_init(ubicom32sd_init);
-+
-+/*
-+ * ubicom32sd_exit
-+ */
-+static void __exit ubicom32sd_exit(void)
-+{
-+    platform_driver_unregister(&ubicom32sd_driver);
-+}
-+module_exit(ubicom32sd_exit);
-+
-+MODULE_AUTHOR("Patrick Tjin");
-+MODULE_DESCRIPTION("Ubicom32 Secure Digital Host Controller Interface driver");
-+MODULE_LICENSE("GPL");
---- a/drivers/mtd/devices/Kconfig
-+++ b/drivers/mtd/devices/Kconfig
-@@ -104,6 +104,31 @@ config M25PXX_USE_FAST_READ
-       help
-         This option enables FAST_READ access supported by ST M25Pxx.
-+config MTD_UBI32_NAND_SPI_ER
-+      tristate "UBI32_NAND SPI-ER support"
-+      help
-+        This driver supports the Micron MT29F1G01 SPI-ER NAND flash chip
-+        using the built in flash controller on the Ubicom32 architecture.
-+        Partial page writes are not supported by this driver.
-+
-+config MTD_NAND_SPI_ER
-+      tristate "NAND SPI-ER support"
-+      help
-+        This driver supports the Micron MT29F1G01 SPI-ER NAND flash chip
-+        using a generic SPI bus.  Partial page writes are supported
-+        by this driver.
-+
-+config MTD_UBI32_M25P80
-+      tristate "Ubicom processor support for most SPI Flash chips (AT26DF, M25P, W25X, ...)"
-+      depends on UBICOM32
-+      default y
-+      help
-+        This enables access to most modern SPI flash chips, used for
-+        program and data storage.   Series supported include Atmel AT26DF,
-+        Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X.  Other chips
-+        are supported as well.  See the driver source for the current list,
-+        or to add other chips.
-+
- config MTD_SLRAM
-       tristate "Uncached system RAM"
-       help
---- a/drivers/mtd/devices/Makefile
-+++ b/drivers/mtd/devices/Makefile
-@@ -16,3 +16,6 @@ obj-$(CONFIG_MTD_LART)               += lart.o
- obj-$(CONFIG_MTD_BLOCK2MTD)   += block2mtd.o
- obj-$(CONFIG_MTD_DATAFLASH)   += mtd_dataflash.o
- obj-$(CONFIG_MTD_M25P80)      += m25p80.o
-+obj-$(CONFIG_MTD_UBI32_M25P80)        += ubi32-m25p80.o
-+obj-$(CONFIG_MTD_NAND_SPI_ER) += nand-spi-er.o
-+obj-$(CONFIG_MTD_UBI32_NAND_SPI_ER)   += ubi32-nand-spi-er.o
---- /dev/null
-+++ b/drivers/mtd/devices/nand-spi-er.c
-@@ -0,0 +1,1017 @@
-+/*
-+ * Micron SPI-ER NAND Flash Memory
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+*/
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/mutex.h>
-+#include <linux/err.h>
-+
-+#include <linux/spi/spi.h>
-+#include <linux/spi/flash.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/partitions.h>
-+
-+#define NAND_SPI_ER_BLOCK_FROM_ROW(row)               (row >> 6)
-+
-+#define NAND_SPI_ER_STATUS_P_FAIL             (1 << 3)
-+#define NAND_SPI_ER_STATUS_E_FAIL             (1 << 2)
-+#define NAND_SPI_ER_STATUS_OIP                        (1 << 0)
-+
-+#define NAND_SPI_ER_LAST_ROW_INVALID          0xFFFFFFFF
-+#define       NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET       0x08
-+
-+struct nand_spi_er_device {
-+      const char              *name;
-+
-+      uint8_t                 id0;
-+      uint8_t                 id1;
-+
-+      unsigned int            blocks;
-+      unsigned int            pages_per_block;
-+      unsigned int            page_size;
-+      unsigned int            write_size;
-+      unsigned int            erase_size;
-+};
-+
-+struct nand_spi_er {
-+      char                            name[24];
-+
-+      const struct nand_spi_er_device *device;
-+
-+      struct mutex                    lock;
-+      struct spi_device               *spi;
-+
-+      struct mtd_info                 mtd;
-+
-+      unsigned int                    last_row;       /* the last row we fetched */
-+
-+      /*
-+       * Bad block table (MUST be last in strcuture)
-+       */
-+      unsigned long                   nbb;
-+      unsigned long                   bbt[0];
-+};
-+
-+const struct nand_spi_er_device nand_spi_er_devices[] = {
-+      {
-+              name:                   "MT29F1G01ZDC",
-+              id0:                    0x2C,
-+              id1:                    0x12,
-+              blocks:                 1024,
-+              pages_per_block:        64,
-+              page_size:              2048,
-+              write_size:             512,
-+              erase_size:             64 * 2048,
-+      },
-+      {
-+              name:                   "MT29F1G01ZDC",
-+              id0:                    0x2C,
-+              id1:                    0x13,
-+              blocks:                 1024,
-+              pages_per_block:        64,
-+              page_size:              2048,
-+              write_size:             512,
-+              erase_size:             64 * 2048,
-+      },
-+};
-+
-+static int read_only = 0;
-+module_param(read_only, int, 0);
-+MODULE_PARM_DESC(read_only, "Leave device locked");
-+
-+/*
-+ * nand_spi_er_get_feature
-+ *    Get Feature register
-+ */
-+static int nand_spi_er_get_feature(struct nand_spi_er *chip, int reg, uint8_t *data)
-+{
-+      uint8_t txbuf[2];
-+      uint8_t rxbuf[1];
-+      int res;
-+
-+      txbuf[0] = 0x0F;
-+      txbuf[1] = reg;
-+      res = spi_write_then_read(chip->spi, txbuf, 2, rxbuf, 1);
-+      if (res) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: failed get feature res=%d\n", chip->name, res);
-+              return res;
-+      }
-+      *data = rxbuf[0];
-+      return 0;
-+}
-+
-+/*
-+ * nand_spi_er_busywait
-+ *    Wait until the chip is not busy
-+ */
-+static int nand_spi_er_busywait(struct nand_spi_er *chip, uint8_t *data)
-+{
-+      int i;
-+
-+      for (i = 0; i < 100; i++) {
-+              int res = nand_spi_er_get_feature(chip, 0xC0, data);
-+              if (res) {
-+                      return res;
-+              }
-+              if (!(*data & NAND_SPI_ER_STATUS_OIP)) {
-+                      break;
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * nand_spi_er_erase
-+ *    Erase a block, parameters must be block aligned
-+ */
-+static int nand_spi_er_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+      struct nand_spi_er *chip = mtd->priv;
-+      struct spi_device *spi = chip->spi;
-+      uint8_t txbuf[4];
-+      int res;
-+
-+      DEBUG(MTD_DEBUG_LEVEL3, "%s: erase addr:%x len:%x\n", chip->name, instr->addr, instr->len);
-+
-+      if ((instr->addr + instr->len) > mtd->size) {
-+              return -EINVAL;
-+      }
-+
-+      if (instr->addr & (chip->device->erase_size - 1)) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: erase address is not aligned %x\n", chip->name, instr->addr);
-+              return -EINVAL;
-+      }
-+
-+      if (instr->len & (chip->device->erase_size - 1)) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: erase len is not aligned %x\n", chip->name, instr->len);
-+              return -EINVAL;
-+      }
-+
-+      mutex_lock(&chip->lock);
-+      chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID;
-+
-+      while (instr->len) {
-+              uint32_t block = instr->addr >> 17;
-+              uint32_t row = block << 6;
-+              uint8_t stat;
-+              DEBUG(MTD_DEBUG_LEVEL3, "%s: block erase row:%x block:%x addr:%x rem:%x\n", chip->name, row, block, instr->addr, instr->len);
-+
-+              /*
-+               * Write enable
-+               */
-+              txbuf[0] = 0x06;
-+              res = spi_write(spi, txbuf, 1);
-+              if (res) {
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write enable res=%d\n", chip->name, res);
-+                      mutex_unlock(&chip->lock);
-+                      return res;
-+              }
-+
-+              /*
-+               * Test for bad block
-+               */
-+              if (test_bit(block, chip->bbt)) {
-+                      instr->fail_addr = block << 17;
-+                      instr->state = MTD_ERASE_FAILED;
-+                      res = -EBADMSG;
-+                      goto done;
-+              }
-+
-+              /*
-+               * Block erase
-+               */
-+              txbuf[0] = 0xD8;
-+              txbuf[1] = 0x00;
-+              txbuf[2] = row >> 8;
-+              txbuf[3] = row & 0xFF;
-+              res = spi_write(spi, txbuf, 4);
-+              if (res) {
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: failed block erase res=%d\n", chip->name, res);
-+                      instr->fail_addr = block << 17;
-+                      instr->state = MTD_ERASE_FAILED;
-+                      goto done;
-+              }
-+
-+              /*
-+               * Wait
-+               */
-+              res = nand_spi_er_busywait(chip, &stat);
-+              if (res || (stat & NAND_SPI_ER_STATUS_OIP)) {
-+                      instr->fail_addr = block << 17;
-+                      instr->state = MTD_ERASE_FAILED;
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat);
-+                      if (res) {
-+                              goto done;
-+                      }
-+
-+                      /*
-+                       * Chip is stuck?
-+                       */
-+                      res = -EIO;
-+                      goto done;
-+              }
-+
-+              /*
-+               * Check the status register
-+               */
-+              if (stat & NAND_SPI_ER_STATUS_E_FAIL) {
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: E_FAIL signalled (%02x)\n", chip->name, stat);
-+                      instr->fail_addr = block << 17;
-+                      instr->state = MTD_ERASE_FAILED;
-+                      goto done;
-+              }
-+
-+              /*
-+               * Next
-+               */
-+              block++;
-+              instr->len -= chip->device->erase_size;
-+              instr->addr += chip->device->erase_size;
-+      }
-+
-+      instr->state = MTD_ERASE_DONE;
-+
-+      mutex_unlock(&chip->lock);
-+      return 0;
-+
-+done:
-+      /*
-+       * Write disable
-+       */
-+      txbuf[0] = 0x04;
-+      res = spi_write(spi, txbuf, 1);
-+      if (res) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write disable res=%d\n", chip->name, res);
-+      }
-+
-+      mutex_unlock(&chip->lock);
-+
-+      mtd_erase_callback(instr);
-+      return 0;
-+}
-+
-+/*
-+ * nand_spi_er_read
-+ *
-+ * return -EUCLEAN: ecc error recovered
-+ * return -EBADMSG: ecc error not recovered
-+*/
-+static int nand_spi_er_read(struct mtd_info *mtd, loff_t from, size_t len,
-+                             size_t *retlen, u_char *buf)
-+{
-+      struct nand_spi_er *chip = mtd->priv;
-+      struct spi_device *spi = chip->spi;
-+
-+      uint32_t row;
-+      uint32_t column;
-+      int retval = 0;
-+
-+      *retlen = 0;
-+      DEBUG(MTD_DEBUG_LEVEL2, "%s: read block from %llx len %d into %p\n", chip->name, from, len, buf);
-+
-+      /*
-+       * Zero length reads, nothing to do
-+       */
-+      if (len == 0) {
-+              return 0;
-+      }
-+
-+      /*
-+       * Reject reads which go over the end of the flash
-+       */
-+      if ((from + len) > mtd->size) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Get the row and column address to start at
-+       */
-+      row = from >> 11;
-+      column = from & 0x7FF;
-+      DEBUG(MTD_DEBUG_LEVEL3, "%s: row=%x %d column=%x %d last_row=%x %d\n", chip->name, row, row, column, column, chip->last_row, chip->last_row);
-+
-+      /*
-+       * Read the data from the chip
-+       */
-+      mutex_lock(&chip->lock);
-+      while (len) {
-+              uint8_t stat;
-+              uint8_t txbuf[4];
-+              struct spi_message message;
-+              struct spi_transfer x[2];
-+              int res;
-+              size_t toread;
-+
-+              /*
-+               * Figure out how much to read
-+               *
-+               * If we are reading from the middle of a page then the most we
-+               * can read is to the end of the page
-+               */
-+              toread = len;
-+              if (toread > (chip->device->page_size - column)) {
-+                      toread = chip->device->page_size - column;
-+              }
-+
-+              DEBUG(MTD_DEBUG_LEVEL3, "%s: buf=%p toread=%x row=%x column=%x last_row=%x\n", chip->name, buf, toread, row, column, chip->last_row);
-+
-+              if (chip->last_row != row) {
-+                      /*
-+                       * Check if the block is bad
-+                       */
-+                      if (test_bit(NAND_SPI_ER_BLOCK_FROM_ROW(row), chip->bbt)) {
-+                              mutex_unlock(&chip->lock);
-+                              return -EBADMSG;
-+                      }
-+
-+                      /*
-+                       * Load the appropriate page
-+                       */
-+                      txbuf[0] = 0x13;
-+                      txbuf[1] = 0x00;
-+                      txbuf[2] = row >> 8;
-+                      txbuf[3] = row & 0xFF;
-+                      res = spi_write(spi, txbuf, 4);
-+                      if (res) {
-+                              DEBUG(MTD_DEBUG_LEVEL1, "%s: failed page load res=%d\n", chip->name, res);
-+                              mutex_unlock(&chip->lock);
-+                              return res;
-+                      }
-+
-+                      /*
-+                       * Wait
-+                       */
-+                      res = nand_spi_er_busywait(chip, &stat);
-+                      if (res || (stat & NAND_SPI_ER_STATUS_OIP)) {
-+                              DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat);
-+                              if (res) {
-+                                      mutex_unlock(&chip->lock);
-+                                      return res;
-+                              }
-+
-+                              /*
-+                               * Chip is stuck?
-+                               */
-+                              mutex_unlock(&chip->lock);
-+                              return -EIO;
-+                      }
-+
-+                      /*
-+                       * Check the ECC bits
-+                       */
-+                      stat >>= 4;
-+                      if (stat == 1) {
-+                              DEBUG(MTD_DEBUG_LEVEL1, "%s: ECC recovered, row=%x\n", chip->name, row);
-+                              retval = -EUCLEAN;
-+                      }
-+                      if (stat == 2) {
-+                              DEBUG(MTD_DEBUG_LEVEL0, "%s: failed ECC, row=%x\n", chip->name, row);
-+                              chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID;
-+                              mutex_unlock(&chip->lock);
-+                              return -EBADMSG;
-+                      }
-+
-+              }
-+
-+              chip->last_row = row;
-+
-+              /*
-+               * Read out the data
-+               */
-+              spi_message_init(&message);
-+              memset(x, 0, sizeof(x));
-+
-+              txbuf[0] = 0x03;
-+              txbuf[1] = column >> 8;
-+              txbuf[2] = column & 0xFF;
-+              txbuf[3] = 0;
-+              x[0].tx_buf = txbuf;
-+              x[0].len = 4;
-+              spi_message_add_tail(&x[0], &message);
-+
-+              x[1].rx_buf = buf;
-+              x[1].len = toread;
-+              spi_message_add_tail(&x[1], &message);
-+
-+              res = spi_sync(spi, &message);
-+              if (res) {
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: failed data read res=%d\n", chip->name, res);
-+                      mutex_unlock(&chip->lock);
-+                      return res;
-+              }
-+              buf += toread;
-+              len -= toread;
-+              *retlen += toread;
-+
-+              /*
-+               * For the next page, increment the row and always start at column 0
-+               */
-+              column = 0;
-+              row++;
-+      }
-+
-+      mutex_unlock(&chip->lock);
-+      return retval;
-+}
-+
-+/*
-+ * nand_spi_er_write
-+ */
-+#define NOT_ALIGNED(x) ((x & (device->write_size - 1)) != 0)
-+static int nand_spi_er_write(struct mtd_info *mtd, loff_t to, size_t len,
-+                              size_t *retlen, const u_char *buf)
-+{
-+      struct nand_spi_er *chip = mtd->priv;
-+      struct spi_device *spi = chip->spi;
-+      const struct nand_spi_er_device *device = chip->device;
-+      uint32_t row;
-+      uint32_t col;
-+      uint8_t txbuf[4];
-+      int res;
-+      size_t towrite;
-+
-+      DEBUG(MTD_DEBUG_LEVEL2, "%s: write block to %llx len %d from %p\n", chip->name, to, len, buf);
-+
-+      *retlen = 0;
-+
-+      /*
-+       * nothing to write
-+       */
-+      if (!len) {
-+              return 0;
-+      }
-+
-+      /*
-+       * Reject writes which go over the end of the flash
-+       */
-+      if ((to + len) > mtd->size) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Check to see if everything is page aligned
-+       */
-+      if (NOT_ALIGNED(to) || NOT_ALIGNED(len)) {
-+              printk(KERN_NOTICE "nand_spi_er_write: Attempt to write non page aligned data\n");
-+              return -EINVAL;
-+      }
-+
-+      mutex_lock(&chip->lock);
-+      chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID;
-+
-+      /*
-+       * If the first write is a partial write then write at most the number of
-+       * bytes to get us page aligned and then the remainder will be
-+       * page aligned.  The last bit may be a partial page as well.
-+       */
-+      col = to & (device->page_size - 1);
-+      towrite = device->page_size - col;
-+      if (towrite > len) {
-+              towrite = len;
-+      }
-+
-+      /*
-+       * Write the data
-+       */
-+      row = to >> 11;
-+      while (len) {
-+              struct spi_message message;
-+              struct spi_transfer x[2];
-+              uint8_t stat;
-+
-+              DEBUG(MTD_DEBUG_LEVEL3, "%s: write %p to row:%x col:%x len:%x rem:%x\n", chip->name, buf, row, col, towrite, len);
-+
-+              /*
-+               * Write enable
-+               */
-+              txbuf[0] = 0x06;
-+              res = spi_write(spi, txbuf, 1);
-+              if (res) {
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write enable res=%d\n", chip->name, res);
-+                      mutex_unlock(&chip->lock);
-+                      return res;
-+              }
-+
-+              /*
-+               * Write the data into the cache
-+               */
-+              spi_message_init(&message);
-+              memset(x, 0, sizeof(x));
-+              txbuf[0] = 0x02;
-+              txbuf[1] = col >> 8;
-+              txbuf[2] = col & 0xFF;
-+              x[0].tx_buf = txbuf;
-+              x[0].len = 3;
-+              spi_message_add_tail(&x[0], &message);
-+              x[1].tx_buf = buf;
-+              x[1].len = towrite;
-+              spi_message_add_tail(&x[1], &message);
-+              res = spi_sync(spi, &message);
-+              if (res) {
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: failed cache write res=%d\n", chip->name, res);
-+                      goto done;
-+              }
-+
-+              /*
-+               * Program execute
-+               */
-+              txbuf[0] = 0x10;
-+              txbuf[1] = 0x00;
-+              txbuf[2] = row >> 8;
-+              txbuf[3] = row & 0xFF;
-+              res = spi_write(spi, txbuf, 4);
-+              if (res) {
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: failed prog execute res=%d\n", chip->name, res);
-+                      goto done;
-+              }
-+
-+              /*
-+               * Wait
-+               */
-+              res = nand_spi_er_busywait(chip, &stat);
-+              if (res || (stat & NAND_SPI_ER_STATUS_OIP)) {
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat);
-+                      if (res) {
-+                              goto done;
-+                      }
-+
-+                      /*
-+                       * Chip is stuck?
-+                       */
-+                      res = -EIO;
-+                      goto done;
-+              }
-+
-+              if (stat & (1 << 3)) {
-+                      res = -EBADMSG;
-+                      goto done;
-+              }
-+
-+              row++;
-+              buf += towrite;
-+              len -= towrite;
-+              *retlen += towrite;
-+
-+              /*
-+               * At this point, we are always page aligned so start at column 0.
-+               * Note we may not have a full page to write at the end, hence the
-+               * check if towrite > len.
-+               */
-+              col = 0;
-+              towrite = device->page_size;
-+              if (towrite > len) {
-+                      towrite = len;
-+              }
-+      }
-+
-+      mutex_unlock(&chip->lock);
-+      return res;
-+
-+done:
-+      /*
-+       * Write disable
-+       */
-+      txbuf[0] = 0x04;
-+      res = spi_write(spi, txbuf, 1);
-+      if (res) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write disable res=%d\n", chip->name, res);
-+      }
-+
-+      mutex_unlock(&chip->lock);
-+
-+      return res;
-+}
-+
-+/*
-+ * nand_spi_er_isbad
-+ */
-+static int nand_spi_er_isbad(struct mtd_info *mtd, loff_t ofs)
-+{
-+      struct nand_spi_er *chip = mtd->priv;
-+      uint32_t block;
-+
-+      if (ofs & (chip->device->erase_size - 1)) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs);
-+              return -EINVAL;
-+      }
-+
-+      block = ofs >> 17;
-+
-+      return test_bit(block, chip->bbt);
-+}
-+
-+/*
-+ * nand_spi_er_markbad
-+ */
-+static int nand_spi_er_markbad(struct mtd_info *mtd, loff_t ofs)
-+{
-+      struct nand_spi_er *chip = mtd->priv;
-+      struct spi_device *spi = chip->spi;
-+      uint32_t block;
-+      uint32_t row;
-+      uint8_t txbuf[7];
-+      int res;
-+      uint8_t stat;
-+
-+      if (ofs & (chip->device->erase_size - 1)) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs);
-+              return -EINVAL;
-+      }
-+
-+      block = ofs >> 17;
-+
-+      /*
-+       * If it's already marked bad, no need to mark it
-+       */
-+      if (test_bit(block, chip->bbt)) {
-+              return 0;
-+      }
-+
-+      /*
-+       * Mark it in our cache
-+       */
-+      __set_bit(block, chip->bbt);
-+
-+      /*
-+       * Write the user bad block mark.  If it fails, then we really
-+       * can't do anything about it.
-+       */
-+      mutex_lock(&chip->lock);
-+      chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID;
-+
-+      /*
-+       * Write enable
-+       */
-+      txbuf[0] = 0x06;
-+      res = spi_write(spi, txbuf, 1);
-+      if (res) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write enable res=%d\n", chip->name, res);
-+              mutex_unlock(&chip->lock);
-+              return res;
-+      }
-+
-+      /*
-+       * Write the mark
-+       */
-+      txbuf[0] = 0x84;
-+      txbuf[1] = 0x08;
-+      txbuf[2] = NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET;
-+      txbuf[3] = 0xde;
-+      txbuf[4] = 0xad;
-+      txbuf[5] = 0xbe;
-+      txbuf[6] = 0xef;
-+      res = spi_write(spi, txbuf, 7);
-+      if (res) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write mark res=%d\n", chip->name, res);
-+              goto done;
-+      }
-+
-+      /*
-+       * Program execute
-+       */
-+      row = ofs >> 11;
-+      txbuf[0] = 0x10;
-+      txbuf[1] = 0x00;
-+      txbuf[2] = row >> 8;
-+      txbuf[3] = row & 0xFF;
-+      res = spi_write(spi, txbuf, 4);
-+      if (res) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: failed program execute res=%d\n", chip->name, res);
-+              goto done;
-+      }
-+
-+      /*
-+       * Wait
-+       */
-+      res = nand_spi_er_busywait(chip, &stat);
-+      if (res || (stat & NAND_SPI_ER_STATUS_OIP)) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat);
-+              if (res) {
-+                      goto done;
-+              }
-+
-+              /*
-+               * Chip is stuck?
-+               */
-+              res = -EIO;
-+              goto done;
-+      }
-+
-+      if (stat & (1 << 3)) {
-+              res = -EBADMSG;
-+      }
-+
-+done:
-+      /*
-+       * Write disable
-+       */
-+      txbuf[0] = 0x04;
-+      res = spi_write(spi, txbuf, 1);
-+      if (res) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: failed write disable res=%d\n", chip->name, res);
-+      }
-+
-+      mutex_unlock(&chip->lock);
-+
-+      return res;
-+}
-+
-+/*
-+ * nand_spi_er_read_bbt
-+ */
-+static int nand_spi_er_read_bbt(struct nand_spi_er *chip)
-+{
-+      int j;
-+      for (j = 0; j < chip->device->blocks; j++) {
-+              uint8_t txbuf[4];
-+              uint8_t rxbuf[16];
-+              uint32_t bbmark;
-+              int res;
-+              unsigned short row = j << 6;
-+              uint8_t stat;
-+
-+              /*
-+               * Read Page
-+               */
-+              txbuf[0] = 0x13;
-+              txbuf[1] = 0x00;
-+              txbuf[2] = row >> 8;
-+              txbuf[3] = row & 0xFF;
-+              res = spi_write(chip->spi, txbuf, 4);
-+              if (res) {
-+                      return res;
-+              }
-+
-+              /*
-+               * Wait
-+               */
-+              res = nand_spi_er_busywait(chip, &stat);
-+              if (res || (stat & NAND_SPI_ER_STATUS_OIP)) {
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive res=%d stat=%02x\n", chip->name, res, stat);
-+                      if (res) {
-+                              return res;
-+                      }
-+
-+                      /*
-+                       * Chip is stuck?
-+                       */
-+                      return -EIO;
-+              }
-+
-+              /*
-+               * Check factory bad block mark
-+               */
-+              txbuf[0] = 0x03;
-+              txbuf[1] = 0x08;
-+              txbuf[2] = 0x00;
-+              txbuf[3] = 0x00;
-+              res = spi_write_then_read(chip->spi, txbuf, 4, rxbuf, 16);
-+              if (res) {
-+                      return res;
-+              }
-+              if (rxbuf[0] != 0xFF) {
-+                      chip->nbb++;
-+                      __set_bit(j, chip->bbt);
-+                      continue;
-+              }
-+
-+              memcpy(&bbmark, &rxbuf[8], 4);
-+              if (bbmark == 0xdeadbeef) {
-+                      chip->nbb++;
-+                      __set_bit(j, chip->bbt);
-+              }
-+      }
-+
-+#if defined(CONFIG_MTD_DEBUG) && (MTD_DEBUG_LEVEL3 <= CONFIG_MTD_DEBUG_VERBOSE)
-+      printk("%s: Bad Block Table:", chip->name);
-+      for (j = 0; j < chip->device->blocks; j++) {
-+              if ((j % 64) == 0) {
-+                      printk("\n%s: block %03x: ", chip->name, j);
-+              }
-+              printk("%c", test_bit(j, chip->bbt) ? 'X' : '.');
-+      }
-+      printk("\n%s: Bad Block Numbers: ", chip->name);
-+      for (j = 0; j < chip->device->blocks; j++) {
-+              if (test_bit(j, chip->bbt)) {
-+                      printk("%x ", j);
-+              }
-+      }
-+      printk("\n");
-+#endif
-+
-+      return 0;
-+}
-+
-+#ifndef MODULE
-+/*
-+ * Called at boot time:
-+ *
-+ * nand_spi_er=read_only
-+ *    if read_only specified then do not unlock device
-+ */
-+static int __init nand_spi_er_setup(char *str)
-+{
-+      if (str && (strncasecmp(str, "read_only", 9) == 0)) {
-+              read_only = 1;
-+      }
-+      return 0;
-+}
-+
-+__setup("nand_spi_er=", nand_spi_er_setup);
-+#endif
-+
-+/*
-+ * nand_spi_er_probe
-+ *    Detect and initialize nand_spi_er device.
-+ */
-+static int __devinit nand_spi_er_probe(struct spi_device *spi)
-+{
-+      uint8_t txbuf[3];
-+      uint8_t rxbuf[2];
-+      int i;
-+      int res;
-+      size_t bbt_bytes;
-+      struct nand_spi_er *chip;
-+      const struct nand_spi_er_device *device;
-+
-+      res = spi_setup(spi);
-+      if (res) {
-+              return res;
-+      }
-+
-+      /*
-+       * Reset
-+       */
-+      for (i = 0; i < 2; i++) {
-+              txbuf[0] = 0xFF;
-+              res = spi_write(spi, txbuf, 1);
-+              if (res) {
-+                      return res;
-+              }
-+              udelay(250);
-+      }
-+      udelay(1000);
-+
-+      /*
-+       * Read ID
-+       */
-+      txbuf[0] = 0x9F;
-+      txbuf[1] = 0x00;
-+      res = spi_write_then_read(spi, txbuf, 2, rxbuf, 2);
-+      if (res) {
-+              return res;
-+      }
-+
-+      device = nand_spi_er_devices;
-+      for (i = 0; i < ARRAY_SIZE(nand_spi_er_devices); i++) {
-+              if ((device->id0 == rxbuf[0]) && (device->id1 == rxbuf[1])) {
-+                      break;
-+              }
-+              device++;
-+      }
-+      if (i == ARRAY_SIZE(nand_spi_er_devices)) {
-+              return -ENODEV;
-+      }
-+
-+      /*
-+       * Initialize our chip structure
-+       */
-+      bbt_bytes = DIV_ROUND_UP(device->blocks, BITS_PER_BYTE);
-+      chip = kzalloc(sizeof(struct nand_spi_er) + bbt_bytes, GFP_KERNEL);
-+      if (!chip) {
-+              return -ENOMEM;
-+      }
-+      snprintf(chip->name, sizeof(chip->name), "%s.%d.%d", device->name, spi->master->bus_num, spi->chip_select);
-+
-+      chip->spi = spi;
-+      chip->device = device;
-+      chip->last_row = NAND_SPI_ER_LAST_ROW_INVALID;
-+
-+      mutex_init(&chip->lock);
-+
-+      chip->mtd.type = MTD_NANDFLASH;
-+      chip->mtd.flags = MTD_WRITEABLE;
-+
-+      /*
-+       * #blocks * block size * n blocks
-+       */
-+      chip->mtd.size = device->blocks * device->pages_per_block * device->page_size;
-+      chip->mtd.erasesize = device->erase_size;
-+
-+      /*
-+       * 1 page, optionally we can support partial write (512)
-+       */
-+      chip->mtd.writesize = device->write_size;
-+      chip->mtd.name = device->name;
-+      chip->mtd.erase = nand_spi_er_erase;
-+      chip->mtd.read = nand_spi_er_read;
-+      chip->mtd.write = nand_spi_er_write;
-+      chip->mtd.block_isbad = nand_spi_er_isbad;
-+      chip->mtd.block_markbad = nand_spi_er_markbad;
-+      chip->mtd.priv = chip;
-+
-+      /*
-+       * Cache the bad block table
-+       */
-+      res = nand_spi_er_read_bbt(chip);
-+      if (res) {
-+              kfree(chip);
-+              return res;
-+      }
-+
-+      /*
-+       * Un/lock the chip
-+       */
-+      txbuf[0] = 0x1F;
-+      txbuf[1] = 0xA0;
-+      if (read_only) {
-+              txbuf[2] = 0x38;
-+      } else {
-+              txbuf[2] = 0x00;
-+      }
-+      res = spi_write(spi, txbuf, 3);
-+      if (res) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: failed lock operation res=%d\n", chip->name, res);
-+              mutex_unlock(&chip->lock);
-+              return res;
-+      }
-+
-+      spi_set_drvdata(spi, chip);
-+
-+      printk(KERN_INFO "%s: added device %s size: %u KBytes %u bad blocks %s\n", spi->dev.bus_id, chip->mtd.name, DIV_ROUND_UP(chip->mtd.size, 1024), chip->nbb, read_only ? "[read only]" : "");
-+      return add_mtd_device(&chip->mtd);
-+}
-+
-+/*
-+ * nand_spi_er_remove
-+ */
-+static int __devexit nand_spi_er_remove(struct spi_device *spi)
-+{
-+      struct nand_spi_er *chip = spi_get_drvdata(spi);
-+      int status = 0;
-+
-+      DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", spi->dev.bus_id);
-+      status = del_mtd_device(&chip->mtd);
-+      if (status == 0)
-+              kfree(chip);
-+      return status;
-+}
-+
-+static struct spi_driver nand_spi_er_driver = {
-+      .driver = {
-+              .name           = "nand-spi-er",
-+              .bus            = &spi_bus_type,
-+              .owner          = THIS_MODULE,
-+      },
-+
-+      .probe          = nand_spi_er_probe,
-+      .remove         = __devexit_p(nand_spi_er_remove),
-+
-+      /* FIXME:  investigate suspend and resume... */
-+};
-+
-+/*
-+ * nand_spi_er_init
-+ */
-+static int __init nand_spi_er_init(void)
-+{
-+      return spi_register_driver(&nand_spi_er_driver);
-+}
-+module_init(nand_spi_er_init);
-+
-+/*
-+ * nand_spi_er_exit
-+ */
-+static void __exit nand_spi_er_exit(void)
-+{
-+      spi_unregister_driver(&nand_spi_er_driver);
-+}
-+module_exit(nand_spi_er_exit);
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Patrick Tjin");
-+MODULE_DESCRIPTION("MTD nand_spi_er driver");
---- /dev/null
-+++ b/drivers/mtd/devices/ubi32-m25p80.c
-@@ -0,0 +1,1066 @@
-+/*
-+ * drivers/mtd/devices/ubi32-m25p80.c
-+ *   NOR flash driver, Ubicom processor internal SPI flash interface.
-+ *
-+ *   This code instantiates the serial flash that contains the
-+ *   original bootcode.  The serial flash start at address 0x60000000
-+ *   in both Ubicom32V3 and Ubicom32V4 ISAs.
-+ *
-+ *   This piece of flash is made to appear as a Memory Technology
-+ *   Device (MTD) with this driver to allow Read/Write/Erase operations.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/types.h>
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/mtd/physmap.h>
-+#include <linux/spi/spi.h>
-+#include <linux/spi/flash.h>
-+
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/mutex.h>
-+
-+#include <asm/ip5000.h>
-+#include <asm/devtree.h>
-+
-+#define UBICOM32_FLASH_BASE   0x60000000
-+#define UBICOM32_FLASH_MAX_SIZE 0x01000000
-+#define UBICOM32_FLASH_START  0x00000000
-+#define UBICOM32_KERNEL_OFFSET        0x00010000 /* The kernel starts after Ubicom
-+                                          * .protect section. */
-+
-+static struct mtd_partition ubicom32_flash_partitions[] = {
-+      {
-+              .name   = "Bootloader",         /* Protected Section
-+                                               * Partition */
-+              .size   = 0x10000,
-+              .offset = UBICOM32_FLASH_START,
-+//            .mask_flags = MTD_WRITEABLE     /* Mark Read-only */
-+      },
-+      {
-+              .name   = "Kernel",             /* Kernel Partition. */
-+              .size   = 0,                    /* this will be set up during
-+                                               * probe stage. At that time we
-+                                               * will know end of linux image
-+                                               * in flash. */
-+              .offset = MTDPART_OFS_APPEND,   /* Starts right after Protected
-+                                               * section. */
-+//            .mask_flags = MTD_WRITEABLE     /* Mark Read-only */
-+      },
-+      {
-+              .name   = "Rest",               /* Rest of the flash. */
-+              .size   = 0x200000,             /* Use up what remains in the
-+                                               * flash. */
-+              .offset = MTDPART_OFS_NXTBLK,   /* Starts right after Protected
-+                                               * section. */
-+      }
-+};
-+
-+static struct flash_platform_data ubicom32_flash_data = {
-+      .name = "ubicom32_boot_flash",
-+      .parts = ubicom32_flash_partitions,
-+      .nr_parts = ARRAY_SIZE(ubicom32_flash_partitions),
-+};
-+
-+static struct resource ubicom32_flash_resource[] = {
-+      {
-+              .start  = UBICOM32_FLASH_BASE,
-+              .end    = UBICOM32_FLASH_BASE +
-+              UBICOM32_FLASH_MAX_SIZE - 1,
-+              .flags  = IORESOURCE_MEM,
-+      },
-+};
-+
-+static struct platform_device ubicom32_flash_device = {
-+      .name = "ubicom32flashdriver",
-+      .id = 0, /* Bus number */
-+      .num_resources = ARRAY_SIZE(ubicom32_flash_resource),
-+      .resource = ubicom32_flash_resource,
-+      .dev = {
-+              .platform_data = &ubicom32_flash_data,
-+      },
-+};
-+
-+static struct platform_device *ubicom32_flash_devices[] = {
-+      &ubicom32_flash_device,
-+};
-+
-+static int __init ubicom32_flash_init(void)
-+{
-+      printk(KERN_INFO "%s(): registering device resources\n",
-+             __FUNCTION__);
-+      platform_add_devices(ubicom32_flash_devices,
-+                           ARRAY_SIZE(ubicom32_flash_devices));
-+      return 0;
-+}
-+
-+arch_initcall(ubicom32_flash_init);
-+
-+/*
-+ * MTD SPI driver for ST M25Pxx (and similar) serial flash chips through
-+ * Ubicom32 SPI controller.
-+ *
-+ * Author: Mike Lavender, mike@steroidmicros.com
-+ *
-+ * Copyright (c) 2005, Intec Automation Inc.
-+ *
-+ * Some parts are based on lart.c by Abraham Van Der Merwe
-+ *
-+ * Cleaned up and generalized based on mtd_dataflash.c
-+ *
-+ * This code is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ */
-+
-+#define FLASH_PAGESIZE                256
-+
-+/* Flash opcodes. */
-+#define       OPCODE_WREN             0x06    /* Write enable */
-+#define       OPCODE_RDSR             0x05    /* Read status register */
-+#define       OPCODE_READ             0x03    /* Read data bytes (low frequency) */
-+#define       OPCODE_FAST_READ        0x0b    /* Read data bytes (high frequency) */
-+#define       OPCODE_PP               0x02    /* Page program (up to 256 bytes) */
-+#define       OPCODE_BE_4K            0x20    /* Erase 4KiB block */
-+#define       OPCODE_BE_32K           0x52    /* Erase 32KiB block */
-+#define       OPCODE_SE               0xd8    /* Sector erase (usually 64KiB) */
-+#define       OPCODE_RDID             0x9f    /* Read JEDEC ID */
-+
-+/* Status Register bits. */
-+#define       SR_WIP                  1       /* Write in progress */
-+#define       SR_WEL                  2       /* Write enable latch */
-+/* meaning of other SR_* bits may differ between vendors */
-+#define       SR_BP0                  4       /* Block protect 0 */
-+#define       SR_BP1                  8       /* Block protect 1 */
-+#define       SR_BP2                  0x10    /* Block protect 2 */
-+#define       SR_SRWD                 0x80    /* SR write protect */
-+
-+/* Define max times to check status register before we give up. */
-+#define       MAX_READY_WAIT_COUNT    100000
-+
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+#define       mtd_has_partitions()    (1)
-+#else
-+#define       mtd_has_partitions()    (0)
-+#endif
-+
-+/*
-+ * Ubicom32 FLASH Command Set
-+ */
-+#define FLASH_FC_INST_CMD     0x00    /* for SPI command only transaction */
-+#define FLASH_FC_INST_WR      0x01    /* for SPI write transaction */
-+#define FLASH_FC_INST_RD      0x02    /* for SPI read transaction */
-+
-+#define ALIGN_DOWN(v, a) ((v) & ~((a) - 1))
-+#define ALIGN_UP(v, a) (((v) + ((a) - 1)) & ~((a) - 1))
-+
-+#define       FLASH_COMMAND_KICK_OFF(io)                                                      \
-+      asm volatile(                                                                   \
-+      "       bset    "D(IO_INT_CLR)"(%0), #0, #%%bit("D(IO_XFL_INT_DONE)")   \n\t"   \
-+      "       jmpt.t  .+4                                                     \n\t"   \
-+      "       bset    "D(IO_INT_SET)"(%0), #0, #%%bit("D(IO_XFL_INT_START)")  \n\t"   \
-+              :                                                                       \
-+              : "a" (io)                                                              \
-+              : "memory", "cc"                                                        \
-+      );
-+
-+#define       FLASH_COMMAND_WAIT_FOR_COMPLETION(io)                                           \
-+      asm volatile(                                                                   \
-+      "       btst    "D(IO_INT_STATUS)"(%0), #%%bit("D(IO_XFL_INT_DONE)")    \n\t"   \
-+      "       jmpeq.f .-4                                                     \n\t"   \
-+              :                                                                       \
-+              : "a" (io)                                                              \
-+              : "memory", "cc"                                                                        \
-+      );
-+
-+#define       FLASH_COMMAND_EXEC(io)                                                          \
-+      FLASH_COMMAND_KICK_OFF(io)                                                      \
-+      FLASH_COMMAND_WAIT_FOR_COMPLETION(io)
-+
-+
-+#define OSC1_FREQ 12000000
-+#define TEN_MICRO_SECONDS (OSC1_FREQ * 10 / 1000000)
-+
-+/*
-+ * We will have to eventually replace this null definition with the real thing.
-+ */
-+#define WATCHDOG_RESET()
-+
-+#define EXTFLASH_WRITE_FIFO_SIZE 32
-+#define EXTFLASH_WRITE_BLOCK_SIZE EXTFLASH_WRITE_FIFO_SIZE /* limit the size to
-+                                                          * FIFO capacity, so
-+                                                          * the thread can be
-+                                                          * suspended. */
-+
-+#define JFFS2_FILESYSTEM_SIZE 0x100000
-+
-+/****************************************************************************/
-+
-+struct m25p {
-+      struct platform_device  *plt_dev;
-+      struct mutex            lock;
-+      struct mtd_info         mtd;
-+      unsigned                partitioned:1;
-+      u8                      erase_opcode;
-+      u8                      command[4];
-+};
-+
-+static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
-+{
-+      return container_of(mtd, struct m25p, mtd);
-+}
-+
-+/****************************************************************************/
-+
-+/*
-+ * Internal helper functions
-+ */
-+
-+/*
-+ * Read the status register, returning its value in the location
-+ * Return the status register value.
-+ * Returns negative if error occurred.
-+ */
-+static int read_sr(struct m25p *flash)
-+{
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA;
-+
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) |
-+              IO_XFL_CTL1_FC_DATA(1);
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_RDSR);
-+      FLASH_COMMAND_EXEC(io);
-+
-+      return io->status1 & 0xff;
-+}
-+
-+/*
-+ * mem_flash_io_read_u32()
-+ */
-+static u32 mem_flash_io_read_u32(u32 addr)
-+{
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA;
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) |
-+              IO_XFL_CTL1_FC_DATA(4) | IO_XFL_CTL1_FC_DUMMY(1) |
-+              IO_XFL_CTL1_FC_ADDR;
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_FAST_READ) |
-+              IO_XFL_CTL2_FC_ADDR(addr);
-+      FLASH_COMMAND_EXEC(io);
-+      return io->status1;
-+}
-+
-+/*
-+ * mem_flash_read_u8()
-+ */
-+static u8 mem_flash_read_u8(u32 addr)
-+{
-+      u32 tmp_addr = ALIGN_DOWN(addr, 4);
-+      u32 tmp_data = mem_flash_io_read_u32(tmp_addr);
-+      u8 *ptr = (u8 *)&tmp_data;
-+      return ptr[addr & 0x3];
-+}
-+
-+/*
-+ * mem_flash_read()
-+ *    No need to lock as read is implemented with ireads (same as normal flash
-+ *    execution).
-+ */
-+static void mem_flash_read(u32 addr, void *dst, size_t length)
-+{
-+      /*
-+       * Range check
-+       */
-+      /*
-+       * Fix source alignment.
-+       */
-+      while (addr & 0x03) {
-+              if (length == 0) {
-+                      return;
-+              }
-+              *((u8 *)dst) = mem_flash_read_u8(addr++);
-+              dst++;
-+              length--;
-+      }
-+
-+      while (length >= 4) {
-+              u32 tmp_data = mem_flash_io_read_u32(addr);
-+              addr += 4;
-+              length -= 4;
-+
-+              /*
-+               * Send the data to the destination.
-+               */
-+              memcpy((void *)dst, (void *)&tmp_data, 4);
-+              dst += 4;
-+      }
-+
-+      while (length--) {
-+              *((u8 *)dst) = mem_flash_read_u8(addr++);
-+              dst++;
-+      }
-+}
-+
-+/*
-+ * mem_flash_wait_until_complete()
-+ */
-+static void mem_flash_wait_until_complete(void)
-+{
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA;
-+
-+      do {
-+              /*
-+               * Put a delay here to deal with flash programming problem.
-+               */
-+              u32 mptval = UBICOM32_IO_TIMER->mptval + TEN_MICRO_SECONDS;
-+              while (UBICOM32_IO_TIMER->mptval < mptval)
-+                      ;
-+
-+              io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+              io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) |
-+                      IO_XFL_CTL1_FC_DATA(1);
-+              io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_RDSR);
-+              FLASH_COMMAND_EXEC(io);
-+      } while (io->status1 & SR_WIP);
-+}
-+
-+/*
-+ * mem_flash_write_next()
-+ */
-+static size_t mem_flash_write_next(u32 addr, u8 *buf, size_t length)
-+{
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA;
-+      u32 data_start = addr;
-+      u32 data_end = addr + length;
-+      size_t count;
-+      u32 i, j;
-+
-+      /*
-+       * Top limit address.
-+       */
-+      u32 block_start = ALIGN_DOWN(data_start, 4);
-+      u32 block_end = block_start + EXTFLASH_WRITE_BLOCK_SIZE;
-+
-+      union {
-+              u8 byte[EXTFLASH_WRITE_BLOCK_SIZE];
-+              u32 word[EXTFLASH_WRITE_BLOCK_SIZE / 4];
-+      } write_buf;
-+
-+      u32 *flash_addr = (u32 *)block_start;
-+
-+      /*
-+       * The write block must be limited by FLASH internal buffer.
-+       */
-+      u32 block_end_align = ALIGN_DOWN(block_end, 256);
-+      bool write_needed;
-+
-+      block_end = (block_end_align > block_start)
-+              ? block_end_align : block_end;
-+      data_end = (data_end <= block_end) ? data_end : block_end;
-+      block_end = ALIGN_UP(data_end, 4);
-+      count = data_end - data_start;
-+
-+      /*
-+       * Transfer data to a buffer.
-+       */
-+      for (i = 0; i < (block_end - block_start) / 4; i++) {
-+              /*
-+               * The FLASH read can hold D-cache for a long time.
-+               * Use I/O operation to read FLASH to avoid starving other
-+               * threads, especially HRT.  (Do this for application only)
-+               */
-+              write_buf.word[i] = mem_flash_io_read_u32(
-+                      (u32)(&flash_addr[i]));
-+      }
-+
-+      write_needed = false;
-+      for (i = 0, j = (data_start - block_start);
-+           i < (data_end - data_start); i++, j++) {
-+              write_needed = write_needed || (write_buf.byte[j] != buf[i]);
-+              write_buf.byte[j] &= buf[i];
-+      }
-+
-+
-+      /*
-+       * If the data in FLASH is identical to what to be written. Then skip
-+       * it.
-+       */
-+      if (write_needed) {
-+              /*
-+               * Write to flash.
-+               */
-+              void *tmp __attribute__((unused));
-+              s32 extra_words;
-+
-+              asm volatile(
-+              "       move.4  %0, %2                                                                  \n\t"
-+              "       bset    "D(IO_INT_SET)"(%1), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)")        \n\t"
-+              "       pipe_flush 0                                                                    \n\t"
-+              "       .rept   "D(EXTFLASH_WRITE_FIFO_SIZE / 4)"                                       \n\t"
-+              "       move.4  "D(IO_TX_FIFO)"(%1), (%0)4++                                            \n\t"
-+              "       .endr                                                                           \n\t"
-+                      : "=&a" (tmp)
-+                      : "a" (io), "r" (&write_buf.word[0])
-+                      : "memory", "cc"
-+              );
-+
-+              /* Lock FLASH for write access. */
-+              io->ctl0 |= IO_XFL_CTL0_MCB_LOCK;
-+
-+              /* Command: WREN */
-+              io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+              io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD);
-+              io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_WREN);
-+              FLASH_COMMAND_EXEC(io);
-+
-+              /* Command: BYTE PROGRAM */
-+              io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+              io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) |
-+                      IO_XFL_CTL1_FC_DATA(block_end - block_start) |
-+                      IO_XFL_CTL1_FC_ADDR;
-+              io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_PP) |
-+                      IO_XFL_CTL2_FC_ADDR(block_start);
-+              FLASH_COMMAND_KICK_OFF(io);
-+
-+              extra_words = (s32)(block_end - block_start -
-+                                  EXTFLASH_WRITE_FIFO_SIZE) / 4;
-+              if (extra_words > 0) {
-+                      asm volatile(
-+                      "       move.4          %0, %3                          \n\t"
-+                      "1:     cmpi            "D(IO_FIFO_LEVEL)"(%1), #4      \n\t"
-+                      "       jmpgt.s.t       1b                              \n\t"
-+                      "       move.4          "D(IO_TX_FIFO)"(%1), (%0)4++    \n\t"
-+                      "       add.4           %2, #-1, %2                     \n\t"
-+                      "       jmpgt.t         1b                              \n\t"
-+                              : "=&a" (tmp)
-+                              : "a" (io), "d" (extra_words),
-+                                "r" (&write_buf.word[EXTFLASH_WRITE_FIFO_SIZE / 4])
-+                              : "memory", "cc"
-+                      );
-+              }
-+              FLASH_COMMAND_WAIT_FOR_COMPLETION(io);
-+
-+              mem_flash_wait_until_complete();
-+
-+
-+              /* Unlock FLASH for cache access. */
-+              io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK;
-+      }
-+
-+      /*
-+       * Complete.
-+       */
-+      return count;
-+}
-+
-+/*
-+ * mem_flash_write()
-+ */
-+static void mem_flash_write(u32 addr, const void *src, size_t length)
-+{
-+      /*
-+       * Write data
-+       */
-+      u8_t *ptr = (u8_t *)src;
-+      while (length) {
-+              size_t count = mem_flash_write_next(addr, ptr, length);
-+              addr += count;
-+              ptr += count;
-+              length -= count;
-+      }
-+}
-+
-+/*
-+ * Service routine to read status register until ready, or timeout occurs.
-+ * Returns non-zero if error.
-+ */
-+static int wait_till_ready(struct m25p *flash)
-+{
-+      int count;
-+      int sr;
-+
-+      /* one chip guarantees max 5 msec wait here after page writes,
-+       * but potentially three seconds (!) after page erase.
-+       */
-+      for (count = 0; count < MAX_READY_WAIT_COUNT; count++) {
-+              u32 mptval;
-+              sr = read_sr(flash);
-+              if (sr < 0)
-+                      break;
-+              else if (!(sr & SR_WIP))
-+                      return 0;
-+
-+              /*
-+               * Put a 10us delay here to deal with flash programming problem.
-+               */
-+              mptval = UBICOM32_IO_TIMER->mptval + TEN_MICRO_SECONDS;
-+              while ((s32)(mptval - UBICOM32_IO_TIMER->mptval) > 0) {
-+                      WATCHDOG_RESET();
-+              }
-+              /* REVISIT sometimes sleeping would be best */
-+      }
-+
-+      return 1;
-+}
-+
-+/*
-+ * mem_flash_erase_page()
-+ */
-+static void mem_flash_erase_page(u32 addr)
-+{
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA;
-+
-+      /* Lock FLASH for write access. */
-+      io->ctl0 |= IO_XFL_CTL0_MCB_LOCK;
-+
-+      /* Command: WREN */
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD);
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_WREN);
-+      FLASH_COMMAND_EXEC(io);
-+
-+      /* Command: ERASE */
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD) |
-+              IO_XFL_CTL1_FC_ADDR;
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_SE) |
-+              IO_XFL_CTL2_FC_ADDR(addr);
-+      FLASH_COMMAND_EXEC(io);
-+
-+      mem_flash_wait_until_complete();
-+
-+      /* Unlock FLASH for cache access. */
-+      io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK;
-+}
-+
-+/*
-+ * mem_flash_erase()
-+ */
-+static u32 mem_flash_erase(u32 addr, u32 length)
-+{
-+      /*
-+       * Calculate the endaddress to be the first address of the page
-+       * just beyond this erase section of pages.
-+       */
-+      u32 endaddr = addr + length;
-+
-+      /*
-+       * Erase.
-+       */
-+      while (addr < endaddr) {
-+              u32 test_addr = addr;
-+              mem_flash_erase_page(addr);
-+
-+              /*
-+               * Test how much was erased as actual flash page at this address
-+               * may be smaller than the expected page size.
-+               */
-+              while (test_addr < endaddr) {
-+                      /*
-+                       * The FLASH read can hold D-cache for a long time.  Use
-+                       * I/O operation to read FLASH to avoid starving other
-+                       * threads, especially HRT.  (Do this for application
-+                       * only)
-+                       */
-+                      if (mem_flash_io_read_u32(test_addr) != 0xFFFFFFFF) {
-+                              break;
-+                      }
-+                      test_addr += 4;
-+              }
-+              if (test_addr == addr) {
-+                      printk("erase failed at address 0x%x, skipping",
-+                             test_addr);
-+                      test_addr += 4;
-+                      return 1;
-+              }
-+              addr = test_addr;
-+      }
-+      return 0;
-+}
-+
-+
-+/****************************************************************************/
-+
-+/*
-+ * MTD implementation
-+ */
-+
-+/*
-+ * Erase an address range on the flash chip.  The address range may extend
-+ * one or more erase sectors.  Return an error is there is a problem erasing.
-+ */
-+static int ubicom32_flash_driver_erase(struct mtd_info *mtd,
-+                                     struct erase_info *instr)
-+{
-+      struct m25p *flash = mtd_to_m25p(mtd);
-+      u32 addr, len;
-+
-+      DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %lld\n",
-+            dev_name(&flash->plt_dev->dev), __FUNCTION__, "at",
-+            (u32)instr->addr, instr->len);
-+
-+      /* sanity checks */
-+      if (instr->addr + instr->len > flash->mtd.size)
-+              return -EINVAL;
-+      if ((instr->addr % mtd->erasesize) != 0
-+                      || (instr->len % mtd->erasesize) != 0) {
-+              return -EINVAL;
-+      }
-+
-+      addr = instr->addr + UBICOM32_FLASH_BASE;
-+      len = instr->len;
-+
-+      mutex_lock(&flash->lock);
-+
-+      /* REVISIT in some cases we could speed up erasing large regions
-+       * by using OPCODE_SE instead of OPCODE_BE_4K
-+       */
-+
-+      /* now erase those sectors */
-+      if (mem_flash_erase(addr, len)) {
-+              instr->state = MTD_ERASE_FAILED;
-+              mutex_unlock(&flash->lock);
-+              return -EIO;
-+      }
-+
-+      mutex_unlock(&flash->lock);
-+      instr->state = MTD_ERASE_DONE;
-+      mtd_erase_callback(instr);
-+      return 0;
-+}
-+
-+/*
-+ * Read an address range from the flash chip.  The address range
-+ * may be any size provided it is within the physical boundaries.
-+ */
-+static int ubicom32_flash_driver_read(struct mtd_info *mtd, loff_t from,
-+                                    size_t len, size_t *retlen, u_char *buf)
-+{
-+      struct m25p *flash = mtd_to_m25p(mtd);
-+      u32 base_addr = UBICOM32_FLASH_BASE + from;
-+
-+      DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n",
-+            dev_name(&flash->plt_dev->dev), __FUNCTION__, "from",
-+            (u32)from, len);
-+
-+      /* sanity checks */
-+      if (!len)
-+              return 0;
-+
-+      if (from + len > flash->mtd.size)
-+              return -EINVAL;
-+
-+      /* Byte count starts at zero. */
-+      if (retlen)
-+              *retlen = 0;
-+
-+      mutex_lock(&flash->lock);
-+
-+      /* Wait till previous write/erase is done. */
-+      if (wait_till_ready(flash)) {
-+              /* REVISIT status return?? */
-+              mutex_unlock(&flash->lock);
-+              return 1;
-+      }
-+
-+      mem_flash_read(base_addr, (void *)buf, len);
-+
-+      if (retlen)
-+              *retlen = len;
-+
-+      mutex_unlock(&flash->lock);
-+
-+      return 0;
-+}
-+
-+/*
-+ * Write an address range to the flash chip.  Data must be written in
-+ * FLASH_PAGESIZE chunks.  The address range may be any size provided
-+ * it is within the physical boundaries.
-+ */
-+static int ubicom32_flash_driver_write(struct mtd_info *mtd, loff_t to,
-+                                     size_t len, size_t *retlen,
-+                                     const u_char *buf)
-+{
-+      struct m25p *flash = mtd_to_m25p(mtd);
-+      u32 base_addr = UBICOM32_FLASH_BASE + to;
-+      DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n",
-+            dev_name(&flash->plt_dev->dev), __FUNCTION__, "to",
-+            (u32)to, len);
-+
-+      if (retlen)
-+              *retlen = 0;
-+
-+      /* sanity checks */
-+      if (!len)
-+              return 0;
-+
-+      if (to + len > flash->mtd.size)
-+              return -EINVAL;
-+
-+      mutex_lock(&flash->lock);
-+
-+      mem_flash_write(base_addr, (void *) buf, len);
-+
-+      /* Wait until finished previous write command. */
-+      if (wait_till_ready(flash)) {
-+              mutex_unlock(&flash->lock);
-+              return 1;
-+      }
-+
-+      if (retlen)
-+              *retlen = len;
-+
-+      mutex_unlock(&flash->lock);
-+      return 0;
-+}
-+
-+
-+/****************************************************************************/
-+
-+/*
-+ * SPI device driver setup and teardown
-+ */
-+
-+struct flash_info {
-+      char            *name;
-+
-+      /* JEDEC id zero means "no ID" (most older chips); otherwise it has
-+       * a high byte of zero plus three data bytes: the manufacturer id,
-+       * then a two byte device id.
-+       */
-+      u32             jedec_id;
-+
-+      /* The size listed here is what works with OPCODE_SE, which isn't
-+       * necessarily called a "sector" by the vendor.
-+       */
-+      unsigned        sector_size;
-+      u16             n_sectors;
-+
-+      u16             flags;
-+#define       SECT_4K         0x01            /* OPCODE_BE_4K works uniformly */
-+};
-+
-+
-+/* NOTE: double check command sets and memory organization when you add
-+ * more flash chips.  This current list focusses on newer chips, which
-+ * have been converging on command sets which including JEDEC ID.
-+ */
-+static struct flash_info __devinitdata m25p_data[] = {
-+
-+      /* Atmel -- some are (confusingly) marketed as "DataFlash" */
-+      { "at25fs010",  0x1f6601, 32 * 1024, 4, SECT_4K, },
-+      { "at25fs040",  0x1f6604, 64 * 1024, 8, SECT_4K, },
-+
-+      { "at25df041a", 0x1f4401, 64 * 1024, 8, SECT_4K, },
-+
-+      { "at26f004",   0x1f0400, 64 * 1024, 8, SECT_4K, },
-+      { "at26df081a", 0x1f4501, 64 * 1024, 16, SECT_4K, },
-+      { "at26df161a", 0x1f4601, 64 * 1024, 32, SECT_4K, },
-+      { "at26df321",  0x1f4701, 64 * 1024, 64, SECT_4K, },
-+
-+      /* Spansion -- single (large) sector size only, at least
-+       * for the chips listed here (without boot sectors).
-+       */
-+      { "s25sl004a", 0x010212, 64 * 1024, 8, },
-+      { "s25sl008a", 0x010213, 64 * 1024, 16, },
-+      { "s25sl016a", 0x010214, 64 * 1024, 32, },
-+      { "s25sl032a", 0x010215, 64 * 1024, 64, },
-+      { "s25sl064a", 0x010216, 64 * 1024, 128, },
-+
-+      /* SST -- large erase sizes are "overlays", "sectors" are 4K */
-+      { "sst25vf040b", 0xbf258d, 64 * 1024, 8, SECT_4K, },
-+      { "sst25vf080b", 0xbf258e, 64 * 1024, 16, SECT_4K, },
-+      { "sst25vf016b", 0xbf2541, 64 * 1024, 32, SECT_4K, },
-+      { "sst25vf032b", 0xbf254a, 64 * 1024, 64, SECT_4K, },
-+
-+      /* ST Microelectronics -- newer production may have feature updates */
-+      { "m25p05",  0x202010,  32 * 1024, 2, },
-+      { "m25p10",  0x202011,  32 * 1024, 4, },
-+      { "m25p20",  0x202012,  64 * 1024, 4, },
-+      { "m25p40",  0x202013,  64 * 1024, 8, },
-+      { "m25p80",         0,  64 * 1024, 16, },
-+      { "m25p16",  0x202015,  64 * 1024, 32, },
-+      { "m25p32",  0x202016,  64 * 1024, 64, },
-+      { "m25p64",  0x202017,  64 * 1024, 128, },
-+      { "m25p128", 0x202018, 256 * 1024, 64, },
-+
-+      { "m45pe80", 0x204014,  64 * 1024, 16, },
-+      { "m45pe16", 0x204015,  64 * 1024, 32, },
-+
-+      { "m25pe80", 0x208014,  64 * 1024, 16, },
-+      { "m25pe16", 0x208015,  64 * 1024, 32, SECT_4K, },
-+
-+      /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
-+      { "w25x10", 0xef3011, 64 * 1024, 2, SECT_4K, },
-+      { "w25x20", 0xef3012, 64 * 1024, 4, SECT_4K, },
-+      { "w25x40", 0xef3013, 64 * 1024, 8, SECT_4K, },
-+      { "w25x80", 0xef3014, 64 * 1024, 16, SECT_4K, },
-+      { "w25x16", 0xef3015, 64 * 1024, 32, SECT_4K, },
-+      { "w25x32", 0xef3016, 64 * 1024, 64, SECT_4K, },
-+      { "w25x64", 0xef3017, 64 * 1024, 128, SECT_4K, },
-+
-+      /* Macronix -- mx25lxxx */
-+      { "mx25l32",  0xc22016, 64 * 1024,  64, },
-+      { "mx25l64",  0xc22017, 64 * 1024, 128, },
-+      { "mx25l128", 0xc22018, 64 * 1024, 256, },
-+
-+};
-+
-+struct flash_info *__devinit jedec_probe(struct platform_device *spi)
-+{
-+      int                     tmp;
-+      u32                     jedec;
-+      struct flash_info       *info;
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)RA;
-+
-+      /*
-+       * Setup and run RDID command on the flash.
-+       */
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) |
-+              IO_XFL_CTL1_FC_DATA(3);
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(OPCODE_RDID);
-+      FLASH_COMMAND_EXEC(io);
-+
-+      jedec = io->status1 & 0x00ffffff;
-+
-+      for (tmp = 0, info = m25p_data;
-+                      tmp < ARRAY_SIZE(m25p_data);
-+                      tmp++, info++) {
-+              if (info->jedec_id == jedec)
-+                      return info;
-+      }
-+      dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
-+      return NULL;
-+}
-+
-+
-+/*
-+ * board specific setup should have ensured the SPI clock used here
-+ * matches what the READ command supports, at least until this driver
-+ * understands FAST_READ (for clocks over 25 MHz).
-+ */
-+static int __devinit ubicom32_flash_probe(struct platform_device *spi)
-+{
-+      struct flash_platform_data      *data;
-+      struct m25p                     *flash;
-+      struct flash_info               *info;
-+      unsigned                        i;
-+
-+      /* Platform data helps sort out which chip type we have, as
-+       * well as how this board partitions it.  If we don't have
-+       * a chip ID, try the JEDEC id commands; they'll work for most
-+       * newer chips, even if we don't recognize the particular chip.
-+       */
-+      data = spi->dev.platform_data;
-+      if (data && data->type) {
-+              for (i = 0, info = m25p_data;
-+                              i < ARRAY_SIZE(m25p_data);
-+                              i++, info++) {
-+                      if (strcmp(data->type, info->name) == 0)
-+                              break;
-+              }
-+
-+              /* unrecognized chip? */
-+              if (i == ARRAY_SIZE(m25p_data)) {
-+                      DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n",
-+                            dev_name(&spi->dev), data->type);
-+                      info = NULL;
-+
-+              /* recognized; is that chip really what's there? */
-+              } else if (info->jedec_id) {
-+                      struct flash_info       *chip = jedec_probe(spi);
-+
-+                      if (!chip || chip != info) {
-+                              dev_warn(&spi->dev, "found %s, expected %s\n",
-+                                              chip ? chip->name : "UNKNOWN",
-+                                              info->name);
-+                              info = NULL;
-+                      }
-+              }
-+      } else
-+              info = jedec_probe(spi);
-+
-+      if (!info)
-+              return -ENODEV;
-+
-+      flash = kzalloc(sizeof *flash, GFP_KERNEL);
-+      if (!flash)
-+              return -ENOMEM;
-+
-+      flash->plt_dev = spi;
-+      mutex_init(&flash->lock);
-+      dev_set_drvdata(&spi->dev, flash);
-+
-+      if (data && data->name)
-+              flash->mtd.name = data->name;
-+      else
-+              flash->mtd.name = dev_name(&spi->dev);
-+
-+      flash->mtd.type = MTD_NORFLASH;
-+      flash->mtd.writesize = 1;
-+      flash->mtd.flags = MTD_CAP_NORFLASH;
-+      flash->mtd.size = info->sector_size * info->n_sectors;
-+      flash->mtd.erase = ubicom32_flash_driver_erase;
-+      flash->mtd.read = ubicom32_flash_driver_read;
-+      flash->mtd.write = ubicom32_flash_driver_write;
-+
-+      /* prefer "small sector" erase if possible */
-+      /*
-+       * The Ubicom erase code does not use the opcode for smaller sectors,
-+       * so disable that functionality and keep erasesize == sector_size
-+       * so that the test in ubicom32_flash_driver_erase works properly.
-+       *
-+       * This was: `if (info->flags & SECT_4K) {' instead of `if (0) {'
-+       */
-+      if (0) {
-+              flash->erase_opcode = OPCODE_BE_4K;
-+              flash->mtd.erasesize = 4096;
-+      } else {
-+              flash->erase_opcode = OPCODE_SE;
-+              flash->mtd.erasesize = info->sector_size;
-+      }
-+
-+      dev_info(&spi->dev, "%s (%lld Kbytes)\n", info->name,
-+               flash->mtd.size / 1024);
-+
-+      DEBUG(MTD_DEBUG_LEVEL2,
-+              "mtd .name = %s, .size = 0x%.8llx (%lluMiB) "
-+                      ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
-+              flash->mtd.name,
-+              flash->mtd.size, flash->mtd.size / (1024*1024),
-+              flash->mtd.erasesize, flash->mtd.erasesize / 1024,
-+              flash->mtd.numeraseregions);
-+
-+      if (flash->mtd.numeraseregions)
-+              for (i = 0; i < flash->mtd.numeraseregions; i++)
-+                      DEBUG(MTD_DEBUG_LEVEL2,
-+                              "mtd.eraseregions[%d] = { .offset = 0x%.8llx, "
-+                              ".erasesize = 0x%.8x (%uKiB), "
-+                              ".numblocks = %d }\n",
-+                              i, flash->mtd.eraseregions[i].offset,
-+                              flash->mtd.eraseregions[i].erasesize,
-+                              flash->mtd.eraseregions[i].erasesize / 1024,
-+                              flash->mtd.eraseregions[i].numblocks);
-+
-+
-+      /* partitions should match sector boundaries; and it may be good to
-+       * use readonly partitions for writeprotected sectors (BP2..BP0).
-+       */
-+      if (mtd_has_partitions()) {
-+              struct mtd_partition    *parts = NULL;
-+              int                     nr_parts = 0;
-+
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+              static const char *part_probes[] = { "cmdlinepart", NULL, };
-+
-+              nr_parts = parse_mtd_partitions(&flash->mtd,
-+                              part_probes, &parts, 0);
-+#endif
-+
-+              if (nr_parts <= 0 && data && data->parts) {
-+                      parts = data->parts;
-+                      nr_parts = data->nr_parts;
-+                      if (nr_parts >= 2) {
-+                              /*
-+                               * Set last partition size to be 1M.
-+                               */
-+                              parts[1].size = flash->mtd.size -
-+                                      parts[0].size - JFFS2_FILESYSTEM_SIZE;
-+                              parts[2].size = JFFS2_FILESYSTEM_SIZE;
-+                      }
-+              }
-+
-+              if (nr_parts > 0) {
-+                      for (i = 0; i < nr_parts; i++) {
-+                              DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
-+                                      "{.name = %s, .offset = 0x%.8llx, "
-+                                              ".size = 0x%.8llx (%lluKiB) }\n",
-+                                      i, parts[i].name,
-+                                      parts[i].offset,
-+                                      parts[i].size,
-+                                      parts[i].size / 1024);
-+                      }
-+                      flash->partitioned = 1;
-+                      return add_mtd_partitions(&flash->mtd, parts, nr_parts);
-+              }
-+      } else if (data->nr_parts)
-+              dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
-+                              data->nr_parts, data->name);
-+
-+      return add_mtd_device(&flash->mtd) == 1 ? -ENODEV : 0;
-+}
-+
-+
-+static int __devexit ubicom32_flash_remove(struct spi_device *spi)
-+{
-+      struct m25p     *flash = dev_get_drvdata(&spi->dev);
-+      int             status;
-+
-+      /* Clean up MTD stuff. */
-+      if (mtd_has_partitions() && flash->partitioned)
-+              status = del_mtd_partitions(&flash->mtd);
-+      else
-+              status = del_mtd_device(&flash->mtd);
-+      if (status == 0)
-+              kfree(flash);
-+      return 0;
-+}
-+
-+static struct platform_driver ubicom32_flash_driver = {
-+      .driver = {
-+              .name   = "ubicom32flashdriver",
-+              .bus    = &platform_bus_type,
-+              .owner  = THIS_MODULE,
-+      },
-+      .probe  = ubicom32_flash_probe,
-+      .remove = NULL,
-+};
-+
-+static int ubicom32_flash_driver_init(void)
-+{
-+      return platform_driver_register(&ubicom32_flash_driver);
-+}
-+
-+
-+static void ubicom32_flash_driver_exit(void)
-+{
-+      platform_driver_unregister(&ubicom32_flash_driver);
-+}
-+
-+
-+module_init(ubicom32_flash_driver_init);
-+module_exit(ubicom32_flash_driver_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Mike Lavender");
-+MODULE_DESCRIPTION("Ubicom32 MTD SPI driver for ST M25Pxx flash chips");
---- /dev/null
-+++ b/drivers/mtd/devices/ubi32-nand-spi-er.c
-@@ -0,0 +1,1188 @@
-+/*
-+ * Micron SPI-ER NAND Flash Memory
-+ *    This code uses the built in Ubicom flash controller
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+*/
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/delay.h>
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/mutex.h>
-+#include <linux/err.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/partitions.h>
-+
-+#define DRIVER_NAME                           "ubi32-nand-spi-er"
-+#define UBI32_NAND_SPI_ER_BLOCK_FROM_ROW(row) (row >> 6)
-+
-+#define UBI32_NAND_SPI_ER_STATUS_P_FAIL               (1 << 3)
-+#define UBI32_NAND_SPI_ER_STATUS_E_FAIL               (1 << 2)
-+#define UBI32_NAND_SPI_ER_STATUS_OIP          (1 << 0)
-+
-+#define UBI32_NAND_SPI_ER_LAST_ROW_INVALID    0xFFFFFFFF
-+#define       UBI32_NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET 0x08
-+
-+struct ubi32_nand_spi_er_device {
-+      const char              *name;
-+
-+      uint16_t                id;
-+
-+      unsigned int            blocks;
-+      unsigned int            pages_per_block;
-+      unsigned int            page_size;
-+      unsigned int            write_size;
-+      unsigned int            erase_size;
-+};
-+
-+struct ubi32_nand_spi_er {
-+      char                            name[24];
-+
-+      const struct ubi32_nand_spi_er_device   *device;
-+
-+      struct mutex                    lock;
-+      struct platform_device          *pdev;
-+
-+      struct mtd_info                 mtd;
-+
-+      unsigned int                    last_row;       /* the last row we fetched */
-+
-+      /*
-+       * Bad block table (MUST be last in strcuture)
-+       */
-+      unsigned long                   nbb;
-+      unsigned long                   bbt[0];
-+};
-+
-+/*
-+ * Chip supports a write_size of 512, but we cannot do partial
-+ * page with command 0x84.
-+ *
-+ * We need to use command 0x84 because we cannot fill the FIFO fast
-+ * enough to transfer the whole 512 bytes at a time. (maybe through
-+ * OCM?)
-+ */
-+const struct ubi32_nand_spi_er_device ubi32_nand_spi_er_devices[] = {
-+      {
-+              name:                   "MT29F1G01ZDC",
-+              id:                     0x2C12,
-+              blocks:                 1024,
-+              pages_per_block:        64,
-+              page_size:              2048,
-+              write_size:             2048,
-+              erase_size:             64 * 2048,
-+      },
-+      {
-+              name:                   "MT29F1G01ZDC",
-+              id:                     0x2C13,
-+              blocks:                 1024,
-+              pages_per_block:        64,
-+              page_size:              2048,
-+              write_size:             2048,
-+              erase_size:             64 * 2048,
-+      },
-+};
-+
-+static int read_only = 0;
-+module_param(read_only, int, 0);
-+MODULE_PARM_DESC(read_only, "Leave device locked");
-+
-+/*
-+ * Ubicom32 FLASH Command Set
-+ */
-+#define FLASH_PORT            RA
-+
-+#define FLASH_FC_INST_CMD     0x00    /* for SPI command only transaction */
-+#define FLASH_FC_INST_WR      0x01    /* for SPI write transaction */
-+#define FLASH_FC_INST_RD      0x02    /* for SPI read transaction */
-+
-+#define FLASH_COMMAND_KICK_OFF(io)                                                            \
-+      asm volatile(                                                                           \
-+              "       bset    "D(IO_INT_CLR)"(%0), #0, #%%bit("D(IO_XFL_INT_DONE)")   \n\t"   \
-+              "       jmpt.t  .+4                                                     \n\t"   \
-+              "       bset    "D(IO_INT_SET)"(%0), #0, #%%bit("D(IO_XFL_INT_START)")  \n\t"   \
-+              :                                                                               \
-+              : "a" (io)                                                                      \
-+              : "cc"                                                                          \
-+              );
-+
-+#define FLASH_COMMAND_WAIT_FOR_COMPLETION(io)                                                 \
-+      asm volatile(                                                                           \
-+              "       btst    "D(IO_INT_STATUS)"(%0), #%%bit("D(IO_XFL_INT_DONE)")    \n\t"   \
-+              "       jmpeq.f .-4                                                     \n\t"   \
-+              :                                                                               \
-+              : "a" (io)                                                                      \
-+              : "cc"                                                                          \
-+      );
-+
-+#define FLASH_COMMAND_EXEC(io)                                \
-+              FLASH_COMMAND_KICK_OFF(io)              \
-+              FLASH_COMMAND_WAIT_FOR_COMPLETION(io)
-+
-+/*
-+ * ubi32_nand_spi_er_get_feature
-+ *    Get Feature register
-+ */
-+static uint8_t ubi32_nand_spi_er_get_feature(uint32_t reg)
-+{
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
-+
-+      /*
-+       * Note that this will produce the sequence:
-+       *      SI [0F][REG][00][00]
-+       *      SO ---------[SR][SR][SR]
-+       * Since the flash controller can only output 24 bits of address, this is
-+       * ok for this command since the data will just repeat as long as the CS
-+       * is asserted and the clock is running.
-+       */
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | IO_XFL_CTL1_FC_DATA(1) |
-+                  IO_XFL_CTL1_FC_ADDR;
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(0x0F) | IO_XFL_CTL2_FC_ADDR(reg << 16);
-+      FLASH_COMMAND_EXEC(io);
-+
-+      return io->status1 & 0xFF;
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_write_buf
-+ *    writes a buffer to the bus
-+ *
-+ * Writes 511 + 1 bytes to the bus, we have to stuff one data byte into the address.
-+ */
-+static void ubi32_nand_spi_er_write_buf(const uint8_t *buf, uint32_t col)
-+{
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
-+      uint32_t tmp;
-+
-+      asm volatile (
-+              "       bset            "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)")   \n\t"
-+              "       pipe_flush      0                                                                       \n\t"
-+              :
-+              : [port] "a" (FLASH_PORT)
-+              : "cc"
-+      );
-+
-+      /*
-+       * Write the data into the cache
-+       */
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+#ifdef SUPPORT_512_FIFO
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(511) |
-+#endif
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(31) |
-+                  IO_XFL_CTL1_FC_ADDR;
-+
-+      /*
-+       * Construct the address with the first byte of data
-+       */
-+      tmp = (col << 8) | *buf++;
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(0x84) | IO_XFL_CTL2_FC_ADDR(tmp);
-+
-+      asm volatile (
-+
-+              /*
-+               * Move 32 bytes
-+               *
-+               * The first word needs to be [11][22][33][33] to work around a flash
-+               * controller bug.
-+               */
-+              "       move.2          %[tmp], (%[data])2++                                                    \n\t"
-+              "       shmrg.1         %[tmp], (%[data]), %[tmp]                                               \n\t"
-+              "       shmrg.1         %[tmp], (%[data])1++, %[tmp]                                            \n\t"
-+              "       move.4          "D(IO_TX_FIFO)"(%[port]), %[tmp]                                        \n\t"
-+
-+              /*
-+               * We're aligned again!
-+               */
-+              "       .rept 7                                                                                 \n\t"
-+              "       move.4          "D(IO_TX_FIFO)"(%[port]), (%[data])4++                                  \n\t"
-+              "       .endr                                                                                   \n\t"
-+
-+              /*
-+               * Kick off the flash command
-+               */
-+              "       bset    "D(IO_INT_CLR)"(%[port]), #0, #%%bit("D(IO_XFL_INT_DONE)")                      \n\t"
-+              "       jmpt.t  .+4                                                                             \n\t"
-+              "       bset    "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_XFL_INT_START)")                     \n\t"
-+
-+#ifdef SUPPORT_512_FIFO
-+              /*
-+               * Fill the remaining 120 words as space becomes available
-+               */
-+              "1:                                                                                             \n\t"
-+              "       cmpi            "D(IO_FIFO_LEVEL)"(%[port]), #4                                         \n\t"
-+              "       jmpgt.s.t       1b                                                                      \n\t"
-+              "       move.4          "D(IO_TX_FIFO)"(%[port]), (%[data])4++                                  \n\t"
-+              "       move.4          "D(IO_TX_FIFO)"(%[port]), (%[data])4++                                  \n\t"
-+              "       move.4          "D(IO_TX_FIFO)"(%[port]), (%[data])4++                                  \n\t"
-+              "       move.4          "D(IO_TX_FIFO)"(%[port]), (%[data])4++                                  \n\t"
-+              "       add.4           %[cnt], #-4, %[cnt]                                                     \n\t"
-+              "       jmpgt.t         1b                                                                      \n\t"
-+#endif
-+              /*
-+               * Wait for the transaction to finish
-+               */
-+              "       btst    "D(IO_INT_STATUS)"(%[port]), #%%bit("D(IO_XFL_INT_DONE)")                       \n\t"
-+              "       jmpeq.f .-4                                                                             \n\t"
-+
-+              : [tmp] "=&d" (tmp),
-+                [data] "+&a" (buf)
-+              : [column] "d" (col),
-+                [port] "a" (FLASH_PORT),
-+                [cnt] "d" (120)               // see above comment
-+              : "cc"
-+      );
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_send_rd_addr
-+ *    perform FC_RD: CMD + address
-+ */
-+static void ubi32_nand_spi_er_send_rd_addr(uint8_t command, uint32_t address)
-+{
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
-+
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | IO_XFL_CTL1_FC_DATA(4) |
-+                  IO_XFL_CTL1_FC_ADDR;
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(command) | IO_XFL_CTL2_FC_ADDR(address);
-+      FLASH_COMMAND_EXEC(io);
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_send_cmd_addr
-+ *    perform FC_(xxx): CMD + address
-+ */
-+static void ubi32_nand_spi_er_send_cmd_addr(uint8_t command, uint32_t address)
-+{
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
-+
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD) | IO_XFL_CTL1_FC_ADDR;
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(command) | IO_XFL_CTL2_FC_ADDR(address);
-+      FLASH_COMMAND_EXEC(io);
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_write_disable
-+ *    clear the write enable bit
-+ */
-+static void ubi32_nand_spi_er_write_disable(void)
-+{
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
-+
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD);
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(0x04);
-+      FLASH_COMMAND_EXEC(io);
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_write_enable
-+ *    set the write enable bit
-+ */
-+static void ubi32_nand_spi_er_write_enable(void)
-+{
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
-+
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD);
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(0x06);
-+      FLASH_COMMAND_EXEC(io);
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_busywait
-+ *    Wait until the chip is not busy
-+ */
-+static uint8_t ubi32_nand_spi_er_busywait(void)
-+{
-+      int i;
-+      uint8_t data;
-+
-+      /*
-+       * tRD is 100us, so don't delay too long, however, tERS is
-+       * 10ms so you'd better loop enough.
-+       */
-+      for (i = 0; i < 200; i++) {
-+              data = ubi32_nand_spi_er_get_feature(0xC0);
-+              if (!(data & UBI32_NAND_SPI_ER_STATUS_OIP)) {
-+                      break;
-+              }
-+
-+              udelay(50);
-+      }
-+
-+      return data;
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_erase
-+ *    Erase a block, parameters must be block aligned
-+ */
-+static int ubi32_nand_spi_er_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+      struct ubi32_nand_spi_er *chip = mtd->priv;
-+      int res;
-+
-+      DEBUG(MTD_DEBUG_LEVEL3, "%s: erase addr:%x len:%x\n", chip->name, instr->addr, instr->len);
-+
-+      if ((instr->addr + instr->len) > mtd->size) {
-+              return -EINVAL;
-+      }
-+
-+      if (instr->addr & (chip->device->erase_size - 1)) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: erase address is not aligned %x\n", chip->name, instr->addr);
-+              return -EINVAL;
-+      }
-+
-+      if (instr->len & (chip->device->erase_size - 1)) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: erase len is not aligned %x\n", chip->name, instr->len);
-+              return -EINVAL;
-+      }
-+
-+      mutex_lock(&chip->lock);
-+      chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID;
-+
-+      while (instr->len) {
-+              uint32_t block = instr->addr >> 17;
-+              uint32_t row = block << 6;
-+              uint8_t stat;
-+              DEBUG(MTD_DEBUG_LEVEL3, "%s: block erase row:%x block:%x addr:%x rem:%x\n", chip->name, row, block, instr->addr, instr->len);
-+
-+              /*
-+               * Test for bad block
-+               */
-+              if (test_bit(block, chip->bbt)) {
-+                      instr->fail_addr = block << 17;
-+                      instr->state = MTD_ERASE_FAILED;
-+                      res = -EBADMSG;
-+                      goto done;
-+              }
-+
-+              ubi32_nand_spi_er_write_enable();
-+
-+              /*
-+               * Block erase
-+               */
-+              ubi32_nand_spi_er_send_cmd_addr(0xD8, row);
-+
-+              /*
-+               * Wait
-+               */
-+              stat = ubi32_nand_spi_er_busywait();
-+              if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) {
-+                      instr->fail_addr = block << 17;
-+                      instr->state = MTD_ERASE_FAILED;
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat);
-+
-+                      /*
-+                       * Chip is stuck?
-+                       */
-+                      res = -EIO;
-+                      goto done;
-+              }
-+
-+              /*
-+               * Check the status register
-+               */
-+              if (stat & UBI32_NAND_SPI_ER_STATUS_E_FAIL) {
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: E_FAIL signalled (%02x)\n", chip->name, stat);
-+                      instr->fail_addr = block << 17;
-+                      instr->state = MTD_ERASE_FAILED;
-+                      goto done;
-+              }
-+
-+              /*
-+               * Next
-+               */
-+              block++;
-+              instr->len -= chip->device->erase_size;
-+              instr->addr += chip->device->erase_size;
-+      }
-+
-+      instr->state = MTD_ERASE_DONE;
-+
-+      mutex_unlock(&chip->lock);
-+      return 0;
-+
-+done:
-+      ubi32_nand_spi_er_write_disable();
-+
-+      mutex_unlock(&chip->lock);
-+
-+      mtd_erase_callback(instr);
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_read
-+ *
-+ * return -EUCLEAN: ecc error recovered
-+ * return -EBADMSG: ecc error not recovered
-+*/
-+static int ubi32_nand_spi_er_read(struct mtd_info *mtd, loff_t from, size_t len,
-+                                size_t *retlen, u_char *buf)
-+{
-+      struct ubi32_nand_spi_er *chip = mtd->priv;
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
-+
-+      uint32_t row;
-+      uint32_t column;
-+      int retval = 0;
-+      uint32_t *pbuf = (uint32_t *)buf;
-+
-+      *retlen = 0;
-+      DEBUG(MTD_DEBUG_LEVEL2, "%s: read block from %llx len %d into %p\n", chip->name, from, len, buf);
-+
-+      /*
-+       * buf should be aligned
-+       */
-+      if ((uint32_t)buf & 0x03) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Zero length reads, nothing to do
-+       */
-+      if (len == 0) {
-+              return 0;
-+      }
-+
-+      /*
-+       * Reject reads which go over the end of the flash
-+       */
-+      if ((from + len) > mtd->size) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Get the row and column address to start at
-+       */
-+      row = from >> 11;
-+      column = from & 0x7FF;
-+      DEBUG(MTD_DEBUG_LEVEL3, "%s: row=%x %d column=%x %d last_row=%x %d\n", chip->name, row, row, column, column, chip->last_row, chip->last_row);
-+
-+      /*
-+       * Read the data from the chip
-+       */
-+      mutex_lock(&chip->lock);
-+      while (len) {
-+              uint8_t stat;
-+              size_t toread;
-+              int i;
-+              int tmp;
-+
-+              /*
-+               * Figure out how much to read
-+               *
-+               * If we are reading from the middle of a page then the most we
-+               * can read is to the end of the page
-+               */
-+              toread = len;
-+              if (toread > (chip->device->page_size - column)) {
-+                      toread = chip->device->page_size - column;
-+              }
-+
-+              DEBUG(MTD_DEBUG_LEVEL3, "%s: buf=%p toread=%x row=%x column=%x last_row=%x\n", chip->name, pbuf, toread, row, column, chip->last_row);
-+
-+              if (chip->last_row != row) {
-+                      /*
-+                       * Check if the block is bad
-+                       */
-+                      if (test_bit(UBI32_NAND_SPI_ER_BLOCK_FROM_ROW(row), chip->bbt)) {
-+                              mutex_unlock(&chip->lock);
-+                              return -EBADMSG;
-+                      }
-+
-+                      /*
-+                       * Load the appropriate page
-+                       */
-+                      ubi32_nand_spi_er_send_cmd_addr(0x13, row);
-+
-+                      /*
-+                       * Wait
-+                       */
-+                      stat = ubi32_nand_spi_er_busywait();
-+                      if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) {
-+                              DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat);
-+
-+                              /*
-+                               * Chip is stuck?
-+                               */
-+                              mutex_unlock(&chip->lock);
-+                              return -EIO;
-+                      }
-+
-+                      /*
-+                       * Check the ECC bits
-+                       */
-+                      stat >>= 4;
-+                      if (stat == 1) {
-+                              DEBUG(MTD_DEBUG_LEVEL1, "%s: ECC recovered, row=%x\n", chip->name, row);
-+                              retval = -EUCLEAN;
-+                      }
-+                      if (stat == 2) {
-+                              DEBUG(MTD_DEBUG_LEVEL0, "%s: failed ECC, row=%x\n", chip->name, row);
-+                              chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID;
-+                              mutex_unlock(&chip->lock);
-+                              return -EBADMSG;
-+                      }
-+
-+              }
-+
-+              chip->last_row = row;
-+
-+              /*
-+               * Read out the data:
-+               *      We can always read a little too much since there is the
-+               *      OOB after byte addr 2047.  The most we'll overread is 3 bytes.
-+               */
-+              if (((uint32_t)pbuf & 0x03) == 0) {
-+                      /*
-+                       * Aligned read
-+                       */
-+                      tmp = toread & (~0x03);
-+                      for (i = 0; i < tmp; i += 4) {
-+                              ubi32_nand_spi_er_send_rd_addr(0x03, column << 8);
-+                              *pbuf++ = io->status1;
-+                              column += 4;
-+                      }
-+              } else {
-+                      /*
-+                       * Unaligned read
-+                       */
-+                      tmp = toread & (~0x03);
-+                      for (i = 0; i < tmp; i += 4) {
-+                              ubi32_nand_spi_er_send_rd_addr(0x03, column << 8);
-+                              memcpy(pbuf, &io->status1, 4);
-+                              column += 4;
-+                      }
-+              }
-+
-+              /*
-+               * Fill in any single bytes
-+               */
-+              tmp = toread & 0x03;
-+              if (tmp) {
-+                      uint8_t *bbuf = pbuf;
-+                      uint32_t val;
-+                      ubi32_nand_spi_er_send_rd_addr(0x03, column << 8);
-+                      val = io->status1;
-+                      for (i = 0; i < tmp; i++) {
-+                              *bbuf++ = val >> 24;
-+                              val <<= 8;
-+                      }
-+              }
-+
-+              len -= toread;
-+              *retlen += toread;
-+
-+              /*
-+               * For the next page, increment the row and always start at column 0
-+               */
-+              column = 0;
-+              row++;
-+      }
-+
-+      mutex_unlock(&chip->lock);
-+      return retval;
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_write
-+ */
-+#define WRITE_NOT_ALIGNED(x) ((x & (device->write_size - 1)) != 0)
-+static int ubi32_nand_spi_er_write(struct mtd_info *mtd, loff_t to, size_t len,
-+                                 size_t *retlen, const u_char *buf)
-+{
-+      struct ubi32_nand_spi_er *chip = mtd->priv;
-+      const struct ubi32_nand_spi_er_device *device = chip->device;
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
-+      uint32_t row;
-+      uint32_t col;
-+      int res = 0;
-+      size_t towrite;
-+
-+      DEBUG(MTD_DEBUG_LEVEL2, "%s: write block to %llx len %d from %p\n", chip->name, to, len, buf);
-+
-+      *retlen = 0;
-+
-+      /*
-+       * nothing to write
-+       */
-+      if (!len) {
-+              return 0;
-+      }
-+
-+      /*
-+       * Reject writes which go over the end of the flash
-+       */
-+      if ((to + len) > mtd->size) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * buf should be aligned to 16 bits
-+       */
-+      if ((uint32_t)buf & 0x01) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Check to see if everything is page aligned
-+       */
-+      if (WRITE_NOT_ALIGNED(to) || WRITE_NOT_ALIGNED(len)) {
-+              printk(KERN_NOTICE "ubi32_nand_spi_er_write: Attempt to write non page aligned data\n");
-+              return -EINVAL;
-+      }
-+
-+      mutex_lock(&chip->lock);
-+
-+      io->ctl0 |= IO_XFL_CTL0_MCB_LOCK;
-+
-+      chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID;
-+
-+      /*
-+       * If the first write is a partial write then write at most the number of
-+       * bytes to get us page aligned and then the remainder will be
-+       * page aligned.  The last bit may be a partial page as well.
-+       */
-+      col = to & (device->page_size - 1);
-+      towrite = device->page_size - col;
-+      if (towrite > len) {
-+              towrite = len;
-+      }
-+
-+      /*
-+       * Write the data
-+       */
-+      row = to >> 11;
-+      while (len) {
-+              uint8_t stat;
-+              uint32_t my_towrite;
-+
-+              DEBUG(MTD_DEBUG_LEVEL3, "%s: write %p to row:%x col:%x len:%x rem:%x\n", chip->name, buf, row, col, towrite, len);
-+
-+              ubi32_nand_spi_er_write_enable();
-+
-+              /*
-+               * Move the data into the cache
-+               */
-+              my_towrite = towrite;
-+              while (my_towrite) {
-+                      uint32_t len = my_towrite;
-+                      if (len > 32) {
-+                              len = 32;
-+                      }
-+
-+                      ubi32_nand_spi_er_write_buf(buf, col);
-+                      buf += len;
-+                      col += len;
-+                      my_towrite -= len;
-+              }
-+
-+              /*
-+               * Program execute
-+               */
-+              ubi32_nand_spi_er_send_cmd_addr(0x10, row);
-+
-+              /*
-+               * Wait
-+               */
-+              stat = ubi32_nand_spi_er_busywait();
-+              if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) {
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat);
-+
-+                      /*
-+                       * Chip is stuck?
-+                       */
-+                      res = -EIO;
-+                      goto done;
-+              }
-+
-+              if (stat & (1 << 3)) {
-+                      res = -EBADMSG;
-+                      goto done;
-+              }
-+
-+              row++;
-+              len -= towrite;
-+              *retlen += towrite;
-+
-+              /*
-+               * At this point, we are always page aligned so start at column 0.
-+               * Note we may not have a full page to write at the end, hence the
-+               * check if towrite > len.
-+               */
-+              col = 0;
-+              towrite = device->page_size;
-+              if (towrite > len) {
-+                      towrite = len;
-+              }
-+      }
-+
-+      io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK;
-+
-+      mutex_unlock(&chip->lock);
-+      return res;
-+
-+done:
-+      ubi32_nand_spi_er_write_disable();
-+
-+      io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK;
-+
-+      mutex_unlock(&chip->lock);
-+
-+      return res;
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_isbad
-+ */
-+static int ubi32_nand_spi_er_isbad(struct mtd_info *mtd, loff_t ofs)
-+{
-+      struct ubi32_nand_spi_er *chip = mtd->priv;
-+      uint32_t block;
-+
-+      if (ofs & (chip->device->erase_size - 1)) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs);
-+              return -EINVAL;
-+      }
-+
-+      block = ofs >> 17;
-+
-+      return test_bit(block, chip->bbt);
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_markbad
-+ */
-+static int ubi32_nand_spi_er_markbad(struct mtd_info *mtd, loff_t ofs)
-+{
-+      struct ubi32_nand_spi_er *chip = mtd->priv;
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
-+      uint32_t block;
-+      uint32_t row;
-+      int res = 0;
-+      uint8_t stat;
-+
-+      if (ofs & (chip->device->erase_size - 1)) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: address not aligned %llx\n", chip->name, ofs);
-+              return -EINVAL;
-+      }
-+
-+      block = ofs >> 17;
-+
-+      /*
-+       * If it's already marked bad, no need to mark it
-+       */
-+      if (test_bit(block, chip->bbt)) {
-+              return 0;
-+      }
-+
-+      /*
-+       * Mark it in our cache
-+       */
-+      __set_bit(block, chip->bbt);
-+
-+      /*
-+       * Write the user bad block mark.  If it fails, then we really
-+       * can't do anything about it.
-+       */
-+      mutex_lock(&chip->lock);
-+      chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID;
-+
-+      ubi32_nand_spi_er_write_enable();
-+
-+      /*
-+       * Write the mark
-+       */
-+      io->ctl0 |= IO_XFL_CTL0_MCB_LOCK;
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(6);
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(0x84);
-+
-+      asm volatile (
-+              "       bset            "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)")   \n\t"
-+              "       pipe_flush      0                                                                       \n\t"
-+
-+              /*
-+               * Move the data into the FIFO
-+               */
-+              "       move.4          "D(IO_TX_FIFO)"(%[port]), %[word1]                                      \n\t"
-+              "       move.4          "D(IO_TX_FIFO)"(%[port]), %[word2]                                      \n\t"
-+
-+              /*
-+               * Kick off the flash command
-+               */
-+              "       bset    "D(IO_INT_CLR)"(%[port]), #0, #%%bit("D(IO_XFL_INT_DONE)")                      \n\t"
-+              "       jmpt.t  .+4                                                                             \n\t"
-+              "       bset    "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_XFL_INT_START)")                     \n\t"
-+
-+              /*
-+               * Wait for the transaction to finish
-+               */
-+              "       btst    "D(IO_INT_STATUS)"(%[port]), #%%bit("D(IO_XFL_INT_DONE)")                       \n\t"
-+              "       jmpeq.f .-4                                                                             \n\t"
-+
-+              :
-+              : [word1] "d" (0x0800dead | (UBI32_NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET << 16)),
-+                [word2] "d" (0xbeef0000),
-+                [port] "a" (FLASH_PORT)
-+              : "cc"
-+      );
-+
-+      io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK;
-+
-+      /*
-+       * Program execute
-+       */
-+      row = block << 6;
-+      ubi32_nand_spi_er_send_cmd_addr(0x10, row);
-+
-+      /*
-+       * Wait
-+       */
-+      stat = ubi32_nand_spi_er_busywait();
-+      if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) {
-+              DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat);
-+
-+              /*
-+               * Chip is stuck?
-+               */
-+              res = -EIO;
-+              goto done;
-+      }
-+
-+      if (stat & (1 << 3)) {
-+              res = -EBADMSG;
-+      }
-+
-+done:
-+      ubi32_nand_spi_er_write_disable();
-+
-+      mutex_unlock(&chip->lock);
-+
-+      return res;
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_read_bbt
-+ */
-+static int ubi32_nand_spi_er_read_bbt(struct ubi32_nand_spi_er *chip)
-+{
-+      int j;
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
-+
-+      for (j = 0; j < chip->device->blocks; j++) {
-+              unsigned short row = j << 6;
-+              uint8_t stat;
-+
-+              /*
-+               * Read Page
-+               */
-+              ubi32_nand_spi_er_send_cmd_addr(0x13, row);
-+
-+              /*
-+               * Wait
-+               */
-+              stat = ubi32_nand_spi_er_busywait();
-+              if (stat & UBI32_NAND_SPI_ER_STATUS_OIP) {
-+                      DEBUG(MTD_DEBUG_LEVEL1, "%s: chip is busy or nonresponsive stat=%02x\n", chip->name, stat);
-+
-+                      /*
-+                       * Chip is stuck?
-+                       */
-+                      return -EIO;
-+              }
-+
-+              /*
-+               * Check factory bad block mark
-+               */
-+              ubi32_nand_spi_er_send_rd_addr(0x03, 0x080000);
-+
-+              if ((io->status1 >> 24) != 0xFF) {
-+                      chip->nbb++;
-+                      __set_bit(j, chip->bbt);
-+                      continue;
-+              }
-+
-+              ubi32_nand_spi_er_send_rd_addr(0x03, 0x080000 | (UBI32_NAND_SPI_ER_BAD_BLOCK_MARK_OFFSET << 8));
-+              if (io->status1 == 0xdeadbeef) {
-+                      chip->nbb++;
-+                      __set_bit(j, chip->bbt);
-+              }
-+      }
-+
-+#if defined(CONFIG_MTD_DEBUG) && (MTD_DEBUG_LEVEL3 <= CONFIG_MTD_DEBUG_VERBOSE)
-+      printk("%s: Bad Block Table:", chip->name);
-+      for (j = 0; j < chip->device->blocks; j++) {
-+              if ((j % 64) == 0) {
-+                      printk("\n%s: block %03x: ", chip->name, j);
-+              }
-+              printk("%c", test_bit(j, chip->bbt) ? 'X' : '.');
-+      }
-+      printk("\n%s: Bad Block Numbers: ", chip->name);
-+      for (j = 0; j < chip->device->blocks; j++) {
-+              if (test_bit(j, chip->bbt)) {
-+                      printk("%x ", j);
-+              }
-+      }
-+      printk("\n");
-+#endif
-+
-+      return 0;
-+}
-+
-+#ifndef MODULE
-+/*
-+ * Called at boot time:
-+ *
-+ * ubi32_nand_spi_er=read_only
-+ *    if read_only specified then do not unlock device
-+ */
-+static int __init ubi32_nand_spi_er_setup(char *str)
-+{
-+      if (str && (strncasecmp(str, "read_only", 9) == 0)) {
-+              read_only = 1;
-+      }
-+      return 0;
-+}
-+
-+__setup("ubi32_nand_spi_er=", ubi32_nand_spi_er_setup);
-+#endif
-+
-+/*
-+ * ubi32_nand_spi_er_probe
-+ *    Detect and initialize ubi32_nand_spi_er device.
-+ */
-+static int __devinit ubi32_nand_spi_er_probe(struct platform_device *pdev)
-+{
-+      uint32_t i;
-+      uint32_t id;
-+      int res;
-+      size_t bbt_bytes;
-+      struct ubi32_nand_spi_er *chip;
-+      const struct ubi32_nand_spi_er_device *device;
-+      struct ubicom32_io_port *io = (struct ubicom32_io_port *)FLASH_PORT;
-+
-+      /*
-+       * Reset
-+       */
-+      for (i = 0; i < 2; i++) {
-+              io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+              io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_CMD);
-+              io->ctl2 = IO_XFL_CTL2_FC_CMD(0xFF);
-+              FLASH_COMMAND_EXEC(io);
-+              udelay(250);
-+      }
-+      udelay(1000);
-+
-+      /*
-+       * Read out ID
-+       */
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_RD) | IO_XFL_CTL1_FC_DATA(2) |
-+                  IO_XFL_CTL1_FC_ADDR;
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(0x9F);
-+      FLASH_COMMAND_EXEC(io);
-+
-+      id = io->status1 >> 16;
-+      device = ubi32_nand_spi_er_devices;
-+      for (i = 0; i < ARRAY_SIZE(ubi32_nand_spi_er_devices); i++) {
-+              if (device->id == id) {
-+                      break;
-+              }
-+              device++;
-+      }
-+      if (i == ARRAY_SIZE(ubi32_nand_spi_er_devices)) {
-+              return -ENODEV;
-+      }
-+
-+      /*
-+       * Initialize our chip structure
-+       */
-+      bbt_bytes = DIV_ROUND_UP(device->blocks, BITS_PER_BYTE);
-+      chip = kzalloc(sizeof(struct ubi32_nand_spi_er) + bbt_bytes, GFP_KERNEL);
-+      if (!chip) {
-+              return -ENOMEM;
-+      }
-+      snprintf(chip->name, sizeof(chip->name), "%s", device->name);
-+
-+      chip->device = device;
-+      chip->last_row = UBI32_NAND_SPI_ER_LAST_ROW_INVALID;
-+
-+      mutex_init(&chip->lock);
-+
-+      chip->mtd.type = MTD_NANDFLASH;
-+      chip->mtd.flags = MTD_WRITEABLE;
-+
-+      /*
-+       * #blocks * block size * n blocks
-+       */
-+      chip->mtd.size = device->blocks * device->pages_per_block * device->page_size;
-+      chip->mtd.erasesize = device->erase_size;
-+
-+      /*
-+       * 1 page, optionally we can support partial write (512)
-+       */
-+      chip->mtd.writesize = device->write_size;
-+      chip->mtd.name = device->name;
-+      chip->mtd.erase = ubi32_nand_spi_er_erase;
-+      chip->mtd.read = ubi32_nand_spi_er_read;
-+      chip->mtd.write = ubi32_nand_spi_er_write;
-+      chip->mtd.block_isbad = ubi32_nand_spi_er_isbad;
-+      chip->mtd.block_markbad = ubi32_nand_spi_er_markbad;
-+      chip->mtd.priv = chip;
-+
-+      /*
-+       * Cache the bad block table
-+       */
-+      res = ubi32_nand_spi_er_read_bbt(chip);
-+      if (res) {
-+              kfree(chip);
-+              return res;
-+      }
-+
-+      /*
-+       * Un/lock the chip
-+       */
-+      io->ctl0 |= IO_XFL_CTL0_MCB_LOCK;
-+      io->ctl1 &= ~IO_XFL_CTL1_MASK;
-+      io->ctl1 |= IO_XFL_CTL1_FC_INST(FLASH_FC_INST_WR) | IO_XFL_CTL1_FC_DATA(2);
-+      io->ctl2 = IO_XFL_CTL2_FC_CMD(0x1F);
-+
-+      if (read_only) {
-+              i = 0xa0380000;
-+      } else {
-+              i = 0xa0000000;
-+      }
-+      asm volatile (
-+              "       bset            "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_PORTX_INT_FIFO_TX_RESET)")   \n\t"
-+              "       pipe_flush      0                                                                       \n\t"
-+
-+              /*
-+               * Move the data into the FIFO
-+               */
-+              "       move.4          "D(IO_TX_FIFO)"(%[port]), %[word1]                                      \n\t"
-+
-+              /*
-+               * Kick off the flash command
-+               */
-+              "       bset    "D(IO_INT_CLR)"(%[port]), #0, #%%bit("D(IO_XFL_INT_DONE)")                      \n\t"
-+              "       jmpt.t  .+4                                                                             \n\t"
-+              "       bset    "D(IO_INT_SET)"(%[port]), #0, #%%bit("D(IO_XFL_INT_START)")                     \n\t"
-+
-+              /*
-+               * Wait for the transaction to finish
-+               */
-+              "       btst    "D(IO_INT_STATUS)"(%[port]), #%%bit("D(IO_XFL_INT_DONE)")                       \n\t"
-+              "       jmpeq.f .-4                                                                             \n\t"
-+
-+              :
-+              : [word1] "d" (i),
-+                [port] "a" (FLASH_PORT)
-+              : "cc"
-+      );
-+      io->ctl0 &= ~IO_XFL_CTL0_MCB_LOCK;
-+
-+      dev_set_drvdata(&pdev->dev, chip);
-+
-+      printk(KERN_INFO "%s: added device size: %u KBytes %lu bad blocks %s\n", chip->mtd.name, DIV_ROUND_UP(chip->mtd.size, 1024), chip->nbb, read_only ? "[read only]" : "");
-+      return add_mtd_device(&chip->mtd);
-+}
-+
-+/*
-+ * ubi32_nand_spi_er_remove
-+ */
-+static int __devexit ubi32_nand_spi_er_remove(struct platform_device *pdev)
-+{
-+      struct ubi32_nand_spi_er *chip = dev_get_drvdata(&pdev->dev);
-+      int status;
-+
-+      DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", chip->name);
-+
-+      status = del_mtd_device(&chip->mtd);
-+      if (status == 0) {
-+              kfree(chip);
-+      }
-+
-+      dev_set_drvdata(&pdev->dev, NULL);
-+      return status;
-+}
-+
-+static struct platform_device *ubi32_nand_spi_er_device;
-+
-+static struct platform_driver ubi32_nand_spi_er_driver = {
-+      .driver = {
-+              .name           = DRIVER_NAME,
-+              .owner          = THIS_MODULE,
-+      },
-+
-+      .probe          = ubi32_nand_spi_er_probe,
-+      .remove         = ubi32_nand_spi_er_remove,
-+};
-+
-+/*
-+ * ubi32_nand_spi_er_init
-+ */
-+static int __init ubi32_nand_spi_er_init(void)
-+{
-+      int ret;
-+
-+      ret = platform_driver_register(&ubi32_nand_spi_er_driver);
-+
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      ubi32_nand_spi_er_device = platform_device_alloc(DRIVER_NAME, 0);
-+      if (!ubi32_nand_spi_er_device) {
-+              return -ENOMEM;
-+      }
-+
-+      ret = platform_device_add(ubi32_nand_spi_er_device);
-+      if (ret) {
-+              platform_device_put(ubi32_nand_spi_er_device);
-+              platform_driver_unregister(&ubi32_nand_spi_er_driver);
-+      }
-+
-+      return ret;
-+}
-+module_init(ubi32_nand_spi_er_init);
-+
-+/*
-+ * ubi32_nand_spi_er_exit
-+ */
-+static void __exit ubi32_nand_spi_er_exit(void)
-+{
-+      platform_device_unregister(ubi32_nand_spi_er_device);
-+      platform_driver_unregister(&ubi32_nand_spi_er_driver);
-+}
-+module_exit(ubi32_nand_spi_er_exit);
-+
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Patrick Tjin");
-+MODULE_DESCRIPTION("MTD ubi32_nand_spi_er driver for ubicom32 SPI flash controller.");
---- a/drivers/net/Kconfig
-+++ b/drivers/net/Kconfig
-@@ -2540,6 +2540,19 @@ config JME
-         To compile this driver as a module, choose M here. The module
-         will be called jme.
-+config UBICOM32_GMAC
-+      tristate "Ubicom Gigabit Ethernet support"
-+      depends on UBICOM32
-+      help
-+        Gigabit Ethernet support for ubicom32 processors
-+
-+config UBICOM32_OCM_FOR_SKB
-+        bool  "USE OCM for SKB (EXPERIMENTAL)"
-+        depends on UBICOM32_GMAC
-+      default n
-+        help
-+          Allocate skb from OCM for Ethernet Receive when possible
-+
- endif # NETDEV_1000
- #
---- a/drivers/net/Makefile
-+++ b/drivers/net/Makefile
-@@ -272,3 +272,5 @@ obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
- obj-$(CONFIG_SFC) += sfc/
- obj-$(CONFIG_WIMAX) += wimax/
-+
-+obj-$(CONFIG_UBICOM32_GMAC) += ubi32-eth.o
---- /dev/null
-+++ b/drivers/net/ubi32-eth.c
-@@ -0,0 +1,760 @@
-+/*
-+ * drivers/net/ubi32-eth.c
-+ *   Ubicom32 ethernet TIO interface driver.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+/*
-+ * ubi32_eth.c
-+ * Ethernet driver for Ip5k/Ip7K
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/moduleparam.h>
-+
-+#include <linux/sched.h>
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/types.h>
-+#include <linux/interrupt.h>
-+
-+#include <linux/in.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/mii.h>
-+#include <linux/if_vlan.h>
-+#include <linux/ip.h>
-+#include <linux/tcp.h>
-+#include <linux/skbuff.h>
-+#include <asm/checksum.h>
-+#include <asm/ip5000.h>
-+#include <asm/devtree.h>
-+#include <asm/system.h>
-+
-+#define UBICOM32_USE_NAPI     /* define this to use NAPI instead of tasklet */
-+//#define UBICOM32_USE_POLLING        /* define this to use polling instead of interrupt */
-+#include "ubi32-eth.h"
-+
-+/*
-+ * TODO:
-+ * mac address from flash
-+ * multicast filter
-+ * ethtool support
-+ * sysfs support
-+ * skb->nrfrag support
-+ * ioctl
-+ * monitor phy status
-+ */
-+
-+extern int ubi32_ocm_skbuf_max, ubi32_ocm_skbuf, ubi32_ddr_skbuf;
-+static const char *eth_if_name[UBI32_ETH_NUM_OF_DEVICES] =
-+      {"eth_lan", "eth_wan"};
-+static struct net_device *ubi32_eth_devices[UBI32_ETH_NUM_OF_DEVICES] =
-+      {NULL, NULL};
-+static u8_t mac_addr[UBI32_ETH_NUM_OF_DEVICES][ETH_ALEN] = {
-+      {0x00, 0x03, 0x64, 'l', 'a', 'n'},
-+      {0x00, 0x03, 0x64, 'w', 'a', 'n'}};
-+
-+#if (defined(CONFIG_ZONE_DMA) && defined(CONFIG_UBICOM32_OCM_FOR_SKB))
-+static inline struct sk_buff *ubi32_alloc_skb_ocm(struct net_device *dev, unsigned int length)
-+{
-+      return __dev_alloc_skb(length, GFP_ATOMIC | __GFP_NOWARN | __GFP_NORETRY | GFP_DMA);
-+}
-+#endif
-+
-+static inline struct sk_buff *ubi32_alloc_skb(struct net_device *dev, unsigned int length)
-+{
-+      return __dev_alloc_skb(length, GFP_ATOMIC | __GFP_NOWARN);
-+}
-+
-+static void ubi32_eth_vp_rxtx_enable(struct net_device *dev)
-+{
-+      struct ubi32_eth_private *priv = netdev_priv(dev);
-+      priv->regs->command = UBI32_ETH_VP_CMD_RX_ENABLE | UBI32_ETH_VP_CMD_TX_ENABLE;
-+      priv->regs->int_mask = (UBI32_ETH_VP_INT_RX | UBI32_ETH_VP_INT_TX);
-+      ubicom32_set_interrupt(priv->vp_int_bit);
-+}
-+
-+static void ubi32_eth_vp_rxtx_stop(struct net_device *dev)
-+{
-+      struct ubi32_eth_private *priv = netdev_priv(dev);
-+      priv->regs->command = 0;
-+      priv->regs->int_mask = 0;
-+      ubicom32_set_interrupt(priv->vp_int_bit);
-+
-+      /* Wait for graceful shutdown */
-+      while (priv->regs->status & (UBI32_ETH_VP_STATUS_RX_STATE | UBI32_ETH_VP_STATUS_TX_STATE));
-+}
-+
-+/*
-+ * ubi32_eth_tx_done()
-+ */
-+static int ubi32_eth_tx_done(struct net_device *dev)
-+{
-+      struct ubi32_eth_private *priv;
-+      struct sk_buff *skb;
-+      volatile void *pdata;
-+      struct ubi32_eth_dma_desc *desc;
-+      u32_t   count = 0;
-+
-+      priv = netdev_priv(dev);
-+
-+      priv->regs->int_status &= ~UBI32_ETH_VP_INT_TX;
-+      while (priv->tx_tail != priv->regs->tx_out) {
-+              pdata = priv->regs->tx_dma_ring[priv->tx_tail];
-+              BUG_ON(pdata == NULL);
-+
-+              skb = container_of((void *)pdata, struct sk_buff, cb);
-+              desc = (struct ubi32_eth_dma_desc *)pdata;
-+              if (unlikely(!(desc->status & UBI32_ETH_VP_TX_OK))) {
-+                      dev->stats.tx_errors++;
-+              } else {
-+                      dev->stats.tx_packets++;
-+                      dev->stats.tx_bytes += skb->len;
-+              }
-+              dev_kfree_skb_any(skb);
-+              priv->regs->tx_dma_ring[priv->tx_tail] = NULL;
-+              priv->tx_tail = (priv->tx_tail + 1) & TX_DMA_RING_MASK;
-+              count++;
-+      }
-+
-+      if (unlikely(priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL)) {
-+              spin_lock(&priv->lock);
-+              if (priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL) {
-+                      priv->regs->status &= ~UBI32_ETH_VP_STATUS_TX_Q_FULL;
-+                      netif_wake_queue(dev);
-+              }
-+              spin_unlock(&priv->lock);
-+      }
-+      return count;
-+}
-+
-+/*
-+ * ubi32_eth_receive()
-+ *    To avoid locking overhead, this is called only
-+ *    by tasklet when not using NAPI, or
-+ *    by NAPI poll when using NAPI.
-+ *    return number of frames processed
-+ */
-+static int ubi32_eth_receive(struct net_device *dev, int quota)
-+{
-+      struct ubi32_eth_private *priv = netdev_priv(dev);
-+      unsigned short rx_in = priv->regs->rx_in;
-+      struct sk_buff *skb;
-+      struct ubi32_eth_dma_desc *desc = NULL;
-+      volatile void *pdata;
-+
-+      int extra_reserve_adj;
-+      int extra_alloc = UBI32_ETH_RESERVE_SPACE + UBI32_ETH_TRASHED_MEMORY;
-+      int replenish_cnt, count = 0;
-+      int replenish_max = RX_DMA_MAX_QUEUE_SIZE;
-+#if (defined(CONFIG_ZONE_DMA) && defined(CONFIG_UBICOM32_OCM_FOR_SKB))
-+      if (likely(dev == ubi32_eth_devices[0]))
-+              replenish_max = min(ubi32_ocm_skbuf_max, RX_DMA_MAX_QUEUE_SIZE);;
-+#endif
-+
-+      if (unlikely(rx_in == priv->regs->rx_out))
-+              priv->vp_stats.rx_q_full_cnt++;
-+
-+      priv->regs->int_status &= ~UBI32_ETH_VP_INT_RX;
-+      while (priv->rx_tail != priv->regs->rx_out) {
-+              if (unlikely(count == quota)) {
-+                      /* There is still frame pending to be processed */
-+                      priv->vp_stats.rx_throttle++;
-+                      break;
-+              }
-+
-+              pdata = priv->regs->rx_dma_ring[priv->rx_tail];
-+              BUG_ON(pdata == NULL);
-+
-+              desc = (struct ubi32_eth_dma_desc *)pdata;
-+              skb = container_of((void *)pdata, struct sk_buff, cb);
-+              count++;
-+              priv->regs->rx_dma_ring[priv->rx_tail] = NULL;
-+              priv->rx_tail = ((priv->rx_tail + 1) & RX_DMA_RING_MASK);
-+
-+              /*
-+               * Check only RX_OK bit here.
-+               * The rest of status word is used as timestamp
-+               */
-+              if (unlikely(!(desc->status & UBI32_ETH_VP_RX_OK))) {
-+                      dev->stats.rx_errors++;
-+                      dev_kfree_skb_any(skb);
-+                      continue;
-+              }
-+
-+              skb_put(skb, desc->data_len);
-+              skb->dev = dev;
-+              skb->protocol = eth_type_trans(skb, dev);
-+              skb->ip_summed = CHECKSUM_NONE;
-+              dev->stats.rx_bytes += skb->len;
-+              dev->stats.rx_packets++;
-+#ifndef UBICOM32_USE_NAPI
-+              netif_rx(skb);
-+#else
-+              netif_receive_skb(skb);
-+#endif
-+      }
-+
-+      /* fill in more descripor for VP*/
-+      replenish_cnt =  replenish_max -
-+              ((RX_DMA_RING_SIZE + rx_in - priv->rx_tail) & RX_DMA_RING_MASK);
-+      if (replenish_cnt > 0) {
-+#if (defined(CONFIG_ZONE_DMA) && defined(CONFIG_UBICOM32_OCM_FOR_SKB))
-+              /*
-+               * black magic for perforamnce:
-+               *   Try to allocate skb from OCM only for first Ethernet I/F.
-+               *   Also limit number of RX buffers to 21 due to limited OCM.
-+               */
-+              if (likely(dev == ubi32_eth_devices[0])) {
-+                      do {
-+                              skb = ubi32_alloc_skb_ocm(dev, RX_BUF_SIZE + extra_alloc);
-+                              if (!skb) {
-+                                      break;
-+                              }
-+                              /* set up dma descriptor */
-+                              ubi32_ocm_skbuf++;
-+                              desc = (struct ubi32_eth_dma_desc *)skb->cb;
-+                              extra_reserve_adj =
-+                                      ((u32)skb->data + UBI32_ETH_RESERVE_SPACE + ETH_HLEN) &
-+                                      (CACHE_LINE_SIZE - 1);
-+                              skb_reserve(skb, UBI32_ETH_RESERVE_SPACE - extra_reserve_adj);
-+                              desc->data_pointer = skb->data;
-+                              desc->buffer_len = RX_BUF_SIZE + UBI32_ETH_TRASHED_MEMORY;
-+                              desc->data_len = 0;
-+                              desc->status = 0;
-+                              priv->regs->rx_dma_ring[rx_in] = desc;
-+                              rx_in = (rx_in + 1) & RX_DMA_RING_MASK;
-+                      } while (--replenish_cnt > 0);
-+              }
-+#endif
-+
-+              while (replenish_cnt-- > 0) {
-+                      skb = ubi32_alloc_skb(dev, RX_BUF_SIZE + extra_alloc);
-+                      if (!skb) {
-+                              priv->vp_stats.rx_alloc_err++;
-+                              break;
-+                      }
-+                      /* set up dma descriptor */
-+                      ubi32_ddr_skbuf++;
-+                      desc = (struct ubi32_eth_dma_desc *)skb->cb;
-+                      extra_reserve_adj =
-+                              ((u32)skb->data + UBI32_ETH_RESERVE_SPACE + ETH_HLEN) &
-+                              (CACHE_LINE_SIZE - 1);
-+                      skb_reserve(skb, UBI32_ETH_RESERVE_SPACE - extra_reserve_adj);
-+                      desc->data_pointer = skb->data;
-+                      desc->buffer_len = RX_BUF_SIZE + UBI32_ETH_TRASHED_MEMORY;
-+                      desc->data_len = 0;
-+                      desc->status = 0;
-+                      priv->regs->rx_dma_ring[rx_in] = desc;
-+                      rx_in = (rx_in + 1) & RX_DMA_RING_MASK;
-+              }
-+
-+              wmb();
-+              priv->regs->rx_in = rx_in;
-+              ubicom32_set_interrupt(priv->vp_int_bit);
-+      }
-+
-+      if (likely(count > 0)) {
-+              dev->last_rx = jiffies;
-+      }
-+      return count;
-+}
-+
-+#ifdef UBICOM32_USE_NAPI
-+static int ubi32_eth_napi_poll(struct napi_struct *napi, int budget)
-+{
-+      struct ubi32_eth_private *priv = container_of(napi, struct ubi32_eth_private, napi);
-+      struct net_device *dev = priv->dev;
-+      u32_t count;
-+
-+      if (priv->tx_tail != priv->regs->tx_out) {
-+                ubi32_eth_tx_done(dev);
-+        }
-+
-+      count = ubi32_eth_receive(dev, budget);
-+
-+      if (count < budget) {
-+              napi_complete(napi);
-+              priv->regs->int_mask |= (UBI32_ETH_VP_INT_RX | UBI32_ETH_VP_INT_TX);
-+              if ((priv->rx_tail != priv->regs->rx_out) || (priv->tx_tail != priv->regs->tx_out)) {
-+                      if (napi_reschedule(napi)) {
-+                              priv->regs->int_mask = 0;
-+                      }
-+              }
-+      }
-+      return count;
-+}
-+
-+#else
-+static void ubi32_eth_do_tasklet(unsigned long arg)
-+{
-+      struct net_device *dev = (struct net_device *)arg;
-+      struct ubi32_eth_private *priv = netdev_priv(dev);
-+
-+      if (priv->tx_tail != priv->regs->tx_out) {
-+              ubi32_eth_tx_done(dev);
-+      }
-+
-+      /* always call receive to process new RX frame as well as replenish RX buffers */
-+      ubi32_eth_receive(dev, UBI32_RX_BOUND);
-+
-+      priv->regs->int_mask |= (UBI32_ETH_VP_INT_RX | UBI32_ETH_VP_INT_TX);
-+      if ((priv->rx_tail != priv->regs->rx_out) || (priv->tx_tail != priv->regs->tx_out)) {
-+              priv->regs->int_mask = 0;
-+              tasklet_schedule(&priv->tsk);
-+      }
-+}
-+#endif
-+
-+#if defined(UBICOM32_USE_POLLING)
-+static struct timer_list eth_poll_timer;
-+
-+static void ubi32_eth_poll(unsigned long arg)
-+{
-+      struct net_device *dev;
-+      struct ubi32_eth_private *priv;
-+      int i;
-+
-+      for (i = 0; i < UBI32_ETH_NUM_OF_DEVICES; i++) {
-+              dev = ubi32_eth_devices[i];
-+              if (dev && (dev->flags & IFF_UP)) {
-+                      priv = netdev_priv(dev);
-+#ifdef UBICOM32_USE_NAPI
-+                      napi_schedule(&priv->napi);
-+#else
-+                      tasklet_schedule(&priv->tsk);
-+#endif
-+              }
-+      }
-+
-+      eth_poll_timer.expires = jiffies + 2;
-+      add_timer(&eth_poll_timer);
-+}
-+
-+#else
-+static irqreturn_t ubi32_eth_interrupt(int irq, void *dev_id)
-+{
-+      struct ubi32_eth_private *priv;
-+
-+      struct net_device *dev = (struct net_device *)dev_id;
-+      BUG_ON(irq != dev->irq);
-+
-+      priv = netdev_priv(dev);
-+      if (unlikely(!(priv->regs->int_status & priv->regs->int_mask))) {
-+              return IRQ_NONE;
-+      }
-+
-+      /*
-+       * Disable port interrupt
-+       */
-+#ifdef UBICOM32_USE_NAPI
-+      if (napi_schedule_prep(&priv->napi)) {
-+              priv->regs->int_mask = 0;
-+              __napi_schedule(&priv->napi);
-+      }
-+#else
-+      priv->regs->int_mask = 0;
-+      tasklet_schedule(&priv->tsk);
-+#endif
-+      return IRQ_HANDLED;
-+}
-+#endif
-+
-+/*
-+ * ubi32_eth_open
-+ */
-+static int ubi32_eth_open(struct net_device *dev)
-+{
-+      struct ubi32_eth_private *priv = netdev_priv(dev);
-+      int err;
-+
-+      printk(KERN_INFO "eth open %s\n",dev->name);
-+#ifndef UBICOM32_USE_POLLING
-+      /* request_region() */
-+      err = request_irq(dev->irq, ubi32_eth_interrupt, IRQF_DISABLED, dev->name, dev);
-+      if (err) {
-+              printk(KERN_WARNING "fail to request_irq %d\n",err);
-+               return -ENODEV;
-+      }
-+#endif
-+#ifdef  UBICOM32_USE_NAPI
-+      napi_enable(&priv->napi);
-+#else
-+      tasklet_init(&priv->tsk, ubi32_eth_do_tasklet, (unsigned long)dev);
-+#endif
-+
-+      /* call receive to supply RX buffers */
-+      ubi32_eth_receive(dev, RX_DMA_MAX_QUEUE_SIZE);
-+
-+      /* check phy status and call netif_carrier_on */
-+      ubi32_eth_vp_rxtx_enable(dev);
-+      netif_start_queue(dev);
-+      return 0;
-+}
-+
-+static int ubi32_eth_close(struct net_device *dev)
-+{
-+      struct ubi32_eth_private *priv = netdev_priv(dev);
-+      volatile void *pdata;
-+      struct sk_buff *skb;
-+
-+#ifndef UBICOM32_USE_POLLING
-+      free_irq(dev->irq, dev);
-+#endif
-+      netif_stop_queue(dev); /* can't transmit any more */
-+#ifdef UBICOM32_USE_NAPI
-+      napi_disable(&priv->napi);
-+#else
-+      tasklet_kill(&priv->tsk);
-+#endif
-+      ubi32_eth_vp_rxtx_stop(dev);
-+
-+      /*
-+       * RX clean up
-+       */
-+      while (priv->rx_tail != priv->regs->rx_in) {
-+              pdata = priv->regs->rx_dma_ring[priv->rx_tail];
-+              skb = container_of((void *)pdata, struct sk_buff, cb);
-+              priv->regs->rx_dma_ring[priv->rx_tail] = NULL;
-+              dev_kfree_skb_any(skb);
-+              priv->rx_tail = ((priv->rx_tail + 1) & RX_DMA_RING_MASK);
-+      }
-+      priv->regs->rx_in = 0;
-+      priv->regs->rx_out = priv->regs->rx_in;
-+      priv->rx_tail = priv->regs->rx_in;
-+
-+      /*
-+       * TX clean up
-+       */
-+      BUG_ON(priv->regs->tx_out != priv->regs->tx_in);
-+      ubi32_eth_tx_done(dev);
-+      BUG_ON(priv->tx_tail != priv->regs->tx_in);
-+      priv->regs->tx_in = 0;
-+      priv->regs->tx_out = priv->regs->tx_in;
-+      priv->tx_tail = priv->regs->tx_in;
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_eth_set_config
-+ */
-+static int ubi32_eth_set_config(struct net_device *dev, struct ifmap *map)
-+{
-+      /* if must to down to config it */
-+      printk(KERN_INFO "set_config %x\n", dev->flags);
-+      if (dev->flags & IFF_UP)
-+              return -EBUSY;
-+
-+      /* I/O and IRQ can not be changed */
-+      if (map->base_addr != dev->base_addr) {
-+              printk(KERN_WARNING "%s: Can't change I/O address\n", dev->name);
-+              return -EOPNOTSUPP;
-+      }
-+
-+#ifndef UBICOM32_USE_POLLING
-+      if (map->irq != dev->irq) {
-+              printk(KERN_WARNING "%s: Can't change IRQ\n", dev->name);
-+              return -EOPNOTSUPP;
-+      }
-+#endif
-+
-+      /* ignore other fields */
-+      return 0;
-+}
-+
-+static int ubi32_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+      struct ubi32_eth_private *priv = netdev_priv(dev);
-+      struct ubi32_eth_dma_desc *desc = NULL;
-+      unsigned short space, tx_in;
-+
-+      tx_in = priv->regs->tx_in;
-+
-+      dev->trans_start = jiffies; /* save the timestamp */
-+      space = TX_DMA_RING_MASK - ((TX_DMA_RING_SIZE + tx_in - priv->tx_tail) & TX_DMA_RING_MASK);
-+
-+      if (unlikely(space == 0)) {
-+              if (!(priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL)) {
-+                      spin_lock(&priv->lock);
-+                      if (!(priv->regs->status & UBI32_ETH_VP_STATUS_TX_Q_FULL)) {
-+                              priv->regs->status |= UBI32_ETH_VP_STATUS_TX_Q_FULL;
-+                              priv->vp_stats.tx_q_full_cnt++;
-+                              netif_stop_queue(dev);
-+                      }
-+                      spin_unlock(&priv->lock);
-+              }
-+
-+              /* give both HW and this driver an extra trigger */
-+              priv->regs->int_mask |= UBI32_ETH_VP_INT_TX;
-+#ifndef UBICOM32_USE_POLLING
-+              ubicom32_set_interrupt(dev->irq);
-+#endif
-+              ubicom32_set_interrupt(priv->vp_int_bit);
-+
-+              return NETDEV_TX_BUSY;
-+      }
-+
-+      /*still have room */
-+      desc = (struct ubi32_eth_dma_desc *)skb->cb;
-+      desc->data_pointer = skb->data;
-+      desc->data_len = skb->len;
-+      priv->regs->tx_dma_ring[tx_in] = desc;
-+      tx_in = ((tx_in + 1) & TX_DMA_RING_MASK);
-+      wmb();
-+      priv->regs->tx_in = tx_in;
-+      /* kick the HRT */
-+      ubicom32_set_interrupt(priv->vp_int_bit);
-+
-+      return NETDEV_TX_OK;
-+}
-+
-+/*
-+ * Deal with a transmit timeout.
-+ */
-+static void ubi32_eth_tx_timeout (struct net_device *dev)
-+{
-+      struct ubi32_eth_private *priv = netdev_priv(dev);
-+      dev->stats.tx_errors++;
-+      priv->regs->int_mask |= UBI32_ETH_VP_INT_TX;
-+#ifndef UBICOM32_USE_POLLING
-+      ubicom32_set_interrupt(dev->irq);
-+#endif
-+      ubicom32_set_interrupt(priv->vp_int_bit);
-+}
-+
-+static int ubi32_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-+{
-+      struct ubi32_eth_private *priv = netdev_priv(dev);
-+      struct mii_ioctl_data *data = if_mii(rq);
-+
-+      printk(KERN_INFO "ioctl %s, %d\n", dev->name, cmd);
-+      switch (cmd) {
-+      case SIOCGMIIPHY:
-+              data->phy_id = 0;
-+              break;
-+
-+      case SIOCGMIIREG:
-+              if ((data->reg_num & 0x1F) == MII_BMCR) {
-+                      /* Make up MII control register value from what we know */
-+                      data->val_out = 0x0000
-+                      | ((priv->regs->status & UBI32_ETH_VP_STATUS_DUPLEX)
-+                                      ? BMCR_FULLDPLX : 0)
-+                      | ((priv->regs->status & UBI32_ETH_VP_STATUS_SPEED100)
-+                                      ? BMCR_SPEED100 : 0)
-+                      | ((priv->regs->status & UBI32_ETH_VP_STATUS_SPEED1000)
-+                                      ? BMCR_SPEED1000 : 0);
-+              } else if ((data->reg_num & 0x1F) == MII_BMSR) {
-+                      /* Make up MII status register value from what we know */
-+                      data->val_out =
-+                      (BMSR_100FULL|BMSR_100HALF|BMSR_10FULL|BMSR_10HALF)
-+                      | ((priv->regs->status & UBI32_ETH_VP_STATUS_LINK)
-+                                      ? BMSR_LSTATUS : 0);
-+              } else {
-+                      return -EIO;
-+              }
-+              break;
-+
-+      case SIOCSMIIREG:
-+              return -EOPNOTSUPP;
-+              break;
-+
-+      default:
-+              return -EOPNOTSUPP;
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * Return statistics to the caller
-+ */
-+static struct net_device_stats *ubi32_eth_get_stats(struct net_device *dev)
-+{
-+      return &dev->stats;
-+}
-+
-+
-+static int ubi32_eth_change_mtu(struct net_device *dev, int new_mtu)
-+{
-+      struct ubi32_eth_private *priv = netdev_priv(dev);
-+      unsigned long flags;
-+
-+      if ((new_mtu < 68) || (new_mtu > 1500))
-+              return -EINVAL;
-+
-+      spin_lock_irqsave(&priv->lock, flags);
-+      dev->mtu = new_mtu;
-+      spin_unlock_irqrestore(&priv->lock, flags);
-+      printk(KERN_INFO "set mtu to %d", new_mtu);
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_eth_cleanup: unload the module
-+ */
-+void ubi32_eth_cleanup(void)
-+{
-+      struct ubi32_eth_private *priv;
-+      struct net_device *dev;
-+      int i;
-+
-+      for (i = 0; i < UBI32_ETH_NUM_OF_DEVICES; i++) {
-+              dev = ubi32_eth_devices[i];
-+              if (dev) {
-+                      priv = netdev_priv(dev);
-+                      kfree(priv->regs->tx_dma_ring);
-+                      unregister_netdev(dev);
-+                      free_netdev(dev);
-+                      ubi32_eth_devices[i] = NULL;
-+              }
-+      }
-+}
-+
-+int ubi32_eth_init_module(void)
-+{
-+      struct ethtionode *eth_node;
-+      struct net_device *dev;
-+      struct ubi32_eth_private *priv;
-+      int i, err;
-+
-+      /*
-+       * Device allocation.
-+       */
-+      err = 0;
-+      for (i = 0; i < UBI32_ETH_NUM_OF_DEVICES; i++) {
-+              /*
-+               * See if the eth_vp is in the device tree.
-+               */
-+              eth_node = (struct ethtionode *)devtree_find_node(eth_if_name[i]);
-+              if (!eth_node) {
-+                      printk(KERN_INFO "%s does not exist\n", eth_if_name[i]);
-+                      continue;
-+              }
-+
-+              eth_node->tx_dma_ring = (struct ubi32_eth_dma_desc **)kmalloc(
-+                              sizeof(struct ubi32_eth_dma_desc *) *
-+                              (TX_DMA_RING_SIZE + RX_DMA_RING_SIZE),
-+                              GFP_ATOMIC | __GFP_NOWARN | __GFP_NORETRY | GFP_DMA);
-+
-+              if (eth_node->tx_dma_ring == NULL) {
-+                      eth_node->tx_dma_ring = (struct ubi32_eth_dma_desc **)kmalloc(
-+                              sizeof(struct ubi32_eth_dma_desc *) *
-+                              (TX_DMA_RING_SIZE + RX_DMA_RING_SIZE), GFP_KERNEL);
-+                      printk(KERN_INFO "fail to allocate from OCM\n");
-+              }
-+
-+              if (!eth_node->tx_dma_ring) {
-+                      err = -ENOMEM;
-+                      break;
-+              }
-+              eth_node->rx_dma_ring = eth_node->tx_dma_ring + TX_DMA_RING_SIZE;
-+              eth_node->tx_sz = TX_DMA_RING_SIZE - 1;
-+              eth_node->rx_sz = RX_DMA_RING_SIZE - 1;
-+
-+              dev = alloc_etherdev(sizeof(struct ubi32_eth_private));
-+              if (!dev) {
-+                      kfree(eth_node->tx_dma_ring);
-+                      err = -ENOMEM;
-+                      break;
-+              }
-+              priv = netdev_priv(dev);
-+              priv->dev = dev;
-+
-+              /*
-+               * This just fill in some default Ubicom MAC address
-+               */
-+              memcpy(dev->dev_addr, mac_addr[i], ETH_ALEN);
-+              memset(dev->broadcast, 0xff, ETH_ALEN);
-+
-+              priv->regs = eth_node;
-+              priv->regs->command = 0;
-+              priv->regs->int_mask = 0;
-+              priv->regs->int_status = 0;
-+              priv->regs->tx_out = 0;
-+              priv->regs->rx_out = 0;
-+              priv->regs->tx_in = 0;
-+              priv->regs->rx_in = 0;
-+              priv->rx_tail = 0;
-+              priv->tx_tail = 0;
-+
-+              priv->vp_int_bit = eth_node->dn.sendirq;
-+              dev->irq = eth_node->dn.recvirq;
-+
-+              spin_lock_init(&priv->lock);
-+
-+              dev->open               = ubi32_eth_open;
-+              dev->stop               = ubi32_eth_close;
-+              dev->hard_start_xmit    = ubi32_eth_start_xmit;
-+              dev->tx_timeout         = ubi32_eth_tx_timeout;
-+              dev->watchdog_timeo     = UBI32_ETH_VP_TX_TIMEOUT;
-+
-+              dev->set_config         = ubi32_eth_set_config;
-+              dev->do_ioctl           = ubi32_eth_ioctl;
-+              dev->get_stats          = ubi32_eth_get_stats;
-+              dev->change_mtu         = ubi32_eth_change_mtu;
-+#ifdef UBICOM32_USE_NAPI
-+              netif_napi_add(dev, &priv->napi, ubi32_eth_napi_poll, UBI32_ETH_NAPI_WEIGHT);
-+#endif
-+              err = register_netdev(dev);
-+              if (err) {
-+                      printk(KERN_WARNING "Failed to register netdev %s\n", eth_if_name[i]);
-+                      //release_region();
-+                      free_netdev(dev);
-+                      kfree(eth_node->tx_dma_ring);
-+                      break;
-+              }
-+
-+              ubi32_eth_devices[i] = dev;
-+              printk(KERN_INFO "%s vp_base:0x%p, tio_int:%d irq:%d feature:0x%lx\n",
-+                      dev->name, priv->regs, eth_node->dn.sendirq, dev->irq, dev->features);
-+      }
-+
-+      if (err) {
-+              ubi32_eth_cleanup();
-+              return err;
-+      }
-+
-+      if (!ubi32_eth_devices[0] && !ubi32_eth_devices[1]) {
-+              return -ENODEV;
-+      }
-+
-+#if defined(UBICOM32_USE_POLLING)
-+      init_timer(&eth_poll_timer);
-+      eth_poll_timer.function = ubi32_eth_poll;
-+      eth_poll_timer.data = (unsigned long)0;
-+      eth_poll_timer.expires = jiffies + 2;
-+      add_timer(&eth_poll_timer);
-+#endif
-+
-+      return 0;
-+}
-+
-+module_init(ubi32_eth_init_module);
-+module_exit(ubi32_eth_cleanup);
-+
-+MODULE_AUTHOR("Kan Yan, Greg Ren");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/net/ubi32-eth.h
-@@ -0,0 +1,132 @@
-+/*
-+ * drivers/net/ubi32-eth.h
-+ *   Ubicom32 ethernet TIO interface driver definitions.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#ifndef _UBI32_ETH_H
-+#define _UBI32_ETH_H
-+
-+#include <asm/devtree.h>
-+
-+#define UBI32_ETH_NUM_OF_DEVICES 2
-+
-+/*
-+ * Number of bytes trashed beyond the packet data.
-+ */
-+#define UBI32_ETH_TRASHED_MEMORY      (CACHE_LINE_SIZE + ETH_HLEN - 1)
-+
-+/*
-+ * Linux already reserves NET_SKB_PAD bytes of headroom in each sk_buff.
-+ * We want to be able to reserve at least one cache line to align Ethernet
-+ * and IP header to cache line.
-+ * Note that the TIO expects a CACHE_LINE_SIZE - ETH_HLEN aligned Ethernet
-+ * header, while satisfies NET_IP_ALIGN (= 2) automatically.
-+ * (NET_SKB_PAD is 16, NET_IP_ALIGN is 2, CACHE_LINE_SIZE is 32).
-+ * You can add more space by making UBI32_ETH_RESERVE_EXTRA != 0.
-+ */
-+#define UBI32_ETH_RESERVE_EXTRA (1 * CACHE_LINE_SIZE)
-+#define UBI32_ETH_RESERVE_SPACE       (UBI32_ETH_RESERVE_EXTRA + CACHE_LINE_SIZE)
-+
-+struct ubi32_eth_dma_desc {
-+      volatile void   *data_pointer;  /* pointer to the buffer */
-+      volatile u16    buffer_len;     /* the buffer size */
-+      volatile u16    data_len;       /* actual frame length */
-+      volatile u32    status;         /* bit0: status to be update by VP; bit[31:1] time stamp */
-+};
-+
-+#define TX_DMA_RING_SIZE (1<<8)
-+#define TX_DMA_RING_MASK (TX_DMA_RING_SIZE - 1)
-+#define RX_DMA_RING_SIZE (1<<8)
-+#define RX_DMA_RING_MASK (RX_DMA_RING_SIZE - 1)
-+
-+#define RX_DMA_MAX_QUEUE_SIZE (RX_DMA_RING_SIZE - 1)  /* no more than (RX_DMA_RING_SIZE - 1) */
-+#define RX_MAX_PKT_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN)
-+#define RX_MIN_PKT_SIZE       ETH_ZLEN
-+#define RX_BUF_SIZE (RX_MAX_PKT_SIZE + VLAN_HLEN)     /* allow double VLAN tag */
-+
-+#define UBI32_ETH_VP_TX_TIMEOUT (10*HZ)
-+
-+struct ubi32_eth_vp_stats {
-+      u32     rx_alloc_err;
-+      u32     tx_q_full_cnt;
-+      u32     rx_q_full_cnt;
-+      u32     rx_throttle;
-+};
-+
-+struct ubi32_eth_private {
-+      struct net_device *dev;
-+      struct ubi32_eth_vp_stats vp_stats;
-+      spinlock_t lock;
-+#ifdef UBICOM32_USE_NAPI
-+      struct napi_struct napi;
-+#else
-+      struct tasklet_struct tsk;
-+#endif
-+      struct ethtionode *regs;
-+      u16     rx_tail;
-+      u16     tx_tail;
-+      u32     vp_int_bit;
-+};
-+
-+struct ethtionode {
-+      struct devtree_node dn;
-+      volatile u16    command;
-+      volatile u16    status;
-+      volatile u16    int_mask;       /* interrupt mask */
-+      volatile u16    int_status;     /* interrupt mask */
-+      volatile u16    tx_in;          /* owned by driver */
-+      volatile u16    tx_out;         /* owned by vp */
-+      volatile u16    rx_in;          /* owned by driver */
-+      volatile u16    rx_out;         /* owned by vp */
-+      u16             tx_sz;          /* owned by driver */
-+      u16             rx_sz;          /* owned by driver */
-+      struct ubi32_eth_dma_desc **tx_dma_ring;
-+      struct ubi32_eth_dma_desc **rx_dma_ring;
-+};
-+
-+#define UBI32_ETH_VP_STATUS_LINK      (1<<0)
-+#define UBI32_ETH_VP_STATUS_SPEED100  (0x1<<1)
-+#define UBI32_ETH_VP_STATUS_SPEED1000 (0x1<<2)
-+#define UBI32_ETH_VP_STATUS_DUPLEX    (0x1<<3)
-+#define UBI32_ETH_VP_STATUS_FLOW_CTRL (0x1<<4)
-+
-+#define UBI32_ETH_VP_STATUS_RX_STATE  (0x1<<5)
-+#define UBI32_ETH_VP_STATUS_TX_STATE  (0x1<<6)
-+
-+#define UBI32_ETH_VP_STATUS_TX_Q_FULL (1<<8)
-+
-+#define UBI32_ETH_VP_INT_RX   (1<<0)
-+#define UBI32_ETH_VP_INT_TX   (1<<1)
-+
-+#define UBI32_ETH_VP_CMD_RX_ENABLE    (1<<0)
-+#define UBI32_ETH_VP_CMD_TX_ENABLE    (1<<1)
-+
-+#define UBI32_ETH_VP_RX_OK            (1<<0)
-+#define UBI32_ETH_VP_TX_OK            (1<<1)
-+
-+#define UBI32_TX_BOUND                TX_DMA_RING_SIZE
-+#define UBI32_RX_BOUND                64
-+#define UBI32_ETH_NAPI_WEIGHT 64              /* for GigE */
-+#endif
---- a/drivers/net/usb/asix.c
-+++ b/drivers/net/usb/asix.c
-@@ -319,14 +319,33 @@ static int asix_rx_fixup(struct usbnet *
-               /* get the packet length */
-               size = (u16) (header & 0x0000ffff);
--              if ((skb->len) - ((size + 1) & 0xfffe) == 0)
-+              if ((skb->len) - ((size + 1) & 0xfffe) == 0) {
-+#ifndef HAVE_EFFICIENT_UNALIGNED_ACCESS
-+                      if (((u32)packet & 0x02) == 0) {
-+                              memmove(packet - 2, packet, size);
-+                              skb->data -= 2;
-+                              skb->tail -= 2;
-+                      }
-+#endif
-                       return 2;
-+              }
-+
-               if (size > ETH_FRAME_LEN) {
-                       deverr(dev,"asix_rx_fixup() Bad RX Length %d", size);
-                       return 0;
-               }
-               ax_skb = skb_clone(skb, GFP_ATOMIC);
-               if (ax_skb) {
-+#ifndef HAVE_EFFICIENT_UNALIGNED_ACCESS
-+                      if (((u32)packet & 0x02) == 0) {
-+                              memmove(packet - 2, packet, size);
-+                              ax_skb->data = packet - 2;
-+                      } else {
-+                              ax_skb->data = packet;
-+                      }
-+#else
-+                      ax_skb->data = packet;
-+#endif
-                       ax_skb->len = size;
-                       ax_skb->data = packet;
-                       skb_set_tail_pointer(ax_skb, size);
-@@ -1125,13 +1144,19 @@ static int ax88178_link_reset(struct usb
-       mode = AX88178_MEDIUM_DEFAULT;
-       if (ecmd.speed == SPEED_1000)
-+#ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS
-               mode |= AX_MEDIUM_GM;
-+#else
-+              mode |= AX_MEDIUM_GM | AX_MEDIUM_ENCK;
-+#endif
-       else if (ecmd.speed == SPEED_100)
-               mode |= AX_MEDIUM_PS;
-       else
-               mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM);
-+#ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS
-       mode |= AX_MEDIUM_ENCK;
-+#endif
-       if (ecmd.duplex == DUPLEX_FULL)
-               mode |= AX_MEDIUM_FD;
---- a/drivers/oprofile/cpu_buffer.c
-+++ b/drivers/oprofile/cpu_buffer.c
-@@ -328,10 +328,10 @@ static inline void oprofile_end_trace(st
- }
- static inline void
--__oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
--                        unsigned long event, int is_kernel)
-+__oprofile_add_ext_sample_cpu(unsigned long pc, struct pt_regs * const regs,
-+                            unsigned long event, int is_kernel, int cpu)
- {
--      struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer);
-+      struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu);
-       unsigned long backtrace = oprofile_backtrace_depth;
-       /*
-@@ -353,7 +353,8 @@ __oprofile_add_ext_sample(unsigned long 
- void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
-                            unsigned long event, int is_kernel)
- {
--      __oprofile_add_ext_sample(pc, regs, event, is_kernel);
-+      __oprofile_add_ext_sample_cpu(pc, regs, event,
-+                                    is_kernel, smp_processor_id());
- }
- void oprofile_add_sample(struct pt_regs * const regs, unsigned long event)
-@@ -361,7 +362,8 @@ void oprofile_add_sample(struct pt_regs 
-       int is_kernel = !user_mode(regs);
-       unsigned long pc = profile_pc(regs);
--      __oprofile_add_ext_sample(pc, regs, event, is_kernel);
-+      __oprofile_add_ext_sample_cpu(pc, regs, event,
-+                                    is_kernel, smp_processor_id());
- }
- /*
---- a/drivers/pci/Makefile
-+++ b/drivers/pci/Makefile
-@@ -44,8 +44,8 @@ obj-$(CONFIG_PPC) += setup-bus.o
- obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
- obj-$(CONFIG_X86_VISWS) += setup-irq.o
- obj-$(CONFIG_MN10300) += setup-bus.o
-+obj-$(CONFIG_UBICOM32) += setup-bus.o setup-irq.o
--#
- # ACPI Related PCI FW Functions
- #
- obj-$(CONFIG_ACPI)    += pci-acpi.o
---- a/drivers/serial/Kconfig
-+++ b/drivers/serial/Kconfig
-@@ -871,6 +871,57 @@ config SERIAL_UARTLITE_CONSOLE
-         console (the system console is the device which receives all kernel
-         messages and warnings and which allows logins in single user mode).
-+config SERIAL_UBI32_UARTTIO
-+        tristate "Ubicom UARTTIO support"
-+        depends on UBICOM32=y
-+        select SERIAL_CORE
-+      default y
-+        help
-+          Add support for the Ubicom virtual peripherial serial interface.
-+
-+config SERIAL_UBI32_UARTTIO_NR_UARTS
-+      int "Maximum number of UARTTIO virtual serial ports"
-+      depends on SERIAL_UBI32_UARTTIO
-+      default "4"
-+      help
-+        Set this to the maximum number of serial ports you want the driver to support.
-+
-+config SERIAL_UBI32_UARTTIO_CONSOLE
-+        tristate "Ubicom UARTTIO console support"
-+        depends on SERIAL_UBI32_UARTTIO=y
-+        select SERIAL_CORE_CONSOLE
-+      default y
-+        help
-+          Add support for console on the Ubicom virtual peripherial serial interface.
-+
-+config SERIAL_UBI32_SERDES
-+        bool "Ubicom serial port support"
-+        depends on UBICOM32=y
-+        select SERIAL_CORE
-+      default y
-+        help
-+          Add support for the Ubicom serial interface.
-+
-+config SERIAL_UBI32_SERDES_CONSOLE
-+        bool "Ubicom serial console support"
-+        depends on SERIAL_UBI32_SERDES=y
-+        select SERIAL_CORE_CONSOLE
-+      default y
-+
-+config SERIAL_UBI32_MAILBOX
-+        bool "Ubicom mailbox support"
-+        depends on UBICOM32=y
-+        select SERIAL_CORE
-+      default n
-+        help
-+          Add support for the Ubicom mailbox interface.
-+
-+config SERIAL_UBI32_MAILBOX_CONSOLE
-+        bool "Ubicom mailbox console support"
-+        depends on SERIAL_UBI32_MAILBOX=y
-+        select SERIAL_CORE_CONSOLE
-+      default y
-+
- config SERIAL_SUNCORE
-       bool
-       depends on SPARC
---- a/drivers/serial/Makefile
-+++ b/drivers/serial/Makefile
-@@ -77,3 +77,6 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIA
- obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
- obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
- obj-$(CONFIG_SERIAL_QE) += ucc_uart.o
-+obj-$(CONFIG_SERIAL_UBI32_SERDES) += ubi32_serdes.o
-+obj-$(CONFIG_SERIAL_UBI32_UARTTIO) += ubi32_uarttio.o
-+obj-$(CONFIG_SERIAL_UBI32_MAILBOX) += ubi32_mailbox.o
---- /dev/null
-+++ b/drivers/serial/ubi32_mailbox.c
-@@ -0,0 +1,928 @@
-+/*
-+ * drivers/serial/ubi32_mailbox.c
-+ *   Ubicom32 On-Chip Mailbox Driver
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/module.h>
-+#include <linux/ioport.h>
-+#include <linux/init.h>
-+#include <linux/console.h>
-+#include <linux/sysrq.h>
-+#include <linux/platform_device.h>
-+#include <linux/tty.h>
-+#include <linux/tty_flip.h>
-+#include <linux/serial_core.h>
-+
-+#include <asm/ip5000.h>
-+
-+#define SERIAL_UBICOM_BAUDRATE        115200
-+#define SERIAL_UBICOM_DATA_BIT        8       /* Fixed parameter - do not change */
-+#define SERIAL_UBICOM_PAR_BIT 0       /* Fixed parameter - do not change */
-+#define SERIAL_UBICOM_STOP_BIT        1       /* Fixed parameter - do not change */
-+
-+/* UART name and device definitions */
-+#define UBI32_MAILBOX_NAME    "ttyUM" // XXX
-+#define UBI32_MAILBOX_MAJOR   207 // XXX
-+#define UBI32_MAILBOX_MINOR   64
-+
-+#define PORT_UBI32_MAILBOX    1235
-+#define NR_PORTS 1
-+
-+#define get_sclk() 0
-+
-+struct ubi32_mailbox_port {
-+      struct uart_port port;
-+      /*
-+       * NOTE (rkeller):
-+       * the uart port is wrapped in another structure in case we need to hold more state than
-+       * what we can hold in the uart_port.
-+       * Not sure if we need this, I took over the concept from the blackfin driver.
-+       */
-+} ubi32_mailbox_ports[NR_PORTS];
-+
-+struct ubi32_mailbox_resource {
-+      int uart_base_addr;
-+      int uart_irq;
-+} ubi32_mailbox_resource[NR_PORTS] = {
-+      /*
-+       * uart_base_addr has to be non-NULL because it is put in the uart_port membase.
-+       * If membase if null the kernel skips the configuration and our port_type never gets set.
-+       */
-+      {ISD_MAILBOX_BASE, ISD_MAILBOX_INT}
-+};
-+
-+static volatile struct ubicom32_isd_mailbox {
-+      volatile u32_t in;
-+      volatile u32_t out;
-+      volatile u32_t status;
-+} *ubi32_mailbox = (struct ubicom32_isd_mailbox *)ISD_MAILBOX_BASE;
-+
-+static void ubi32_mailbox_tx_chars(struct ubi32_mailbox_port *uart);
-+
-+static void ubi32_mailbox_mctrl_check(struct ubi32_mailbox_port *uart);
-+
-+#define TRUE 1
-+#define FALSE 0
-+
-+static int mailbox_console_flg = TRUE;
-+static int num_timeouts = 0;
-+
-+/*
-+ * dummy functions and defined to be able to compile the Blackfin code
-+ */
-+#define UART_GET_LSR(port) (1)
-+#define UART_PUT_LSR(port, bits)
-+#define UART_CLEAR_LSR(port) (1)
-+#define TEMT 1
-+#define TFI 1
-+#define BI 1
-+#define PE 1
-+#define OE 1
-+#define FE 1
-+#define THRE 1
-+#define DR 1
-+#define UART_GET_LCR(port) (1)
-+#define UART_PUT_LCR(port, bits)
-+#define SB 1
-+#define STB 1
-+#define PEN 1
-+#define EPS 1
-+#define STP 1
-+#define WLS(n) 0
-+#define UART_GET_IER(port) (1)
-+#define UART_SET_IER(port, bits)
-+#define UART_CLEAR_IER(port, bits)
-+#define ETBEI 0
-+#define ERBFI 0
-+#define UART_GET_CHAR(port) ubi32_mailbox_get_char()
-+#define UART_PUT_CHAR(port, ch) ubi32_mailbox_put_char(ch)
-+#define SSYNC()
-+#define UART_GET_DLL(port) 0
-+#define UART_PUT_DLL(port, ch)
-+#define UART_GET_DLH(port) 0
-+#define UART_PUT_DLH(port, ch)
-+#define UART_GET_GCTL(port) (0)
-+#define UART_PUT_GCTL(port, ch)
-+#define UCEN 1
-+
-+/*
-+ * ubi32_mailbox_get_char_avail()
-+ */
-+static int ubi32_mailbox_get_char_avail(void)
-+{
-+      return !(ubi32_mailbox->status & ISD_MAILBOX_STATUS_IN_EMPTY);
-+}
-+
-+/*
-+ * ubi32_mailbox_get_char()
-+ */
-+static u32_t ubi32_mailbox_get_char(void)
-+{
-+      if (mailbox_console_flg == TRUE) {
-+              /*
-+               * Mailbox console is connected.
-+               */
-+              while (ubi32_mailbox->status & ISD_MAILBOX_STATUS_IN_EMPTY);
-+              return ubi32_mailbox->in & 0xff;
-+      }
-+
-+      /*
-+       * Mailbox console was not connected.
-+       */
-+      if (ubi32_mailbox->status & ISD_MAILBOX_STATUS_IN_EMPTY) {
-+              return 0xff;
-+      }
-+
-+      /*
-+       * Mailbox console is connecting.
-+       */
-+      mailbox_console_flg = TRUE;
-+      num_timeouts = 0;
-+      return ubi32_mailbox->in & 0xff;
-+}
-+
-+#define MAILBOX_MAX_ATTEMPTS 1000000
-+#define MAILBOX_MAX_TIMEOUTS 5
-+/*
-+ * ubi32_mailbox_put_char()
-+ */
-+static void ubi32_mailbox_put_char(u32_t v)
-+{
-+      /*
-+       * Wait to be able to output.
-+       */
-+      u32_t num_attempts = 0;
-+
-+      if(mailbox_console_flg == TRUE) {
-+              while(num_attempts++ < MAILBOX_MAX_ATTEMPTS) {
-+                      if(ubi32_mailbox->status & ISD_MAILBOX_STATUS_OUT_EMPTY) {
-+                              break;
-+                      }
-+              }
-+
-+              /*
-+               * If timed out more than 5 times on send, mailbox console is disconnected now.
-+               */
-+              if (num_attempts > MAILBOX_MAX_ATTEMPTS) {
-+                      if (num_timeouts++ > MAILBOX_MAX_TIMEOUTS) {
-+                              mailbox_console_flg = FALSE;
-+                      }
-+              }
-+      }
-+
-+      asm volatile(
-+              "pipe_flush 0   \n\t"
-+              "pipe_flush 0   \n\t"
-+              "pipe_flush 0   \n\t"
-+              "pipe_flush 0   \n\t"
-+              "pipe_flush 0   \n\t"
-+              "pipe_flush 0   \n\t"
-+              "pipe_flush 0   \n\t"
-+      );
-+
-+      ubi32_mailbox->out = v & 0xff;
-+}
-+
-+static void ubi32_mailbox_hw_init(struct ubi32_mailbox_port *uart)
-+{
-+// NOTE: It does not do any good to do these here because we are running on the linux hardware thread,
-+//    and these have to be called on the ldsr thread.
-+//    ubicom32_clear_interrupt(ISD_MAILBOX_INT);
-+//    ubicom32_enable_interrupt(ISD_MAILBOX_INT);
-+}
-+
-+/*
-+ * interrupts are disabled on entry
-+ */
-+static void ubi32_mailbox_stop_tx(struct uart_port *port)
-+{
-+//    struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
-+//    struct circ_buf *xmit = &uart->port.info->xmit;
-+
-+      while (!(UART_GET_LSR(uart) & TEMT))
-+              cpu_relax();
-+
-+      /* Clear TFI bit */
-+      UART_PUT_LSR(uart, TFI);
-+      UART_CLEAR_IER(uart, ETBEI);
-+}
-+
-+/*
-+ * port is locked and interrupts are disabled
-+ */
-+static void ubi32_mailbox_start_tx(struct uart_port *port)
-+{
-+      struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
-+
-+      UART_SET_IER(uart, ETBEI);
-+
-+      ubi32_mailbox_tx_chars(uart);
-+}
-+
-+/*
-+ * Interrupts are enabled
-+ */
-+static void ubi32_mailbox_stop_rx(struct uart_port *port)
-+{
-+//    struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
-+      UART_CLEAR_IER(uart, ERBFI);
-+}
-+
-+/*
-+ * Set the modem control timer to fire immediately.
-+ */
-+static void ubi32_mailbox_enable_ms(struct uart_port *port)
-+{
-+}
-+
-+static void ubi32_mailbox_rx_chars(struct ubi32_mailbox_port *uart)
-+{
-+      struct uart_info *info = uart->port.info;
-+      struct tty_struct *tty = info->port.tty;
-+      unsigned int status, ch, flg;
-+
-+      status = 0; // XXX? UART_GET_LSR(uart);
-+      UART_CLEAR_LSR(uart);
-+
-+      ch = UART_GET_CHAR(uart);
-+
-+      if(ch == 0xff)
-+              return;
-+
-+      uart->port.icount.rx++;
-+
-+      if (status & BI) {
-+              uart->port.icount.brk++;
-+              if (uart_handle_break(&uart->port))
-+                      goto ignore_char;
-+              status &= ~(PE | FE);
-+      }
-+      if (status & PE)
-+              uart->port.icount.parity++;
-+      if (status & OE)
-+              uart->port.icount.overrun++;
-+      if (status & FE)
-+              uart->port.icount.frame++;
-+
-+      status &= uart->port.read_status_mask;
-+
-+      if (status & BI)
-+              flg = TTY_BREAK;
-+      else if (status & PE)
-+              flg = TTY_PARITY;
-+      else if (status & FE)
-+              flg = TTY_FRAME;
-+      else
-+              flg = TTY_NORMAL;
-+
-+      if (uart_handle_sysrq_char(&uart->port, ch))
-+              goto ignore_char;
-+
-+      uart_insert_char(&uart->port, status, OE, ch, flg);
-+
-+ ignore_char:
-+      tty_flip_buffer_push(tty);
-+}
-+
-+static void ubi32_mailbox_tx_chars(struct ubi32_mailbox_port *uart)
-+{
-+      struct circ_buf *xmit = &uart->port.info->xmit;
-+
-+      if (uart->port.x_char) {
-+              UART_PUT_CHAR(uart, uart->port.x_char);
-+              uart->port.icount.tx++;
-+              uart->port.x_char = 0;
-+      }
-+      /*
-+       * Check the modem control lines before
-+       * transmitting anything.
-+       */
-+      ubi32_mailbox_mctrl_check(uart);
-+
-+      if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-+              ubi32_mailbox_stop_tx(&uart->port);
-+              return;
-+      }
-+
-+      while ((UART_GET_LSR(uart) & THRE) && xmit->tail != xmit->head) {
-+              UART_PUT_CHAR(uart, xmit->buf[xmit->tail]);
-+              xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-+              uart->port.icount.tx++;
-+              SSYNC();
-+      }
-+
-+      if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-+              uart_write_wakeup(&uart->port);
-+
-+      if (uart_circ_empty(xmit))
-+              ubi32_mailbox_stop_tx(&uart->port);
-+}
-+
-+static irqreturn_t ubi32_mailbox_isr(int irq, void *dev_id)
-+{
-+      struct ubi32_mailbox_port *uart = dev_id;
-+
-+      spin_lock(&uart->port.lock);
-+
-+      //XXX?while (UART_GET_LSR(uart) & DR)
-+
-+      /*
-+       * RX process
-+       */
-+      while (ubi32_mailbox_get_char_avail()) {
-+              ubi32_mailbox_rx_chars(uart);
-+      }
-+
-+#if 0
-+      /*
-+       * TX process
-+       */
-+      if (this_uart.tx_in == this_uart.tx_out) {
-+              UBICOM32_IO_PORT(SERIAL_UBICOM_PORT)->int_mask &= ~IO_PORTX_INT_SERDES_TXBE;
-+      } else if (UBICOM32_IO_PORT(SERIAL_UBICOM_PORT)->int_status & IO_PORTX_INT_SERDES_TXBE) {
-+              uart_ubicom32_send(this_uart.tx_buf[this_uart.tx_out & (SERIAL_UBICOM_BUF_SIZE - 1)]);
-+              this_uart.tx_out++;
-+              UBICOM32_IO_PORT(SERIAL_UBICOM_PORT)->int_mask |= IO_PORTX_INT_SERDES_TXBE;
-+      }
-+#endif
-+
-+      spin_unlock(&uart->port.lock);
-+
-+      return IRQ_HANDLED;
-+}
-+#if 0
-+static irqreturn_t ubi32_mailbox_tx_int(int irq, void *dev_id)
-+{
-+      struct ubi32_mailbox_port *uart = dev_id;
-+
-+      spin_lock(&uart->port.lock);
-+      if (UART_GET_LSR(uart) & THRE)
-+              ubi32_mailbox_tx_chars(uart);
-+      spin_unlock(&uart->port.lock);
-+
-+      return IRQ_HANDLED;
-+}
-+#endif
-+
-+/*
-+ * Return TIOCSER_TEMT when transmitter is not busy.
-+ */
-+static unsigned int ubi32_mailbox_tx_empty(struct uart_port *port)
-+{
-+//    struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
-+      unsigned short lsr;
-+
-+      lsr = UART_GET_LSR(uart);
-+      if (lsr & TEMT)
-+              return TIOCSER_TEMT;
-+      else
-+              return 0;
-+}
-+
-+static unsigned int ubi32_mailbox_get_mctrl(struct uart_port *port)
-+{
-+              return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-+}
-+
-+static void ubi32_mailbox_set_mctrl(struct uart_port *port, unsigned int mctrl)
-+{
-+}
-+
-+/*
-+ * Handle any change of modem status signal since we were last called.
-+ */
-+static void ubi32_mailbox_mctrl_check(struct ubi32_mailbox_port *uart)
-+{
-+}
-+
-+/*
-+ * Interrupts are always disabled.
-+ */
-+static void ubi32_mailbox_break_ctl(struct uart_port *port, int break_state)
-+{
-+//    struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
-+      u16 lcr = UART_GET_LCR(uart);
-+      if (break_state)
-+              lcr |= SB;
-+      else
-+              lcr &= ~SB;
-+      UART_PUT_LCR(uart, lcr);
-+      SSYNC();
-+}
-+
-+static int ubi32_mailbox_startup(struct uart_port *port)
-+{
-+      struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
-+
-+      if (request_irq(uart->port.irq, ubi32_mailbox_isr, IRQF_DISABLED,
-+           "UBI32_MAILBOX", uart)) {
-+              printk(KERN_NOTICE "Unable to attach Ubicom32 SERDES interrupt\n");
-+              return -EBUSY;
-+      }
-+
-+      UART_SET_IER(uart, ERBFI);
-+      return 0;
-+}
-+
-+static void ubi32_mailbox_shutdown(struct uart_port *port)
-+{
-+      struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
-+
-+      free_irq(uart->port.irq, uart);
-+}
-+
-+static void
-+ubi32_mailbox_set_termios(struct uart_port *port, struct ktermios *termios,
-+                 struct ktermios *old)
-+{
-+      struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
-+      unsigned long flags;
-+      unsigned int baud, quot;
-+      unsigned short val, ier, lsr, lcr = 0;
-+
-+      switch (termios->c_cflag & CSIZE) {
-+      case CS8:
-+              lcr = WLS(8);
-+              break;
-+      case CS7:
-+              lcr = WLS(7);
-+              break;
-+      case CS6:
-+              lcr = WLS(6);
-+              break;
-+      case CS5:
-+              lcr = WLS(5);
-+              break;
-+      default:
-+              printk(KERN_ERR "%s: word lengh not supported\n",
-+                      __FUNCTION__);
-+      }
-+
-+      if (termios->c_cflag & CSTOPB)
-+              lcr |= STB;
-+      if (termios->c_cflag & PARENB)
-+              lcr |= PEN;
-+      if (!(termios->c_cflag & PARODD))
-+              lcr |= EPS;
-+      if (termios->c_cflag & CMSPAR)
-+              lcr |= STP;
-+
-+      port->read_status_mask = OE;
-+      if (termios->c_iflag & INPCK)
-+              port->read_status_mask |= (FE | PE);
-+      if (termios->c_iflag & (BRKINT | PARMRK))
-+              port->read_status_mask |= BI;
-+
-+      /*
-+       * Characters to ignore
-+       */
-+      port->ignore_status_mask = 0;
-+      if (termios->c_iflag & IGNPAR)
-+              port->ignore_status_mask |= FE | PE;
-+      if (termios->c_iflag & IGNBRK) {
-+              port->ignore_status_mask |= BI;
-+              /*
-+               * If we're ignoring parity and break indicators,
-+               * ignore overruns too (for real raw support).
-+               */
-+              if (termios->c_iflag & IGNPAR)
-+                      port->ignore_status_mask |= OE;
-+      }
-+
-+      baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-+      quot = uart_get_divisor(port, baud);
-+      spin_lock_irqsave(&uart->port.lock, flags);
-+
-+      do {
-+              lsr = UART_GET_LSR(uart);
-+      } while (!(lsr & TEMT));
-+
-+      /* Disable UART */
-+      ier = UART_GET_IER(uart);
-+      UART_CLEAR_IER(uart, 0xF);
-+
-+      UART_PUT_DLL(uart, quot & 0xFF);
-+      SSYNC();
-+      UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
-+      SSYNC();
-+
-+      UART_PUT_LCR(uart, lcr);
-+
-+      /* Enable UART */
-+      UART_SET_IER(uart, ier);
-+
-+      val = UART_GET_GCTL(uart);
-+      val |= UCEN;
-+      UART_PUT_GCTL(uart, val);
-+
-+      spin_unlock_irqrestore(&uart->port.lock, flags);
-+}
-+
-+static const char *ubi32_mailbox_type(struct uart_port *port)
-+{
-+      struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
-+
-+      return uart->port.type == PORT_UBI32_MAILBOX ? "UBI32_MAILBOX" : NULL;
-+}
-+
-+/*
-+ * Release the memory region(s) being used by 'port'.
-+ */
-+static void ubi32_mailbox_release_port(struct uart_port *port)
-+{
-+}
-+
-+/*
-+ * Request the memory region(s) being used by 'port'.
-+ */
-+static int ubi32_mailbox_request_port(struct uart_port *port)
-+{
-+      return 0;
-+}
-+
-+/*
-+ * Configure/autoconfigure the port.
-+ */
-+static void ubi32_mailbox_config_port(struct uart_port *port, int flags)
-+{
-+      struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
-+
-+      if (flags & UART_CONFIG_TYPE && ubi32_mailbox_request_port(&uart->port) == 0)
-+              uart->port.type = PORT_UBI32_MAILBOX;
-+}
-+
-+/*
-+ * Verify the new serial_struct (for TIOCSSERIAL).
-+ * The only change we allow are to the flags and type, and
-+ * even then only between PORT_UBI32_MAILBOX and PORT_UNKNOWN
-+ */
-+static int
-+ubi32_mailbox_verify_port(struct uart_port *port, struct serial_struct *ser)
-+{
-+      return 0;
-+}
-+
-+static struct uart_ops ubi32_mailbox_pops = {
-+      .tx_empty       = ubi32_mailbox_tx_empty,
-+      .set_mctrl      = ubi32_mailbox_set_mctrl,
-+      .get_mctrl      = ubi32_mailbox_get_mctrl,
-+      .stop_tx        = ubi32_mailbox_stop_tx,
-+      .start_tx       = ubi32_mailbox_start_tx,
-+      .stop_rx        = ubi32_mailbox_stop_rx,
-+      .enable_ms      = ubi32_mailbox_enable_ms,
-+      .break_ctl      = ubi32_mailbox_break_ctl,
-+      .startup        = ubi32_mailbox_startup,
-+      .shutdown       = ubi32_mailbox_shutdown,
-+      .set_termios    = ubi32_mailbox_set_termios,
-+      .type           = ubi32_mailbox_type,
-+      .release_port   = ubi32_mailbox_release_port,
-+      .request_port   = ubi32_mailbox_request_port,
-+      .config_port    = ubi32_mailbox_config_port,
-+      .verify_port    = ubi32_mailbox_verify_port,
-+};
-+
-+static void __init ubi32_mailbox_init_ports(void)
-+{
-+      static int first = 1;
-+      int i;
-+
-+      if (!first)
-+              return;
-+      first = 0;
-+
-+      for (i = 0; i < NR_PORTS; i++) {
-+              ubi32_mailbox_ports[i].port.uartclk   = get_sclk();
-+              ubi32_mailbox_ports[i].port.ops       = &ubi32_mailbox_pops;
-+              ubi32_mailbox_ports[i].port.line      = i;
-+              ubi32_mailbox_ports[i].port.iotype    = UPIO_MEM;
-+              ubi32_mailbox_ports[i].port.membase   =
-+                      (void __iomem *)ubi32_mailbox_resource[i].uart_base_addr;
-+              ubi32_mailbox_ports[i].port.mapbase   =
-+                      ubi32_mailbox_resource[i].uart_base_addr;
-+              ubi32_mailbox_ports[i].port.irq       =
-+                      ubi32_mailbox_resource[i].uart_irq;
-+              ubi32_mailbox_ports[i].port.flags     = UPF_BOOT_AUTOCONF;
-+              spin_lock_init(&ubi32_mailbox_ports[i].port.lock);
-+
-+              ubi32_mailbox_hw_init(&ubi32_mailbox_ports[i]);
-+      }
-+
-+}
-+
-+#ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE
-+/*
-+ * If the port was already initialised (eg, by a boot loader),
-+ * try to determine the current setup.
-+ */
-+static void __init
-+ubi32_mailbox_console_get_options(struct ubi32_mailbox_port *uart, int *baud,
-+                         int *parity, int *bits)
-+{
-+      unsigned short status;
-+
-+      status = UART_GET_IER(uart) & (ERBFI | ETBEI);
-+      if (status == (ERBFI | ETBEI)) {
-+              /* ok, the port was enabled */
-+              unsigned short lcr;
-+              unsigned short dlh, dll;
-+
-+              lcr = UART_GET_LCR(uart);
-+
-+              *parity = 'n';
-+              if (lcr & PEN) {
-+                      if (lcr & EPS)
-+                              *parity = 'e';
-+                      else
-+                              *parity = 'o';
-+              }
-+              switch (lcr & 0x03) {
-+                      case 0: *bits = 5; break;
-+                      case 1: *bits = 6; break;
-+                      case 2: *bits = 7; break;
-+                      case 3: *bits = 8; break;
-+              }
-+
-+              dll = UART_GET_DLL(uart);
-+              dlh = UART_GET_DLH(uart);
-+
-+              *baud = get_sclk() / (16*(dll | dlh << 8));
-+      }
-+      pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
-+}
-+#endif
-+
-+#if defined(CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
-+static struct uart_driver ubi32_mailbox_reg;
-+
-+static int __init
-+ubi32_mailbox_console_setup(struct console *co, char *options)
-+{
-+      struct ubi32_mailbox_port *uart;
-+# ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE
-+      int baud = SERIAL_UBICOM_BAUDRATE;
-+      int bits = 8;
-+      int parity = 'n';
-+      int flow = 'n';
-+# endif
-+
-+      /*
-+       * Check whether an invalid uart number has been specified, and
-+       * if so, search for the first available port that does have
-+       * console support.
-+       */
-+      if (co->index == -1 || co->index >= NR_PORTS)
-+              co->index = 0;
-+      uart = &ubi32_mailbox_ports[co->index];
-+
-+# ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE
-+      if (options)
-+              uart_parse_options(options, &baud, &parity, &bits, &flow);
-+      else
-+              ubi32_mailbox_console_get_options(uart, &baud, &parity, &bits);
-+
-+      //JB return uart_set_options(&uart->port, co, baud, parity, bits, flow);
-+      return 0;
-+# else
-+      return 0;
-+# endif
-+}
-+#endif /* defined (CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE) ||
-+                               defined (CONFIG_EARLY_PRINTK) */
-+
-+#ifdef CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE
-+static void ubi32_mailbox_console_putchar(struct uart_port *port, int ch)
-+{
-+//    struct ubi32_mailbox_port *uart = (struct ubi32_mailbox_port *)port;
-+      while (!(UART_GET_LSR(uart) & THRE))
-+              barrier();
-+      UART_PUT_CHAR(uart, ch);
-+      SSYNC();
-+}
-+
-+/*
-+ * Interrupts are disabled on entering
-+ */
-+static void
-+ubi32_mailbox_console_write(struct console *co, const char *s, unsigned int count)
-+{
-+      struct ubi32_mailbox_port *uart = &ubi32_mailbox_ports[co->index];
-+      unsigned long flags = 0;
-+
-+      spin_lock_irqsave(&uart->port.lock, flags);
-+      uart_console_write(&uart->port, s, count, ubi32_mailbox_console_putchar);
-+      spin_unlock_irqrestore(&uart->port.lock, flags);
-+
-+}
-+
-+static struct console ubi32_mailbox_console = {
-+      .name           = UBI32_MAILBOX_NAME,
-+      .write          = ubi32_mailbox_console_write,
-+      .device         = uart_console_device,
-+      .setup          = ubi32_mailbox_console_setup,
-+      .flags          = CON_PRINTBUFFER,
-+      .index          = -1,
-+      .data           = &ubi32_mailbox_reg,
-+};
-+
-+static int __init ubi32_mailbox_console_init(void)
-+{
-+      ubi32_mailbox_init_ports();
-+      register_console(&ubi32_mailbox_console);
-+      return 0;
-+}
-+console_initcall(ubi32_mailbox_console_init);
-+
-+#define UBI32_MAILBOX_CONSOLE &ubi32_mailbox_console
-+#else
-+#define UBI32_MAILBOX_CONSOLE NULL
-+#endif /* CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE */
-+
-+
-+#ifdef CONFIG_EARLY_PRINTK
-+static __init void ubi32_mailbox_early_putc(struct uart_port *port, int ch)
-+{
-+      UART_PUT_CHAR(uart, ch);
-+}
-+
-+static __init void ubi32_mailbox_early_write(struct console *con, const char *s,
-+                                      unsigned int n)
-+{
-+      struct ubi32_mailbox_port *uart = &ubi32_mailbox_ports[con->index];
-+      unsigned int i;
-+
-+      for (i = 0; i < n; i++, s++) {
-+              if (*s == '\n')
-+                      ubi32_mailbox_early_putc(&uart->port, '\r');
-+              ubi32_mailbox_early_putc(&uart->port, *s);
-+      }
-+}
-+
-+static struct __init console ubi32_mailbox_early_console = {
-+      .name = "early_UM",
-+      .write = ubi32_mailbox_early_write,
-+      .device = uart_console_device,
-+      .flags = CON_PRINTBUFFER,
-+      .setup = ubi32_mailbox_console_setup,
-+      .index = -1,
-+      .data  = &ubi32_mailbox_reg,
-+};
-+
-+/*
-+ * XXX Unused in our driver. Need to find out what the termios initialization is good/needed for.
-+ */
-+struct console __init *ubi32_mailbox_early_init(unsigned int port,
-+                                              unsigned int cflag)
-+{
-+      struct ubi32_mailbox_port *uart;
-+      struct ktermios t;
-+
-+      if (port == -1 || port >= NR_PORTS)
-+              port = 0;
-+      ubi32_mailbox_init_ports();
-+      ubi32_mailbox_early_console.index = port;
-+      uart = &ubi32_mailbox_ports[port];
-+      t.c_cflag = cflag;
-+      t.c_iflag = 0;
-+      t.c_oflag = 0;
-+      t.c_lflag = ICANON;
-+      t.c_line = port;
-+      ubi32_mailbox_set_termios(&uart->port, &t, &t);
-+      return &ubi32_mailbox_early_console;
-+}
-+
-+#endif /* CONFIG_SERIAL_UBI32_MAILBOX_CONSOLE */
-+
-+static struct uart_driver ubi32_mailbox_reg = {
-+      .owner                  = THIS_MODULE,
-+      .driver_name            = "ubi32_mailbox",
-+      .dev_name               = UBI32_MAILBOX_NAME,
-+      .major                  = UBI32_MAILBOX_MAJOR,
-+      .minor                  = UBI32_MAILBOX_MINOR,
-+      .nr                     = NR_PORTS,
-+      .cons                   = UBI32_MAILBOX_CONSOLE,
-+};
-+
-+static int ubi32_mailbox_suspend(struct platform_device *dev, pm_message_t state)
-+{
-+      struct ubi32_mailbox_port *uart = platform_get_drvdata(dev);
-+
-+      if (uart)
-+              uart_suspend_port(&ubi32_mailbox_reg, &uart->port);
-+
-+      return 0;
-+}
-+
-+static int ubi32_mailbox_resume(struct platform_device *dev)
-+{
-+      struct ubi32_mailbox_port *uart = platform_get_drvdata(dev);
-+
-+      if (uart)
-+              uart_resume_port(&ubi32_mailbox_reg, &uart->port);
-+
-+      return 0;
-+}
-+
-+static int ubi32_mailbox_probe(struct platform_device *dev)
-+{
-+      struct resource *res = dev->resource;
-+      int i;
-+
-+      for (i = 0; i < dev->num_resources; i++, res++)
-+              if (res->flags & IORESOURCE_MEM)
-+                      break;
-+
-+      if (i < dev->num_resources) {
-+              for (i = 0; i < NR_PORTS; i++, res++) {
-+                      if (ubi32_mailbox_ports[i].port.mapbase != res->start)
-+                              continue;
-+                      ubi32_mailbox_ports[i].port.dev = &dev->dev;
-+                      uart_add_one_port(&ubi32_mailbox_reg, &ubi32_mailbox_ports[i].port);
-+                      platform_set_drvdata(dev, &ubi32_mailbox_ports[i]);
-+              }
-+      }
-+
-+      return 0;
-+}
-+
-+static int ubi32_mailbox_remove(struct platform_device *pdev)
-+{
-+      struct ubi32_mailbox_port *uart = platform_get_drvdata(pdev);
-+
-+      platform_set_drvdata(pdev, NULL);
-+
-+      if (uart)
-+              uart_remove_one_port(&ubi32_mailbox_reg, &uart->port);
-+
-+      return 0;
-+}
-+
-+static struct platform_driver ubi32_mailbox_driver = {
-+      .probe          = ubi32_mailbox_probe,
-+      .remove         = ubi32_mailbox_remove,
-+      .suspend        = ubi32_mailbox_suspend,
-+      .resume         = ubi32_mailbox_resume,
-+      .driver         = {
-+              .name   = "ubi32-mbox",
-+              .owner  = THIS_MODULE,
-+      },
-+};
-+
-+static int __init ubi32_mailbox_init(void)
-+{
-+      int ret;
-+
-+      pr_info("Serial: Ubicom32 mailbox serial driver.\n");
-+
-+      mailbox_console_flg = TRUE;
-+      num_timeouts = 0;
-+      ubi32_mailbox_init_ports();
-+
-+      ret = uart_register_driver(&ubi32_mailbox_reg);
-+      if (ret == 0) {
-+              ret = platform_driver_register(&ubi32_mailbox_driver);
-+              if (ret) {
-+                      pr_debug("uart register failed\n");
-+                      uart_unregister_driver(&ubi32_mailbox_reg);
-+              }
-+      }
-+
-+      /*
-+       * XXX HACK: currently probe does not get called, but the port needs to be added to work.
-+       */
-+      uart_add_one_port(&ubi32_mailbox_reg, &ubi32_mailbox_ports[0].port);
-+      return ret;
-+}
-+
-+static void __exit ubi32_mailbox_exit(void)
-+{
-+      platform_driver_unregister(&ubi32_mailbox_driver);
-+      uart_unregister_driver(&ubi32_mailbox_reg);
-+}
-+
-+module_init(ubi32_mailbox_init);
-+module_exit(ubi32_mailbox_exit);
-+
-+MODULE_ALIAS_CHARDEV_MAJOR(UBI32_MAILBOX_MAJOR);
-+MODULE_ALIAS("platform:ubi32_mailbox");
---- /dev/null
-+++ b/drivers/serial/ubi32_serdes.c
-@@ -0,0 +1,817 @@
-+/*
-+ * drivers/serial/ubi32_serdes.c
-+ *   Ubicom32 On-Chip Serial Driver
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/module.h>
-+#include <linux/ioport.h>
-+#include <linux/init.h>
-+#include <linux/console.h>
-+#include <linux/sysrq.h>
-+#include <linux/platform_device.h>
-+#include <linux/tty.h>
-+#include <linux/tty_flip.h>
-+#include <linux/serial_core.h>
-+
-+#include <asm/ip5000.h>
-+#include <asm/ubicom32suart.h>
-+
-+
-+#define SERIAL_UBICOM_PIN_RXD (1 << 0)
-+#define SERIAL_UBICOM_PIN_TXD (1 << 6)
-+#define SERIAL_UBICOM_CTL0    0x8b300000
-+#define SERIAL_UBICOM_CTL1    0x00000009
-+
-+#define SERIAL_UBICOM_DATA_BIT        8       /* Fixed parameter - do not change */
-+#define SERIAL_UBICOM_PAR_BIT 0       /* Fixed parameter - do not change */
-+#define SERIAL_UBICOM_STOP_BIT        1       /* Fixed parameter - do not change */
-+
-+/* UART name and device definitions */
-+#define UBI32_SERDES_NAME     "ttyUS" // XXX
-+#define UBI32_SERDES_MAJOR    206 // XXX
-+#define UBI32_SERDES_MINOR    64 // XXX
-+
-+#define PORT_UBI32_SERDES     1234
-+#define NR_PORTS 1
-+
-+struct uart_port ubi32_serdes_ports[NR_PORTS];
-+
-+struct ubi32_serdes_resource {
-+      void *uart_base_addr;
-+      int uart_irq;
-+      int uart_clock;
-+} ubi32_serdes_resource[NR_PORTS] = {
-+      /*
-+       * Get params from kernel command line (required for early printk)
-+       * or from platform resources.
-+       */
-+      {0, 0, 0}
-+};
-+
-+/*
-+ * Can get overridden by 'serdes=' kernel command line.
-+ */
-+static int ubi32_serdes_default_baud_rate = 115200;
-+
-+
-+#define IO_PORT(port) ((struct ubicom32_io_port *)port->membase)
-+#define IO_PORT_INT_STATUS(port) (IO_PORT(port)->int_status)
-+#define IO_PORT_INT_MASK(port) (IO_PORT(port)->int_mask)
-+#define IO_PORT_INT_CLR(port) (IO_PORT(port)->int_clr)
-+
-+
-+/*
-+ * ubi32_serdes_get_char()
-+ */
-+static u8_t ubi32_serdes_get_char(struct ubicom32_io_port *io_port)
-+{
-+      /*
-+       * Read from hardware (forced 32-bit atomic read).
-+       */
-+      u32_t data = 0;
-+
-+      if ( io_port ) {
-+              io_port->int_clr = IO_PORTX_INT_SERDES_RXBF;
-+              asm volatile (
-+                      "move.4         %0, %1          \n\t"
-+                      : "=r" (data)
-+                      : "m" (*(u32_t *)&(io_port->rx_fifo))
-+                      );
-+      }
-+
-+      return (u8_t)(data & 0x000000ff);
-+}
-+
-+/*
-+ * ubi32_serdes_put_char()
-+ */
-+static void ubi32_serdes_put_char(struct ubicom32_io_port *io_port, u8_t c)
-+{
-+      u32_t data = 0x0000fe00 | (c << 1);
-+
-+      if ( io_port ) {
-+              /*
-+               * Fixed data format:
-+               * [LSB]1 start bit - 8 data bits - no parity - 1 stop bit[MSB]
-+               */
-+              io_port->int_clr = IO_PORTX_INT_SERDES_TXBE;
-+              io_port->ctl2 = data;
-+              io_port->int_set = IO_PORTX_INT_SERDES_TXBUF_VALID;
-+      }
-+}
-+
-+static void ubi32_serdes_hw_init(struct uart_port *port, int baud)
-+{
-+      struct ubicom32_io_port *io_port = IO_PORT(port);
-+
-+      if ( io_port ) {
-+              /*
-+               * Put port functions 1-4 into reset state.
-+               * Function 0 (GPIO) does not need or have a reset bit.
-+               *
-+               * Select SERDES function for restart below.
-+               */
-+              io_port->function =
-+                      IO_FUNC_FUNCTION_RESET(1) | IO_FUNC_FUNCTION_RESET(2) |
-+                      IO_FUNC_FUNCTION_RESET(3) | IO_FUNC_FUNCTION_RESET(4) |
-+                      IO_PORTX_FUNC_SERDES;
-+
-+              /*
-+               * Configure SERDES baudrate
-+               */
-+              if ( baud == 0 ) {
-+                      baud = ubi32_serdes_default_baud_rate;
-+              }
-+
-+              io_port->ctl0 =
-+                      SERIAL_UBICOM_CTL0 |
-+                      ((port->uartclk / (16 * baud)) - 1);
-+
-+              io_port->ctl1 =
-+                      SERIAL_UBICOM_CTL1;
-+
-+              /*
-+               * don't interrupt until startup and start_tx
-+               */
-+              io_port->int_mask = 0;
-+
-+              /*
-+               * Set TXD pin output, RXD input and prevent GPIO
-+               * override on the TXD & RXD pins
-+               */
-+              io_port->gpio_ctl &= ~SERIAL_UBICOM_PIN_RXD;
-+              io_port->gpio_ctl |= SERIAL_UBICOM_PIN_TXD;
-+              io_port->gpio_mask &= ~(SERIAL_UBICOM_PIN_RXD | SERIAL_UBICOM_PIN_TXD);
-+
-+              /*
-+               * Restart (un-reset) the port's SERDES function.
-+               */
-+              io_port->function &= ~(IO_FUNC_FUNCTION_RESET(IO_PORTX_FUNC_SERDES));
-+      }
-+}
-+
-+#define ULITE_STATUS_RXVALID IO_PORTX_INT_SERDES_RXBF
-+#define ULITE_STATUS_OVERRUN 0
-+#define ULITE_STATUS_FRAME 0
-+#define ULITE_STATUS_PARITY 0
-+#define ULITE_STATUS_TXEMPTY IO_PORTX_INT_SERDES_TXBE
-+#define ULITE_STATUS_TXFULL 0
-+
-+static int ubi32_serdes_receive(struct uart_port *port, int stat)
-+{
-+      struct tty_struct *tty = port->info->port.tty;
-+      unsigned char ch = 0;
-+      char flag = TTY_NORMAL;
-+
-+      if ((stat & (ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
-+                   | ULITE_STATUS_FRAME)) == 0)
-+              return 0;
-+
-+      /* stats */
-+      if (stat & ULITE_STATUS_RXVALID) {
-+              port->icount.rx++;
-+              ch = ubi32_serdes_get_char((struct ubicom32_io_port *)port->membase);
-+
-+              if (stat & ULITE_STATUS_PARITY)
-+                      port->icount.parity++;
-+      }
-+
-+      if (stat & ULITE_STATUS_OVERRUN)
-+              port->icount.overrun++;
-+
-+      if (stat & ULITE_STATUS_FRAME)
-+              port->icount.frame++;
-+
-+
-+      /* drop byte with parity error if IGNPAR specificed */
-+      if (stat & port->ignore_status_mask & ULITE_STATUS_PARITY)
-+              stat &= ~ULITE_STATUS_RXVALID;
-+
-+      stat &= port->read_status_mask;
-+
-+      if (stat & ULITE_STATUS_PARITY)
-+              flag = TTY_PARITY;
-+
-+      stat &= ~port->ignore_status_mask;
-+
-+      if (stat & ULITE_STATUS_RXVALID)
-+              tty_insert_flip_char(tty, ch, flag);
-+
-+      if (stat & ULITE_STATUS_FRAME)
-+              tty_insert_flip_char(tty, 0, TTY_FRAME);
-+
-+      if (stat & ULITE_STATUS_OVERRUN)
-+              tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-+
-+      return 1;
-+}
-+
-+/*
-+ * interrupts are disabled on entry
-+ */
-+static void ubi32_serdes_stop_tx(struct uart_port *port)
-+{
-+      IO_PORT_INT_MASK(port) = IO_PORT_INT_MASK(port) & ~IO_PORTX_INT_SERDES_TXBE;
-+}
-+
-+static int ubi32_serdes_transmit(struct uart_port *port, int stat)
-+{
-+      struct circ_buf *xmit  = &port->info->xmit;
-+
-+      if (!(stat & IO_PORTX_INT_SERDES_TXBE))
-+              return 0;
-+
-+      if (port->x_char) {
-+              ubi32_serdes_put_char(IO_PORT(port), port->x_char);
-+              port->x_char = 0;
-+              port->icount.tx++;
-+              return 1;
-+      }
-+
-+      if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-+              ubi32_serdes_stop_tx(port);
-+              return 0;
-+      }
-+
-+      ubi32_serdes_put_char(IO_PORT(port), xmit->buf[xmit->tail]);
-+      xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
-+      port->icount.tx++;
-+
-+      /* wake up */
-+      if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-+              uart_write_wakeup(port);
-+
-+      if (uart_circ_empty(xmit))
-+              ubi32_serdes_stop_tx(port);
-+
-+      return 1;
-+}
-+
-+/*
-+ * port is locked and interrupts are disabled
-+ */
-+static void ubi32_serdes_start_tx(struct uart_port *port)
-+{
-+      IO_PORT_INT_MASK(port) = IO_PORT_INT_MASK(port) | IO_PORTX_INT_SERDES_TXBE;
-+      ubi32_serdes_transmit(port, IO_PORT_INT_STATUS(port));
-+}
-+
-+/*
-+ * Interrupts are enabled
-+ */
-+static void ubi32_serdes_stop_rx(struct uart_port *port)
-+{
-+      /* don't forward any more data (like !CREAD) */
-+      port->ignore_status_mask = IO_PORTX_INT_SERDES_RXBF;
-+}
-+
-+/*
-+ * Set the modem control timer to fire immediately.
-+ */
-+static void ubi32_serdes_enable_ms(struct uart_port *port)
-+{
-+      /* N/A */
-+}
-+
-+static irqreturn_t ubi32_serdes_isr(int irq, void *dev_id)
-+{
-+      struct uart_port *port = dev_id;
-+      int busy;
-+
-+      spin_lock(&port->lock);
-+
-+      do {
-+              int stat = IO_PORT_INT_STATUS(port);
-+              busy  = ubi32_serdes_receive(port, stat);
-+              busy |= ubi32_serdes_transmit(port, stat);
-+      } while (busy);
-+
-+      tty_flip_buffer_push(port->info->port.tty);
-+
-+      spin_unlock(&port->lock);
-+
-+      return IRQ_HANDLED;
-+}
-+
-+/*
-+ * Return TIOCSER_TEMT when transmitter is not busy.
-+ */
-+static unsigned int ubi32_serdes_tx_empty(struct uart_port *port)
-+{
-+      unsigned long flags;
-+      unsigned int ret;
-+
-+      spin_lock_irqsave(&port->lock, flags);
-+      ret = IO_PORT_INT_STATUS(port);
-+      spin_unlock_irqrestore(&port->lock, flags);
-+
-+      return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
-+}
-+
-+static unsigned int ubi32_serdes_get_mctrl(struct uart_port *port)
-+{
-+      return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-+}
-+
-+static void ubi32_serdes_set_mctrl(struct uart_port *port, unsigned int mctrl)
-+{
-+      /* N/A */
-+}
-+
-+/*
-+ * Interrupts are always disabled.
-+ */
-+static void ubi32_serdes_break_ctl(struct uart_port *port, int break_state)
-+{
-+      /* N/A */
-+}
-+
-+static int ubi32_serdes_startup(struct uart_port *port)
-+{
-+      if (request_irq(port->irq, ubi32_serdes_isr, IRQF_DISABLED,
-+           "UBI32_SERDES", port)) {
-+              printk(KERN_NOTICE "Unable to attach port interrupt\n");
-+              return -EBUSY;
-+      }
-+
-+      IO_PORT_INT_CLR(port) = IO_PORTX_INT_SERDES_RXBF;
-+      IO_PORT_INT_MASK(port) = IO_PORTX_INT_SERDES_RXBF;
-+      return 0;
-+}
-+
-+static void ubi32_serdes_shutdown(struct uart_port *port)
-+{
-+      struct ubi32_serdes_port *uart = (struct ubi32_serdes_port *)port;
-+
-+      IO_PORT_INT_MASK(port) = 0;
-+      free_irq(port->irq, uart);
-+}
-+
-+static void
-+ubi32_serdes_set_termios(struct uart_port *port, struct ktermios *termios,
-+                 struct ktermios *old)
-+{
-+      unsigned long flags;
-+      unsigned int baud;
-+
-+      spin_lock_irqsave(&port->lock, flags);
-+
-+      port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
-+              | ULITE_STATUS_TXFULL;
-+
-+      if (termios->c_iflag & INPCK)
-+              port->read_status_mask |=
-+                      ULITE_STATUS_PARITY | ULITE_STATUS_FRAME;
-+
-+      port->ignore_status_mask = 0;
-+      if (termios->c_iflag & IGNPAR)
-+              port->ignore_status_mask |= ULITE_STATUS_PARITY
-+                      | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
-+
-+      /* ignore all characters if CREAD is not set */
-+      if ((termios->c_cflag & CREAD) == 0)
-+              port->ignore_status_mask |=
-+                      ULITE_STATUS_RXVALID | ULITE_STATUS_PARITY
-+                      | ULITE_STATUS_FRAME | ULITE_STATUS_OVERRUN;
-+
-+      /* update timeout */
-+      baud = uart_get_baud_rate(port, termios, old, 0, 460800);
-+      uart_update_timeout(port, termios->c_cflag, baud);
-+
-+      IO_PORT(port)->ctl0 = SERIAL_UBICOM_CTL0 |
-+                      ((port->uartclk / (16 * baud)) - 1);
-+
-+      spin_unlock_irqrestore(&port->lock, flags);
-+}
-+
-+static const char *ubi32_serdes_type(struct uart_port *port)
-+{
-+      return port->type == PORT_UBI32_SERDES ? "UBI32_SERDES" : NULL;
-+}
-+
-+/*
-+ * Release the memory region(s) being used by 'port'.
-+ */
-+static void ubi32_serdes_release_port(struct uart_port *port)
-+{
-+}
-+
-+/*
-+ * Request the memory region(s) being used by 'port'.
-+ */
-+static int ubi32_serdes_request_port(struct uart_port *port)
-+{
-+      return 0;
-+}
-+
-+/*
-+ * Configure/autoconfigure the port.
-+ */
-+static void ubi32_serdes_config_port(struct uart_port *port, int flags)
-+{
-+      if (flags & UART_CONFIG_TYPE &&
-+          ubi32_serdes_request_port(port) == 0)
-+              port->type = PORT_UBI32_SERDES;
-+}
-+
-+/*
-+ * Verify the new serial_struct (for TIOCSSERIAL).
-+ * The only change we allow are to the flags and type, and
-+ * even then only between PORT_UBI32_SERDES and PORT_UNKNOWN
-+ */
-+static int
-+ubi32_serdes_verify_port(struct uart_port *port, struct serial_struct *ser)
-+{
-+      return 0;
-+}
-+
-+static struct uart_ops ubi32_serdes_pops = {
-+      .tx_empty       = ubi32_serdes_tx_empty,
-+      .set_mctrl      = ubi32_serdes_set_mctrl,
-+      .get_mctrl      = ubi32_serdes_get_mctrl,
-+      .stop_tx        = ubi32_serdes_stop_tx,
-+      .start_tx       = ubi32_serdes_start_tx,
-+      .stop_rx        = ubi32_serdes_stop_rx,
-+      .enable_ms      = ubi32_serdes_enable_ms,
-+      .break_ctl      = ubi32_serdes_break_ctl,
-+      .startup        = ubi32_serdes_startup,
-+      .shutdown       = ubi32_serdes_shutdown,
-+      .set_termios    = ubi32_serdes_set_termios,
-+      .type           = ubi32_serdes_type,
-+      .release_port   = ubi32_serdes_release_port,
-+      .request_port   = ubi32_serdes_request_port,
-+      .config_port    = ubi32_serdes_config_port,
-+      .verify_port    = ubi32_serdes_verify_port,
-+};
-+
-+static void __init ubi32_serdes_init_ports(void)
-+{
-+      int i;
-+
-+      for (i = 0; i < NR_PORTS; i++) {
-+              ubi32_serdes_ports[i].uartclk   = ubi32_serdes_resource[i].uart_clock;
-+              ubi32_serdes_ports[i].ops       = &ubi32_serdes_pops;
-+              ubi32_serdes_ports[i].line      = i;
-+              ubi32_serdes_ports[i].iotype    = UPIO_MEM;
-+              ubi32_serdes_ports[i].membase   =
-+                      (void __iomem *)ubi32_serdes_resource[i].uart_base_addr;
-+              ubi32_serdes_ports[i].mapbase   =
-+                      (resource_size_t)ubi32_serdes_resource[i].uart_base_addr;
-+              ubi32_serdes_ports[i].irq       =
-+                      ubi32_serdes_resource[i].uart_irq;
-+              ubi32_serdes_ports[i].flags     = UPF_BOOT_AUTOCONF;
-+
-+              ubi32_serdes_hw_init(&ubi32_serdes_ports[i], 0);
-+      }
-+
-+}
-+
-+#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE
-+/*
-+ * If the port was already initialised (eg, by a boot loader),
-+ * try to determine the current setup.
-+ */
-+static void __init
-+ubi32_serdes_console_get_options(struct uart_port *port, int *baud)
-+{
-+      u32 round_to = 1200;
-+      u32 real_baud;
-+
-+      /*
-+       * We might get called before platform init and with no
-+       * kernel command line options, so port might be NULL.
-+       */
-+      *baud = ubi32_serdes_default_baud_rate;;
-+      if ( IO_PORT(port) == 0 )
-+              return;
-+
-+      real_baud = port->uartclk
-+              / (16 * ((IO_PORT(port)->ctl0 & ~SERIAL_UBICOM_CTL0) + 1));
-+
-+      *baud = ((real_baud + round_to - 1) / round_to) * round_to;
-+
-+      pr_debug("%s:baud = %d, real_baud = %d\n", __FUNCTION__, *baud, real_baud);
-+}
-+#endif
-+
-+#if defined(CONFIG_SERIAL_UBI32_SERDES_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
-+static struct uart_driver ubi32_serdes_reg;
-+
-+static int __init
-+ubi32_serdes_console_setup(struct console *co, char *options)
-+{
-+      struct uart_port *port;
-+#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE
-+      int baud = ubi32_serdes_default_baud_rate;
-+      int bits = 8;
-+      int parity = 'n';
-+      int flow = 'n';
-+#endif
-+
-+      /*
-+       * Check whether an invalid uart number has been specified, and
-+       * if so, search for the first available port that does have
-+       * console support.
-+       */
-+      if (co->index == -1 || co->index >= NR_PORTS)
-+              co->index = 0;
-+      port = &ubi32_serdes_ports[co->index];
-+
-+#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE
-+      if (options) {
-+              uart_parse_options(options, &baud, &parity, &bits, &flow);
-+              ubi32_serdes_hw_init(port, baud);
-+      }
-+      else
-+              ubi32_serdes_console_get_options(port, &baud);
-+
-+      return uart_set_options(port, co, baud, parity, bits, flow);
-+#else
-+      return 0;
-+#endif
-+}
-+#endif /* defined (CONFIG_SERIAL_UBI32_SERDES_CONSOLE) ||
-+                               defined (CONFIG_EARLY_PRINTK) */
-+
-+#ifdef CONFIG_SERIAL_UBI32_SERDES_CONSOLE
-+static void
-+ubi32_serdes_console_putchar(struct uart_port *port, int ch)
-+{
-+      if ( IO_PORT(port) ) {
-+              while (!(IO_PORT_INT_STATUS(port) & IO_PORTX_INT_SERDES_TXBE))
-+                      barrier();
-+              ubi32_serdes_put_char(IO_PORT(port), ch);
-+      }
-+}
-+
-+/*
-+ * Interrupts are disabled on entering
-+ */
-+static void
-+ubi32_serdes_console_write(struct console *co, const char *s, unsigned int count)
-+{
-+      struct uart_port *port = &ubi32_serdes_ports[co->index];
-+      unsigned long flags = 0;
-+
-+      spin_lock_irqsave(&port->lock, flags);
-+      uart_console_write(port, s, count, ubi32_serdes_console_putchar);
-+      spin_unlock_irqrestore(&port->lock, flags);
-+
-+}
-+
-+static struct console ubi32_serdes_console = {
-+      .name           = UBI32_SERDES_NAME,
-+      .write          = ubi32_serdes_console_write,
-+      .device         = uart_console_device,
-+      .setup          = ubi32_serdes_console_setup,
-+      .flags          = CON_PRINTBUFFER,
-+      .index          = -1,
-+      .data           = &ubi32_serdes_reg,
-+};
-+
-+static int __init ubi32_serdes_console_init(void)
-+{
-+      ubi32_serdes_init_ports();
-+      register_console(&ubi32_serdes_console);
-+      return 0;
-+}
-+console_initcall(ubi32_serdes_console_init);
-+
-+#define UBI32_SERDES_CONSOLE  &ubi32_serdes_console
-+#else
-+#define UBI32_SERDES_CONSOLE  NULL
-+#endif /* CONFIG_SERIAL_UBI32_SERDES_CONSOLE */
-+
-+
-+#ifdef CONFIG_EARLY_PRINTK
-+static __init void ubi32_serdes_early_putc(struct uart_port *port, int ch)
-+{
-+      unsigned timeout = 0xffff;
-+
-+      while ((!(IO_PORT_INT_STATUS(port) & IO_PORTX_INT_SERDES_TXBE)) && --timeout)
-+              cpu_relax();
-+      ubi32_serdes_put_char(IO_PORT(port), ch);
-+}
-+
-+static __init void ubi32_serdes_early_write(struct console *con, const char *s,
-+                                      unsigned int n)
-+{
-+      struct uart_port *port = &ubi32_serdes_ports[con->index];
-+      unsigned int i;
-+
-+      for (i = 0; i < n; i++, s++) {
-+              if (*s == '\n')
-+                      ubi32_serdes_early_putc(port, '\r');
-+              ubi32_serdes_early_putc(port, *s);
-+      }
-+}
-+
-+static struct __init console ubi32_serdes_early_console = {
-+      .name = "early_US",
-+      .write = ubi32_serdes_early_write,
-+      .device = uart_console_device,
-+      .flags = CON_PRINTBUFFER,
-+      .setup = ubi32_serdes_console_setup,
-+      .index = -1,
-+      .data  = &ubi32_serdes_reg,
-+};
-+
-+/*
-+ * XXX Unused in our driver. Need to find out what the termios initialization is good/needed for.
-+ */
-+struct console __init *ubi32_serdes_early_init(unsigned int port_index,
-+                                              unsigned int cflag)
-+{
-+      struct uart_port *uart;
-+      struct ktermios t;
-+
-+      if (port_index == -1 || port_index >= NR_PORTS)
-+              port_index = 0;
-+      ubi32_serdes_init_ports();
-+      ubi32_serdes_early_console.index = port_index;
-+      uart = &ubi32_serdes_ports[port_index];
-+      t.c_cflag = cflag;
-+      t.c_iflag = 0;
-+      t.c_oflag = 0;
-+      t.c_lflag = ICANON;
-+      t.c_line = port_index;
-+      ubi32_serdes_set_termios(uart, &t, &t);
-+      return &ubi32_serdes_early_console;
-+}
-+
-+#endif /* CONFIG_SERIAL_UBI32_SERDES_CONSOLE */
-+
-+static struct uart_driver ubi32_serdes_reg = {
-+      .owner                  = THIS_MODULE,
-+      .driver_name            = "ubi32_serdes",
-+      .dev_name               = UBI32_SERDES_NAME,
-+      .major                  = UBI32_SERDES_MAJOR,
-+      .minor                  = UBI32_SERDES_MINOR,
-+      .nr                     = NR_PORTS,
-+      .cons                   = UBI32_SERDES_CONSOLE,
-+};
-+
-+static int ubi32_serdes_suspend(struct platform_device *dev, pm_message_t state)
-+{
-+      struct uart_port *port = platform_get_drvdata(dev);
-+
-+      if (port)
-+              uart_suspend_port(&ubi32_serdes_reg, port);
-+
-+      return 0;
-+}
-+
-+static int ubi32_serdes_resume(struct platform_device *dev)
-+{
-+      struct uart_port *port = platform_get_drvdata(dev);
-+
-+      if (port)
-+              uart_resume_port(&ubi32_serdes_reg, port);
-+
-+      return 0;
-+}
-+
-+static int ubi32_serdes_probe(struct platform_device *dev)
-+{
-+      struct resource *res = dev->resource;
-+      int i;
-+
-+      for (i = 0; i < dev->num_resources; i++, res++) {
-+              if (res->flags & IORESOURCE_MEM) {
-+                      ubi32_serdes_resource[0].uart_base_addr = (void *) res->start;
-+              }
-+              else if (res->flags & IORESOURCE_IRQ) {
-+                      ubi32_serdes_resource[0].uart_irq = res->start;
-+              }
-+              else if (res->flags & UBICOM32_SUART_IORESOURCE_CLOCK) {
-+                      ubi32_serdes_resource[0].uart_clock = res->start;
-+              }
-+      }
-+
-+      ubi32_serdes_init_ports();
-+
-+      return 0;
-+}
-+
-+static int ubi32_serdes_remove(struct platform_device *pdev)
-+{
-+      struct uart_port *port = platform_get_drvdata(pdev);
-+
-+      platform_set_drvdata(pdev, NULL);
-+
-+      if (port)
-+              uart_remove_one_port(&ubi32_serdes_reg, port);
-+
-+      return 0;
-+}
-+
-+static struct platform_driver ubi32_serdes_driver = {
-+      .remove         = ubi32_serdes_remove,
-+      .suspend        = ubi32_serdes_suspend,
-+      .resume         = ubi32_serdes_resume,
-+      .driver         = {
-+              .name   = "ubicom32suart",
-+              .owner  = THIS_MODULE,
-+      },
-+};
-+
-+
-+#ifndef MODULE
-+/*
-+ * Called at boot time.
-+ *
-+ * You can specify IO base, IRQ, and clock for the serdes serial port
-+ * using kernel command line "serdes=0xiobase,irq,clock".  Values
-+ * specified will be overwritten by platform device data, if present.
-+ */
-+static int __init ubi32_serdes_setup(char *str)
-+{
-+#define N_PARMS   (4+1)
-+      int ints[N_PARMS];
-+      int i;
-+
-+      str = get_options(str, ARRAY_SIZE(ints), ints);
-+
-+      for (i = 0; i < N_PARMS; i++) {
-+              if (i < ints[0]) {
-+                      if (i == 0) {
-+                              ubi32_serdes_resource[0].uart_base_addr = (void *) ints[i+1];
-+                      }
-+                      else if (i == 1) {
-+                              ubi32_serdes_resource[0].uart_irq = ints[i+1];
-+                      }
-+                      else if (i == 2) {
-+                              ubi32_serdes_resource[0].uart_clock = ints[i+1];
-+                      }
-+                      else if (i == 3) {
-+                              ubi32_serdes_default_baud_rate = ints[i+1];
-+                      }
-+              }
-+      }
-+      return 1;
-+}
-+
-+__setup("serdes=", ubi32_serdes_setup);
-+#endif
-+
-+static int __init ubi32_serdes_init(void)
-+{
-+      int ret;
-+
-+      pr_info("Serial: Ubicom32 serdes uart serial driver\n");
-+
-+      ret = platform_driver_probe(&ubi32_serdes_driver, ubi32_serdes_probe);
-+      if (ret != 0) {
-+              printk(KERN_INFO "serdes platform_driver_probe() failed: %d\n", ret);
-+              return ret;
-+      }
-+
-+      ubi32_serdes_init_ports();
-+
-+      ret = uart_register_driver(&ubi32_serdes_reg);
-+      if ( ret == 0 ) {
-+              ret = uart_add_one_port(&ubi32_serdes_reg, &ubi32_serdes_ports[0]);
-+              if ( ret != 0 ) {
-+                      uart_unregister_driver(&ubi32_serdes_reg);
-+              }
-+      }
-+
-+      return ret;
-+}
-+
-+static void __exit ubi32_serdes_exit(void)
-+{
-+      platform_driver_unregister(&ubi32_serdes_driver);
-+      uart_unregister_driver(&ubi32_serdes_reg);
-+}
-+
-+module_init(ubi32_serdes_init);
-+module_exit(ubi32_serdes_exit);
-+
-+MODULE_AUTHOR("Rainer Keller <rkeller@ubicom.com>");
-+MODULE_DESCRIPTION("Ubicom generic serial port driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS_CHARDEV_MAJOR(UBI32_SERDES_MAJOR);
-+MODULE_ALIAS("platform:ubi32_serdes");
---- /dev/null
-+++ b/drivers/serial/ubi32_uarttio.c
-@@ -0,0 +1,1172 @@
-+/*
-+ * drivers/serial/ubi32_uarttio.c
-+ *   Ubicom32 Serial Virtual Peripherial Driver
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/ioport.h>
-+#include <linux/init.h>
-+#include <linux/console.h>
-+#include <linux/sysrq.h>
-+#include <linux/platform_device.h>
-+#include <linux/tty.h>
-+#include <linux/tty_flip.h>
-+#include <linux/serial_core.h>
-+
-+#include <asm/ip5000.h>
-+#include <asm/gpio.h>
-+#include <asm/thread.h>
-+#include <asm/uart_tio.h>
-+
-+#define DRIVER_NAME   "ubi32_uarttio"
-+
-+/*
-+ * For storing the module parameters.
-+ */
-+#define UBI32_UARTTIO_MAX_PARAM_LEN   80
-+static char utio_ports_param[UBI32_UARTTIO_MAX_PARAM_LEN];
-+
-+/*
-+ * UART name and device definitions
-+ */
-+#define UBI32_UARTTIO_NAME    "ttyUV" // XXX
-+#define UBI32_UARTTIO_MAJOR   206 // XXX
-+#define UBI32_UARTTIO_MINOR   64 // XXX
-+
-+/*
-+ * The following structures are allocated statically because the
-+ * memory allocation subsystem is not initialized this early on
-+ */
-+
-+/*
-+ * Per port structure
-+ */
-+struct ubi32_uarttio_port {
-+      struct uarttio_uart             *uart;
-+      unsigned int                    tx_pin;
-+      unsigned int                    rx_pin;
-+
-+      struct uart_port                port;
-+
-+      u8_t                            added;
-+
-+      /*
-+       * If this value is set, the port has had its direction set already
-+       */
-+      u8_t                            port_init;
-+};
-+static struct ubi32_uarttio_port uarttio_ports[CONFIG_SERIAL_UBI32_UARTTIO_NR_UARTS];
-+
-+/*
-+ * Number of ports currently initialized
-+ */
-+static int uarttio_nports;
-+
-+/*
-+ * Per device structure
-+ */
-+struct ubi32_uarttio_instance {
-+      struct uarttio_regs             *regs;
-+      struct ubi32_uarttio_port       *ports;
-+
-+      u8_t                            irq_requested;
-+      u8_t                            driver_registered;
-+      u8_t                            irq;
-+};
-+static struct ubi32_uarttio_instance uarttio_inst;
-+
-+#ifdef CONFIG_SERIAL_UBI32_UARTTIO_CONSOLE
-+static struct console ubi32_uarttio_console;
-+#define UBI32_UARTTIO_CONSOLE &ubi32_uarttio_console
-+#else
-+#define UBI32_UARTTIO_CONSOLE NULL
-+#endif
-+
-+static struct uart_driver ubi32_uarttio_uart_driver = {
-+      .owner                  = THIS_MODULE,
-+      .driver_name            = DRIVER_NAME,
-+      .dev_name               = UBI32_UARTTIO_NAME,
-+      .major                  = UBI32_UARTTIO_MAJOR,
-+      .minor                  = UBI32_UARTTIO_MINOR,
-+      .cons                   = UBI32_UARTTIO_CONSOLE,
-+};
-+
-+#ifdef UBI32_UARTTIO_UNUSED
-+/*
-+ * ubi32_uarttio_get_send_space
-+ */
-+static int ubi32_uarttio_get_send_space(struct uarttio_uart *uart)
-+{
-+      int count = uart->tx_fifo_head - uart->tx_fifo_tail;
-+      if (count < 0) {
-+              count += uart->tx_fifo_size;
-+      }
-+      return uart->tx_fifo_size - count;
-+}
-+#endif
-+
-+/*
-+ * ubi32_uarttio_get_recv_ready
-+ */
-+static int ubi32_uarttio_get_recv_ready(struct uarttio_uart *uart)
-+{
-+      int count = uart->rx_fifo_head - uart->rx_fifo_tail;
-+      if (count < 0) {
-+              count += uart->rx_fifo_size;
-+      }
-+      return count;
-+}
-+
-+/*
-+ * ubi32_uarttio_get_char()
-+ */
-+static u8_t ubi32_uarttio_get_char(struct uarttio_uart *uart)
-+{
-+      /*
-+       * Retrieve byte
-+       */
-+      u32_t tail = uart->rx_fifo_tail;
-+      u8_t data = uart->rx_fifo[tail];
-+
-+      if (++tail == uart->rx_fifo_size) {
-+              tail = 0;
-+      }
-+      uart->rx_fifo_tail = tail;
-+
-+      return data;
-+}
-+
-+/*
-+ * ubi32_uarttio_put_char()
-+ */
-+static int ubi32_uarttio_put_char(struct uarttio_uart *uart, u8_t c)
-+{
-+      u32_t head = uart->tx_fifo_head;
-+      u32_t prev = head;
-+
-+      /*
-+       * Wrap
-+       */
-+      if (++head == uart->tx_fifo_size) {
-+              head = 0;
-+      }
-+
-+      /*
-+       * If there isn't any space, return EBUSY
-+       */
-+      if (head == uart->tx_fifo_tail) {
-+              return -EBUSY;
-+      }
-+
-+      /*
-+       * Put the character in the queue
-+       */
-+      uart->tx_fifo[prev] = c;
-+      uart->tx_fifo_head = head;
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_uarttio_set_baud
-+ */
-+static int ubi32_uarttio_set_baud(struct ubi32_uarttio_port *uup, unsigned int baud)
-+{
-+      if (uup->uart->current_baud_rate == baud) {
-+              return 0;
-+      }
-+
-+      uup->uart->baud_rate = baud;
-+      uup->uart->flags |= UARTTIO_UART_FLAG_SET_RATE;
-+      while (uup->uart->flags & UARTTIO_UART_FLAG_SET_RATE) {
-+              cpu_relax();
-+      }
-+
-+      if (uup->uart->current_baud_rate != baud) {
-+              /*
-+               * Failed to set baud rate
-+               */
-+              printk(KERN_WARNING "Invalid baud rate %u, running at %u\n", baud, uup->uart->current_baud_rate);
-+              return -EINVAL;
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_uarttio_handle_receive
-+ */
-+static void ubi32_uarttio_handle_receive(struct ubi32_uarttio_port *uup, int stat)
-+{
-+      struct uarttio_uart *uart = uup->uart;
-+      struct uart_port *port = &uup->port;
-+      struct tty_struct *tty = port->info->port.tty;
-+      unsigned char ch = 0;
-+      char flag = TTY_NORMAL;
-+      int count;
-+
-+      if ((stat & (UARTTIO_UART_INT_RX | UARTTIO_UART_INT_RXFRAME | UARTTIO_UART_INT_RXOVF)) == 0) {
-+              return;
-+      }
-+
-+      if (stat & UARTTIO_UART_INT_RX) {
-+              count = ubi32_uarttio_get_recv_ready(uart);
-+              port->icount.rx += count;
-+      }
-+
-+      if (stat & UARTTIO_UART_INT_RXOVF) {
-+              port->icount.overrun++;
-+      }
-+
-+      if (stat & UARTTIO_UART_INT_RXFRAME) {
-+              port->icount.frame++;
-+      }
-+
-+      stat &= ~port->ignore_status_mask;
-+
-+      if (stat & UARTTIO_UART_INT_RX) {
-+              int i;
-+              for (i = 0; i < count; i++) {
-+                      ch = ubi32_uarttio_get_char(uart);
-+                      tty_insert_flip_char(tty, ch, flag);
-+              }
-+      }
-+
-+      if (stat & UARTTIO_UART_INT_RXFRAME) {
-+              tty_insert_flip_char(tty, 0, TTY_FRAME);
-+      }
-+
-+      if (stat & UARTTIO_UART_INT_RXOVF) {
-+              tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-+      }
-+}
-+
-+/*
-+ * ubi32_uarttio_stop_tx
-+ *    interrupts are disabled on entry
-+ */
-+static void ubi32_uarttio_stop_tx(struct uart_port *port)
-+{
-+      struct ubi32_uarttio_port *uup = port->private_data;
-+
-+      uup->uart->int_mask &= ~UARTTIO_UART_INT_TXBE;
-+}
-+
-+/*
-+ * ubi32_uarttio_handle_transmit
-+ */
-+static void ubi32_uarttio_handle_transmit(struct ubi32_uarttio_port *uup, int stat)
-+{
-+      struct uarttio_uart *uart = uup->uart;
-+      struct uart_port *port = &uup->port;
-+      struct circ_buf *xmit  = &port->info->xmit;
-+
-+      if (!(stat & UARTTIO_UART_INT_TXBE)) {
-+              return;
-+      }
-+
-+      if (port->x_char) {
-+              if (ubi32_uarttio_put_char(uart, port->x_char)) {
-+                      return;
-+              }
-+              port->x_char = 0;
-+              port->icount.tx++;
-+              return;
-+      }
-+
-+      if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-+              ubi32_uarttio_stop_tx(port);
-+              return;
-+      }
-+
-+      /*
-+       * Send as many characters as we can
-+       */
-+      while (ubi32_uarttio_put_char(uart, xmit->buf[xmit->tail]) == 0) {
-+              xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-+              port->icount.tx++;
-+              if (uart_circ_empty(xmit)) {
-+                      break;
-+              }
-+      }
-+
-+      /* wake up */
-+      if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
-+              uart_write_wakeup(port);
-+      }
-+
-+      if (uart_circ_empty(xmit)) {
-+              ubi32_uarttio_stop_tx(port);
-+      }
-+}
-+
-+/*
-+ * ubi32_uarttio_start_tx
-+ *    port is locked and interrupts are disabled
-+ */
-+static void ubi32_uarttio_start_tx(struct uart_port *port)
-+{
-+      struct ubi32_uarttio_port *uup = port->private_data;
-+      struct uarttio_uart *uart = uup->uart;
-+
-+      uart->int_mask |= UARTTIO_UART_INT_TXBE;
-+}
-+
-+/*
-+ * ubi32_uarttio_stop_rx
-+ *    Interrupts are enabled
-+ */
-+static void ubi32_uarttio_stop_rx(struct uart_port *port)
-+{
-+      struct ubi32_uarttio_port *uup = port->private_data;
-+      struct uarttio_uart *uart = uup->uart;
-+
-+      /*
-+       * don't forward any more data (like !CREAD)
-+       */
-+      uart->int_mask &= ~UARTTIO_UART_INT_RX;
-+      port->ignore_status_mask = UARTTIO_UART_INT_RX;
-+}
-+
-+/*
-+ * ubi32_uarttio_enable_ms
-+ *    Set the modem control timer to fire immediately.
-+ */
-+static void ubi32_uarttio_enable_ms(struct uart_port *port)
-+{
-+      /* N/A */
-+}
-+
-+/*
-+ * ubi32_uarttio_isr
-+ */
-+static irqreturn_t ubi32_uarttio_isr(int irq, void *appdata)
-+{
-+      struct ubi32_uarttio_port *uup = uarttio_ports;
-+      int i;
-+
-+      /*
-+       * Service all of the ports
-+       */
-+      for (i = 0; i < uarttio_nports; i++) {
-+              unsigned int flags;
-+
-+              if (!(uup->uart->flags & UARTTIO_UART_FLAG_ENABLED)) {
-+                      uup++;
-+                      continue;
-+              }
-+
-+              spin_lock(&uup->port.lock);
-+
-+              flags = uup->uart->int_flags;
-+
-+              uup->uart->int_flags = 0;
-+
-+              ubi32_uarttio_handle_receive(uup, flags);
-+              ubi32_uarttio_handle_transmit(uup, flags);
-+
-+              tty_flip_buffer_push(uup->port.info->port.tty);
-+
-+              spin_unlock(&uup->port.lock);
-+
-+              uup++;
-+      }
-+
-+      return IRQ_HANDLED;
-+}
-+
-+/*
-+ * ubi32_uarttio_tx_empty
-+ *    Return TIOCSER_TEMT when transmitter is not busy.
-+ */
-+static unsigned int ubi32_uarttio_tx_empty(struct uart_port *port)
-+{
-+      struct ubi32_uarttio_port *uup = port->private_data;
-+
-+      if (uup->uart->tx_fifo_head == uup->uart->tx_fifo_tail) {
-+              return TIOCSER_TEMT;
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_uarttio_get_mctrl
-+ */
-+static unsigned int ubi32_uarttio_get_mctrl(struct uart_port *port)
-+{
-+      return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
-+}
-+
-+/*
-+ * ubi32_uarttio_set_mctrl
-+ */
-+static void ubi32_uarttio_set_mctrl(struct uart_port *port, unsigned int mctrl)
-+{
-+      /* N/A */
-+}
-+
-+/*
-+ * ubi32_uarttio_break_ctl
-+ */
-+static void ubi32_uarttio_break_ctl(struct uart_port *port, int break_state)
-+{
-+      /* N/A */
-+}
-+
-+/*
-+ * ubi32_uarttio_startup
-+ */
-+static int ubi32_uarttio_startup(struct uart_port *port)
-+{
-+      struct ubi32_uarttio_port *uup = port->private_data;
-+      struct uarttio_uart *uart = uup->uart;
-+
-+      uart->flags |= UARTTIO_UART_FLAG_ENABLED;
-+
-+      uart->int_mask |= UARTTIO_UART_INT_TXBE | UARTTIO_UART_INT_RX;
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_uarttio_shutdown
-+ */
-+static void ubi32_uarttio_shutdown(struct uart_port *port)
-+{
-+      struct ubi32_uarttio_port *uup = port->private_data;
-+      struct uarttio_uart *uart = uup->uart;
-+
-+      uart->int_mask = 0;
-+      uart->flags &= ~UARTTIO_UART_FLAG_ENABLED;
-+}
-+
-+/*
-+ * ubi32_uarttio_set_termios
-+ */
-+static void ubi32_uarttio_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
-+{
-+      struct ubi32_uarttio_port *uup = port->private_data;
-+      unsigned long flags;
-+      unsigned int baud;
-+
-+      spin_lock_irqsave(&port->lock, flags);
-+
-+#if 0
-+      port->read_status_mask = UBI32_UARTTIO_RX | UBI32_UARTTIO_RXOVF | UBI32_UARTTIO_TXOVF;
-+
-+      if (termios->c_iflag & INPCK) {
-+              port->read_status_mask |= UBI32_UARTTIO_RXFRAME;
-+      }
-+#endif
-+
-+      port->ignore_status_mask = 0;
-+      if (termios->c_iflag & IGNPAR) {
-+              port->ignore_status_mask |= UARTTIO_UART_INT_RXFRAME |
-+                                          UARTTIO_UART_INT_RXOVF;
-+      }
-+
-+      /*
-+       * ignore all characters if CREAD is not set
-+       */
-+      if ((termios->c_cflag & CREAD) == 0) {
-+              port->ignore_status_mask |= UARTTIO_UART_INT_RX |
-+                                          UARTTIO_UART_INT_RXFRAME |
-+                                          UARTTIO_UART_INT_RXOVF;
-+      }
-+
-+      /* update timeout */
-+      baud = uart_get_baud_rate(port, termios, old, 0, 460800);
-+      uart_update_timeout(port, termios->c_cflag, baud);
-+
-+      ubi32_uarttio_set_baud(uup, baud);
-+      spin_unlock_irqrestore(&port->lock, flags);
-+}
-+
-+/*
-+ * ubi32_uarttio_type
-+ */
-+static const char *ubi32_uarttio_type(struct uart_port *port)
-+{
-+      return (port->type == PORT_UBI32_UARTTIO) ? "UBI32_UARTTIO" : NULL;
-+}
-+
-+/*
-+ * ubi32_uarttio_release_port
-+ *    Release the memory region(s) being used by 'port'.
-+ */
-+static void ubi32_uarttio_release_port(struct uart_port *port)
-+{
-+}
-+
-+/*
-+ * ubi32_uarttio_request_port
-+ *    Request the memory region(s) being used by 'port'.
-+ */
-+static int ubi32_uarttio_request_port(struct uart_port *port)
-+{
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_uarttio_config_port
-+ *    Configure/autoconfigure the port.
-+ */
-+static void ubi32_uarttio_config_port(struct uart_port *port, int flags)
-+{
-+      if ((flags & UART_CONFIG_TYPE) && (ubi32_uarttio_request_port(port) == 0)) {
-+              port->type = PORT_UBI32_UARTTIO;
-+      }
-+}
-+
-+/*
-+ * ubi32_uarttio_verify_port
-+ *    Verify the new serial_struct (for TIOCSSERIAL).
-+ *
-+ * The only change we allow are to the flags and type, and
-+ * even then only between PORT_UBI32_UARTTIO and PORT_UNKNOWN
-+ */
-+static int ubi32_uarttio_verify_port(struct uart_port *port, struct serial_struct *ser)
-+{
-+      return 0;
-+}
-+
-+static struct uart_ops ubi32_uarttio_pops = {
-+      .tx_empty       = ubi32_uarttio_tx_empty,
-+      .set_mctrl      = ubi32_uarttio_set_mctrl,
-+      .get_mctrl      = ubi32_uarttio_get_mctrl,
-+      .stop_tx        = ubi32_uarttio_stop_tx,
-+      .start_tx       = ubi32_uarttio_start_tx,
-+      .stop_rx        = ubi32_uarttio_stop_rx,
-+      .enable_ms      = ubi32_uarttio_enable_ms,
-+      .break_ctl      = ubi32_uarttio_break_ctl,
-+      .startup        = ubi32_uarttio_startup,
-+      .shutdown       = ubi32_uarttio_shutdown,
-+      .set_termios    = ubi32_uarttio_set_termios,
-+      .type           = ubi32_uarttio_type,
-+      .release_port   = ubi32_uarttio_release_port,
-+      .request_port   = ubi32_uarttio_request_port,
-+      .config_port    = ubi32_uarttio_config_port,
-+      .verify_port    = ubi32_uarttio_verify_port,
-+};
-+
-+/*
-+ * ubi32_uarttio_add_ports
-+ */
-+static int __init ubi32_uarttio_add_ports(void)
-+{
-+      int res = 0;
-+      struct ubi32_uarttio_port *uup = uarttio_ports;
-+      int i = 0;
-+
-+      for (i = 0; i < uarttio_nports; i++) {
-+              /*
-+               * Setup the GPIOs
-+               */
-+              res = gpio_request(uup->tx_pin, "ubi32_uarttio_tx");
-+              if (res) {
-+                      printk(KERN_WARNING "Failed to request GPIO %d\n", uup->tx_pin);
-+                      res = -EBUSY;
-+                      goto next;
-+              }
-+
-+              res = gpio_request(uup->rx_pin, "ubi32_uarttio_rx");
-+              if (res) {
-+                      gpio_free(uup->tx_pin);
-+                      printk(KERN_WARNING "Failed to request GPIO %d\n", uup->rx_pin);
-+                      res = -EBUSY;
-+                      goto next;
-+              }
-+
-+              res = uart_add_one_port(&ubi32_uarttio_uart_driver, &uup->port);
-+              if (res) {
-+                      gpio_free(uup->rx_pin);
-+                      gpio_free(uup->tx_pin);
-+                      res = -ENODEV;
-+                      printk(KERN_WARNING "Failed to add port %d,%d\n", uup->tx_pin, uup->rx_pin);
-+                      goto next;
-+              }
-+              uup->added = 1;
-+
-+              /*
-+               * Set the direction of the ports now, after we're sure that everything is ok
-+               */
-+              if (!uup->port_init) {
-+                      gpio_direction_output(uup->tx_pin, 1);
-+                      gpio_direction_input(uup->rx_pin);
-+              }
-+
-+next:
-+              uup++;
-+      }
-+      return res;
-+}
-+
-+/*
-+ * ubi32_uarttio_cleanup
-+ */
-+static void ubi32_uarttio_cleanup(void)
-+{
-+      struct ubi32_uarttio_port *uup;
-+      int i;
-+
-+      /*
-+       * Stop the hardware thread
-+       */
-+      if (uarttio_inst.regs) {
-+              thread_disable(uarttio_inst.regs->thread);
-+      }
-+      if (uarttio_inst.irq_requested) {
-+              free_irq(uarttio_inst.irq, NULL);
-+      }
-+
-+      /*
-+       * Get rid of the ports
-+       */
-+      uup = uarttio_inst.ports;
-+      for (i = 0; i < uarttio_nports; i++) {
-+              gpio_free(uup->tx_pin);
-+              gpio_free(uup->rx_pin);
-+              if (uup->added) {
-+                      uart_remove_one_port(&ubi32_uarttio_uart_driver, &uup->port);
-+              }
-+              uup++;
-+      }
-+
-+      if (uarttio_inst.driver_registered) {
-+              uart_unregister_driver(&ubi32_uarttio_uart_driver);
-+      }
-+}
-+
-+/*
-+ * ubi32_uarttio_setup_port
-+ *    Setup a port in the TIO registers
-+ */
-+static int ubi32_uarttio_setup_port(int index,
-+                                  struct uarttio_uart *uart,
-+                                  unsigned int baud, unsigned int tx_pin,
-+                                  unsigned int rx_pin)
-+{
-+      struct ubi32_uarttio_port *uup = &uarttio_ports[index];
-+      void *tx_port = ubi_gpio_get_port(tx_pin);
-+      void *rx_port = ubi_gpio_get_port(rx_pin);
-+
-+      /*
-+       * Verify the ports are on chip
-+       */
-+      if (!tx_port || !rx_port) {
-+              printk(KERN_WARNING "Invalid port(s) specified: %u or %u\n", tx_pin, rx_pin);
-+              return -EINVAL;
-+      }
-+
-+      uup->tx_pin = tx_pin;
-+      uup->rx_pin = rx_pin;
-+      uup->uart = uart;
-+
-+      /*
-+       * Setup the port structure
-+       */
-+      uup->port.ops           = &ubi32_uarttio_pops;
-+      uup->port.line          = index;
-+      uup->port.iotype        = UPIO_MEM;
-+      uup->port.flags         = UPF_BOOT_AUTOCONF;
-+      uup->port.fifosize      = uup->uart->tx_fifo_size;
-+      uup->port.private_data  = uup;
-+
-+      /*
-+       * We share this IRQ across all ports
-+       */
-+      uup->port.irq           = uarttio_inst.irq;
-+
-+      /*
-+       * We really don't have a mem/map base but without these variables
-+       * set, the serial_core won't startup.
-+       */
-+      uup->port.membase       = (void __iomem *)uup;
-+      uup->port.mapbase       = (resource_size_t)uup;
-+      spin_lock_init(&uup->port.lock);
-+
-+      /*
-+       * Set up the hardware
-+       */
-+      uart->flags = UARTTIO_UART_FLAG_SET_RATE | UARTTIO_UART_FLAG_RESET;
-+
-+      uart->tx_port = (unsigned int)tx_port;
-+      uart->tx_pin = gpio_pin_index(tx_pin);
-+      uart->tx_bits = 8;
-+      uart->tx_stop_bits = 1;
-+
-+      uart->rx_port = (unsigned int)rx_port;
-+      uart->rx_pin = gpio_pin_index(rx_pin);
-+      uart->rx_bits = 8;
-+      uart->rx_stop_bits = 1;
-+
-+      uart->baud_rate = baud;
-+
-+      return 0;
-+}
-+
-+enum ubi32_uarttio_parse_states {
-+      UBI32_UARTTIO_PARSE_STATE_BAUD,
-+      UBI32_UARTTIO_PARSE_STATE_TX_PIN,
-+      UBI32_UARTTIO_PARSE_STATE_RX_PIN,
-+      UBI32_UARTTIO_PARSE_STATE_HS,
-+      UBI32_UARTTIO_PARSE_STATE_CTS_PIN,
-+      UBI32_UARTTIO_PARSE_STATE_RTS_PIN,
-+};
-+
-+/*
-+ * ubi32_uarttio_parse_param
-+ */
-+static int ubi32_uarttio_parse_param(char *str)
-+{
-+      int res;
-+      int i;
-+      int baud = 0;
-+      int tx_pin = 0;
-+      int rx_pin = 0;
-+      int hs = 0;
-+      int cts_pin = 0;
-+      int rts_pin = 0;
-+      int nfound = 0;
-+      enum ubi32_uarttio_parse_states state = UBI32_UARTTIO_PARSE_STATE_BAUD;
-+      struct uarttio_uart *uart = uarttio_inst.regs->uarts;
-+
-+      /*
-+       * Run though the options and generate the proper structures
-+       */
-+      res = get_option(&str, &i);
-+      while ((res == 2) || (res == 1)) {
-+              switch (state) {
-+              case UBI32_UARTTIO_PARSE_STATE_BAUD:
-+                      /*
-+                       * If we are here and nfound > 0 then create the port
-+                       * based on the previous input
-+                       */
-+                      if (nfound) {
-+                              /*
-+                               * Create the port
-+                               */
-+                              if (ubi32_uarttio_setup_port(nfound - 1, uart, baud, tx_pin, rx_pin)) {
-+                                      /*
-+                                       * Port was invalid
-+                                       */
-+                                      goto fail;
-+                              } else {
-+                                      printk(KERN_INFO "Serial port %d: tx=%d:rx=%d @ %d\n", nfound, tx_pin, rx_pin, baud);
-+                                      uart++;
-+                              }
-+                      }
-+
-+                      /*
-+                       * Reset the variables and go to the next state
-+                       */
-+                      hs = 0;
-+                      baud = i;
-+                      state = UBI32_UARTTIO_PARSE_STATE_TX_PIN;
-+                      break;
-+
-+              case UBI32_UARTTIO_PARSE_STATE_TX_PIN:
-+                      tx_pin = i;
-+                      state = UBI32_UARTTIO_PARSE_STATE_RX_PIN;
-+                      break;
-+
-+              case UBI32_UARTTIO_PARSE_STATE_RX_PIN:
-+                      rx_pin = i;
-+                      state = UBI32_UARTTIO_PARSE_STATE_HS;
-+                      break;
-+
-+              case UBI32_UARTTIO_PARSE_STATE_HS:
-+                      hs = i;
-+                      if (hs) {
-+                              state = UBI32_UARTTIO_PARSE_STATE_CTS_PIN;
-+                              break;
-+                      }
-+
-+                      if (nfound == uarttio_inst.regs->max_uarts) {
-+                              printk(KERN_WARNING "Maximum number of serial ports reached\n");
-+                              goto done;
-+                      }
-+                      nfound++;
-+                      state = UBI32_UARTTIO_PARSE_STATE_BAUD;
-+                      break;
-+
-+              case UBI32_UARTTIO_PARSE_STATE_CTS_PIN:
-+                      cts_pin = i;
-+                      state = UBI32_UARTTIO_PARSE_STATE_RTS_PIN;
-+                      break;
-+
-+              case UBI32_UARTTIO_PARSE_STATE_RTS_PIN:
-+                      rts_pin = i;
-+
-+                      if (nfound == uarttio_inst.regs->max_uarts) {
-+                              printk(KERN_WARNING "Maximum number of serial ports reached\n");
-+                              goto done;
-+                      }
-+                      nfound++;
-+                      state = UBI32_UARTTIO_PARSE_STATE_BAUD;
-+                      break;
-+              }
-+              res = get_option(&str, &i);
-+      }
-+
-+      if ((res > 2) || state != UBI32_UARTTIO_PARSE_STATE_BAUD) {
-+              printk(KERN_WARNING "Parameter syntax error.\n");
-+              res = -EINVAL;
-+              goto fail;
-+      }
-+
-+      /*
-+       * Create the final port
-+       */
-+      if (ubi32_uarttio_setup_port(nfound - 1, uart, baud, tx_pin, rx_pin)) {
-+              goto fail;
-+      }
-+      printk(KERN_INFO "Serial port %d: tx=%d:rx=%d @ %d\n", nfound, tx_pin, rx_pin, baud);
-+
-+done:
-+      uarttio_nports = nfound;
-+
-+      return nfound ? 0 : -ENODEV;
-+
-+fail:
-+      /*
-+       * Reset the ports
-+       */
-+      uart = uarttio_inst.regs->uarts;
-+      for (i = 0; i < uarttio_inst.regs->max_uarts; i++) {
-+              uart->flags = 0;
-+              uart++;
-+      }
-+
-+      return res;
-+}
-+
-+/*
-+ * ubi32_uarttio_probe
-+ */
-+static int ubi32_uarttio_probe(void)
-+{
-+      int ret;
-+      struct uarttio_node *uart_node;
-+      char *str = utio_ports_param;
-+      static int probed;
-+      static int probe_result;
-+
-+      /*
-+       * We only want to be probed once, we could be probed twice
-+       * for example if we are used as a console
-+       */
-+      if (probed) {
-+              return probe_result;
-+      }
-+      probed = 1;
-+
-+      /*
-+       * Extract the TIO name from the setup string
-+       */
-+      while (*str) {
-+              if (*str == ',') {
-+                      *str++ = 0;
-+                      break;
-+              }
-+              str++;
-+      }
-+
-+      if (!*str) {
-+              probe_result = -EINVAL;
-+              return -EINVAL;
-+      }
-+
-+      uart_node = (struct uarttio_node *)devtree_find_node(utio_ports_param);
-+      if (!uart_node) {
-+              probe_result = -ENODEV;
-+              return -ENODEV;
-+      }
-+
-+      uarttio_inst.irq = uart_node->dn.recvirq;
-+      uarttio_inst.regs = uart_node->regs;
-+
-+      /*
-+       * Parse module parameters.
-+       */
-+      ret = ubi32_uarttio_parse_param(str);
-+      if (ret != 0) {
-+              ubi32_uarttio_cleanup();
-+              probe_result = ret;
-+              return ret;
-+      }
-+
-+      ubi32_uarttio_uart_driver.nr = uarttio_nports;
-+
-+      return 0;
-+}
-+
-+#if defined(CONFIG_SERIAL_UBI32_UARTTIO_CONSOLE)
-+/*
-+ * ubi32_uarttio_console_setup
-+ */
-+static int __init ubi32_uarttio_console_setup(struct console *co, char *options)
-+{
-+      int baud;
-+      int bits = 8;
-+      int parity = 'n';
-+      int flow = 'n';
-+      struct ubi32_uarttio_port *uup;
-+
-+      /*
-+       * Check whether an invalid uart number has been specified, and
-+       * if so, search for the first available port that does have
-+       * console support.
-+       */
-+      if (co->index == -1 || co->index >= uarttio_nports) {
-+              co->index = 0;
-+      }
-+      uup = &uarttio_ports[co->index];
-+      baud = uup->uart->baud_rate;
-+      uup->uart->flags |= UARTTIO_UART_FLAG_ENABLED;
-+
-+      /*
-+       * Setup the GPIOs
-+       *      We have to use the direct interface because the gpio
-+       *      subsystem is not available at this point.
-+       */
-+      uup->port_init = 1;
-+      UBICOM32_GPIO_SET_PIN_HIGH(uup->tx_pin);
-+      UBICOM32_GPIO_SET_PIN_OUTPUT(uup->tx_pin);
-+      UBICOM32_GPIO_SET_PIN_INPUT(uup->rx_pin);
-+
-+      /*
-+       * Start the thread
-+       */
-+      thread_enable(uarttio_inst.regs->thread);
-+
-+      /*
-+       * Process options
-+       */
-+      if (options) {
-+              uart_parse_options(options, &baud, &parity, &bits, &flow);
-+              if (ubi32_uarttio_set_baud(uup, baud)) {
-+                      baud = uup->uart->current_baud_rate;
-+              }
-+      }
-+
-+      return uart_set_options(&uup->port, co, baud, 'n', 8, 'n');
-+}
-+
-+/*
-+ * ubi32_uarttio_console_putchar
-+ */
-+static void ubi32_uarttio_console_putchar(struct uart_port *port, int ch)
-+{
-+      struct ubi32_uarttio_port *uup = port->private_data;
-+
-+      while (ubi32_uarttio_put_char(uup->uart, ch)) {
-+              cpu_relax();
-+      }
-+}
-+
-+/*
-+ * ubi32_uarttio_console_write
-+ *    Interrupts are disabled on entering
-+ */
-+static void ubi32_uarttio_console_write(struct console *co, const char *s, unsigned int count)
-+{
-+      struct uart_port *port = &(uarttio_ports[co->index].port);
-+      unsigned long flags = 0;
-+
-+      spin_lock_irqsave(&port->lock, flags);
-+      uart_console_write(port, s, count, ubi32_uarttio_console_putchar);
-+      spin_unlock_irqrestore(&port->lock, flags);
-+}
-+
-+static struct console ubi32_uarttio_console = {
-+      .name           = UBI32_UARTTIO_NAME,
-+      .write          = ubi32_uarttio_console_write,
-+      .device         = uart_console_device,
-+      .setup          = ubi32_uarttio_console_setup,
-+      .flags          = CON_PRINTBUFFER,
-+      .index          = -1,
-+      .data           = &ubi32_uarttio_uart_driver,
-+};
-+
-+static int __init ubi32_uarttio_console_init(void)
-+{
-+      int res;
-+
-+      res = ubi32_uarttio_probe();
-+      if (res) {
-+              return res;
-+      }
-+
-+      register_console(&ubi32_uarttio_console);
-+      return 0;
-+}
-+console_initcall(ubi32_uarttio_console_init);
-+#endif /* CONFIG_SERIAL_UBI32_UARTTIO_CONSOLE */
-+
-+/*
-+ * ubi32_serial_suspend
-+ */
-+static int ubi32_uarttio_suspend(struct platform_device *pdev, pm_message_t state)
-+{
-+      int i;
-+      for (i = 0; i < uarttio_nports; i++) {
-+              uart_suspend_port(&ubi32_uarttio_uart_driver, &uarttio_ports[i].port);
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_serial_resume
-+ */
-+static int ubi32_uarttio_resume(struct platform_device *pdev)
-+{
-+      int i;
-+      for (i = 0; i < uarttio_nports; i++) {
-+              uart_resume_port(&ubi32_uarttio_uart_driver, &uarttio_ports[i].port);
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_uarttio_remove
-+ */
-+static int __devexit ubi32_uarttio_remove(struct platform_device *pdev)
-+{
-+      ubi32_uarttio_cleanup();
-+
-+      uart_unregister_driver(&ubi32_uarttio_uart_driver);
-+
-+      return 0;
-+}
-+
-+static struct platform_driver ubi32_uarttio_platform_driver = {
-+      .remove         = __devexit_p(ubi32_uarttio_remove),
-+      .suspend        = ubi32_uarttio_suspend,
-+      .resume         = ubi32_uarttio_resume,
-+      .driver         = {
-+              .name   = DRIVER_NAME,
-+              .owner  = THIS_MODULE,
-+      },
-+};
-+
-+#ifndef MODULE
-+/*
-+ * Called at boot time.
-+ *
-+ * uarttio=TIONAME,(baud,tx_pin,rx_pin,handshake[,cts_pin,rts_pin],...)
-+ *    TIONAME is the name of the devtree node which describes the UARTTIO
-+ *    pin is the index of the pin, i.e. PA4 is 5 [(port * 32) + pin]
-+ *    handshake = 1 to enable handshaking, provide cts_pin, rts_pin (UNSUPPORTED)
-+ *    handshake = 0 to disable handshaking, do not provide cts_pin, rts_pin
-+ *    Ex: uarttio=UARTTIO,57600,7,6,0,9600,8,9,0
-+ */
-+static int __init ubi32_uarttio_setup(char *str)
-+{
-+      strncpy(utio_ports_param, str, UBI32_UARTTIO_MAX_PARAM_LEN);
-+      utio_ports_param[UBI32_UARTTIO_MAX_PARAM_LEN - 1] = 0;
-+      return 1;
-+}
-+__setup("uarttio=", ubi32_uarttio_setup);
-+#endif
-+
-+/*
-+ * ubi32_uarttio_init
-+ */
-+static int __init ubi32_uarttio_init(void)
-+{
-+      int ret;
-+      int i;
-+
-+      ret = ubi32_uarttio_probe();
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      /*
-+       * Request the IRQ (do it here since many ports share the same IRQ)
-+       */
-+      ret = request_irq(uarttio_inst.irq, ubi32_uarttio_isr, IRQF_DISABLED, DRIVER_NAME, NULL);
-+      if (ret != 0) {
-+              printk(KERN_WARNING "Could not request IRQ %d\n", uarttio_inst.irq);
-+              goto fail;
-+      }
-+      uarttio_inst.irq_requested = 1;
-+
-+      /*
-+       * Register the UART driver and add the ports
-+       */
-+      ret = uart_register_driver(&ubi32_uarttio_uart_driver);
-+      if (ret != 0) {
-+              goto fail;
-+      }
-+      uarttio_inst.driver_registered = 1;
-+
-+      ret = ubi32_uarttio_add_ports();
-+      if (ret != 0) {
-+              ubi32_uarttio_cleanup();
-+              return ret;
-+      }
-+
-+      /*
-+       * Start the thread
-+       */
-+      thread_enable(uarttio_inst.regs->thread);
-+
-+      for (i = 0; i < uarttio_nports; i++) {
-+              pr_info("Serial: Ubicom32 uarttio #%d: tx:%d rx:%d baud:%d\n",
-+                      i, uarttio_ports[i].tx_pin, uarttio_ports[i].rx_pin,
-+                      uarttio_ports[i].uart->current_baud_rate);
-+      }
-+      pr_info("Serial: Ubicom32 uarttio started on thread:%d irq:%d\n", uarttio_inst.regs->thread, uarttio_inst.irq);
-+
-+      return ret;
-+
-+fail:
-+      ubi32_uarttio_cleanup();
-+      return ret;
-+}
-+module_init(ubi32_uarttio_init);
-+
-+/*
-+ * ubi32_uarttio_exit
-+ */
-+static void __exit ubi32_uarttio_exit(void)
-+{
-+      platform_driver_unregister(&ubi32_uarttio_platform_driver);
-+}
-+module_exit(ubi32_uarttio_exit);
-+
-+module_param_string(ports, utio_ports_param, sizeof(utio_ports_param), 0444);
-+MODULE_PARM_DESC(ports, "Sets the ports to allocate: ports=TIONAME,(baud,txpin,rxpin,handshake[,ctspin,rtspin],...)\n"
-+                      "     TIONAME is the name of the devtree node which describes the UARTTIO\n"
-+                      "     pin is the index of the pin, i.e. PA4 is 5 [(port * 32) + pin]\n"
-+                      "     handshake = 1 to enable handshaking, provide ctspin, rtspin (UNSUPPORTED)\n"
-+                      "     handshake = 0 to disable handshaking, do not provide ctspin, rtspin\n"
-+                      "     Ex: ports=UARTTIO,57600,7,6,0,9600,8,9,0\n");
-+MODULE_AUTHOR("Patrick Tjin <pat.tjin@ubicom.com>");
-+MODULE_DESCRIPTION("Ubicom serial virtual peripherial driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS_CHARDEV_MAJOR(UBI32_UARTTIO_MAJOR);
-+MODULE_ALIAS("platform:" DRIVER_NAME);
---- a/drivers/spi/Kconfig
-+++ b/drivers/spi/Kconfig
-@@ -196,6 +196,15 @@ config SPI_S3C24XX
-       help
-         SPI driver for Samsung S3C24XX series ARM SoCs
-+config SPI_UBICOM32_GPIO
-+      tristate "Ubicom32 SPI over GPIO"
-+      depends on SPI_MASTER && UBICOM32 && EXPERIMENTAL
-+      select SPI_BITBANG
-+      select HAS_DMA
-+      help
-+        SPI driver for the Ubicom32 architecture using
-+        GPIO lines to provide the SPI bus.
-+
- config SPI_S3C24XX_GPIO
-       tristate "Samsung S3C24XX series SPI by GPIO"
-       depends on ARCH_S3C2410 && EXPERIMENTAL
---- a/drivers/spi/Makefile
-+++ b/drivers/spi/Makefile
-@@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_ORION)                      += orion_spi.o
- obj-$(CONFIG_SPI_MPC52xx_PSC)         += mpc52xx_psc_spi.o
- obj-$(CONFIG_SPI_MPC83xx)             += spi_mpc83xx.o
- obj-$(CONFIG_SPI_S3C24XX_GPIO)                += spi_s3c24xx_gpio.o
-+obj-$(CONFIG_SPI_UBICOM32_GPIO)               += spi_ubicom32_gpio.o
- obj-$(CONFIG_SPI_S3C24XX)             += spi_s3c24xx.o
- obj-$(CONFIG_SPI_TXX9)                        += spi_txx9.o
- obj-$(CONFIG_SPI_XILINX)              += xilinx_spi.o
---- /dev/null
-+++ b/drivers/spi/spi_ubicom32_gpio.c
-@@ -0,0 +1,267 @@
-+/*
-+ * drivers/spi_spi_ubicom32_gpio.c
-+ *    Ubicom32 GPIO based SPI driver
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/delay.h>
-+#include <linux/spinlock.h>
-+#include <linux/workqueue.h>
-+#include <linux/platform_device.h>
-+
-+#include <linux/spi/spi.h>
-+#include <linux/spi/spi_bitbang.h>
-+
-+#include <linux/gpio.h>
-+
-+#include <asm/ubicom32-spi-gpio.h>
-+
-+#define DRIVER_NAME "ubicom32-spi-gpio"
-+
-+struct ubicom32_spi_gpio {
-+      struct spi_bitbang                       bitbang;
-+
-+      struct ubicom32_spi_gpio_platform_data  *pdata;
-+
-+      struct platform_device                  *dev;
-+};
-+
-+/*
-+ * The following 4 functions are used by EXPAND_BITBANG_TXRX to bitbang the data out.
-+ */
-+static inline void setsck(struct spi_device *dev, int on)
-+{
-+      struct ubicom32_spi_gpio *usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(dev->master);
-+      gpio_set_value(usg->pdata->pin_clk, on ? 1 : 0);
-+}
-+
-+static inline void setmosi(struct spi_device *dev, int on)
-+{
-+      struct ubicom32_spi_gpio *usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(dev->master);
-+      gpio_set_value(usg->pdata->pin_mosi, on ? 1 : 0);
-+}
-+
-+static inline u32 getmiso(struct spi_device *dev)
-+{
-+      struct ubicom32_spi_gpio *usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(dev->master);
-+      return gpio_get_value(usg->pdata->pin_miso) ? 1 : 0;
-+}
-+
-+#define spidelay(x) ndelay(x)
-+
-+#define       EXPAND_BITBANG_TXRX
-+#include <linux/spi/spi_bitbang.h>
-+
-+/*
-+ * ubicom32_spi_gpio_txrx_mode0
-+ */
-+static u32 ubicom32_spi_gpio_txrx_mode0(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
-+{
-+      return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
-+}
-+
-+/*
-+ * ubicom32_spi_gpio_txrx_mode1
-+ */
-+static u32 ubicom32_spi_gpio_txrx_mode1(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
-+{
-+      return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
-+}
-+
-+/*
-+ * ubicom32_spi_gpio_txrx_mode2
-+ */
-+static u32 ubicom32_spi_gpio_txrx_mode2(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
-+{
-+      return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
-+}
-+
-+/*
-+ * ubicom32_spi_gpio_txrx_mode3
-+ */
-+static u32 ubicom32_spi_gpio_txrx_mode3(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
-+{
-+      return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
-+}
-+
-+/*
-+ * ubicom32_spi_gpio_chipselect
-+ */
-+static void ubicom32_spi_gpio_chipselect(struct spi_device *dev, int value)
-+{
-+      struct ubicom32_spi_gpio_controller_data *cd = (struct ubicom32_spi_gpio_controller_data *)dev->controller_data;
-+      unsigned int cs_polarity = dev->mode & SPI_CS_HIGH ? 1 : 0;
-+
-+      if (value == BITBANG_CS_ACTIVE) {
-+              gpio_set_value(cd->pin_cs, cs_polarity);
-+              return;
-+      }
-+      gpio_set_value(cd->pin_cs, !cs_polarity);
-+}
-+
-+/*
-+ * ubicom32_spi_gpio_probe
-+ */
-+static int ubicom32_spi_gpio_probe(struct platform_device *dev)
-+{
-+      struct ubicom32_spi_gpio_platform_data *pdata;
-+      struct spi_master *master;
-+      struct ubicom32_spi_gpio *usg;
-+      int ret;
-+
-+      master = spi_alloc_master(&dev->dev, sizeof(struct ubicom32_spi_gpio));
-+      if (master == NULL) {
-+              dev_err(&dev->dev, "failed to allocate spi master\n");
-+              ret = -ENOMEM;
-+              goto err;
-+      }
-+
-+      usg = (struct ubicom32_spi_gpio *)spi_master_get_devdata(master);
-+
-+      platform_set_drvdata(dev, usg);
-+
-+      /*
-+       * Copy in the platform data
-+       */
-+      pdata = dev->dev.platform_data;
-+      usg->pdata = dev->dev.platform_data;
-+
-+      /*
-+       * Request the GPIO lines
-+       */
-+      ret = gpio_request(pdata->pin_mosi, "spi-mosi");
-+      if (ret) {
-+              dev_err(&dev->dev, "Failed to allocate spi-mosi GPIO\n");
-+              goto err;
-+      }
-+
-+      ret = gpio_request(pdata->pin_miso, "spi-miso");
-+      if (ret) {
-+              dev_err(&dev->dev, "Failed to allocate spi-miso GPIO\n");
-+              goto err_nomiso;
-+      }
-+
-+      ret = gpio_request(pdata->pin_clk, "spi-clk");
-+      if (ret) {
-+              dev_err(&dev->dev, "Failed to allocate spi-clk GPIO\n");
-+              goto err_noclk;
-+      }
-+
-+      /*
-+       * Setup spi-bitbang adaptor
-+       */
-+      usg->bitbang.flags |= SPI_CS_HIGH;
-+      usg->bitbang.master = spi_master_get(master);
-+      usg->bitbang.master->bus_num = pdata->bus_num;
-+      usg->bitbang.master->num_chipselect = pdata->num_chipselect;
-+      usg->bitbang.chipselect = ubicom32_spi_gpio_chipselect;
-+
-+      usg->bitbang.txrx_word[SPI_MODE_0] = ubicom32_spi_gpio_txrx_mode0;
-+      usg->bitbang.txrx_word[SPI_MODE_1] = ubicom32_spi_gpio_txrx_mode1;
-+      usg->bitbang.txrx_word[SPI_MODE_2] = ubicom32_spi_gpio_txrx_mode2;
-+      usg->bitbang.txrx_word[SPI_MODE_3] = ubicom32_spi_gpio_txrx_mode3;
-+
-+      /*
-+       * Setup the GPIO pins
-+       */
-+      gpio_direction_output(pdata->pin_clk, pdata->clk_default);
-+      gpio_direction_output(pdata->pin_mosi, 0);
-+      gpio_direction_input(pdata->pin_miso);
-+
-+      /*
-+       * Ready to go
-+       */
-+      ret = spi_bitbang_start(&usg->bitbang);
-+      if (ret) {
-+              goto err_no_bitbang;
-+      }
-+
-+      return 0;
-+
-+err_no_bitbang:
-+      spi_master_put(usg->bitbang.master);
-+
-+      gpio_free(pdata->pin_clk);
-+
-+err_noclk:
-+      gpio_free(pdata->pin_miso);
-+
-+err_nomiso:
-+      gpio_free(pdata->pin_mosi);
-+
-+err:
-+      return ret;
-+}
-+
-+/*
-+ * ubicom32_spi_gpio_remove
-+ */
-+static int ubicom32_spi_gpio_remove(struct platform_device *dev)
-+{
-+      struct ubicom32_spi_gpio *sp = platform_get_drvdata(dev);
-+
-+      spi_bitbang_stop(&sp->bitbang);
-+      spi_master_put(sp->bitbang.master);
-+
-+      return 0;
-+}
-+
-+/*
-+ * Work with hotplug and coldplug
-+ */
-+MODULE_ALIAS("platform:ubicom32_spi_gpio");
-+
-+static struct platform_driver ubicom32_spi_gpio_drv = {
-+      .probe          = ubicom32_spi_gpio_probe,
-+        .remove               = ubicom32_spi_gpio_remove,
-+        .driver               = {
-+              .name   = DRIVER_NAME,
-+              .owner  = THIS_MODULE,
-+        },
-+};
-+
-+/*
-+ * ubicom32_spi_gpio_init
-+ */
-+static int __init ubicom32_spi_gpio_init(void)
-+{
-+        return platform_driver_register(&ubicom32_spi_gpio_drv);
-+}
-+
-+/*
-+ * ubicom32_spi_gpio_exit
-+ */
-+static void __exit ubicom32_spi_gpio_exit(void)
-+{
-+        platform_driver_unregister(&ubicom32_spi_gpio_drv);
-+}
-+
-+module_init(ubicom32_spi_gpio_init);
-+module_exit(ubicom32_spi_gpio_exit);
-+
-+MODULE_DESCRIPTION("Ubicom32 SPI-GPIO Driver");
-+MODULE_AUTHOR("Pat Tjin, <@ubicom.com>");
-+MODULE_LICENSE("GPL");
---- a/drivers/uio/Kconfig
-+++ b/drivers/uio/Kconfig
-@@ -89,4 +89,12 @@ config UIO_SERCOS3
-         If you compile this as a module, it will be called uio_sercos3.
-+config UIO_UBICOM32RING
-+      tristate "Ubicom32 Ring Buffer driver"
-+      default n
-+      help
-+        Userspace I/O interface for a Ubicom32 Ring Buffer.
-+
-+        If you compile this as a module, it will be called uio_ubicom32ring
-+
- endif
---- a/drivers/uio/Makefile
-+++ b/drivers/uio/Makefile
-@@ -5,3 +5,4 @@ obj-$(CONFIG_UIO_PDRV_GENIRQ)  += uio_pdr
- obj-$(CONFIG_UIO_SMX) += uio_smx.o
- obj-$(CONFIG_UIO_AEC) += uio_aec.o
- obj-$(CONFIG_UIO_SERCOS3)     += uio_sercos3.o
-+obj-$(CONFIG_UIO_UBICOM32RING)        += uio_ubicom32ring.o
---- /dev/null
-+++ b/drivers/uio/uio_ubicom32ring.c
-@@ -0,0 +1,288 @@
-+/*
-+ * drivers/uio/uio_ubicom32ring.c
-+ *
-+ * Userspace I/O platform driver for Ubicom32 ring buffers
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * Based on uio_ubicom32ring.c by Magnus Damm
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/platform_device.h>
-+#include <linux/uio_driver.h>
-+#include <linux/spinlock.h>
-+#include <linux/bitops.h>
-+#include <linux/interrupt.h>
-+#include <linux/stringify.h>
-+
-+#include <asm/ip5000.h>
-+#include <asm/ubicom32ring.h>
-+
-+#define DRIVER_NAME "uio_ubicom32ring"
-+
-+struct uio_ubicom32ring_data {
-+      struct uio_info                 *uioinfo;
-+
-+      struct uio_ubicom32ring_regs    *regs;
-+
-+      /*
-+       * IRQ used to kick the ring buffer
-+       */
-+      int                             irq_tx;
-+      int                             irq_rx;
-+
-+      spinlock_t                      lock;
-+
-+      unsigned long                   flags;
-+
-+      char                            name[0];
-+};
-+
-+static irqreturn_t uio_ubicom32ring_handler(int irq, struct uio_info *dev_info)
-+{
-+      struct uio_ubicom32ring_data *priv = dev_info->priv;
-+
-+      /* Just disable the interrupt in the interrupt controller, and
-+       * remember the state so we can allow user space to enable it later.
-+       */
-+
-+      if (!test_and_set_bit(0, &priv->flags))
-+              disable_irq_nosync(irq);
-+
-+      return IRQ_HANDLED;
-+}
-+
-+static int uio_ubicom32ring_irqcontrol(struct uio_info *dev_info, s32 irq_on)
-+{
-+      struct uio_ubicom32ring_data *priv = dev_info->priv;
-+      unsigned long flags;
-+
-+      /* Allow user space to enable and disable the interrupt
-+       * in the interrupt controller, but keep track of the
-+       * state to prevent per-irq depth damage.
-+       *
-+       * Serialize this operation to support multiple tasks.
-+       */
-+
-+      spin_lock_irqsave(&priv->lock, flags);
-+
-+      if (irq_on & 2) {
-+              /*
-+               * Kick the ring buffer (if we can)
-+               */
-+              if (priv->irq_tx != 0xFF) {
-+                      ubicom32_set_interrupt(priv->irq_tx);
-+              }
-+      }
-+
-+      if (priv->irq_rx != 0xFF) {
-+              if (irq_on & 1) {
-+                      if (test_and_clear_bit(0, &priv->flags))
-+                              enable_irq(dev_info->irq);
-+              } else {
-+                      if (!test_and_set_bit(0, &priv->flags))
-+                              disable_irq(dev_info->irq);
-+              }
-+      }
-+
-+      spin_unlock_irqrestore(&priv->lock, flags);
-+
-+      return 0;
-+}
-+
-+static int uio_ubicom32ring_probe(struct platform_device *pdev)
-+{
-+      struct uio_info *uioinfo;
-+      struct uio_mem *uiomem;
-+      struct uio_ubicom32ring_data *priv;
-+      struct uio_ubicom32ring_regs *regs;
-+      struct resource *mem_resource;
-+      struct resource *irqtx_resource;
-+      struct resource *irqrx_resource;
-+      int ret = -EINVAL;
-+      int i;
-+
-+      uioinfo = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
-+      if (!uioinfo) {
-+              dev_err(&pdev->dev, "unable to kmalloc\n");
-+              return -ENOMEM;
-+      }
-+
-+      /*
-+       * Allocate private data with some string space after
-+       */
-+      i = sizeof(DRIVER_NAME) + 1;
-+      i += pdev->dev.platform_data ? strlen(pdev->dev.platform_data) : 0;
-+      priv = kzalloc(sizeof(struct uio_ubicom32ring_data) + i, GFP_KERNEL);
-+      if (!priv) {
-+              dev_err(&pdev->dev, "unable to kmalloc\n");
-+              kfree(uioinfo);
-+              return -ENOMEM;
-+      }
-+
-+      strcpy(priv->name, DRIVER_NAME ":");
-+      if (pdev->dev.platform_data) {
-+              strcat(priv->name, pdev->dev.platform_data);
-+      }
-+      uioinfo->priv = priv;
-+      uioinfo->name = priv->name;
-+      uioinfo->version = "0.1";
-+
-+      priv->uioinfo = uioinfo;
-+      spin_lock_init(&priv->lock);
-+      priv->flags = 0; /* interrupt is enabled to begin with */
-+
-+      /*
-+       * Get our resources, the IRQ_TX and IRQ_RX are optional.
-+       */
-+      priv->irq_tx = 0xFF;
-+      irqtx_resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-+      if (irqtx_resource) {
-+              priv->irq_tx = irqtx_resource->start;
-+      }
-+
-+      uioinfo->irq = -1;
-+      priv->irq_rx = 0xFF;
-+      irqrx_resource = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
-+      if (irqrx_resource) {
-+              priv->irq_rx = irqrx_resource->start;
-+              uioinfo->irq = priv->irq_rx;
-+              uioinfo->handler = uio_ubicom32ring_handler;
-+      }
-+
-+      mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      if (!mem_resource || !mem_resource->start) {
-+              dev_err(&pdev->dev, "No valid memory resource found\n");
-+              ret = -ENODEV;
-+              goto fail;
-+      }
-+      regs = (struct uio_ubicom32ring_regs *)mem_resource->start;
-+      priv->regs = regs;
-+
-+      if (regs->version != UIO_UBICOM32RING_REG_VERSION) {
-+              dev_err(&pdev->dev, "version %d not supported\n", regs->version);
-+              ret = -ENODEV;
-+              goto fail;
-+      }
-+
-+      /*
-+       * First range is the shared register space, if we have any
-+       */
-+      uiomem = &uioinfo->mem[0];
-+      if (regs->regs_size) {
-+              uiomem->memtype = UIO_MEM_PHYS;
-+              uiomem->addr = (u32_t)regs->regs;
-+              uiomem->size = regs->regs_size;
-+              ++uiomem;
-+              dev_info(&pdev->dev, "regs:%p (%u) / rings: %d found\n", regs->regs, regs->regs_size, regs->num_rings);
-+      } else {
-+              dev_info(&pdev->dev, "rings: %d found\n", regs->num_rings);
-+      }
-+
-+      /*
-+       * The rest of the range correspond to the rings
-+       */
-+      for (i = 0; i < regs->num_rings; i++) {
-+              dev_info(&pdev->dev, "\t%d: entries:%d ring:%p\n",
-+                       i, regs->rings[i]->entries, &(regs->rings[i]->ring));
-+              if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) {
-+                      dev_warn(&pdev->dev, "device has more than "
-+                                      __stringify(MAX_UIO_MAPS)
-+                                      " I/O memory resources.\n");
-+                      break;
-+              }
-+
-+              uiomem->memtype = UIO_MEM_PHYS;
-+              uiomem->addr = (u32_t)&(regs->rings[i]->head);
-+              uiomem->size = (regs->rings[i]->entries * sizeof(u32_t)) +
-+                              sizeof(struct uio_ubicom32ring_desc);
-+              ++uiomem;
-+      }
-+
-+      while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) {
-+              uiomem->size = 0;
-+              ++uiomem;
-+      }
-+
-+      /* This driver requires no hardware specific kernel code to handle
-+       * interrupts. Instead, the interrupt handler simply disables the
-+       * interrupt in the interrupt controller. User space is responsible
-+       * for performing hardware specific acknowledge and re-enabling of
-+       * the interrupt in the interrupt controller.
-+       *
-+       * Interrupt sharing is not supported.
-+       */
-+      uioinfo->irq_flags = IRQF_DISABLED;
-+      uioinfo->irqcontrol = uio_ubicom32ring_irqcontrol;
-+
-+      ret = uio_register_device(&pdev->dev, priv->uioinfo);
-+      if (ret) {
-+              dev_err(&pdev->dev, "unable to register uio device\n");
-+              goto fail;
-+      }
-+
-+      platform_set_drvdata(pdev, priv);
-+
-+      dev_info(&pdev->dev, "'%s' using irq: rx %d tx %d, regs %p\n",
-+               priv->name, priv->irq_rx, priv->irq_tx, priv->regs);
-+
-+      return 0;
-+
-+fail:
-+      kfree(uioinfo);
-+      kfree(priv);
-+      return ret;
-+}
-+
-+static int uio_ubicom32ring_remove(struct platform_device *pdev)
-+{
-+      struct uio_ubicom32ring_data *priv = platform_get_drvdata(pdev);
-+
-+      uio_unregister_device(priv->uioinfo);
-+      kfree(priv->uioinfo);
-+      kfree(priv);
-+      return 0;
-+}
-+
-+static struct platform_driver uio_ubicom32ring = {
-+      .probe = uio_ubicom32ring_probe,
-+      .remove = uio_ubicom32ring_remove,
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+};
-+
-+static int __init uio_ubicom32ring_init(void)
-+{
-+      return platform_driver_register(&uio_ubicom32ring);
-+}
-+
-+static void __exit uio_ubicom32ring_exit(void)
-+{
-+      platform_driver_unregister(&uio_ubicom32ring);
-+}
-+
-+module_init(uio_ubicom32ring_init);
-+module_exit(uio_ubicom32ring_exit);
-+
-+MODULE_AUTHOR("Patrick Tjin");
-+MODULE_DESCRIPTION("Userspace I/O driver for Ubicom32 ring buffers");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:" DRIVER_NAME);
---- a/drivers/usb/gadget/epautoconf.c
-+++ b/drivers/usb/gadget/epautoconf.c
-@@ -154,6 +154,10 @@ ep_matches (
-                       /* configure your hardware with enough buffering!! */
-               }
-               break;
-+
-+      case USB_ENDPOINT_XFER_BULK:
-+              if ((gadget->is_dualspeed) && (ep->maxpacket < 512))
-+                      return 0;
-       }
-       /* MATCH!! */
---- a/drivers/usb/Kconfig
-+++ b/drivers/usb/Kconfig
-@@ -22,6 +22,7 @@ config USB_ARCH_HAS_HCD
-       default y if PCMCIA && !M32R                    # sl811_cs
-       default y if ARM                                # SL-811
-       default y if SUPERH                             # r8a66597-hcd
-+      default y if UBICOM32                           # Ubicom's onchip USB Duial role controller
-       default PCI
- # many non-PCI SOC chips embed OHCI
---- a/drivers/usb/musb/Kconfig
-+++ b/drivers/usb/musb/Kconfig
-@@ -12,7 +12,7 @@ config USB_MUSB_HDRC
-       depends on !SUPERH
-       select TWL4030_USB if MACH_OMAP_3430SDP
-       select USB_OTG_UTILS
--      tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
-+      tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, Ubicom, ...)'
-       help
-         Say Y here if your system has a dual role high speed USB
-         controller based on the Mentor Graphics silicon IP.  Then
---- a/drivers/usb/musb/Makefile
-+++ b/drivers/usb/musb/Makefile
-@@ -30,6 +30,10 @@ ifeq ($(CONFIG_BF52x),y)
-       musb_hdrc-objs  += blackfin.o
- endif
-+ifeq ($(CONFIG_UBICOM32), y)
-+        musb_hdrc-objs  += ubi32_usb.o
-+endif
-+
- ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y)
-       musb_hdrc-objs          += musb_gadget_ep0.o musb_gadget.o
- endif
---- a/drivers/usb/musb/musb_core.c
-+++ b/drivers/usb/musb/musb_core.c
-@@ -105,6 +105,13 @@
- #include <asm/mach-types.h>
- #endif
-+#ifdef CONFIG_UBICOM32
-+#include <asm/ip5000.h>
-+#include <asm/ubicom32-tio.h>
-+extern void ubi32_usb_init(void);
-+extern void ubi32_usb_int_clr(void);
-+#endif
-+
- #include "musb_core.h"
-@@ -147,8 +154,37 @@ static inline struct musb *dev_to_musb(s
- }
- /*-------------------------------------------------------------------------*/
-+#if defined(CONFIG_UBICOM32)
-+
-+/*
-+ * Load an endpoint's FIFO
-+ */
-+void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 wCount, const u8 *pSource)
-+{
-+      void __iomem *fifo = hw_ep->fifo;
-+
-+      prefetch((u8 *)pSource);
-+
-+      DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
-+                      'T', hw_ep->epnum, fifo, wCount, pSource);
-+
-+      usb_tio_write_fifo((u32)fifo, (u32)pSource, wCount);
-+
-+}
-+
-+/*
-+ * Unload an endpoint's FIFO
-+ */
-+void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 wCount, u8 *pDest)
-+{
-+
-+      void __iomem *fifo = hw_ep->fifo;
-+      DBG(4, "%cX ep%d fifo %p count %d buf %p\n",
-+                      'R', hw_ep->epnum, fifo, wCount, pDest);
-+      usb_tio_read_fifo((u32)fifo, (u32)pDest, wCount);
-+}
--#if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN)
-+#elif !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN)
- /*
-  * Load an endpoint's FIFO
-@@ -227,8 +263,7 @@ void musb_read_fifo(struct musb_hw_ep *h
-               readsb(fifo, dst, len);
-       }
- }
--
--#endif        /* normal PIO */
-+#endif /* !T6010 && !BLACKFIN */
- /*-------------------------------------------------------------------------*/
-@@ -874,12 +909,19 @@ void musb_start(struct musb *musb)
-       musb_writeb(regs, MUSB_TESTMODE, 0);
-       /* put into basic highspeed mode and start session */
-+#ifndef CONFIG_UBICOM32
-       musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE
-                                               | MUSB_POWER_SOFTCONN
-                                               | MUSB_POWER_HSENAB
-                                               /* ENSUSPEND wedges tusb */
-                                               /* | MUSB_POWER_ENSUSPEND */
-                                               );
-+#else
-+      musb_writeb(regs, MUSB_POWER,  MUSB_POWER_HSENAB
-+                                              /* ENSUSPEND wedges tusb */
-+                                              /* | MUSB_POWER_ENSUSPEND */
-+                                              );
-+#endif
-       musb->is_active = 0;
-       devctl = musb_readb(regs, MUSB_DEVCTL);
-@@ -1081,6 +1123,7 @@ static struct fifo_cfg __initdata mode_4
- };
-+#ifndef CONFIG_UBICOM32
- /*
-  * configure a fifo; for non-shared endpoints, this may be called
-  * once for a tx fifo and once for an rx fifo.
-@@ -1240,7 +1283,7 @@ static int __init ep_config_from_table(s
-       return 0;
- }
--
-+#endif /* CONFIG_UBICOM32 */
- /*
-  * ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false
-@@ -1256,6 +1299,11 @@ static int __init ep_config_from_hw(stru
-       DBG(2, "<== static silicon ep config\n");
-       /* FIXME pick up ep0 maxpacket size */
-+#ifdef CONFIG_UBICOM32
-+      /* set ep0 to shared_fifo, otherwise urb will be put to out_qh but ep0_irq try to get the urb from in_qh*/
-+      hw_ep = musb->endpoints;
-+      hw_ep->is_shared_fifo = true;
-+#endif
-       for (epnum = 1; epnum < musb->config->num_eps; epnum++) {
-               musb_ep_select(mbase, epnum);
-@@ -1276,14 +1324,27 @@ static int __init ep_config_from_hw(stru
-               /* REVISIT:  this algorithm is lazy, we should at least
-                * try to pick a double buffered endpoint.
-                */
-+#ifndef CONFIG_UBICOM32
-               if (musb->bulk_ep)
-                       continue;
-               musb->bulk_ep = hw_ep;
-+#else
-+              if ((musb->bulk_ep_in) && (musb->bulk_ep_out))
-+                      continue;
-+              /* Save theEP with 1024 Bytes FIFO for ISO */
-+              if(hw_ep->max_packet_sz_tx == 512) {
-+                      if (!musb->bulk_ep_in) {
-+                              musb->bulk_ep_in = hw_ep;
-+                      } else if (!musb->bulk_ep_out) {
-+                              musb->bulk_ep_out = hw_ep;
-+                      }
-+              }
-+#endif /* CONFIG_UBICOM32 */
- #endif
-       }
- #ifdef CONFIG_USB_MUSB_HDRC_HCD
--      if (!musb->bulk_ep) {
-+      if ((!musb->bulk_ep_in) || (!musb->bulk_ep_out)) {
-               pr_debug("%s: missing bulk\n", musb_driver_name);
-               return -EINVAL;
-       }
-@@ -1393,12 +1454,16 @@ static int __init musb_core_init(u16 mus
-       musb->epmask = 1;
-       if (reg & MUSB_CONFIGDATA_DYNFIFO) {
-+#ifndef CONFIG_UBICOM32
-               if (musb->config->dyn_fifo)
-                       status = ep_config_from_table(musb);
--              else {
-+              else
-+#endif
-+              {
-                       ERR("reconfigure software for Dynamic FIFOs\n");
-                       status = -ENODEV;
-               }
-+
-       } else {
-               if (!musb->config->dyn_fifo)
-                       status = ep_config_from_hw(musb);
-@@ -1462,8 +1527,8 @@ static int __init musb_core_init(u16 mus
- /*-------------------------------------------------------------------------*/
--#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
--
-+#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || defined(CONFIG_UBICOM32)
-+static u32_t musb_int_count = 0;
- static irqreturn_t generic_interrupt(int irq, void *__hci)
- {
-       unsigned long   flags;
-@@ -1472,10 +1537,17 @@ static irqreturn_t generic_interrupt(int
-       spin_lock_irqsave(&musb->lock, flags);
-+#ifndef CONFIG_UBICOM32
-       musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
-       musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
-       musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
-+#else
-+      musb_read_int_status(&musb->int_usb, &musb->int_tx, &musb->int_rx);
-+      //ubi32_usb_int_clr();
-+      musb_int_count++;
-+#endif
-+      DBG(4, "usb %x, tx %x, rx %x", musb->int_usb, musb->int_tx, musb->int_rx);
-       if (musb->int_usb || musb->int_tx || musb->int_rx)
-               retval = musb_interrupt(musb);
-@@ -2210,6 +2282,10 @@ static struct platform_driver musb_drive
- static int __init musb_init(void)
- {
-+#ifdef CONFIG_UBICOM32
-+      ubi32_usb_init();
-+#endif
-+
- #ifdef CONFIG_USB_MUSB_HDRC_HCD
-       if (usb_disabled())
-               return 0;
---- a/drivers/usb/musb/musb_core.h
-+++ b/drivers/usb/musb/musb_core.h
-@@ -326,7 +326,12 @@ struct musb {
-        * queue until it completes or NAKs too much; then we try the next
-        * endpoint.
-        */
-+#ifdef CONFIG_UBICOM32
-+      struct musb_hw_ep       *bulk_ep_in;
-+      struct musb_hw_ep       *bulk_ep_out;
-+#else
-       struct musb_hw_ep       *bulk_ep;
-+#endif
-       struct list_head        control;        /* of musb_qh */
-       struct list_head        in_bulk;        /* of musb_qh */
---- a/drivers/usb/musb/musb_gadget.c
-+++ b/drivers/usb/musb/musb_gadget.c
-@@ -432,7 +432,7 @@ void musb_g_tx(struct musb *musb, u8 epn
-                * probably rates reporting as a host error
-                */
-               if (csr & MUSB_TXCSR_P_SENTSTALL) {
--                      csr |= MUSB_TXCSR_P_WZC_BITS;
-+                      csr &= ~(MUSB_TXCSR_P_WZC_BITS);
-                       csr &= ~MUSB_TXCSR_P_SENTSTALL;
-                       musb_writew(epio, MUSB_TXCSR, csr);
-                       if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
-@@ -448,7 +448,7 @@ void musb_g_tx(struct musb *musb, u8 epn
-               if (csr & MUSB_TXCSR_P_UNDERRUN) {
-                       /* we NAKed, no big deal ... little reason to care */
--                      csr |= MUSB_TXCSR_P_WZC_BITS;
-+                      csr &= ~(MUSB_TXCSR_P_WZC_BITS);
-                       csr &= ~(MUSB_TXCSR_P_UNDERRUN
-                                       | MUSB_TXCSR_TXPKTRDY);
-                       musb_writew(epio, MUSB_TXCSR, csr);
-@@ -584,10 +584,16 @@ static void rxstate(struct musb *musb, s
-       u16                     csr = 0;
-       const u8                epnum = req->epnum;
-       struct usb_request      *request = &req->request;
--      struct musb_ep          *musb_ep = &musb->endpoints[epnum].ep_out;
-+      struct musb_ep          *musb_ep = NULL;
-       void __iomem            *epio = musb->endpoints[epnum].regs;
--      unsigned                fifo_count = 0;
--      u16                     len = musb_ep->packet_sz;
-+      u16                     fifo_count = 0;
-+      u16                     len = 0;
-+
-+      if (musb->endpoints[epnum].is_shared_fifo)
-+              musb_ep = &musb->endpoints[epnum].ep_in;
-+      else
-+              musb_ep = &musb->endpoints[epnum].ep_out;
-+      len =  musb_ep->packet_sz;
-       csr = musb_readw(epio, MUSB_RXCSR);
-@@ -726,7 +732,7 @@ static void rxstate(struct musb *musb, s
-                        */
-                       /* ack the read! */
--                      csr |= MUSB_RXCSR_P_WZC_BITS;
-+                      csr &= ~MUSB_RXCSR_P_WZC_BITS;
-                       csr &= ~MUSB_RXCSR_RXPKTRDY;
-                       musb_writew(epio, MUSB_RXCSR, csr);
-               }
-@@ -745,10 +751,15 @@ void musb_g_rx(struct musb *musb, u8 epn
-       u16                     csr;
-       struct usb_request      *request;
-       void __iomem            *mbase = musb->mregs;
--      struct musb_ep          *musb_ep = &musb->endpoints[epnum].ep_out;
-+      struct musb_ep          *musb_ep = NULL;
-       void __iomem            *epio = musb->endpoints[epnum].regs;
-       struct dma_channel      *dma;
-+      if (musb->endpoints[epnum].is_shared_fifo)
-+              musb_ep = &musb->endpoints[epnum].ep_in;
-+      else
-+              musb_ep = &musb->endpoints[epnum].ep_out;
-+
-       musb_ep_select(mbase, epnum);
-       request = next_request(musb_ep);
-@@ -1769,7 +1780,9 @@ int usb_gadget_register_driver(struct us
-                       }
-               }
-       }
--
-+#ifndef CONFIG_USB_MUSB_OTG
-+      musb_pullup(musb, 1);
-+#endif
-       return retval;
- }
- EXPORT_SYMBOL(usb_gadget_register_driver);
---- a/drivers/usb/musb/musb_gadget_ep0.c
-+++ b/drivers/usb/musb/musb_gadget_ep0.c
-@@ -240,14 +240,14 @@ __acquires(musb->lock)
-               case USB_REQ_SET_ADDRESS:
-                       /* change it after the status stage */
-                       musb->set_address = true;
--                      musb->address = (u8) (ctrlrequest->wValue & 0x7f);
-+                      musb->address = (u8) (le16_to_cpu(ctrlrequest->wValue) & 0x7f);
-                       handled = 1;
-                       break;
-               case USB_REQ_CLEAR_FEATURE:
-                       switch (recip) {
-                       case USB_RECIP_DEVICE:
--                              if (ctrlrequest->wValue
-+                              if (le16_to_cpu(ctrlrequest->wValue)
-                                               != USB_DEVICE_REMOTE_WAKEUP)
-                                       break;
-                               musb->may_wakeup = 0;
-@@ -261,8 +261,8 @@ __acquires(musb->lock)
-                               if (num == 0
-                                               || num >= MUSB_C_NUM_EPS
--                                              || ctrlrequest->wValue
--                                                      != USB_ENDPOINT_HALT)
-+                                              || le16_to_cpu(ctrlrequest->wValue
-+                                                      != USB_ENDPOINT_HALT))
-                                       break;
-                               if (ctrlrequest->wIndex & USB_DIR_IN)
-@@ -292,7 +292,7 @@ __acquires(musb->lock)
-                       switch (recip) {
-                       case USB_RECIP_DEVICE:
-                               handled = 1;
--                              switch (ctrlrequest->wValue) {
-+                              switch (le16_to_cpu(ctrlrequest->wValue)) {
-                               case USB_DEVICE_REMOTE_WAKEUP:
-                                       musb->may_wakeup = 1;
-                                       break;
-@@ -374,8 +374,8 @@ stall:
-                               if (epnum == 0
-                                               || epnum >= MUSB_C_NUM_EPS
--                                              || ctrlrequest->wValue
--                                                      != USB_ENDPOINT_HALT)
-+                                              || le16_to_cpu(ctrlrequest->wValue
-+                                                      != USB_ENDPOINT_HALT))
-                                       break;
-                               ep = musb->endpoints + epnum;
---- a/drivers/usb/musb/musb_host.c
-+++ b/drivers/usb/musb/musb_host.c
-@@ -160,7 +160,11 @@ static inline void musb_h_tx_start(struc
-       /* NOTE: no locks here; caller should lock and select EP */
-       if (ep->epnum) {
-               txcsr = musb_readw(ep->regs, MUSB_TXCSR);
-+#ifndef CONFIG_UBICOM32
-               txcsr |= MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_H_WZC_BITS;
-+#else
-+              txcsr |= (MUSB_TXCSR_TXPKTRDY & (~MUSB_TXCSR_H_WZC_BITS));
-+#endif
-               musb_writew(ep->regs, MUSB_TXCSR, txcsr);
-       } else {
-               txcsr = MUSB_CSR0_H_SETUPPKT | MUSB_CSR0_TXPKTRDY;
-@@ -223,6 +227,8 @@ musb_start_urb(struct musb *musb, int is
-               break;
-       default:                /* bulk, interrupt */
-               /* actual_length may be nonzero on retry paths */
-+              if (urb->actual_length)
-+                      DBG(3 ,"musb_start_urb: URB %p retried, len: %d\n", urb, urb->actual_length);
-               buf = urb->transfer_buffer + urb->actual_length;
-               len = urb->transfer_buffer_length - urb->actual_length;
-       }
-@@ -342,13 +348,13 @@ musb_save_toggle(struct musb_hw_ep *ep, 
-       if (!is_in) {
-               csr = musb_readw(epio, MUSB_TXCSR);
-               usb_settoggle(udev, qh->epnum, 1,
--                      (csr & MUSB_TXCSR_H_DATATOGGLE)
--                              ? 1 : 0);
-+                      ((csr & MUSB_TXCSR_H_DATATOGGLE)
-+                              ? 1 : 0));
-       } else {
-               csr = musb_readw(epio, MUSB_RXCSR);
-               usb_settoggle(udev, qh->epnum, 0,
--                      (csr & MUSB_RXCSR_H_DATATOGGLE)
--                              ? 1 : 0);
-+                      ((csr & MUSB_RXCSR_H_DATATOGGLE)
-+                              ? 1 : 0));
-       }
- }
-@@ -556,7 +562,11 @@ musb_host_packet_rx(struct musb *musb, s
-       musb_read_fifo(hw_ep, length, buf);
-       csr = musb_readw(epio, MUSB_RXCSR);
-+#ifndef CONFIG_UBICOM32
-       csr |= MUSB_RXCSR_H_WZC_BITS;
-+#else
-+      csr &= ~MUSB_RXCSR_H_WZC_BITS;
-+#endif
-       if (unlikely(do_flush))
-               musb_h_flush_rxfifo(hw_ep, csr);
-       else {
-@@ -590,6 +600,7 @@ musb_rx_reinit(struct musb *musb, struct
-       /* if programmed for Tx, put it in RX mode */
-       if (ep->is_shared_fifo) {
-+#ifndef  CONFIG_UBICOM32
-               csr = musb_readw(ep->regs, MUSB_TXCSR);
-               if (csr & MUSB_TXCSR_MODE) {
-                       musb_h_tx_flush_fifo(ep);
-@@ -604,7 +615,18 @@ musb_rx_reinit(struct musb *musb, struct
-                */
-               if (csr & MUSB_TXCSR_DMAMODE)
-                       musb_writew(ep->regs, MUSB_TXCSR, MUSB_TXCSR_DMAMODE);
-+
-+#else
-+              /* clear mode (and everything else) to enable Rx */
-               musb_writew(ep->regs, MUSB_TXCSR, 0);
-+              /* scrub all previous state, clearing toggle */
-+              csr = musb_readw(ep->regs, MUSB_RXCSR);
-+              if (csr & MUSB_RXCSR_RXPKTRDY)
-+                      WARNING("rx%d, packet/%d ready?\n", ep->epnum,
-+                              musb_readw(ep->regs, MUSB_RXCOUNT));
-+
-+              musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG);
-+#endif
-       /* scrub all previous state, clearing toggle */
-       } else {
-@@ -1138,8 +1160,18 @@ void musb_host_tx(struct musb *musb, u8 
-       void __iomem            *mbase = musb->mregs;
-       struct dma_channel      *dma;
-+#ifdef CONFIG_UBICOM32
-+      if (hw_ep->is_shared_fifo) {
-+              qh = hw_ep->in_qh;
-+      }
-+#ifdef CONFIG_USB_SERIAL_SIERRAWIRELESS
-+      printk(KERN_DEBUG "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr,
-+                      dma ? ", dma" : "");
-+#endif
-+#endif
-       urb = next_urb(qh);
-+
-       musb_ep_select(mbase, epnum);
-       tx_csr = musb_readw(epio, MUSB_TXCSR);
-@@ -1180,9 +1212,14 @@ void musb_host_tx(struct musb *musb, u8 
-                * we have a candidate... NAKing is *NOT* an error
-                */
-               musb_ep_select(mbase, epnum);
-+#ifndef CONFIG_UBICOM32
-               musb_writew(epio, MUSB_TXCSR,
-                               MUSB_TXCSR_H_WZC_BITS
-                               | MUSB_TXCSR_TXPKTRDY);
-+#else
-+              musb_writew(epio, MUSB_TXCSR,
-+                               MUSB_TXCSR_TXPKTRDY);
-+#endif
-               return;
-       }
-@@ -1353,8 +1390,14 @@ void musb_host_tx(struct musb *musb, u8 
-       qh->segsize = length;
-       musb_ep_select(mbase, epnum);
-+#ifndef CONFIG_UBICOM32
-+      musb_writew(epio, MUSB_TXCSR,
-+                  MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
-+#else
-       musb_writew(epio, MUSB_TXCSR,
--                      MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
-+                  MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY);
-+#endif
-+
- }
-@@ -1414,7 +1457,11 @@ static void musb_bulk_rx_nak_timeout(str
-       /* clear nak timeout bit */
-       rx_csr = musb_readw(epio, MUSB_RXCSR);
-+#ifndef CONFIG_UBICOM32
-       rx_csr |= MUSB_RXCSR_H_WZC_BITS;
-+#else
-+      rx_csr &= ~MUSB_RXCSR_H_WZC_BITS;
-+#endif
-       rx_csr &= ~MUSB_RXCSR_DATAERROR;
-       musb_writew(epio, MUSB_RXCSR, rx_csr);
-@@ -1483,6 +1530,13 @@ void musb_host_rx(struct musb *musb, u8 
-       pipe = urb->pipe;
-+#ifdef CONFIG_UBICOM32
-+#ifdef CONFIG_USB_SERIAL_SIERRAWIRELESS
-+              printk(KERN_DEBUG  "RXCSR%d %04x, reqpkt, len %zu%s\n", epnum, rx_csr,
-+                              xfer_len, dma ? ", dma" : "");
-+#endif
-+#endif
-+
-       DBG(5, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)\n",
-               epnum, rx_csr, urb->actual_length,
-               dma ? dma->actual_len : 0);
-@@ -1521,8 +1575,15 @@ void musb_host_rx(struct musb *musb, u8 
-                               return;
-                       }
-                       musb_ep_select(mbase, epnum);
-+#ifndef CONFIG_UBICOM32
-                       rx_csr |= MUSB_RXCSR_H_WZC_BITS;
-                       rx_csr &= ~MUSB_RXCSR_DATAERROR;
-+#else
-+                      /* NEED TO EVALUATE CHANGE */
-+                      rx_csr &= ~MUSB_RXCSR_H_WZC_BITS;
-+                      rx_csr &= ~MUSB_RXCSR_DATAERROR;
-+//                    musb_writew(epio, MUSB_RXCSR, (~(MUSB_RXCSR_H_WZC_BITS))| MUSB_RXCSR_H_REQPKT);
-+#endif
-                       musb_writew(epio, MUSB_RXCSR, rx_csr);
-                       goto finish;
-@@ -1579,8 +1640,13 @@ void musb_host_rx(struct musb *musb, u8 
-               rx_csr &= ~MUSB_RXCSR_H_REQPKT;
-               musb_ep_select(mbase, epnum);
-+#ifndef CONFIG_UBICOM32
-               musb_writew(epio, MUSB_RXCSR,
-                               MUSB_RXCSR_H_WZC_BITS | rx_csr);
-+#else
-+              musb_writew(epio, MUSB_RXCSR,
-+                              (~MUSB_RXCSR_H_WZC_BITS) & rx_csr);
-+#endif
-       }
- #endif
-       if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) {
-@@ -1610,7 +1676,7 @@ void musb_host_rx(struct musb *musb, u8 
-                       else
-                               done = false;
--              } else  {
-+              } else {
-               /* done if urb buffer is full or short packet is recd */
-               done = (urb->actual_length + xfer_len >=
-                               urb->transfer_buffer_length
-@@ -1823,7 +1889,11 @@ static int musb_schedule(
-               } else  if (hw_ep->out_qh != NULL)
-                       continue;
-+#ifndef CONFIG_UBICOM32
-               if (hw_ep == musb->bulk_ep)
-+#else
-+              if ((hw_ep == musb->bulk_ep_in) || (hw_ep == musb->bulk_ep_out)) /* Ubicom */
-+#endif
-                       continue;
-               if (is_in)
-@@ -1836,7 +1906,14 @@ static int musb_schedule(
-                       best_end = epnum;
-               }
-       }
-+
-+#ifdef CONFIG_UBICOM32
-+      if (((best_diff >= qh->maxpacket)) && ((qh->type == USB_ENDPOINT_XFER_BULK) && (!is_in)))
-+              best_end = -1;
-+#endif
-+
-       /* use bulk reserved ep1 if no other ep is free */
-+#ifndef CONFIG_UBICOM32
-       if (best_end < 0 && qh->type == USB_ENDPOINT_XFER_BULK) {
-               hw_ep = musb->bulk_ep;
-               if (is_in)
-@@ -1858,6 +1935,22 @@ static int musb_schedule(
-       } else if (best_end < 0) {
-               return -ENOSPC;
-       }
-+#else
-+      if (best_end < 0 && qh->type == USB_ENDPOINT_XFER_BULK) {
-+              /* hw_ep = musb->bulk_ep; */
-+              if (is_in) {
-+                      head = &musb->in_bulk;
-+                      hw_ep = musb->bulk_ep_in; /* UBICOM */
-+              }
-+              else {
-+                      head = &musb->out_bulk;
-+                      hw_ep = musb->bulk_ep_out; /* UBICOM */
-+              }
-+              goto success;
-+      } else if (best_end < 0) {
-+              return -ENOSPC;
-+      }
-+#endif
-       idle = 1;
-       qh->mux = 0;
-@@ -1869,6 +1962,13 @@ success:
-               list_add_tail(&qh->ring, head);
-               qh->mux = 1;
-       }
-+      /*
-+       * It's not make sense to set NAK timeout when qh->mux = 0,
-+       * There is nothing else to schedule
-+       */
-+      if ((qh->type == USB_ENDPOINT_XFER_BULK) && (qh->mux == 0))
-+              qh->intv_reg = 0;
-+
-       qh->hw_ep = hw_ep;
-       qh->hep->hcpriv = qh;
-       if (idle)
-@@ -1975,6 +2075,15 @@ static int musb_urb_enqueue(
-               /* ISO always uses logarithmic encoding */
-               interval = min_t(u8, epd->bInterval, 16);
-               break;
-+#ifdef COMFIG_UBICOM32
-+      case USB_ENDPOINT_XFER_BULK:
-+               if (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
-+                      interval = (USB_SPEED_HIGH == urb->dev->speed) ? 16: 2;
-+               else
-+                      interval = 0;
-+               break;
-+#endif
-+
-       default:
-               /* REVISIT we actually want to use NAK limits, hinting to the
-                * transfer scheduling logic to try some other qh, e.g. try
---- a/drivers/usb/musb/musb_io.h
-+++ b/drivers/usb/musb/musb_io.h
-@@ -58,6 +58,7 @@ static inline void writesb(const void __
- #ifndef CONFIG_BLACKFIN
-+#ifndef CONFIG_UBICOM32
- /* NOTE:  these offsets are all in bytes */
- static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
-@@ -72,7 +73,37 @@ static inline void musb_writew(void __io
- static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
-       { __raw_writel(data, addr + offset); }
-+#else
-+#include <asm/ubicom32-tio.h>
-+static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
-+{
-+        u16 data;
-+        usb_tio_read_u16((u32)(addr + offset), &data);
-+        return data;
-+}
-+static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
-+{
-+        u8 data;
-+        usb_tio_read_u8((u32)(addr + offset), &data);
-+        return data;
-+}
-+
-+static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
-+{
-+        usb_tio_write_u16((u32)(addr + offset), data);
-+}
-+
-+static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
-+{
-+        usb_tio_write_u8((u32)(addr + offset), data);
-+}
-+
-+static inline void  musb_read_int_status(u8_t *int_usb, u16_t *int_tx, u16_t *int_rx)
-+{
-+      return usb_tio_read_int_status(int_usb, int_tx, int_rx);
-+}
-+#endif /* CONFIG_UBICOM32 */
- #ifdef CONFIG_USB_TUSB6010
-@@ -106,7 +137,7 @@ static inline void musb_writeb(void __io
-       __raw_writew(tmp, addr + (offset & ~1));
- }
--#else
-+#elif !defined(CONFIG_UBICOM32)
- static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
-       { return __raw_readb(addr + offset); }
---- a/drivers/usb/musb/musb_regs.h
-+++ b/drivers/usb/musb/musb_regs.h
-@@ -167,6 +167,7 @@
-       (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
-       | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
-+
- /* RXCSR in Peripheral and Host mode */
- #define MUSB_RXCSR_AUTOCLEAR          0x8000
- #define MUSB_RXCSR_DMAENAB            0x2000
---- /dev/null
-+++ b/drivers/usb/musb/ubi32_usb.c
-@@ -0,0 +1,156 @@
-+/*
-+ * drivers/usb/musb/ubi32_usb.c
-+ *   Ubicom32 usb controller driver.
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ * Copyright (C) 2005-2006 by Texas Instruments
-+ *
-+ * Derived from the Texas Instruments Inventra Controller Driver for Linux.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/clk.h>
-+#include <linux/io.h>
-+
-+#include <asm/io.h>
-+#include <asm/ip5000.h>
-+#include "musb_core.h"
-+
-+void musb_platform_enable(struct musb *musb)
-+{
-+}
-+void musb_platform_disable(struct musb *musb)
-+{
-+}
-+
-+int musb_platform_set_mode(struct musb *musb, u8 musb_mode) {
-+      return 0;
-+}
-+
-+static void ip5k_usb_hcd_vbus_power(struct musb *musb, int is_on, int sleeping)
-+{
-+}
-+
-+static void ip5k_usb_hcd_set_vbus(struct musb *musb, int is_on)
-+{
-+      u8              devctl;
-+      /* HDRC controls CPEN, but beware current surges during device
-+       * connect.  They can trigger transient overcurrent conditions
-+       * that must be ignored.
-+       */
-+
-+      devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
-+
-+      if (is_on) {
-+              musb->is_active = 1;
-+              musb->xceiv.default_a = 1;
-+              musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
-+              devctl |= MUSB_DEVCTL_SESSION;
-+
-+              MUSB_HST_MODE(musb);
-+      } else {
-+              musb->is_active = 0;
-+
-+              /* NOTE:  we're skipping A_WAIT_VFALL -> A_IDLE and
-+               * jumping right to B_IDLE...
-+               */
-+
-+              musb->xceiv.default_a = 0;
-+              musb->xceiv.state = OTG_STATE_B_IDLE;
-+              devctl &= ~MUSB_DEVCTL_SESSION;
-+
-+              MUSB_DEV_MODE(musb);
-+      }
-+      musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
-+
-+      DBG(1, "VBUS %s, devctl %02x "
-+              /* otg %3x conf %08x prcm %08x */ "\n",
-+              otg_state_string(musb),
-+              musb_readb(musb->mregs, MUSB_DEVCTL));
-+}
-+static int ip5k_usb_hcd_set_power(struct otg_transceiver *x, unsigned mA)
-+{
-+      return 0;
-+}
-+
-+static int musb_platform_resume(struct musb *musb);
-+
-+int __init musb_platform_init(struct musb *musb)
-+{
-+
-+#ifdef CONFIG_UBICOM32_V4
-+      u32_t chip_id;
-+      asm volatile (
-+                    "move.4   %0, CHIP_ID     \n\t"
-+                    : "=r" (chip_id)
-+      );
-+      if (chip_id == 0x30001) {
-+              *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 30);
-+              udelay(1);
-+              *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 31);
-+      } else {
-+              *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 17);
-+              udelay(1);
-+              *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_TEST)) &= ~(1 << 14);
-+      }
-+#endif
-+
-+       *((u32_t *)(GENERAL_CFG_BASE + GEN_USB_PHY_CFG)) |= ((1 << 14) | (1 <<15));
-+
-+      /* The i-clk is AUTO gated. Hence there is no need
-+       * to disable it until the driver is shutdown */
-+
-+      clk_enable(musb->clock);
-+      musb_platform_resume(musb);
-+
-+      ip5k_usb_hcd_vbus_power(musb, musb->board_mode == MUSB_HOST, 1);
-+
-+      if (is_host_enabled(musb))
-+              musb->board_set_vbus = ip5k_usb_hcd_set_vbus;
-+      if (is_peripheral_enabled(musb))
-+              musb->xceiv.set_power = ip5k_usb_hcd_set_power;
-+
-+      return 0;
-+}
-+
-+
-+int musb_platform_suspend(struct musb *musb)
-+{
-+      return 0;
-+}
-+int musb_platform_resume(struct musb *musb)
-+{
-+      return 0;
-+}
-+
-+int musb_platform_exit(struct musb *musb)
-+{
-+      ip5k_usb_hcd_vbus_power(musb, 0 /*off*/, 1);
-+      musb_platform_suspend(musb);
-+      return 0;
-+}
---- a/drivers/video/backlight/Kconfig
-+++ b/drivers/video/backlight/Kconfig
-@@ -93,6 +93,63 @@ config LCD_HP700
-         If you have an HP Jornada 700 series handheld (710/720/728)
-         say Y to enable LCD control driver.
-+config LCD_UBICOM32POWER
-+      tristate "Ubicom LCD power Driver"
-+      depends on LCD_CLASS_DEVICE && UBICOM32
-+      default n
-+      help
-+        If you have a Ubicom32 based system with an LCD panel that requires
-+        power control, say Y to enable the power control driver for it.
-+
-+config LCD_UBICOM32
-+      tristate "Ubicom Backlight Driver"
-+      depends on LCD_CLASS_DEVICE && UBICOM32
-+      default n
-+      help
-+        This driver takes care of initialization of LCD panels with
-+        built in controllers.
-+
-+menu "Ubicom32 LCD Panel Support"
-+      depends on UBICOM32 && LCD_UBICOM32
-+
-+config LCD_UBICOM32_TFT2N0369E_P
-+      bool "TFT2N0369E (Portrait)"
-+      default n
-+      help
-+        Support for TFT2N0369 in portrait mode
-+
-+config LCD_UBICOM32_TFT2N0369E_L
-+      bool "TFT2N0369E (Landscape)"
-+      default n
-+      help
-+        Support for TFT2N0369 in landscape mode
-+
-+config LCD_UBICOM32_CFAF240320KTTS
-+      bool "CFAF240320KTTS"
-+      default n
-+      help
-+        Support for CFAF240320KTTS
-+
-+config LCD_UBICOM32_CFAF240320KTTS_180
-+      bool "CFAF240320KTTS (180 rotation)"
-+      default n
-+      help
-+        Support for CFAF240320KTTS rotated 180 degrees
-+
-+config LCD_UBICOM32_CFAF240320D
-+      bool "CFAF240320D"
-+      default n
-+      help
-+        Support for CFAF240320D
-+
-+config LCD_UBICOM32_CFAF320240F
-+      bool "CFAF320240F"
-+      default n
-+      help
-+        Support for CFAF320240F
-+
-+endmenu
-+
- #
- # Backlight
- #
-@@ -229,3 +286,11 @@ config BACKLIGHT_SAHARA
-       help
-         If you have a Tabletkiosk Sahara Touch-iT, say y to enable the
-         backlight driver.
-+
-+config BACKLIGHT_UBICOM32
-+      tristate "Ubicom Backlight Driver"
-+      depends on BACKLIGHT_CLASS_DEVICE && UBICOM32
-+      default n
-+      help
-+        If you have a Ubicom32 based system with a backlight say Y to enable the
-+        backlight driver.
---- a/drivers/video/backlight/Makefile
-+++ b/drivers/video/backlight/Makefile
-@@ -9,6 +9,9 @@ obj-$(CONFIG_LCD_PLATFORM)        += platfor
- obj-$(CONFIG_LCD_VGG2432A4)      += vgg2432a4.o
- obj-$(CONFIG_LCD_TDO24M)         += tdo24m.o
- obj-$(CONFIG_LCD_TOSA)                   += tosa_lcd.o
-+obj-$(CONFIG_LCD_LTV350QV)       += ltv350qv.o
-+obj-$(CONFIG_LCD_UBICOM32POWER)          += ubicom32lcdpower.o
-+obj-$(CONFIG_LCD_UBICOM32)       += ubicom32lcd.o
- obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
- obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o
-@@ -24,4 +27,4 @@ obj-$(CONFIG_BACKLIGHT_DA903X)       += da903x
- obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o
- obj-$(CONFIG_BACKLIGHT_TOSA)  += tosa_bl.o
- obj-$(CONFIG_BACKLIGHT_SAHARA)        += kb3886_bl.o
--
-+obj-$(CONFIG_BACKLIGHT_UBICOM32) += ubicom32bl.o
---- /dev/null
-+++ b/drivers/video/backlight/ubicom32bl.c
-@@ -0,0 +1,399 @@
-+/*
-+ * drivers/video/backlight/ubicom32bl.c
-+ *    Backlight driver for the Ubicom32 platform
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/backlight.h>
-+#include <linux/fb.h>
-+
-+#include <asm/ubicom32bl.h>
-+#include <asm/ip5000.h>
-+
-+#define DRIVER_NAME                   "ubicom32bl"
-+#define UBICOM32BL_MAX_BRIGHTNESS     255
-+
-+struct ubicom32bl_data {
-+      /*
-+       * Pointer to the platform data structure.  Keep this around since we need values
-+       * from it to set the backlight intensity.
-+       */
-+      const struct ubicom32bl_platform_data   *pdata;
-+
-+      /*
-+       * Backlight device, we have to save this for use when we remove ourselves.
-+       */
-+      struct backlight_device                 *bldev;
-+
-+      /*
-+       * Current intensity, used for get_intensity.
-+       */
-+      int                                     cur_intensity;
-+
-+      /*
-+       * Init function for PWM
-+       */
-+      int (*init_fn)(struct ubicom32bl_data *);
-+
-+      /*
-+       * Set intensity function depending on the backlight type
-+       */
-+      int (*set_intensity_fn)(struct ubicom32bl_data *, int);
-+};
-+
-+/*
-+ * ubicom32bl_set_intensity_gpio
-+ */
-+static int ubicom32bl_set_intensity_gpio(struct ubicom32bl_data *ud, int intensity)
-+{
-+      ud->cur_intensity = intensity ? 255 : 0;
-+
-+      if (intensity) {
-+              // set gpio
-+              return 0;
-+      }
-+
-+      // clear gpio
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32bl_set_intensity_hw
-+ */
-+static int ubicom32bl_set_intensity_hw(struct ubicom32bl_data *ud, int intensity)
-+{
-+      u16_t period = ud->pdata->pwm_period;
-+      u16_t duty;
-+
-+      /*
-+       * Calculate the new duty cycle
-+       */
-+      duty = (period * intensity) / (UBICOM32BL_MAX_BRIGHTNESS + 1);
-+
-+      /*
-+       * Set the new duty cycle
-+       */
-+      switch (ud->pdata->pwm_channel) {
-+      case 0:
-+              /*
-+               * Channel 0 is in the lower half of PORT C ctl0 and ctl1
-+               */
-+              UBICOM32_IO_PORT(RC)->ctl1 = (ud->pdata->pwm_period << 16) | duty;
-+              break;
-+
-+      case 1:
-+              /*
-+               * Channel 1 is in the upper half of PORT C ctl0 and ctl2
-+               */
-+              UBICOM32_IO_PORT(RC)->ctl2 = (ud->pdata->pwm_period << 16) | duty;
-+              break;
-+
-+      case 2:
-+              /*
-+               * Channel 2 is in PORT H ctl0 and ctl1
-+               */
-+              UBICOM32_IO_PORT(RH)->ctl1 = (ud->pdata->pwm_period << 16) | duty;
-+              break;
-+      }
-+
-+      ud->cur_intensity = intensity;
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32bl_set_intensity
-+ */
-+static int ubicom32bl_set_intensity(struct backlight_device *bd)
-+{
-+      struct ubicom32bl_data *ud = (struct ubicom32bl_data *)bl_get_data(bd);
-+      int intensity = bd->props.brightness;
-+
-+      /*
-+       * If we're blanked the the intensity doesn't matter.
-+       */
-+      if ((bd->props.power != FB_BLANK_UNBLANK) || (bd->props.fb_blank != FB_BLANK_UNBLANK)) {
-+              intensity = 0;
-+      }
-+
-+      /*
-+       * Check for inverted backlight.
-+       */
-+      if (ud->pdata->invert) {
-+              intensity = UBICOM32BL_MAX_BRIGHTNESS - intensity;
-+      }
-+
-+      if (ud->set_intensity_fn) {
-+              return ud->set_intensity_fn(ud, intensity);
-+      }
-+
-+      return -ENXIO;
-+}
-+
-+/*
-+ * ubicom32bl_get_intensity
-+ *    Return the current intensity of the backlight.
-+ */
-+static int ubicom32bl_get_intensity(struct backlight_device *bd)
-+{
-+      struct ubicom32bl_data *ud = (struct ubicom32bl_data *)bl_get_data(bd);
-+
-+      return ud->cur_intensity;
-+}
-+
-+/*
-+ * ubicom32bl_init_hw_pwm
-+ *    Set the appropriate PWM registers
-+ */
-+static int ubicom32bl_init_hw_pwm(struct ubicom32bl_data *ud)
-+{
-+      /*
-+       * bit 13: enable
-+       */
-+      u16_t pwm_cfg = (1 << 13) | (ud->pdata->pwm_prescale << 8) ;
-+
-+      switch (ud->pdata->pwm_channel) {
-+      case 0:
-+              /*
-+               * Channel 0 is in the lower half of PORT C ctl0 and ctl1 (PA5)
-+               */
-+              UBICOM32_IO_PORT(RC)->ctl0 &= ~0xFFFF;
-+              UBICOM32_IO_PORT(RC)->ctl0 |= pwm_cfg;
-+              UBICOM32_IO_PORT(RC)->ctl1 = ud->pdata->pwm_period << 16;
-+
-+              /*
-+               * If the port function is not set, set it to GPIO/PWM
-+               */
-+              if (!UBICOM32_IO_PORT(RA)->function) {
-+                      UBICOM32_IO_PORT(RA)->function = 3;
-+              }
-+              break;
-+
-+      case 1:
-+              /*
-+               * Channel 1 is in the upper half of PORT C ctl0 and ctl2 (PE4)
-+               */
-+              UBICOM32_IO_PORT(RC)->ctl0 &= ~0xFFFF0000;
-+              UBICOM32_IO_PORT(RC)->ctl0 |= (pwm_cfg << 16);
-+              UBICOM32_IO_PORT(RC)->ctl2 = ud->pdata->pwm_period << 16;
-+
-+              /*
-+               * If the port function is not set, set it to GPIO/ExtIOInt
-+               */
-+              if (!UBICOM32_IO_PORT(RE)->function) {
-+                      UBICOM32_IO_PORT(RE)->function = 3;
-+              }
-+              break;
-+
-+      case 2:
-+              /*
-+               * Channel 2 is in PORT H ctl0 and ctl1 (PD0)
-+               */
-+              UBICOM32_IO_PORT(RH)->ctl0 &= ~0xFFFF0000;
-+              UBICOM32_IO_PORT(RH)->ctl0 = pwm_cfg;
-+              UBICOM32_IO_PORT(RH)->ctl1 = ud->pdata->pwm_period << 16;
-+
-+              /*
-+               * If the port function is not set, set it to GPIO
-+               */
-+              if (!UBICOM32_IO_PORT(RD)->function) {
-+                      UBICOM32_IO_PORT(RD)->function = 3;
-+              }
-+              break;
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32bl_init_gpio
-+ *    Allocate the appropriate GPIO
-+ */
-+static int ubicom32bl_init_gpio(struct ubicom32bl_data *ud)
-+{
-+      return 0;
-+}
-+
-+static struct backlight_ops ubicom32bl_ops = {
-+      .get_brightness = ubicom32bl_get_intensity,
-+      .update_status  = ubicom32bl_set_intensity,
-+};
-+
-+/*
-+ * ubicom32bl_probe
-+ */
-+static int ubicom32bl_probe(struct platform_device *pdev)
-+{
-+      const struct ubicom32bl_platform_data *pdata = pdev->dev.platform_data;
-+      struct ubicom32bl_data *ud;
-+      struct backlight_device *bldev;
-+      int retval;
-+
-+      /*
-+       * Check to see if we have any platform data, if we don't then the backlight is not
-+       * configured on this device.
-+       */
-+      if (!pdata) {
-+              return -ENODEV;
-+      }
-+
-+      /*
-+       * Allocate our private data
-+       */
-+      ud = kzalloc(sizeof(struct ubicom32bl_data), GFP_KERNEL);
-+      if (!ud) {
-+              return -ENOMEM;
-+      }
-+
-+      ud->pdata = pdata;
-+
-+      /*
-+       * Check to see that the platform data is valid for this driver
-+       */
-+      switch (pdata->type) {
-+      case UBICOM32BL_TYPE_PWM:
-+              {
-+                      /*
-+                       * Make sure we have a PWM peripheral
-+                       */
-+                      u32_t chipid;
-+                      asm volatile (
-+                              "move.4         %0, CHIP_ID     \n\t"
-+                              : "=r" (chipid)
-+                      );
-+                      if (chipid != 0x00030001) {
-+                              retval = -ENODEV;
-+                              goto fail;
-+                      }
-+
-+                      if (pdata->pwm_channel > 3) {
-+                              retval = -ENODEV;
-+                              goto fail;
-+                      }
-+                      if (pdata->pwm_prescale > 16) {
-+                              retval = -EINVAL;
-+                              goto fail;
-+                      }
-+
-+                      ud->init_fn = ubicom32bl_init_hw_pwm;
-+                      ud->set_intensity_fn = ubicom32bl_set_intensity_hw;
-+                      break;
-+              }
-+
-+      case UBICOM32BL_TYPE_PWM_HRT:
-+              // For now, PWM HRT devices are treated as binary lights.
-+
-+      case UBICOM32BL_TYPE_BINARY:
-+              ud->init_fn = ubicom32bl_init_gpio;
-+              ud->set_intensity_fn = ubicom32bl_set_intensity_gpio;
-+              break;
-+      }
-+
-+      /*
-+       * Register our backlight device
-+       */
-+      bldev = backlight_device_register(DRIVER_NAME, &pdev->dev, ud, &ubicom32bl_ops);
-+      if (IS_ERR(bldev)) {
-+              retval = PTR_ERR(bldev);
-+              goto fail;
-+      }
-+
-+      ud->bldev = bldev;
-+      ud->cur_intensity = pdata->default_intensity;
-+      platform_set_drvdata(pdev, ud);
-+
-+      /*
-+       * Start up the backlight at the prescribed default intensity
-+       */
-+      bldev->props.power = FB_BLANK_UNBLANK;
-+      bldev->props.max_brightness = UBICOM32BL_MAX_BRIGHTNESS;
-+      bldev->props.brightness = pdata->default_intensity;
-+
-+      if (ud->init_fn) {
-+              if (ud->init_fn(ud) != 0) {
-+                      retval = -ENODEV;
-+                      backlight_device_unregister(ud->bldev);
-+                      goto fail;
-+              }
-+      }
-+      ubicom32bl_set_intensity(bldev);
-+
-+      printk(KERN_INFO DRIVER_NAME ": Backlight driver started\n");
-+
-+      return 0;
-+
-+fail:
-+      platform_set_drvdata(pdev, NULL);
-+      kfree(ud);
-+      return retval;
-+}
-+
-+/*
-+ * ubicom32bl_remove
-+ */
-+static int __exit ubicom32bl_remove(struct platform_device *pdev)
-+{
-+      struct ubicom32bl_data *ud = platform_get_drvdata(pdev);
-+
-+      backlight_device_unregister(ud->bldev);
-+      platform_set_drvdata(pdev, NULL);
-+      kfree(ud);
-+
-+      return 0;
-+}
-+
-+static struct platform_driver ubicom32bl_driver = {
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+
-+      .remove = __exit_p(ubicom32bl_remove),
-+};
-+
-+/*
-+ * ubicom32bl_init
-+ */
-+static int __init ubicom32bl_init(void)
-+{
-+      return platform_driver_probe(&ubicom32bl_driver, ubicom32bl_probe);
-+}
-+module_init(ubicom32bl_init);
-+
-+/*
-+ * ubicom32bl_exit
-+ */
-+static void __exit ubicom32bl_exit(void)
-+{
-+      platform_driver_unregister(&ubicom32bl_driver);
-+}
-+module_exit(ubicom32bl_exit);
-+
-+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
-+MODULE_DESCRIPTION("Ubicom32 backlight driver");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/video/backlight/ubicom32lcd.c
-@@ -0,0 +1,372 @@
-+/*
-+ * drivers/video/ubicom32lcd.c
-+ *    LCD initilization code
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/delay.h>
-+
-+#include <asm/ip5000.h>
-+#include <asm/gpio.h>
-+#include <asm/ubicom32lcd.h>
-+
-+#include "ubicom32lcd.h"
-+
-+#define DRIVER_NAME                   "ubicom32lcd"
-+
-+struct ubicom32lcd_data {
-+      const struct ubicom32lcd_panel  *panel;
-+
-+      int                             pin_cs;
-+      int                             pin_rd;
-+      int                             pin_rs;
-+      int                             pin_wr;
-+      int                             pin_reset;
-+      struct ubicom32_io_port         *port_data;
-+      int                             data_shift;
-+};
-+
-+/*
-+ * ubicom32lcd_write
-+ *    Performs a write cycle on the bus (assumes CS asserted, RD & WR set)
-+ */
-+static void ubicom32lcd_write(struct ubicom32lcd_data *ud, int command, u16 data)
-+{
-+      if (command) {
-+              UBICOM32_GPIO_SET_PIN_LOW(ud->pin_rs);
-+      } else {
-+              UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs);
-+      }
-+
-+      asm volatile (
-+              "or.4   4(%[port]), 4(%[port]), %[mask] \n\t"
-+              "not.4  %[mask], %[mask]                \n\t"
-+              "and.4  8(%[port]), 8(%[port]), %[mask] \n\t"
-+              "or.4   8(%[port]), 8(%[port]), %[cmd]  \n\t"
-+              :
-+              : [port] "a" (ud->port_data),
-+                [mask] "d" (0xFFFF << ud->data_shift),
-+                [cmd] "d" (data << ud->data_shift)
-+              : "cc"
-+      );
-+
-+      UBICOM32_GPIO_SET_PIN_LOW(ud->pin_wr);
-+
-+      //ndelay(50);
-+      udelay(1);
-+
-+      UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_wr);
-+
-+      udelay(1);
-+      //ndelay(50);
-+}
-+
-+/*
-+ * ubicom32lcd_read_data
-+ *    Performs a read cycle on the bus (assumes CS asserted, RD & WR set)
-+ */
-+static u16 ubicom32lcd_read_data(struct ubicom32lcd_data *ud)
-+{
-+      u32_t data;
-+
-+      UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs);
-+
-+      asm volatile (
-+              "and.4  4(%[port]), 4(%[port]), %[mask]\n\t"
-+              :
-+              : [port] "a" (ud->port_data),
-+                [mask] "d" (~(0xFFFF << ud->data_shift))
-+              : "cc"
-+      );
-+
-+      UBICOM32_GPIO_SET_PIN_LOW(ud->pin_rd);
-+
-+      ndelay(300);
-+
-+      asm volatile (
-+              "lsr.4  %[data], 12(%[port]), %[shamt]  \n\t"
-+              "and.4  %[data], %[data], %[mask]       \n\t"
-+              : [data] "=d" (data)
-+              : [port] "a" (ud->port_data),
-+                [mask] "d" (0xFFFF),
-+                [shamt] "d" (ud->data_shift)
-+              : "cc"
-+      );
-+
-+      ndelay(200);
-+
-+      UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rd);
-+
-+      ndelay(500);
-+
-+      return data;
-+}
-+
-+/*
-+ * ubicom32lcd_execute
-+ *    Executes a script for performing operations on the LCD (assumes CS set)
-+ */
-+static void ubicom32lcd_execute(struct ubicom32lcd_data *ud, const struct ubicom32lcd_step *script)
-+{
-+      while (1) {
-+              switch (script->op) {
-+              case LCD_STEP_CMD:
-+                      ubicom32lcd_write(ud, 1, script->cmd);
-+                      break;
-+
-+              case LCD_STEP_DATA:
-+                      ubicom32lcd_write(ud, 0, script->data);
-+                      break;
-+
-+              case LCD_STEP_CMD_DATA:
-+                      ubicom32lcd_write(ud, 1, script->cmd);
-+                      ubicom32lcd_write(ud, 0, script->data);
-+                      break;
-+
-+              case LCD_STEP_SLEEP:
-+                      udelay(script->data);
-+                      break;
-+
-+              case LCD_STEP_DONE:
-+                      return;
-+              }
-+              script++;
-+      }
-+}
-+
-+/*
-+ * ubicom32lcd_goto
-+ *    Places the gram pointer at a specific X, Y address
-+ */
-+static void ubicom32lcd_goto(struct ubicom32lcd_data *ud, int x, int y)
-+{
-+      ubicom32lcd_write(ud, 1, ud->panel->horz_reg);
-+      ubicom32lcd_write(ud, 0, x);
-+      ubicom32lcd_write(ud, 1, ud->panel->vert_reg);
-+      ubicom32lcd_write(ud, 0, y);
-+      ubicom32lcd_write(ud, 1, ud->panel->gram_reg);
-+}
-+
-+/*
-+ * ubicom32lcd_panel_init
-+ *    Initializes the lcd panel.
-+ */
-+static int ubicom32lcd_panel_init(struct ubicom32lcd_data *ud)
-+{
-+      u16 id;
-+
-+      UBICOM32_GPIO_SET_PIN_LOW(ud->pin_reset);
-+      UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_reset);
-+      UBICOM32_GPIO_ENABLE(ud->pin_reset);
-+
-+      asm volatile (
-+              "or.4   0x50(%[port]), 0x50(%[port]), %[mask]   \n\t"
-+              "not.4  %[mask], %[mask]                        \n\t"
-+              "and.4  0x04(%[port]), 0x04(%[port]), %[mask]   \n\t"
-+              :
-+              : [port] "a" (ud->port_data),
-+                [mask] "d" (0xFFFF << ud->data_shift)
-+              : "cc"
-+      );
-+
-+      UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs);
-+      UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rd);
-+      UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_wr);
-+      UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_cs);
-+
-+      UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_rs);
-+      UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_rd);
-+      UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_wr);
-+      UBICOM32_GPIO_SET_PIN_OUTPUT(ud->pin_cs);
-+
-+      UBICOM32_GPIO_ENABLE(ud->pin_rs);
-+      UBICOM32_GPIO_ENABLE(ud->pin_rd);
-+      UBICOM32_GPIO_ENABLE(ud->pin_wr);
-+      UBICOM32_GPIO_ENABLE(ud->pin_cs);
-+
-+      udelay(20);
-+
-+      UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_reset);
-+
-+      udelay(20);
-+
-+      UBICOM32_GPIO_SET_PIN_LOW(ud->pin_cs);
-+
-+      id = ubicom32lcd_read_data(ud);
-+
-+      /*
-+       * We will try to figure out what kind of panel we have if we were not told.
-+       */
-+      if (!ud->panel) {
-+              const struct ubicom32lcd_panel **p = ubicom32lcd_panels;
-+              while (*p) {
-+                      if ((*p)->id && ((*p)->id == id)) {
-+                              break;
-+                      }
-+                      p++;
-+              }
-+              if (!*p) {
-+                      printk(KERN_WARNING DRIVER_NAME ":Could not find compatible panel, id=%x\n", id);
-+                      return -ENODEV;
-+              }
-+              ud->panel = *p;
-+      }
-+
-+      /*
-+       * Make sure panel ID matches if we were supplied a panel type
-+       */
-+      if (ud->panel->id && (ud->panel->id != id)) {
-+              UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_cs);
-+
-+              return -ENODEV;
-+      }
-+
-+      ubicom32lcd_execute(ud, ud->panel->init_seq);
-+
-+      ubicom32lcd_goto(ud, 0, 0);
-+
-+      UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_cs);
-+      UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rd);
-+      UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_wr);
-+      UBICOM32_GPIO_SET_PIN_HIGH(ud->pin_rs);
-+
-+      printk(KERN_INFO DRIVER_NAME ": Initialized panel %s\n", ud->panel->desc);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32lcd_probe
-+ */
-+static int ubicom32lcd_probe(struct platform_device *pdev)
-+{
-+      const struct ubicom32lcd_platform_data *pdata = pdev->dev.platform_data;
-+      struct ubicom32lcd_data *ud;
-+      int retval;
-+
-+      /*
-+       * Allocate our private data
-+       */
-+      ud = kzalloc(sizeof(struct ubicom32lcd_data), GFP_KERNEL);
-+      if (!ud) {
-+              return -ENOMEM;
-+      }
-+
-+      if (pdata) {
-+              ud->pin_cs = pdata->pin_cs;
-+              ud->pin_rd = pdata->pin_rd;
-+              ud->pin_wr = pdata->pin_wr;
-+              ud->pin_rs = pdata->pin_rs;
-+              ud->pin_reset = pdata->pin_reset;
-+              ud->port_data = pdata->port_data;
-+              ud->data_shift = pdata->data_shift;
-+      } else {
-+              /*
-+               * Defaults
-+               */
-+              ud->pin_cs = GPIO_RD_4;
-+              ud->pin_rd = GPIO_RD_5;
-+              ud->pin_rs = GPIO_RD_3;
-+              ud->pin_wr = GPIO_RD_2;
-+              ud->pin_reset = GPIO_RD_7;
-+              ud->port_data = (struct ubicom32_io_port *)RI;
-+              ud->data_shift = 0;
-+      }
-+
-+      /*
-+       * Initialize the display
-+       */
-+      retval = ubicom32lcd_panel_init(ud);
-+      if (retval) {
-+              kfree(ud);
-+              return retval;
-+      }
-+
-+      printk(KERN_INFO DRIVER_NAME ": LCD initialized\n");
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32lcd_remove
-+ */
-+static int __exit ubicom32lcd_remove(struct platform_device *pdev)
-+{
-+      struct ubicom32lcd_data *ud = platform_get_drvdata(pdev);
-+
-+      kfree(ud);
-+
-+      return 0;
-+}
-+
-+static struct platform_driver ubicom32lcd_driver = {
-+      .probe          = ubicom32lcd_probe,
-+      .remove         = ubicom32lcd_remove,
-+
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+
-+      .remove = __exit_p(ubicom32lcd_remove),
-+};
-+
-+static struct platform_device *ubicom32lcd_device;
-+
-+/*
-+ * ubicom32lcd_init
-+ */
-+static int __init ubicom32lcd_init(void)
-+{
-+      int res;
-+
-+      res = platform_driver_register(&ubicom32lcd_driver);
-+      if (res == 0) {
-+              ubicom32lcd_device = platform_device_alloc(DRIVER_NAME, 0);
-+              if (ubicom32lcd_device) {
-+                      res = platform_device_add(ubicom32lcd_device);
-+              } else {
-+                      res = -ENOMEM;
-+              }
-+              if (res) {
-+                      platform_device_put(ubicom32lcd_device);
-+                      platform_driver_unregister(&ubicom32lcd_driver);
-+              }
-+      }
-+      return res;
-+}
-+module_init(ubicom32lcd_init);
-+
-+/*
-+ * ubicom32lcd_exit
-+ */
-+static void __exit ubicom32lcd_exit(void)
-+{
-+      platform_device_unregister(ubicom32lcd_device);
-+      platform_driver_unregister(&ubicom32lcd_driver);
-+}
-+module_exit(ubicom32lcd_exit);
-+
-+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
-+MODULE_DESCRIPTION("Ubicom32 LCD driver");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/drivers/video/backlight/ubicom32lcd.h
-@@ -0,0 +1,546 @@
-+/*
-+ * ubicom32lcd.h
-+ *    Ubicom32 lcd panel drivers
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * This Ubicom32 library 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 Ubicom32 library 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#ifndef _UBICOM32LCD_H_
-+#define _UBICOM32LCD_H_
-+
-+enum ubicom32lcd_op {
-+      /*
-+       * Sleep for (data) ms
-+       */
-+      LCD_STEP_SLEEP,
-+
-+      /*
-+       * Execute write of command
-+       */
-+      LCD_STEP_CMD,
-+
-+      /*
-+       * Execute write of data
-+       */
-+      LCD_STEP_DATA,
-+
-+      /*
-+       * Execute write of command/data
-+       */
-+      LCD_STEP_CMD_DATA,
-+
-+      /*
-+       * Script done
-+       */
-+      LCD_STEP_DONE,
-+};
-+
-+struct ubicom32lcd_step {
-+      enum ubicom32lcd_op             op;
-+      u16                             cmd;
-+      u16                             data;
-+};
-+
-+struct ubicom32lcd_panel {
-+      const struct ubicom32lcd_step   *init_seq;
-+      const char                      *desc;
-+
-+      u32                             xres;
-+      u32                             yres;
-+      u32                             stride;
-+      u32                             flags;
-+
-+      u16                             id;
-+      u16                             horz_reg;
-+      u16                             vert_reg;
-+      u16                             gram_reg;
-+};
-+
-+#ifdef CONFIG_LCD_UBICOM32_CFAF240320KTTS
-+static const struct ubicom32lcd_step cfaf240320ktts_init_0[] = {
-+      {LCD_STEP_CMD_DATA, 0x0001, 0x0000,}, // Driver Output Control Register (R01h)          Page 14, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0002, 0x0700,}, // LCD Driving Waveform Control (R02h)            Page 15, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0003, 0x50A0,}, // Entry Mode (R03h)                              0 degrees
-+      {LCD_STEP_CMD_DATA, 0x0004, 0x0000,}, // Scaling Control register (R04h)                Page 16, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0008, 0x0207,}, // Display Control 2 (R08h)                       Page 17, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0009, 0x0000,}, // Display Control 3 (R09h)                       Page 18, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x000A, 0x0000,}, // Frame Cycle Control (R0Ah)                     Page 19, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x000C, 0x0000,}, // External Display Interface Control 1 (R0Ch)    Page 20, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x000D, 0x0000,}, // Frame Maker Position (R0Dh)                    Page 21, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x000F, 0x0000,}, // External Display Interface Control 2 (R0Fh)    Page 21, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0010, 0x0000,}, // Power Control 1 (R10h)                         Page 22, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h)                         Page 23, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0012, 0x0000,}, // Power Control 3 (R12h)                         Page 24, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0013, 0x0000,}, // Power Control 4 (R13h)                         Page 25, SPFD5408B Datasheet
-+      {LCD_STEP_SLEEP, 0, 200},
-+      {LCD_STEP_CMD_DATA, 0x0007, 0x0101,}, // Display Control (R07h)                         Page 16, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0010, 0x12B0,}, // Power Control 1 (R10h)                         Page 22, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h)                         Page 23, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0012, 0x01BB,}, // Power Control 3 (R12h)                         Page 24, SPFD5408B Datasheet
-+      {LCD_STEP_SLEEP, 0, 50},
-+      {LCD_STEP_CMD_DATA, 0x0013, 0x1300,}, // Power Control 4 (R13h)                         Page 25, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0029, 0x0010,}, // NVM read data 2 (R29h)                         Page 30, SPFD5408B Datasheet
-+      {LCD_STEP_SLEEP, 0, 50},
-+      {LCD_STEP_CMD_DATA, 0x0030, 0x000A,}, // Gamma Control 1                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0031, 0x1326,}, // Gamma Control 2                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0032, 0x0A29,}, // Gamma Control 3                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0033, 0x290A,}, // Gamma Control 4                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0034, 0x2613,}, // Gamma Control 5                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0035, 0x0A0A,}, // Gamma Control 6                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0036, 0x1E03,}, // Gamma Control 7                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0037, 0x031E,}, // Gamma Control 8                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0038, 0x0706,}, // Gamma Control 9                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0039, 0x0303,}, // Gamma Control 10                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x003A, 0x0E04,}, // Gamma Control 11                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x003B, 0x0E01,}, // Gamma Control 12                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x003C, 0x010E,}, // Gamma Control 13                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x003D, 0x040E,}, // Gamma Control 14                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x003E, 0x0303,}, // Gamma Control 15                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x003F, 0x0607,}, // Gamma Control 16                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0050, 0x0000,}, // Window Horizontal RAM Address Start (R50h)     Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0051, 0x00EF,}, // Window Horizontal RAM Address End (R51h)       Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0052, 0x0000,}, // Window Vertical RAM Address Start (R52h)       Page 33, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0053, 0x013F,}, // Window Vertical RAM Address End (R53h)         Page 33, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0060, 0x2700,}, // Driver Output Control (R60h)                   Page 33, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0061, 0x0001,}, // Driver Output Control (R61h)                   Page 35, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x006A, 0x0000,}, // Vertical Scroll Control (R6Ah)                 Page 35, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0080, 0x0000,}, // Display Position - Partial Display 1 (R80h)    Page 35, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0081, 0x0000,}, // RAM Address Start - Partial Display 1 (R81h)   Page 35, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0082, 0x0000,}, // RAM Address End - Partial Display 1 (R82h)     Page 36, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0083, 0x0000,}, // Display Position - Partial Display 2 (R83h)    Page 36, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0084, 0x0000,}, // RAM Address Start - Partial Display 2 (R84h)   Page 36, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0085, 0x0000,}, // RAM Address End - Partial Display 2 (R85h)     Page 36, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0090, 0x0010,}, // Panel Interface Control 1 (R90h)               Page 36, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0092, 0x0000,}, // Panel Interface Control 2 (R92h)               Page 37, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0093, 0x0103,}, // Panel Interface control 3 (R93h)               Page 38, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0095, 0x0210,}, // Panel Interface control 4 (R95h)               Page 38, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0097, 0x0000,}, // Panel Interface Control 5 (R97h)               Page 40, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0098, 0x0000,}, // Panel Interface Control 6 (R98h)               Page 41, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0007, 0x0173,}, // Display Control (R07h)                         Page 16, SPFD5408B Datasheet
-+      {LCD_STEP_DONE, 0, 0},
-+};
-+
-+const struct ubicom32lcd_panel cfaf240320ktts_0 = {
-+      .desc           = "CFAF240320KTTS",
-+      .init_seq       = cfaf240320ktts_init_0,
-+      .horz_reg       = 0x20,
-+      .vert_reg       = 0x21,
-+      .gram_reg       = 0x22,
-+      .xres           = 240,
-+      .yres           = 320,
-+      .stride         = 240,
-+      .id             = 0x5408,
-+};
-+#endif
-+
-+#ifdef CONFIG_LCD_UBICOM32_CFAF240320KTTS_180
-+static const struct ubicom32lcd_step cfaf240320ktts_init_180[] = {
-+      {LCD_STEP_CMD_DATA, 0x0001, 0x0000,}, // Driver Output Control Register (R01h)          Page 14, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0002, 0x0700,}, // LCD Driving Waveform Control (R02h)            Page 15, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0003, 0x5000,}, // Entry Mode (R03h)                              180 degrees
-+      {LCD_STEP_CMD_DATA, 0x0004, 0x0000,}, // Scaling Control register (R04h)                Page 16, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0008, 0x0207,}, // Display Control 2 (R08h)                       Page 17, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0009, 0x0000,}, // Display Control 3 (R09h)                       Page 18, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x000A, 0x0000,}, // Frame Cycle Control (R0Ah)                     Page 19, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x000C, 0x0000,}, // External Display Interface Control 1 (R0Ch)    Page 20, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x000D, 0x0000,}, // Frame Maker Position (R0Dh)                    Page 21, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x000F, 0x0000,}, // External Display Interface Control 2 (R0Fh)    Page 21, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0010, 0x0000,}, // Power Control 1 (R10h)                         Page 22, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h)                         Page 23, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0012, 0x0000,}, // Power Control 3 (R12h)                         Page 24, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0013, 0x0000,}, // Power Control 4 (R13h)                         Page 25, SPFD5408B Datasheet
-+      {LCD_STEP_SLEEP, 0, 200},
-+      {LCD_STEP_CMD_DATA, 0x0007, 0x0101,}, // Display Control (R07h)                         Page 16, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0010, 0x12B0,}, // Power Control 1 (R10h)                         Page 22, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0011, 0x0007,}, // Power Control 2 (R11h)                         Page 23, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0012, 0x01BB,}, // Power Control 3 (R12h)                         Page 24, SPFD5408B Datasheet
-+      {LCD_STEP_SLEEP, 0, 50},
-+      {LCD_STEP_CMD_DATA, 0x0013, 0x1300,}, // Power Control 4 (R13h)                         Page 25, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0029, 0x0010,}, // NVM read data 2 (R29h)                         Page 30, SPFD5408B Datasheet
-+      {LCD_STEP_SLEEP, 0, 50},
-+      {LCD_STEP_CMD_DATA, 0x0030, 0x000A,}, // Gamma Control 1                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0031, 0x1326,}, // Gamma Control 2                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0032, 0x0A29,}, // Gamma Control 3                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0033, 0x290A,}, // Gamma Control 4                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0034, 0x2613,}, // Gamma Control 5                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0035, 0x0A0A,}, // Gamma Control 6                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0036, 0x1E03,}, // Gamma Control 7                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0037, 0x031E,}, // Gamma Control 8                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0038, 0x0706,}, // Gamma Control 9                                Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0039, 0x0303,}, // Gamma Control 10                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x003A, 0x0E04,}, // Gamma Control 11                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x003B, 0x0E01,}, // Gamma Control 12                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x003C, 0x010E,}, // Gamma Control 13                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x003D, 0x040E,}, // Gamma Control 14                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x003E, 0x0303,}, // Gamma Control 15                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x003F, 0x0607,}, // Gamma Control 16                               Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0050, 0x0000,}, // Window Horizontal RAM Address Start (R50h)     Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0051, 0x00EF,}, // Window Horizontal RAM Address End (R51h)       Page 32, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0052, 0x0000,}, // Window Vertical RAM Address Start (R52h)       Page 33, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0053, 0x013F,}, // Window Vertical RAM Address End (R53h)         Page 33, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0060, 0x2700,}, // Driver Output Control (R60h)                   Page 33, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0061, 0x0001,}, // Driver Output Control (R61h)                   Page 35, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x006A, 0x0000,}, // Vertical Scroll Control (R6Ah)                 Page 35, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0080, 0x0000,}, // Display Position - Partial Display 1 (R80h)    Page 35, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0081, 0x0000,}, // RAM Address Start - Partial Display 1 (R81h)   Page 35, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0082, 0x0000,}, // RAM Address End - Partial Display 1 (R82h)     Page 36, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0083, 0x0000,}, // Display Position - Partial Display 2 (R83h)    Page 36, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0084, 0x0000,}, // RAM Address Start - Partial Display 2 (R84h)   Page 36, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0085, 0x0000,}, // RAM Address End - Partial Display 2 (R85h)     Page 36, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0090, 0x0010,}, // Panel Interface Control 1 (R90h)               Page 36, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0092, 0x0000,}, // Panel Interface Control 2 (R92h)               Page 37, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0093, 0x0103,}, // Panel Interface control 3 (R93h)               Page 38, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0095, 0x0210,}, // Panel Interface control 4 (R95h)               Page 38, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0097, 0x0000,}, // Panel Interface Control 5 (R97h)               Page 40, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0098, 0x0000,}, // Panel Interface Control 6 (R98h)               Page 41, SPFD5408B Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0007, 0x0173,}, // Display Control (R07h)                         Page 16, SPFD5408B Datasheet
-+      {LCD_STEP_DONE, 0, 0},
-+};
-+
-+const struct ubicom32lcd_panel cfaf240320ktts_180 = {
-+      .desc           = "CFAF240320KTTS 180",
-+      .init_seq       = cfaf240320ktts_init_180,
-+      .horz_reg       = 0x20,
-+      .vert_reg       = 0x21,
-+      .gram_reg       = 0x22,
-+      .xres           = 240,
-+      .yres           = 320,
-+      .stride         = 240,
-+      .id             = 0x5408,
-+};
-+#endif
-+
-+#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_P
-+static const struct ubicom32lcd_step tft2n0369ep_init[] = {
-+      {LCD_STEP_CMD_DATA, 0x0028, 0x0006},
-+      {LCD_STEP_CMD_DATA, 0x0000, 0x0001},
-+      {LCD_STEP_SLEEP, 0, 15},
-+      {LCD_STEP_CMD_DATA, 0x002B, 0x9532},
-+      {LCD_STEP_CMD_DATA, 0x0003, 0xAAAC},
-+      {LCD_STEP_CMD_DATA, 0x000C, 0x0002},
-+      {LCD_STEP_CMD_DATA, 0x000D, 0x000A},
-+      {LCD_STEP_CMD_DATA, 0x000E, 0x2C00},
-+      {LCD_STEP_CMD_DATA, 0x001E, 0x00AA},
-+      {LCD_STEP_CMD_DATA, 0x0025, 0x8000},
-+      {LCD_STEP_SLEEP, 0, 15},
-+      {LCD_STEP_CMD_DATA, 0x0001, 0x2B3F},
-+      {LCD_STEP_CMD_DATA, 0x0002, 0x0600},
-+      {LCD_STEP_CMD_DATA, 0x0010, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0011, 0x6030},
-+      {LCD_STEP_SLEEP, 0, 20},
-+      {LCD_STEP_CMD_DATA, 0x0005, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0006, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0016, 0xEF1C},
-+      {LCD_STEP_CMD_DATA, 0x0017, 0x0003},
-+      {LCD_STEP_CMD_DATA, 0x0007, 0x0233},
-+      {LCD_STEP_CMD_DATA, 0x000B, 0x5312},
-+      {LCD_STEP_CMD_DATA, 0x000F, 0x0000},
-+      {LCD_STEP_SLEEP, 0, 20},
-+      {LCD_STEP_CMD_DATA, 0x0041, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0042, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0048, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0049, 0x013F},
-+      {LCD_STEP_CMD_DATA, 0x0044, 0xEF00},
-+      {LCD_STEP_CMD_DATA, 0x0045, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0046, 0x013F},
-+      {LCD_STEP_CMD_DATA, 0x004A, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x004B, 0x0000},
-+      {LCD_STEP_SLEEP, 0, 20},
-+      {LCD_STEP_CMD_DATA, 0x0030, 0x0707},
-+      {LCD_STEP_CMD_DATA, 0x0031, 0x0704},
-+      {LCD_STEP_CMD_DATA, 0x0032, 0x0204},
-+      {LCD_STEP_CMD_DATA, 0x0033, 0x0201},
-+      {LCD_STEP_CMD_DATA, 0x0034, 0x0203},
-+      {LCD_STEP_CMD_DATA, 0x0035, 0x0204},
-+      {LCD_STEP_CMD_DATA, 0x0036, 0x0204},
-+      {LCD_STEP_CMD_DATA, 0x0037, 0x0502},
-+      {LCD_STEP_CMD_DATA, 0x003A, 0x0302},
-+      {LCD_STEP_CMD_DATA, 0x003B, 0x0500},
-+      {LCD_STEP_SLEEP, 0, 20},
-+      {LCD_STEP_CMD_DATA, 0x0044, 239 << 8 | 0},
-+      {LCD_STEP_CMD_DATA, 0x0045, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0046, 319},
-+      {LCD_STEP_DONE, 0, 0},
-+};
-+
-+const struct ubicom32lcd_panel tft2n0369ep = {
-+      .desc           = "TFT2N0369E-Portrait",
-+      .init_seq       = tft2n0369ep_init,
-+      .horz_reg       = 0x4e,
-+      .vert_reg       = 0x4f,
-+      .gram_reg       = 0x22,
-+      .xres           = 240,
-+      .yres           = 320,
-+      .stride         = 240,
-+      .id             = 0x8989,
-+};
-+#endif
-+
-+#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_L
-+static const struct ubicom32lcd_step tft2n0369e_init[] = {
-+      {LCD_STEP_CMD_DATA, 0x0028, 0x0006},
-+      {LCD_STEP_CMD_DATA, 0x0000, 0x0001},
-+      {LCD_STEP_SLEEP, 0, 15},
-+      {LCD_STEP_CMD_DATA, 0x002B, 0x9532},
-+      {LCD_STEP_CMD_DATA, 0x0003, 0xAAAC},
-+      {LCD_STEP_CMD_DATA, 0x000C, 0x0002},
-+      {LCD_STEP_CMD_DATA, 0x000D, 0x000A},
-+      {LCD_STEP_CMD_DATA, 0x000E, 0x2C00},
-+      {LCD_STEP_CMD_DATA, 0x001E, 0x00AA},
-+      {LCD_STEP_CMD_DATA, 0x0025, 0x8000},
-+      {LCD_STEP_SLEEP, 0, 15},
-+      {LCD_STEP_CMD_DATA, 0x0001, 0x2B3F},
-+      {LCD_STEP_CMD_DATA, 0x0002, 0x0600},
-+      {LCD_STEP_CMD_DATA, 0x0010, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0011, 0x60A8},
-+      {LCD_STEP_SLEEP, 0, 20},
-+      {LCD_STEP_CMD_DATA, 0x0005, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0006, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0016, 0xEF1C},
-+      {LCD_STEP_CMD_DATA, 0x0017, 0x0003},
-+      {LCD_STEP_CMD_DATA, 0x0007, 0x0233},
-+      {LCD_STEP_CMD_DATA, 0x000B, 0x5312},
-+      {LCD_STEP_CMD_DATA, 0x000F, 0x0000},
-+      {LCD_STEP_SLEEP, 0, 20},
-+      {LCD_STEP_CMD_DATA, 0x0041, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0042, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0048, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0049, 0x013F},
-+      {LCD_STEP_CMD_DATA, 0x0044, 0xEF00},
-+      {LCD_STEP_CMD_DATA, 0x0045, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0046, 0x013F},
-+      {LCD_STEP_CMD_DATA, 0x004A, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x004B, 0x0000},
-+      {LCD_STEP_SLEEP, 0, 20},
-+      {LCD_STEP_CMD_DATA, 0x0030, 0x0707},
-+      {LCD_STEP_CMD_DATA, 0x0031, 0x0704},
-+      {LCD_STEP_CMD_DATA, 0x0032, 0x0204},
-+      {LCD_STEP_CMD_DATA, 0x0033, 0x0201},
-+      {LCD_STEP_CMD_DATA, 0x0034, 0x0203},
-+      {LCD_STEP_CMD_DATA, 0x0035, 0x0204},
-+      {LCD_STEP_CMD_DATA, 0x0036, 0x0204},
-+      {LCD_STEP_CMD_DATA, 0x0037, 0x0502},
-+      {LCD_STEP_CMD_DATA, 0x003A, 0x0302},
-+      {LCD_STEP_CMD_DATA, 0x003B, 0x0500},
-+      {LCD_STEP_SLEEP, 0, 20},
-+      {LCD_STEP_CMD_DATA, 0x0044, 239 << 8 | 0},
-+      {LCD_STEP_CMD_DATA, 0x0045, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0046, 319},
-+      {LCD_STEP_DONE, 0, 0},
-+};
-+
-+const struct ubicom32lcd_panel tft2n0369e = {
-+      .desc           = "TFT2N0369E-Landscape",
-+      .init_seq       = tft2n0369e_init,
-+      .horz_reg       = 0x4e,
-+      .vert_reg       = 0x4f,
-+      .gram_reg       = 0x22,
-+      .xres           = 320,
-+      .yres           = 240,
-+      .stride         = 320,
-+      .id             = 0x8989,
-+};
-+#endif
-+
-+#ifdef CONFIG_LCD_UBICOM32_CFAF240400D
-+static const struct ubicom32lcd_step cfaf240400d_init[] = {
-+      {LCD_STEP_CMD_DATA, 0x0606, 0x0000},    // Pin Control (R606h)          // Page 41 of SPFD5420A Datasheet
-+      {LCD_STEP_SLEEP, 0, 50},
-+      {LCD_STEP_CMD_DATA, 0x0007, 0x0001},    // Display Control 1 (R007h)    // Page 16 of SPFD5420A Datasheet
-+      {LCD_STEP_SLEEP, 0, 50},
-+      {LCD_STEP_CMD_DATA, 0x0110, 0x0001},    // Power Control 6(R110h)       // Page 30 of SPFD5420A Datasheet
-+      {LCD_STEP_SLEEP, 0, 50},
-+      {LCD_STEP_CMD_DATA, 0x0100, 0x17B0},    // Power Control 1 (R100h)      // Page 26 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0101, 0x0147},    // Power Control 2 (R101h)      // Page 27 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0102, 0x019D},    // Power Control 3 (R102h)      // Page 28 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0103, 0x3600},    // Power Control 4 (R103h)      // Page 29 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0281, 0x0010},    // NVM read data 2 (R281h)      // Page 34 of SPFD5420A Datasheet
-+      {LCD_STEP_SLEEP, 0, 50},
-+      {LCD_STEP_CMD_DATA, 0x0102, 0x01BD},    // Power Control 3 (R102h)      // Page 28 of SPFD5420A Datasheet
-+      {LCD_STEP_SLEEP, 0, 50},
-+
-+      //--------------- Power control 1~6 ---------------//
-+      {LCD_STEP_CMD_DATA, 0x0100, 0x16B0},    // Power Control 1 (R100h)      // Page 26 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0101, 0x0147},    // Power Control 2 (R101h)      // Page 27 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0102, 0x01BD},    // Power Control 3 (R102h)      // Page 28 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0103, 0x2d00},    // Power Control 4 (R103h)      // Page 29 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0107, 0x0000},    // Power Control 5 (R107h)      // Page 30 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0110, 0x0001},    // Power Control 6(R110h)       // Page 30 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0280, 0x0000},    // NVM read data 1 (R280h)      // Page 33 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0281, 0x0006},    // NVM read data 2 (R281h)      // Page 34 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0282, 0x0000},    // NVM read data 3 (R282h)      // Page 34 of SPFD5420A Datasheet
-+
-+      //------- Gamma 2.2 control (R300h to R30Fh) ------//
-+      {LCD_STEP_CMD_DATA, 0x0300, 0x0101},
-+      {LCD_STEP_CMD_DATA, 0x0301, 0x0b27},
-+      {LCD_STEP_CMD_DATA, 0x0302, 0x132a},
-+      {LCD_STEP_CMD_DATA, 0x0303, 0x2a13},
-+      {LCD_STEP_CMD_DATA, 0x0304, 0x270b},
-+      {LCD_STEP_CMD_DATA, 0x0305, 0x0101},
-+      {LCD_STEP_CMD_DATA, 0x0306, 0x1205},
-+      {LCD_STEP_CMD_DATA, 0x0307, 0x0512},
-+      {LCD_STEP_CMD_DATA, 0x0308, 0x0005},
-+      {LCD_STEP_CMD_DATA, 0x0309, 0x0003},
-+      {LCD_STEP_CMD_DATA, 0x030A, 0x0f04},
-+      {LCD_STEP_CMD_DATA, 0x030B, 0x0f00},
-+      {LCD_STEP_CMD_DATA, 0x030C, 0x000f},
-+      {LCD_STEP_CMD_DATA, 0x030D, 0x040f},
-+      {LCD_STEP_CMD_DATA, 0x030E, 0x0300},
-+      {LCD_STEP_CMD_DATA, 0x030F, 0x0500},
-+
-+      {LCD_STEP_CMD_DATA, 0x0400, 0x3500},    // Base Image Number of Line (R400h)            // Page 36 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0401, 0x0001},    // Base Image Display Control (R401h)           // Page 39 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0404, 0x0000},    // Based Image Vertical Scroll Control (R404h)  // Page 40 of SPFD5420A Datasheet
-+
-+      //--------------- Normal set ---------------//
-+      {LCD_STEP_CMD_DATA, 0x0000, 0x0000},    // ID Read Register (R000h)                     // Page 13 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0001, 0x0100},    // Driver Output Control Register (R001h)       // Page 14 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0002, 0x0100},    // LCD Driving Waveform Control (R002h)         // Page 14 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0003, 0x1030},    // Entry Mode (R003h)                           // Page 15 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0006, 0x0000},    // Display Control 1 (R007h)                    // Page 16 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0008, 0x0808},    // Display Control 2 (R008h)                    // Page 17 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0009, 0x0001},    // Display Control 3 (R009h)                    // Page 18 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x000B, 0x0010},    // Low Power Control (R00Bh)                    // Page 19 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x000C, 0x0000},    // External Display Interface Control 1 (R00Ch) // Page 19 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x000F, 0x0000},    // External Display Interface Control 2 (R00Fh) // Page 20 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0007, 0x0001},    // Display Control 1 (R007h)                    // Page 16 of SPFD5420A Datasheet
-+
-+      //--------------- Panel interface control 1~6 ---------------//
-+      {LCD_STEP_CMD_DATA, 0x0010, 0x0012},    // Panel Interface Control 1 (R010h)            // Page 20 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0011, 0x0202},    // Panel Interface Control 2 (R011h)            // Page 21 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0012, 0x0300},    // Panel Interface control 3 (R012h)            // Page 22 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0020, 0x021E},    // Panel Interface control 4 (R020h)            // Page 22 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0021, 0x0202},    // Panel Interface Control 5 (021Rh)            // Page 24 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0022, 0x0100},    // Panel Interface Control 6 (R022h)            // Page 25 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0090, 0x8000},    // Frame Marker Control (R090h)                 // Page 25 of SPFD5420A Datasheet
-+
-+      //--------------- Partial display ---------------//
-+      {LCD_STEP_CMD_DATA, 0x0210, 0x0000},    // Window Horizontal RAM Address Start (R210h)  // Page 35 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0211, 0x00EF},    // Window Horziontal RAM Address End (R211h)    // Page 35 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0212, 0x0000},    // Window Vertical RAM Address Start (R212h)    // Page 35 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0213, 0x018F},    // Window Vertical RAM Address End (R213h)      // Page 35 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0500, 0x0000},    // Display Position - Partial Display 1 (R500h) // Page 40 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0501, 0x0000},    // RAM Address Start - Partial Display 1 (R501h)// Page 40 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0502, 0x0000},    // RAM Address End - Partail Display 1 (R502h)  // Page 40 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0503, 0x0000},    // Display Position - Partial Display 2 (R503h) // Page 40 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0504, 0x0000},    // RAM Address Start . Partial Display 2 (R504h)// Page 41 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0505, 0x0000},    // RAM Address End . Partial Display 2 (R505h)  // Page 41 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0606, 0x0000},    // Pin Control (R606h)                          // Page 41 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x06F0, 0x0000},    // NVM Access Control (R6F0h)                   // Page 41 of SPFD5420A Datasheet
-+      {LCD_STEP_CMD_DATA, 0x0007, 0x0173},    // Display Control 1 (R007h)                    // Page 16 of SPFD5420A Datasheet
-+      {LCD_STEP_SLEEP, 0, 50},
-+      {LCD_STEP_CMD_DATA, 0x0007, 0x0171},    // Display Control 1 (R007h)                    // Page 16 of SPFD5420A Datasheet
-+      {LCD_STEP_SLEEP, 0, 10},
-+      {LCD_STEP_CMD_DATA, 0x0007, 0x0173},    // Display Control 1 (R007h)                    // Page 16 of SPFD5420A Datasheet
-+      {LCD_STEP_DONE, 0, 0},
-+};
-+
-+const struct ubicom32lcd_panel cfaf240400d = {
-+      .desc           = "CFAF240400D",
-+      .init_seq       = cfaf240400d_init,
-+      .horz_reg       = 0x0200,
-+      .vert_reg       = 0x0201,
-+      .gram_reg       = 0x0202,
-+      .xres           = 240,
-+      .yres           = 400,
-+      .stride         = 240,
-+      .id             = 0x5420,
-+};
-+#endif
-+
-+#ifdef CONFIG_LCD_UBICOM32_CFAF240400F
-+static const struct ubicom32lcd_step cfaf320240f_init[] = {
-+      {LCD_STEP_CMD_DATA, 0x0028, 0x0006},    // VCOM OTP                             Page 55-56 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x0000, 0x0001},    // start Oscillator                     Page 36 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x0010, 0x0000},    // Sleep mode                           Page 49 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x0001, 0x32EF},    // Driver Output Control                Page 36-39 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x0002, 0x0600},    // LCD Driving Waveform Control         Page 40-42 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x0003, 0x6A38},    // Power Control 1                      Page 43-44 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x0011, 0x6870},    // Entry Mode                           Page 50-52 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0X000F, 0x0000},    // Gate Scan Position                   Page 49 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0X000B, 0x5308},    // Frame Cycle Control                  Page 45 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x000C, 0x0003},    // Power Control 2                      Page 47 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x000D, 0x000A},    // Power Control 3                      Page 48 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x000E, 0x2E00},    // Power Control 4                      Page 48 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x001E, 0x00BE},    // Power Control 5                      Page 53 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x0025, 0x8000},    // Frame Frequency Control              Page 53 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x0026, 0x7800},    // Analog setting                       Page 54 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x004E, 0x0000},    // Ram Address Set                      Page 58 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x004F, 0x0000},    // Ram Address Set                      Page 58 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x0012, 0x08D9},    // Sleep mode                           Page 49 of SSD2119 datasheet
-+
-+      // Gamma Control (R30h to R3Bh) -- Page 56 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x0030, 0x0000},
-+      {LCD_STEP_CMD_DATA, 0x0031, 0x0104},
-+      {LCD_STEP_CMD_DATA, 0x0032, 0x0100},
-+      {LCD_STEP_CMD_DATA, 0x0033, 0x0305},
-+      {LCD_STEP_CMD_DATA, 0x0034, 0x0505},
-+      {LCD_STEP_CMD_DATA, 0x0035, 0x0305},
-+      {LCD_STEP_CMD_DATA, 0x0036, 0x0707},
-+      {LCD_STEP_CMD_DATA, 0x0037, 0x0300},
-+      {LCD_STEP_CMD_DATA, 0x003A, 0x1200},
-+      {LCD_STEP_CMD_DATA, 0x003B, 0x0800},
-+
-+      {LCD_STEP_CMD_DATA, 0x0007, 0x0033},    // Display Control                       Page 45 of SSD2119 datasheet
-+
-+      {LCD_STEP_CMD_DATA, 0x0044, 0xEF00},    // Vertical RAM address position         Page 57 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x0045, 0x0000},    // Horizontal RAM address position       Page 57 of SSD2119 datasheet
-+      {LCD_STEP_CMD_DATA, 0x0046, 0x013F},    // Horizontal RAM address position       Page 57 of SSD2119 datasheet
-+
-+      {LCD_STEP_SLEEP, 0, 150},
-+
-+      {LCD_STEP_DONE, 0, 0},
-+};
-+
-+const struct ubicom32lcd_panel cfaf320240f = {
-+      .desc           = "CFAF320240F",
-+      .init_seq       = cfaf320240f_init,
-+      .horz_reg       = 0x4e,
-+      .vert_reg       = 0x4f,
-+      .gram_reg       = 0x22,
-+      .xres           = 320,
-+      .yres           = 240,
-+      .stride         = 320,
-+      .id             = 0x9919,
-+};
-+#endif
-+
-+const struct ubicom32lcd_panel *ubicom32lcd_panels[] = {
-+#ifdef CONFIG_LCD_UBICOM32_CFAF240400KTTS_180
-+      &cfaf240320ktts_180,
-+#endif
-+#ifdef CONFIG_LCD_UBICOM32_CFAF240400KTTS
-+      &cfaf240320ktts_0,
-+#endif
-+#ifdef CONFIG_LCD_UBICOM32_CFAF240400D
-+      &cfaf240400d,
-+#endif
-+#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_P
-+      &tft2n0369ep,
-+#endif
-+#ifdef CONFIG_LCD_UBICOM32_TFT2N0369E_L
-+      &tft2n0369e,
-+#endif
-+#ifdef CONFIG_LCD_UBICOM32_CFAF240400F
-+      &cfaf320240f,
-+#endif
-+      NULL,
-+};
-+
-+#endif
---- /dev/null
-+++ b/drivers/video/backlight/ubicom32lcdpower.c
-@@ -0,0 +1,194 @@
-+/*
-+ * drivers/video/backlight/ubicom32lcdpowerpower.c
-+ *    LCD power driver for the Ubicom32 platform
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/lcd.h>
-+#include <linux/fb.h>
-+#include <linux/gpio.h>
-+
-+#include <asm/ubicom32lcdpower.h>
-+#include <asm/ip5000.h>
-+
-+#define DRIVER_NAME                   "ubicom32lcdpower"
-+
-+struct ubicom32lcdpower_data {
-+      /*
-+       * Pointer to the platform data structure.  Keep this around since we need values
-+       * from it to set the backlight intensity.
-+       */
-+      const struct ubicom32lcdpower_platform_data     *pdata;
-+
-+      /*
-+       * LCD device, we have to save this for use when we remove ourselves.
-+       */
-+      struct lcd_device                       *lcddev;
-+};
-+
-+/*
-+ * ubicom32lcdpower_set_power
-+ */
-+static int ubicom32lcdpower_set_power(struct lcd_device *ld, int power)
-+{
-+      struct ubicom32lcdpower_data *ud = (struct ubicom32lcdpower_data *)lcd_get_data(ld);
-+      if (power == FB_BLANK_UNBLANK) {
-+              gpio_direction_output(ud->pdata->vgh_gpio, ud->pdata->vgh_polarity);
-+              return 0;
-+      }
-+
-+      gpio_direction_output(ud->pdata->vgh_gpio, !ud->pdata->vgh_polarity);
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32lcdpower_get_power
-+ */
-+static int ubicom32lcdpower_get_power(struct lcd_device *ld)
-+{
-+      struct ubicom32lcdpower_data *ud = (struct ubicom32lcdpower_data *)lcd_get_data(ld);
-+      int vgh = gpio_get_value(ud->pdata->vgh_gpio);
-+      if ((vgh && ud->pdata->vgh_polarity) || (!vgh && !ud->pdata->vgh_polarity)) {
-+              return 1;
-+      }
-+
-+      return 0;
-+}
-+
-+static struct lcd_ops ubicom32lcdpower_ops = {
-+      .get_power = ubicom32lcdpower_get_power,
-+      .set_power = ubicom32lcdpower_set_power,
-+};
-+
-+/*
-+ * ubicom32lcdpower_probe
-+ */
-+static int ubicom32lcdpower_probe(struct platform_device *pdev)
-+{
-+      const struct ubicom32lcdpower_platform_data *pdata = pdev->dev.platform_data;
-+      struct ubicom32lcdpower_data *ud;
-+      struct lcd_device *lcddev;
-+      int retval;
-+
-+      /*
-+       * Check to see if we have any platform data, if we don't have a LCD to control
-+       */
-+      if (!pdata) {
-+              return -ENODEV;
-+      }
-+
-+      /*
-+       * Allocate our private data
-+       */
-+      ud = kzalloc(sizeof(struct ubicom32lcdpower_data), GFP_KERNEL);
-+      if (!ud) {
-+              return -ENOMEM;
-+      }
-+
-+      ud->pdata = pdata;
-+
-+      /*
-+       * Request our GPIOs
-+       */
-+      retval = gpio_request(pdata->vgh_gpio, "vgh");
-+      if (retval) {
-+              dev_err(&pdev->dev, "Failed to allocate vgh GPIO\n");
-+              goto fail_gpio;
-+      }
-+
-+      /*
-+       * Register our lcd device
-+       */
-+      lcddev = lcd_device_register(DRIVER_NAME, &pdev->dev, ud, &ubicom32lcdpower_ops);
-+      if (IS_ERR(lcddev)) {
-+              retval = PTR_ERR(lcddev);
-+              goto fail;
-+      }
-+
-+      ud->lcddev = lcddev;
-+      platform_set_drvdata(pdev, ud);
-+
-+      ubicom32lcdpower_set_power(lcddev, FB_BLANK_UNBLANK);
-+
-+      printk(KERN_INFO DRIVER_NAME ": LCD driver started\n");
-+
-+      return 0;
-+
-+fail:
-+      gpio_free(pdata->vgh_gpio);
-+
-+fail_gpio:
-+      platform_set_drvdata(pdev, NULL);
-+      kfree(ud);
-+      return retval;
-+}
-+
-+/*
-+ * ubicom32lcdpower_remove
-+ */
-+static int __exit ubicom32lcdpower_remove(struct platform_device *pdev)
-+{
-+      struct ubicom32lcdpower_data *ud = platform_get_drvdata(pdev);
-+
-+      lcd_device_unregister(ud->lcddev);
-+      platform_set_drvdata(pdev, NULL);
-+      kfree(ud);
-+
-+      return 0;
-+}
-+
-+static struct platform_driver ubicom32lcdpower_driver = {
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+
-+      .remove = __exit_p(ubicom32lcdpower_remove),
-+};
-+
-+/*
-+ * ubicom32lcdpower_init
-+ */
-+static int __init ubicom32lcdpower_init(void)
-+{
-+      return platform_driver_probe(&ubicom32lcdpower_driver, ubicom32lcdpower_probe);
-+}
-+module_init(ubicom32lcdpower_init);
-+
-+/*
-+ * ubicom32lcdpower_exit
-+ */
-+static void __exit ubicom32lcdpower_exit(void)
-+{
-+      platform_driver_unregister(&ubicom32lcdpower_driver);
-+}
-+module_exit(ubicom32lcdpower_exit);
-+
-+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
-+MODULE_DESCRIPTION("Ubicom32 lcd power driver");
-+MODULE_LICENSE("GPL");
---- a/drivers/video/Kconfig
-+++ b/drivers/video/Kconfig
-@@ -609,6 +609,50 @@ config FB_BFIN_T350MCQB
-        This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI
-        It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK.
-+config FB_UBICOM32
-+      tristate "Ubicom32 Frame Buffer driver"
-+      depends on FB && UBICOM32
-+      select FB_CFB_FILLRECT
-+      select FB_CFB_COPYAREA
-+      select FB_CFB_IMAGEBLIT
-+      select FONT_6x11 if FRAMEBUFFER_CONSOLE
-+      help
-+       This is the framebuffer device driver for the Ubicom32 architecture.
-+       You can configure video memory by using kernel command line parameters, for example:
-+              video=ubicomfb:vram_size=512,init_value=0xffff
-+
-+config FB_UBICOM32_PLIO80
-+      tristate "Ubicom32 80 Bus PLIO Frame Buffer driver"
-+      depends on FB && UBICOM32
-+      select FB_CFB_FILLRECT
-+      select FB_CFB_COPYAREA
-+      select FB_CFB_IMAGEBLIT
-+      select FONT_6x11 if FRAMEBUFFER_CONSOLE
-+      select UBICOM32_PLIO
-+      help
-+       This is a framebuffer device driver for the Ubicom32 architecture.
-+       You can configure the xres, yres and vram size (in kilobytes) by using
-+       kernel command line parameters, for example:
-+              video=ubicom32vfb:xres=320,yres=240,vram_size=512
-+
-+config FB_UBICOM32_VIRTUAL
-+      tristate "Ubicom32 Virtual Frame Buffer driver"
-+      depends on FB && UBICOM32
-+      select FB_CFB_FILLRECT
-+      select FB_CFB_COPYAREA
-+      select FB_CFB_IMAGEBLIT
-+      select FONT_6x11 if FRAMEBUFFER_CONSOLE
-+      help
-+       This is a virtual framebuffer device driver for the Ubicom32 architecture.
-+       You can configure the xres, yres and vram size (in kilobytes) by using
-+       kernel command line parameters, for example:
-+              video=ubicom32vfb:xres=320,yres=240,vram_size=512
-+
-+config FB_UBICOM32_VIRTUAL_NOAUTO
-+      bool "Do not automatically load"
-+      depends on FB_UBICOM32_VIRTUAL
-+      help
-+       Select this option to prevent the VFB from automatically loading at boot.
- config FB_STI
-       tristate "HP STI frame buffer device support"
---- a/drivers/video/Makefile
-+++ b/drivers/video/Makefile
-@@ -136,6 +136,10 @@ obj-$(CONFIG_FB_BF54X_LQ043)        += bf54x-
- obj-$(CONFIG_FB_BFIN_T350MCQB)          += bfin-t350mcqb-fb.o
- obj-$(CONFIG_FB_MX3)            += mx3fb.o
-+obj-$(CONFIG_FB_UBICOM32)         += ubicom32fb.o
-+obj-$(CONFIG_FB_UBICOM32_PLIO80)  += ubicom32plio80.o
-+obj-$(CONFIG_FB_UBICOM32_VIRTUAL) += ubicom32vfb.o
-+
- # the test framebuffer is last
- obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
---- /dev/null
-+++ b/drivers/video/ubicom32fb.c
-@@ -0,0 +1,779 @@
-+/*
-+ * drivers/video/ubicom32fb.c
-+ *    Ubicom32 frame buffer driver
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+/*
-+ * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by
-+ * Geert Uytterhoeven.
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/version.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/mm.h>
-+#include <linux/fb.h>
-+#include <linux/init.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/platform_device.h>
-+#include <linux/device.h>
-+#include <linux/uaccess.h>
-+#include <linux/interrupt.h>
-+
-+#include <asm/io.h>
-+#include <asm/ip5000.h>
-+#include <asm/vdc_tio.h>
-+#include <asm/ubicom32fb.h>
-+
-+#define DRIVER_NAME           "ubicom32fb"
-+#define DRIVER_DESCRIPTION    "Ubicom32 frame buffer driver"
-+
-+#define PALETTE_ENTRIES_NO    16
-+
-+/*
-+ * Option variables
-+ *
-+ * vram_size: VRAM size in kilobytes, subject to alignment
-+ */
-+static int vram_size = 0;
-+module_param(vram_size, int, 0);
-+MODULE_PARM_DESC(vram, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment");
-+static int init_value = 0;
-+module_param(init_value, int, 0);
-+MODULE_PARM_DESC(init, "Initial value of the framebuffer (16-bit number).");
-+
-+/*
-+ * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in.
-+ */
-+static struct fb_fix_screeninfo ubicom32fb_fix = {
-+      .id =           "Ubicom32",
-+      .type =         FB_TYPE_PACKED_PIXELS,
-+      .visual =       FB_VISUAL_TRUECOLOR,
-+      .accel =        FB_ACCEL_UBICOM32,
-+};
-+
-+/*
-+ * Filled in at probe time when we find out what the hardware supports
-+ */
-+static struct fb_var_screeninfo ubicom32fb_var;
-+
-+/*
-+ * Private data structure
-+ */
-+struct ubicom32fb_drvdata {
-+      struct fb_info                  *fbinfo;
-+      bool                            cmap_alloc;
-+
-+      /*
-+       * The address of the framebuffer in memory
-+       */
-+      void                            *fb;
-+      void                            *fb_aligned;
-+
-+      /*
-+       * Total size of vram including alignment allowance
-+       */
-+      u32                             total_vram_size;
-+
-+      /*
-+       * Interrupt to set when changing registers
-+       */
-+      u32                             vp_int;
-+
-+      /*
-+       * Optional: Interrupt used by TIO to signal us
-+       */
-+      u32                             rx_int;
-+
-+      /*
-+       * Base address of the regs for VDC_TIO
-+       */
-+      volatile struct vdc_tio_vp_regs *regs;
-+
-+      /*
-+       * non-zero if we are in yuv mode
-+       */
-+      u8_t                            is_yuv;
-+
-+      /*
-+       * Fake palette of 16 colors
-+       */
-+      u32                             pseudo_palette[PALETTE_ENTRIES_NO];
-+
-+      /*
-+       * Wait queue and lock used to block when we need to wait
-+       * for something to happen.
-+       */
-+      wait_queue_head_t               waitq;
-+      struct mutex                    lock;
-+
-+};
-+
-+/*
-+ * ubicom32fb_set_next_frame
-+ *    Sets the next frame buffer to display
-+ *
-+ * if sync is TRUE then this function will block until the hardware
-+ * acknowledges the change
-+ */
-+static inline void ubicom32fb_set_next_frame(struct ubicom32fb_drvdata *ud, void *fb, u8_t sync)
-+{
-+      ud->regs->next_frame_flags = ud->is_yuv ? VDCTIO_NEXT_FRAME_FLAG_YUV : 0;
-+      ud->regs->next_frame = (void *)((u32_t)fb | 1);
-+
-+      /*
-+       * If we have interrupts, then we can wait on it
-+       */
-+      if (ud->rx_int != -1) {
-+              DEFINE_WAIT(wait);
-+              unsigned long flags;
-+
-+              spin_lock_irqsave(&ud->lock, flags);
-+              prepare_to_wait(&ud->waitq, &wait, TASK_INTERRUPTIBLE);
-+              spin_unlock_irqrestore(&ud->lock, flags);
-+              schedule();
-+              finish_wait(&ud->waitq, &wait);
-+              return;
-+      }
-+
-+      /*
-+       * No interrupt, we will just spin here
-+       */
-+      while (sync && ((u32_t)ud->regs->next_frame & 1));
-+}
-+
-+/*
-+ * ubicom32fb_send_command
-+ *    Sends a command/data pair to the VDC
-+ */
-+static inline void ubicom32fb_send_command(struct ubicom32fb_drvdata *ud, u16 command, u8_t block)
-+{
-+      ud->regs->command = command;
-+      ubicom32_set_interrupt(ud->vp_int);
-+      while (block && ud->regs->command);
-+}
-+
-+/*
-+ * ubicom32fb_ioctl
-+ *    Handles any ioctls sent to us
-+ */
-+static int ubicom32fb_ioctl(struct fb_info *fbi, unsigned int cmd,
-+                     unsigned long arg)
-+{
-+      struct ubicom32fb_drvdata *ud = (struct ubicom32fb_drvdata *)fbi->par;
-+      void __user *argp = (void __user *)arg;
-+      int retval = -EFAULT;
-+
-+      switch (cmd) {
-+      case UBICOM32FB_IOCTL_SET_NEXT_FRAME_SYNC:
-+              // check alignment, return -EINVAL if necessary
-+              ubicom32fb_set_next_frame(ud, argp, 1);
-+              retval = 0;
-+              break;
-+
-+      case UBICOM32FB_IOCTL_SET_NEXT_FRAME:
-+              // check alignment, return -EINVAL if necessary
-+              ubicom32fb_set_next_frame(ud, argp, 0);
-+              retval = 0;
-+              break;
-+
-+      case UBICOM32FB_IOCTL_SET_MODE:
-+              if (!(ud->regs->caps & VDCTIO_CAPS_SUPPORTS_SCALING)) {
-+                      break;
-+              } else {
-+                      struct ubicom32fb_mode mode;
-+                      volatile struct vdc_tio_vp_regs *regs = ud->regs;
-+                      u32_t flags = 0;
-+
-+                      if (copy_from_user(&mode, argp, sizeof(mode))) {
-+                              break;
-+                      }
-+
-+                      regs->x_in = mode.width;
-+                      regs->y_in = mode.height;
-+                      regs->x_out = regs->xres;
-+                      regs->y_out = regs->yres;
-+                      if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_SCAN_ORDER) {
-+                              flags |= VDCTIO_SCALE_FLAG_YUV_SCAN_ORDER;
-+                      }
-+                      if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV_BLOCK_ORDER) {
-+                              flags |= VDCTIO_SCALE_FLAG_YUV_BLOCK_ORDER;
-+                      }
-+                      ud->is_yuv = mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_YUV;
-+                      if (ud->is_yuv) {
-+                              flags |= VDCTIO_SCALE_FLAG_YUV;
-+                      }
-+                      if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_16_255) {
-+                              flags |= VDCTIO_SCALE_FLAG_VRANGE_16_255;
-+                      }
-+                      if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_VRANGE_0_255) {
-+                              flags |= VDCTIO_SCALE_FLAG_VRANGE_0_255;
-+                      }
-+                      if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_VSUB) {
-+                              flags |= VDCTIO_SCALE_FLAG_VSUB;
-+                      }
-+                      if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_2_1) {
-+                              flags |= VDCTIO_SCALE_FLAG_HSUB_2_1;
-+                      }
-+                      if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_HSUB_1_1) {
-+                              flags |= VDCTIO_SCALE_FLAG_HSUB_1_1;
-+                      }
-+                      if (mode.flags & UBICOM32FB_IOCTL_SET_MODE_FLAG_SCALE_ENABLE) {
-+                              flags |= VDCTIO_SCALE_FLAG_ENABLE;
-+                      }
-+                      if (mode.next_frame) {
-+                              flags |= VDCTIO_SCALE_FLAG_SET_FRAME_BUFFER;
-+                              regs->next_frame = mode.next_frame;
-+                      }
-+
-+                      regs->scale_flags = flags;
-+                      ubicom32fb_send_command(ud, VDCTIO_COMMAND_SET_SCALE_MODE, 1);
-+                      retval = 0;
-+                      break;
-+              }
-+
-+      default:
-+              retval = -ENOIOCTLCMD;
-+              break;
-+      }
-+
-+      return retval;
-+}
-+
-+/*
-+ * ubicom32fb_interrupt
-+ *    Called by the OS when the TIO has set the rx_int
-+ */
-+static irqreturn_t ubicom32fb_interrupt(int vec, void *appdata)
-+{
-+      struct ubicom32fb_drvdata *ud = (struct ubicom32fb_drvdata *)appdata;
-+
-+      spin_lock(&ud->lock);
-+      if (waitqueue_active(&ud->waitq)) {
-+              wake_up(&ud->waitq);
-+      }
-+      spin_unlock(&ud->lock);
-+
-+      return IRQ_HANDLED;
-+}
-+
-+/*
-+ * ubicom32fb_pan_display
-+ *    Pans the display to a given location.  Supports only y direction panning.
-+ */
-+static int ubicom32fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
-+{
-+      struct ubicom32fb_drvdata *ud = (struct ubicom32fb_drvdata *)fbi->par;
-+      void *new_addr;
-+
-+      /*
-+       * Get the last y line that would be displayed.  Since we don't support YWRAP,
-+       * it must be less than our virtual y size.
-+       */
-+      u32 lasty = var->yoffset + var->yres;
-+      if (lasty > fbi->var.yres_virtual) {
-+              /*
-+               * We would fall off the end of our frame buffer if we panned here.
-+               */
-+              return -EINVAL;
-+      }
-+
-+      if (var->xoffset) {
-+              /*
-+               * We don't support panning in the x direction
-+               */
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Everything looks sane, go ahead and pan
-+       *
-+       * We have to calculate a new address for the VDC to look at
-+       */
-+      new_addr = ud->fb_aligned + (var->yoffset * fbi->fix.line_length);
-+
-+      /*
-+       * Send down the command.  The buffer will switch at the next vertical blank
-+       */
-+      ubicom32fb_set_next_frame(ud, (void *)new_addr, 0);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32fb_setcolreg
-+ *    Sets a color in our virtual palette
-+ */
-+static int ubicom32fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi)
-+{
-+      u32 *palette = fbi->pseudo_palette;
-+
-+      if (regno >= PALETTE_ENTRIES_NO) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * We only use 8 bits from each color
-+       */
-+      red >>= 8;
-+      green >>= 8;
-+      blue >>= 8;
-+
-+      /*
-+       * Convert any grayscale values
-+       */
-+      if (fbi->var.grayscale) {
-+              u16 gray = red + green + blue;
-+              gray += (gray >> 2) + (gray >> 3) - (gray >> 7);
-+              gray >>= 2;
-+              if (gray > 255) {
-+                      gray = 255;
-+              }
-+              red = gray;
-+              blue = gray;
-+              green = gray;
-+      }
-+
-+      palette[regno] = (red << fbi->var.red.offset) | (green << fbi->var.green.offset) |
-+                       (blue << fbi->var.blue.offset);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32fb_mmap
-+ */
-+static int ubicom32fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-+{
-+      struct ubicom32fb_drvdata *drvdata = (struct ubicom32fb_drvdata *)info->par;
-+
-+      vma->vm_start = (unsigned long)(drvdata->fb_aligned);
-+
-+      vma->vm_end = vma->vm_start + info->fix.smem_len;
-+
-+      /* For those who don't understand how mmap works, go read
-+       *   Documentation/nommu-mmap.txt.
-+       * For those that do, you will know that the VM_MAYSHARE flag
-+       * must be set in the vma->vm_flags structure on noMMU
-+       *   Other flags can be set, and are documented in
-+       *   include/linux/mm.h
-+       */
-+
-+      vma->vm_flags |=  VM_MAYSHARE | VM_SHARED;
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32fb_blank
-+ */
-+static int ubicom32fb_blank(int blank_mode, struct fb_info *fbi)
-+{
-+      return 0;
-+#if 0
-+      struct ubicom32fb_drvdata *drvdata = to_ubicom32fb_drvdata(fbi);
-+
-+      switch (blank_mode) {
-+      case FB_BLANK_UNBLANK:
-+              /* turn on panel */
-+              ubicom32fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
-+              break;
-+
-+      case FB_BLANK_NORMAL:
-+      case FB_BLANK_VSYNC_SUSPEND:
-+      case FB_BLANK_HSYNC_SUSPEND:
-+      case FB_BLANK_POWERDOWN:
-+              /* turn off panel */
-+              ubicom32fb_out_be32(drvdata, REG_CTRL, 0);
-+      default:
-+              break;
-+
-+      }
-+      return 0; /* success */
-+#endif
-+}
-+
-+static struct fb_ops ubicom32fb_ops =
-+{
-+      .owner                  = THIS_MODULE,
-+      .fb_pan_display         = ubicom32fb_pan_display,
-+      .fb_setcolreg           = ubicom32fb_setcolreg,
-+      .fb_blank               = ubicom32fb_blank,
-+      .fb_mmap                = ubicom32fb_mmap,
-+      .fb_ioctl               = ubicom32fb_ioctl,
-+      .fb_fillrect            = cfb_fillrect,
-+      .fb_copyarea            = cfb_copyarea,
-+      .fb_imageblit           = cfb_imageblit,
-+};
-+
-+/*
-+ * ubicom32fb_release
-+ */
-+static int ubicom32fb_release(struct device *dev)
-+{
-+      struct ubicom32fb_drvdata *ud = dev_get_drvdata(dev);
-+
-+#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
-+      //ubicom32fb_blank(VESA_POWERDOWN, &drvdata->info);
-+#endif
-+
-+      unregister_framebuffer(ud->fbinfo);
-+
-+      if (ud->cmap_alloc) {
-+              fb_dealloc_cmap(&ud->fbinfo->cmap);
-+      }
-+
-+      if (ud->fb) {
-+              kfree(ud->fb);
-+      }
-+
-+      if (ud->rx_int != -1) {
-+              free_irq(ud->rx_int, ud);
-+      }
-+
-+      /*
-+       * Turn off the display
-+       */
-+      //ubicom32fb_out_be32(drvdata, REG_CTRL, 0);
-+      //iounmap(drvdata->regs);
-+
-+      framebuffer_release(ud->fbinfo);
-+      dev_set_drvdata(dev, NULL);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32fb_platform_probe
-+ */
-+static int __init ubicom32fb_platform_probe(struct platform_device *pdev)
-+{
-+      struct ubicom32fb_drvdata *ud;
-+      struct resource *irq_resource_rx;
-+      struct resource *irq_resource_tx;
-+      struct resource *mem_resource;
-+      struct fb_info *fbinfo;
-+      int rc;
-+      size_t fbsize;
-+      struct device *dev = &pdev->dev;
-+      int offset;
-+      struct vdc_tio_vp_regs *regs;
-+
-+      /*
-+       * Get our resources
-+       */
-+      irq_resource_tx = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-+      if (!irq_resource_tx) {
-+              dev_err(dev, "No tx IRQ resource assigned\n");
-+              return -ENODEV;
-+      }
-+
-+      irq_resource_rx = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
-+      if (!irq_resource_rx) {
-+              dev_err(dev, "No rx IRQ resource assigned\n");
-+              return -ENODEV;
-+      }
-+
-+      mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+      if (!mem_resource || !mem_resource->start) {
-+              dev_err(dev, "No mem resource assigned\n");
-+              return -ENODEV;
-+      }
-+      regs = (struct vdc_tio_vp_regs *)mem_resource->start;
-+      if (regs->version != VDCTIO_VP_VERSION) {
-+              dev_err(dev, "VDCTIO is not compatible with this driver tio:%x drv:%x\n",
-+                      regs->version, VDCTIO_VP_VERSION);
-+              return -ENODEV;
-+      }
-+
-+      /*
-+       * This is the minimum VRAM size
-+       */
-+      fbsize = regs->xres * regs->yres * (regs->bpp / 8);
-+      if (!vram_size) {
-+              vram_size = (fbsize + 1023) / 1024;
-+      } else {
-+              if (fbsize > (vram_size * 1024)) {
-+                      dev_err(dev, "Not enough VRAM for display, need >= %u bytes\n", fbsize);
-+                      return -ENOMEM; // should be ebadparam?
-+              }
-+      }
-+
-+      /*
-+       * Allocate the framebuffer instance + our private data
-+       */
-+      fbinfo = framebuffer_alloc(sizeof(struct ubicom32fb_drvdata), &pdev->dev);
-+      if (!fbinfo) {
-+              dev_err(dev, "Not enough memory to allocate instance.\n");
-+              return -ENOMEM;
-+      }
-+
-+      /*
-+       * Fill in our private data.
-+       */
-+      ud = (struct ubicom32fb_drvdata *)fbinfo->par;
-+      ud->fbinfo = fbinfo;
-+      ud->regs = (struct vdc_tio_vp_regs *)(mem_resource->start);
-+      dev_set_drvdata(dev, ud);
-+
-+      ud->vp_int = irq_resource_tx->start;
-+
-+      /*
-+       * If we were provided an rx_irq then we need to init the appropriate
-+       * queues, locks, and functions.
-+       */
-+      ud->rx_int = -1;
-+      if (irq_resource_rx->start != DEVTREE_IRQ_NONE) {
-+              init_waitqueue_head(&ud->waitq);
-+              mutex_init(&ud->lock);
-+              if (request_irq(ud->rx_int, ubicom32fb_interrupt, IRQF_SHARED, "ubicom32fb_rx", ud)) {
-+                      dev_err(dev, "Couldn't request rx IRQ\n");
-+                      rc = -ENOMEM;
-+                      goto fail;
-+              }
-+              ud->rx_int = irq_resource_rx->start;
-+      }
-+
-+      /*
-+       * Allocate and align the requested amount of VRAM
-+       */
-+      ud->total_vram_size = (vram_size * 1024) + regs->fb_align;
-+      ud->fb = kmalloc(ud->total_vram_size, GFP_KERNEL);
-+      if (ud->fb == NULL) {
-+              dev_err(dev, "Couldn't allocate VRAM\n");
-+              rc = -ENOMEM;
-+              goto fail;
-+      }
-+
-+      offset = (u32_t)ud->fb & (regs->fb_align - 1);
-+      if (!offset) {
-+              ud->fb_aligned = ud->fb;
-+      } else {
-+              offset = regs->fb_align - offset;
-+              ud->fb_aligned = ud->fb + offset;
-+      }
-+
-+      /*
-+       * Clear the entire frame buffer
-+       */
-+      if (!init_value) {
-+              memset(ud->fb_aligned, 0, vram_size * 1024);
-+      } else {
-+              unsigned short *p = ud->fb_aligned;
-+              int i;
-+              for (i = 0; i < ((vram_size * 1024) / sizeof(u16_t)); i++) {
-+                      *p++ = init_value;
-+              }
-+      }
-+
-+      /*
-+       * Fill in the fb_var_screeninfo structure
-+       */
-+      memset(&ubicom32fb_var, 0, sizeof(ubicom32fb_var));
-+      ubicom32fb_var.bits_per_pixel = regs->bpp;
-+      ubicom32fb_var.red.offset = regs->rshift;
-+      ubicom32fb_var.green.offset = regs->gshift;
-+      ubicom32fb_var.blue.offset = regs->bshift;
-+      ubicom32fb_var.red.length = regs->rbits;
-+      ubicom32fb_var.green.length = regs->gbits;
-+      ubicom32fb_var.blue.length = regs->bbits;
-+      ubicom32fb_var.activate = FB_ACTIVATE_NOW;
-+
-+#if 0
-+      /*
-+       * Turn on the display
-+       */
-+      ud->reg_ctrl_default = REG_CTRL_ENABLE;
-+      if (regs->rotate_screen)
-+              ud->reg_ctrl_default |= REG_CTRL_ROTATE;
-+      ubicom32fb_out_be32(ud, REG_CTRL, ud->reg_ctrl_default);
-+#endif
-+
-+      /*
-+       * Fill in the fb_info structure
-+       */
-+      ud->fbinfo->device = dev;
-+      ud->fbinfo->screen_base = (void *)ud->fb_aligned;
-+      ud->fbinfo->fbops = &ubicom32fb_ops;
-+      ud->fbinfo->fix = ubicom32fb_fix;
-+      ud->fbinfo->fix.smem_start = (u32)ud->fb_aligned;
-+      ud->fbinfo->fix.smem_len = vram_size * 1024;
-+      ud->fbinfo->fix.line_length = regs->xres * (regs->bpp / 8);
-+      ud->fbinfo->fix.mmio_start = (u32)regs;
-+      ud->fbinfo->fix.mmio_len = sizeof(struct vdc_tio_vp_regs);
-+
-+      /*
-+       * We support panning in the y direction only
-+       */
-+      ud->fbinfo->fix.xpanstep = 0;
-+      ud->fbinfo->fix.ypanstep = 1;
-+
-+      ud->fbinfo->pseudo_palette = ud->pseudo_palette;
-+      ud->fbinfo->flags = FBINFO_DEFAULT;
-+      ud->fbinfo->var = ubicom32fb_var;
-+      ud->fbinfo->var.xres = regs->xres;
-+      ud->fbinfo->var.yres = regs->yres;
-+
-+      /*
-+       * We cannot pan in the X direction, so xres_virtual is regs->xres
-+       * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length
-+       */
-+      ud->fbinfo->var.xres_virtual = regs->xres;
-+      ud->fbinfo->var.yres_virtual = (vram_size * 1024) / ud->fbinfo->fix.line_length;
-+
-+      //ud->fbinfo->var.height = regs->height_mm;
-+      //ud->fbinfo->var.width = regs->width_mm;
-+
-+      /*
-+       * Allocate a color map
-+       */
-+      rc = fb_alloc_cmap(&ud->fbinfo->cmap, PALETTE_ENTRIES_NO, 0);
-+      if (rc) {
-+              dev_err(dev, "Fail to allocate colormap (%d entries)\n",
-+                      PALETTE_ENTRIES_NO);
-+              goto fail;
-+      }
-+      ud->cmap_alloc = true;
-+
-+      /*
-+       * Register new frame buffer
-+       */
-+      rc = register_framebuffer(ud->fbinfo);
-+      if (rc) {
-+              dev_err(dev, "Could not register frame buffer\n");
-+              goto fail;
-+      }
-+
-+      /*
-+       * Start up the VDC
-+       */
-+      ud->regs->next_frame = ud->fb;
-+      ubicom32fb_send_command(ud, VDCTIO_COMMAND_START, 0);
-+
-+      /*
-+       * Tell the log we are here
-+       */
-+      dev_info(dev, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u), regs=%p irqtx=%u irqrx=%u\n",
-+              ud->fb, ud->fb_aligned, vram_size, ud->fbinfo->var.xres, ud->fbinfo->var.yres,
-+              ud->fbinfo->var.xres_virtual, ud->fbinfo->var.yres_virtual, ud->regs,
-+              irq_resource_tx->start, irq_resource_rx->start);
-+
-+      /*
-+       * Success
-+       */
-+      return 0;
-+
-+fail:
-+      ubicom32fb_release(dev);
-+      return rc;
-+}
-+
-+/*
-+ * ubicom32fb_platform_remove
-+ */
-+static int ubicom32fb_platform_remove(struct platform_device *pdev)
-+{
-+      dev_info(&(pdev->dev), "Ubicom32 FB Driver Remove\n");
-+      return ubicom32fb_release(&pdev->dev);
-+}
-+
-+static struct platform_driver ubicom32fb_platform_driver = {
-+      .probe          = ubicom32fb_platform_probe,
-+      .remove         = ubicom32fb_platform_remove,
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+};
-+
-+#ifndef MODULE
-+/*
-+ * ubicom32fb_setup
-+ *    Process kernel boot options
-+ */
-+static int __init ubicom32fb_setup(char *options)
-+{
-+      char *this_opt;
-+
-+      if (!options || !*options) {
-+              return 0;
-+      }
-+
-+      while ((this_opt = strsep(&options, ",")) != NULL) {
-+              if (!*this_opt) {
-+                      continue;
-+              }
-+
-+              if (!strncmp(this_opt, "init_value=", 10)) {
-+                      init_value = simple_strtoul(this_opt + 11, NULL, 0);
-+                      continue;
-+              }
-+
-+              if (!strncmp(this_opt, "vram_size=", 10)) {
-+                      vram_size = simple_strtoul(this_opt + 10, NULL, 0);
-+                      continue;
-+              }
-+      }
-+      return 0;
-+}
-+#endif /* MODULE */
-+
-+/*
-+ * ubicom32fb_init
-+ */
-+static int __devinit ubicom32fb_init(void)
-+{
-+#ifndef MODULE
-+      /*
-+       * Get kernel boot options (in 'video=ubicom32fb:<options>')
-+       */
-+      char *option = NULL;
-+
-+      if (fb_get_options(DRIVER_NAME, &option)) {
-+              return -ENODEV;
-+      }
-+      ubicom32fb_setup(option);
-+#endif /* MODULE */
-+
-+      return platform_driver_register(&ubicom32fb_platform_driver);
-+}
-+module_init(ubicom32fb_init);
-+
-+/*
-+ * ubicom32fb_exit
-+ */
-+static void __exit ubicom32fb_exit(void)
-+{
-+      platform_driver_unregister(&ubicom32fb_platform_driver);
-+}
-+module_exit(ubicom32fb_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
-+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
---- /dev/null
-+++ b/drivers/video/ubicom32plio80.c
-@@ -0,0 +1,780 @@
-+/*
-+ * drivers/video/ubicom32plio80.c
-+ *    Ubicom32 80 bus PLIO buffer driver
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+/*
-+ * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by
-+ * Geert Uytterhoeven.
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/version.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/mm.h>
-+#include <linux/fb.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/platform_device.h>
-+#include <linux/device.h>
-+#include <linux/uaccess.h>
-+#include <asm/plio.h>
-+
-+#define DRIVER_NAME           "ubicom32plio80"
-+#define DRIVER_DESCRIPTION    "Ubicom32 80 bus PLIO frame buffer driver"
-+
-+#define PALETTE_ENTRIES_NO    16
-+
-+/*
-+ * Option variables
-+ *
-+ * vram_size: VRAM size in kilobytes, subject to alignment
-+ */
-+static int vram_size = 0;
-+module_param(vram_size, int, 0);
-+MODULE_PARM_DESC(vram_size, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment");
-+
-+static int xres = 240;
-+module_param(xres, int, 0);
-+MODULE_PARM_DESC(xres, "x (horizontal) resolution");
-+
-+static int yres = 320;
-+module_param(yres, int, 0);
-+MODULE_PARM_DESC(yres, "y (vertical) resolution");
-+
-+static int bgr = 0;
-+module_param(bgr, int, 0);
-+MODULE_PARM_DESC(bgr, "display is BGR (Blue is MSB)");
-+
-+#define BITS_PER_PIXEL        16
-+
-+/*
-+ * Buffer alignment, must not be 0
-+ */
-+#define UBICOM32PLIO80_ALIGNMENT 4
-+
-+/*
-+ * PLIO FSM
-+ *    16-bit data bus on port I
-+ *    CS on EXTCTL[6]
-+ *    WR on EXTCTL[4]
-+ */
-+static const plio_fctl_t plio_fctl = {
-+      .fctl0 = {
-+              .ptif_port_mode = PLIO_PORT_MODE_DI,
-+              .ptif_portd_cfg = 0,
-+              .ptif_porti_cfg = 3,
-+              .edif_ds = 6,
-+              .edif_cmp_mode = 1,
-+              .ecif_extclk_ena = 0, // enable clock output on PD7 table 2.65/p111 says extctl[0]?
-+              .icif_clk_src_sel = PLIO_CLK_IO,
-+      },
-+      .fctl2 = {
-+              .icif_eclk_div = 10,
-+              .icif_iclk_div = 10,
-+      },
-+
-+      };
-+
-+      static const plio_config_t plio_config = {
-+      .pfsm = {
-+              /*
-+               * Table 12.63
-+               */
-+              .grpsel[0] = {1,1,1,1,1,1,1,1,1,1},
-+
-+              /*
-+              * Table 12.66 Counter load value
-+              */
-+              .cs_lut[0] = {0,0,0,0,0,0,0,0},
-+
-+              /*
-+               * Table 2.75 PLIO PFSM Configuration Registers
-+               */
-+              //                      3     2     1     0
-+              .extctl_o_lut[0] = {0x3f, 0x2f, 0x3f, 0x3f},
-+              //                      7     6     5     4
-+              .extctl_o_lut[1] = {0x3f, 0x3f, 0x3f, 0x2f},
-+      },
-+      .edif = {
-+              .odr_oe = 0xffff,
-+      },
-+      .ecif = {
-+              .output_ena = (1 << 6) | (1 << 4),
-+      },
-+};
-+
-+static const u32_t ubicom32plio80_plio_fsm[] = {
-+      // 0-F
-+      0x00070007, 0x00070007,
-+      0x00070007, 0x00070007,
-+      0x00070007, 0x00070007,
-+      0x00070007, 0x00070007,
-+
-+      0x16260806, 0x16260806,
-+      0x16260806, 0x16260806,
-+      0x16260806, 0x16260806,
-+      0x16260806, 0x16260806,
-+
-+      // 10 - 1f
-+      0x22061806, 0x22061806,
-+      0x22061806, 0x22061806,
-+      0x22061806, 0x22061806,
-+      0x22061806, 0x22061806,
-+
-+      0x22061806, 0x22061806,
-+      0x22061806, 0x22061806,
-+      0x22061806, 0x22061806,
-+      0x22061806, 0x22061806,
-+
-+      // 20 - 2f
-+      0x00070806, 0x00070806,
-+      0x00070806, 0x00070806,
-+      0x00070806, 0x00070806,
-+      0x00070806, 0x00070806,
-+
-+      0x00070806, 0x00070806,
-+      0x00070806, 0x00070806,
-+      0x00070806, 0x00070806,
-+      0x00070806, 0x00070806,
-+};
-+
-+/*
-+ * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in.
-+ */
-+static struct fb_fix_screeninfo ubicom32plio80_fix = {
-+      .id =           "Ubicom32",
-+      .type =         FB_TYPE_PACKED_PIXELS,
-+      .visual =       FB_VISUAL_TRUECOLOR,
-+      .accel =        FB_ACCEL_UBICOM32_PLIO80,
-+};
-+
-+/*
-+ * Filled in at probe time when we find out what the hardware supports
-+ */
-+static struct fb_var_screeninfo ubicom32plio80_var;
-+
-+/*
-+ * Private data structure
-+ */
-+struct ubicom32plio80_drvdata {
-+      struct fb_info                  *fbinfo;
-+      bool                            cmap_alloc;
-+
-+      /*
-+       * The address of the framebuffer in memory
-+       */
-+      void                            *fb;
-+      void                            *fb_aligned;
-+
-+      /*
-+       * Total size of vram including alignment allowance
-+       */
-+      u32                             total_vram_size;
-+
-+      /*
-+       * Fake palette of 16 colors
-+       */
-+      u32                             pseudo_palette[PALETTE_ENTRIES_NO];
-+
-+      int                             irq_req;
-+
-+      /*
-+       * Current pointer and bytes left to transfer with the PLIO
-+       */
-+      void                            *xfer_ptr;
-+      u32                             bytes_to_xfer;
-+      u32                             busy;
-+};
-+
-+static struct platform_device *ubicom32plio80_platform_device;
-+
-+/*
-+ * ubicom32plio80_isr
-+ */
-+static int ubicom32plio80_isr(int irq, void *appdata)
-+{
-+      struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)appdata;
-+
-+      if (!ud->bytes_to_xfer) {
-+              ubicom32_disable_interrupt(TX_FIFO_INT(PLIO_PORT));
-+              PLIO_NBR->intmask.txfifo_wm = 0;
-+              ud->busy = 0;
-+              return IRQ_HANDLED;
-+      }
-+
-+      asm volatile (
-+              ".rept 8                                \n\t"
-+              "move.4 (%[fifo]), (%[data])4++         \n\t"
-+              ".endr                                  \n\t"
-+              : [data] "+a" (ud->xfer_ptr)
-+              : [fifo] "a" (&PLIO_NBR->tx_lo)
-+      );
-+
-+      ud->bytes_to_xfer -= 32;
-+
-+      return IRQ_HANDLED;
-+}
-+
-+/*
-+ * ubicom32plio80_update
-+ */
-+static void ubicom32plio80_update(struct ubicom32plio80_drvdata *ud, u32 *fb)
-+{
-+      struct ubicom32_io_port *ri = (struct ubicom32_io_port *)RI;
-+      struct ubicom32_io_port *rd = (struct ubicom32_io_port *)RD;
-+
-+      ud->xfer_ptr = fb;
-+      ud->bytes_to_xfer = (xres * yres * 2) - 64;
-+      ud->busy = 1;
-+
-+      ri->gpio_mask = 0;
-+      rd->gpio_mask &= ~((1 << 4) | (1 << 2));
-+
-+      *(u32 *)(&PLIO_NBR->intclr) = ~0;
-+      PLIO_NBR->intmask.txfifo_wm = 1;
-+      PLIO_NBR->fifo_wm.tx = 8;
-+      ubicom32_enable_interrupt(TX_FIFO_INT(PLIO_PORT));
-+
-+      asm volatile (
-+              ".rept 16                               \n\t"
-+              "move.4 (%[fifo]), (%[data])4++         \n\t"
-+              ".endr                                  \n\t"
-+              : [data] "+a" (ud->xfer_ptr)
-+              : [fifo] "a" (&PLIO_NBR->tx_lo)
-+      );
-+}
-+
-+/*
-+ * ubicom32plio80_pan_display
-+ *    Pans the display to a given location.  Supports only y direction panning.
-+ */
-+static int ubicom32plio80_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
-+{
-+      struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)fbi->par;
-+      void *new_addr;
-+
-+      /*
-+       * Get the last y line that would be displayed.  Since we don't support YWRAP,
-+       * it must be less than our virtual y size.
-+       */
-+      u32 lasty = var->yoffset + var->yres;
-+      if (lasty > fbi->var.yres_virtual) {
-+              /*
-+               * We would fall off the end of our frame buffer if we panned here.
-+               */
-+              return -EINVAL;
-+      }
-+
-+      if (var->xoffset) {
-+              /*
-+               * We don't support panning in the x direction
-+               */
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Everything looks sane, go ahead and pan
-+       *
-+       * We have to calculate a new address for the VDC to look at
-+       */
-+      new_addr = ud->fb_aligned + (var->yoffset * fbi->fix.line_length);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32plio80_setcolreg
-+ *    Sets a color in our virtual palette
-+ */
-+static int ubicom32plio80_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi)
-+{
-+      u32 *palette = fbi->pseudo_palette;
-+
-+      if (regno >= PALETTE_ENTRIES_NO) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * We only use 8 bits from each color
-+       */
-+      red >>= 8;
-+      green >>= 8;
-+      blue >>= 8;
-+
-+      /*
-+       * Convert any grayscale values
-+       */
-+      if (fbi->var.grayscale) {
-+              u16 gray = red + green + blue;
-+              gray += (gray >> 2) + (gray >> 3) - (gray >> 7);
-+              gray >>= 2;
-+              if (gray > 255) {
-+                      gray = 255;
-+              }
-+              red = gray;
-+              blue = gray;
-+              green = gray;
-+      }
-+
-+      palette[regno] = (red << fbi->var.red.offset) | (green << fbi->var.green.offset) |
-+                       (blue << fbi->var.blue.offset);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32plio80_mmap
-+ */
-+static int ubicom32plio80_mmap(struct fb_info *info, struct vm_area_struct *vma)
-+{
-+      struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)info->par;
-+
-+      vma->vm_start = (unsigned long)(ud->fb_aligned);
-+
-+      vma->vm_end = vma->vm_start + info->fix.smem_len;
-+
-+      /* For those who don't understand how mmap works, go read
-+       *   Documentation/nommu-mmap.txt.
-+       * For those that do, you will know that the VM_MAYSHARE flag
-+       * must be set in the vma->vm_flags structure on noMMU
-+       *   Other flags can be set, and are documented in
-+       *   include/linux/mm.h
-+       */
-+
-+      vma->vm_flags |=  VM_MAYSHARE | VM_SHARED;
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32plio80_check_var
-+ *    Check the var, tweak it but don't change operational parameters.
-+ */
-+static int ubicom32plio80_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-+{
-+      struct ubicom32plio80_drvdata *ud = (struct ubicom32plio80_drvdata *)info->par;
-+      u32 line_size = var->xres * (BITS_PER_PIXEL / 8);
-+
-+      /*
-+       * See if we can handle this bpp
-+       */
-+      if (var->bits_per_pixel > BITS_PER_PIXEL) {
-+              return -EINVAL;
-+      }
-+      var->bits_per_pixel = BITS_PER_PIXEL;
-+
-+      /*
-+       * See if we have enough memory to handle this resolution
-+       */
-+      if ((line_size * var->yres * BITS_PER_PIXEL / 8) > ud->total_vram_size) {
-+              return -EINVAL;
-+      }
-+
-+      var->xres_virtual = var->xres;
-+      var->yres_virtual = ud->total_vram_size / line_size;
-+
-+      var->red.length = 5;
-+      var->green.length = 6;
-+      var->green.offset = 5;
-+      var->blue.length = 5;
-+      var->transp.offset = var->transp.length = 0;
-+
-+      if (bgr) {
-+              var->red.offset = 0;
-+              var->blue.offset = 11;
-+      } else {
-+              var->red.offset = 11;
-+              var->blue.offset = 0;
-+      }
-+
-+      var->nonstd = 0;
-+      var->height = -1;
-+      var->width = -1;
-+      var->vmode = FB_VMODE_NONINTERLACED;
-+      var->sync = 0;
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32plio80_set_par
-+ *    Set the video mode according to info->var
-+ */
-+static int ubicom32plio80_set_par(struct fb_info *info)
-+{
-+      /*
-+       * Anything changed?
-+       */
-+      if ((xres == info->var.xres) && (yres == info->var.yres)) {
-+              return 0;
-+      }
-+
-+      /*
-+       * Implement changes
-+       */
-+      xres = info->var.xres;
-+      yres = info->var.yres;
-+      info->fix.visual = FB_VISUAL_TRUECOLOR;
-+      info->fix.xpanstep = 0;
-+      info->fix.ypanstep = 1;
-+      info->fix.line_length = xres * (BITS_PER_PIXEL / 8);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32plio80_ops
-+ *    List of supported operations
-+ */
-+static struct fb_ops ubicom32plio80_ops =
-+{
-+      .owner                  = THIS_MODULE,
-+      .fb_pan_display         = ubicom32plio80_pan_display,
-+      .fb_setcolreg           = ubicom32plio80_setcolreg,
-+      .fb_mmap                = ubicom32plio80_mmap,
-+      .fb_check_var           = ubicom32plio80_check_var,
-+      .fb_set_par             = ubicom32plio80_set_par,
-+      .fb_fillrect            = cfb_fillrect,
-+      .fb_copyarea            = cfb_copyarea,
-+      .fb_imageblit           = cfb_imageblit,
-+};
-+
-+/*
-+ * ubicom32plio80_release
-+ */
-+static int ubicom32plio80_release(struct device *dev)
-+{
-+      struct ubicom32plio80_drvdata *ud = dev_get_drvdata(dev);
-+
-+      unregister_framebuffer(ud->fbinfo);
-+
-+      if (ud->irq_req) {
-+              free_irq(TX_FIFO_INT(PLIO_PORT), ud);
-+      }
-+      if (ud->cmap_alloc) {
-+              fb_dealloc_cmap(&ud->fbinfo->cmap);
-+      }
-+
-+      if (ud->fb) {
-+              kfree(ud->fb);
-+      }
-+
-+      framebuffer_release(ud->fbinfo);
-+      dev_set_drvdata(dev, NULL);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32plio80_platform_probe
-+ */
-+static int __init ubicom32plio80_platform_probe(struct platform_device *pdev)
-+{
-+      struct ubicom32plio80_drvdata *ud;
-+      struct fb_info *fbinfo;
-+      int rc;
-+      size_t fbsize;
-+      struct device *dev = &pdev->dev;
-+      int offset;
-+
-+      /*
-+       * This is the minimum VRAM size
-+       */
-+      fbsize = xres * yres * 2;
-+      if (!vram_size) {
-+              vram_size = (fbsize + 1023) / 1024;
-+      } else {
-+              if (fbsize > (vram_size * 1024)) {
-+                      dev_err(dev, "Not enough VRAM for display, need >= %u bytes\n", fbsize);
-+                      return -ENOMEM; // should be ebadparam?
-+              }
-+      }
-+
-+      /*
-+       * Allocate the framebuffer instance + our private data
-+       */
-+      fbinfo = framebuffer_alloc(sizeof(struct ubicom32plio80_drvdata), &pdev->dev);
-+      if (!fbinfo) {
-+              dev_err(dev, "Not enough memory to allocate instance.\n");
-+              return -ENOMEM;
-+      }
-+
-+      /*
-+       * Fill in our private data.
-+       */
-+      ud = (struct ubicom32plio80_drvdata *)fbinfo->par;
-+      ud->fbinfo = fbinfo;
-+      dev_set_drvdata(dev, ud);
-+
-+      /*
-+       * Allocate and align the requested amount of VRAM
-+       */
-+      ud->total_vram_size = (vram_size * 1024) + UBICOM32PLIO80_ALIGNMENT;
-+      ud->fb = kmalloc(ud->total_vram_size, GFP_KERNEL);
-+      if (ud->fb == NULL) {
-+              dev_err(dev, "Couldn't allocate VRAM\n");
-+              rc = -ENOMEM;
-+              goto fail;
-+      }
-+
-+      offset = (u32_t)ud->fb & (UBICOM32PLIO80_ALIGNMENT - 1);
-+      if (!offset) {
-+              ud->fb_aligned = ud->fb;
-+      } else {
-+              offset =  UBICOM32PLIO80_ALIGNMENT - offset;
-+              ud->fb_aligned = ud->fb + offset;
-+      }
-+
-+      /*
-+       * Clear the entire frame buffer
-+       */
-+      memset(ud->fb_aligned, 0, vram_size * 1024);
-+
-+      /*
-+       * Fill in the fb_var_screeninfo structure
-+       */
-+      memset(&ubicom32plio80_var, 0, sizeof(ubicom32plio80_var));
-+      ubicom32plio80_var.bits_per_pixel = BITS_PER_PIXEL;
-+      ubicom32plio80_var.red.length = 5;
-+      ubicom32plio80_var.green.length = 6;
-+      ubicom32plio80_var.green.offset = 5;
-+      ubicom32plio80_var.blue.length = 5;
-+      ubicom32plio80_var.activate = FB_ACTIVATE_NOW;
-+
-+      if (bgr) {
-+              ubicom32plio80_var.red.offset = 0;
-+              ubicom32plio80_var.blue.offset = 11;
-+      } else {
-+              ubicom32plio80_var.red.offset = 11;
-+              ubicom32plio80_var.blue.offset = 0;
-+      }
-+
-+      /*
-+       * Fill in the fb_info structure
-+       */
-+      ud->fbinfo->device = dev;
-+      ud->fbinfo->screen_base = (void *)ud->fb_aligned;
-+      ud->fbinfo->fbops = &ubicom32plio80_ops;
-+      ud->fbinfo->fix = ubicom32plio80_fix;
-+      ud->fbinfo->fix.smem_start = (u32)ud->fb_aligned;
-+      ud->fbinfo->fix.smem_len = vram_size * 1024;
-+      ud->fbinfo->fix.line_length = xres * 2;
-+      ud->fbinfo->fix.mmio_start = (u32)ud;
-+      ud->fbinfo->fix.mmio_len = sizeof(struct ubicom32plio80_drvdata);
-+
-+      /*
-+       * We support panning in the y direction only
-+       */
-+      ud->fbinfo->fix.xpanstep = 0;
-+      ud->fbinfo->fix.ypanstep = 1;
-+
-+      ud->fbinfo->pseudo_palette = ud->pseudo_palette;
-+      ud->fbinfo->flags = FBINFO_DEFAULT;
-+      ud->fbinfo->var = ubicom32plio80_var;
-+      ud->fbinfo->var.xres = xres;
-+      ud->fbinfo->var.yres = yres;
-+
-+      /*
-+       * We cannot pan in the X direction, so xres_virtual is xres
-+       * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length
-+       */
-+      ud->fbinfo->var.xres_virtual = xres;
-+      ud->fbinfo->var.yres_virtual = (vram_size * 1024) / ud->fbinfo->fix.line_length;
-+
-+      /*
-+       * Allocate a color map
-+       */
-+      rc = fb_alloc_cmap(&ud->fbinfo->cmap, PALETTE_ENTRIES_NO, 0);
-+      if (rc) {
-+              dev_err(dev, "Fail to allocate colormap (%d entries)\n",
-+                      PALETTE_ENTRIES_NO);
-+              goto fail;
-+      }
-+      ud->cmap_alloc = true;
-+
-+      /*
-+       * Register new frame buffer
-+       */
-+      rc = register_framebuffer(ud->fbinfo);
-+      if (rc) {
-+              dev_err(dev, "Could not register frame buffer\n");
-+              goto fail;
-+      }
-+
-+      /*
-+       * request the PLIO IRQ
-+       */
-+      rc = request_irq(TX_FIFO_INT(PLIO_PORT), ubicom32plio80_isr, IRQF_DISABLED, "ubicom32plio80", ud);
-+      if (rc) {
-+              dev_err(dev, "Could not request IRQ\n");
-+              goto fail;
-+      }
-+      ud->irq_req = 1;
-+
-+      /*
-+       * Clear any garbage out of the TX FIFOs (idif_txfifo_flush)
-+       *
-+       * cast through ubicom32_io_port to make sure the compiler does a word write
-+       */
-+      ((struct ubicom32_io_port *)PLIO_NBR)->int_set = (1 << 18);
-+
-+      /*
-+       * Start up the state machine
-+       */
-+      plio_init(&plio_fctl, &plio_config, (plio_sram_t *)ubicom32plio80_plio_fsm, sizeof(ubicom32plio80_plio_fsm));
-+      PLIO_NBR->fctl0.pfsm_cmd = 0;
-+
-+      ubicom32plio80_update(ud, ud->fb_aligned);
-+
-+      /*
-+       * Tell the log we are here
-+       */
-+      dev_info(dev, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u)\n",
-+              ud->fb, ud->fb_aligned, vram_size, ud->fbinfo->var.xres, ud->fbinfo->var.yres,
-+              ud->fbinfo->var.xres_virtual, ud->fbinfo->var.yres_virtual);
-+
-+      /*
-+       * Success
-+       */
-+      return 0;
-+
-+fail:
-+      ubicom32plio80_release(dev);
-+      return rc;
-+}
-+
-+/*
-+ * ubicom32plio80_platform_remove
-+ */
-+static int ubicom32plio80_platform_remove(struct platform_device *pdev)
-+{
-+      dev_info(&(pdev->dev), "Ubicom32 FB Driver Remove\n");
-+      return ubicom32plio80_release(&pdev->dev);
-+}
-+
-+static struct platform_driver ubicom32plio80_platform_driver = {
-+      .probe          = ubicom32plio80_platform_probe,
-+      .remove         = ubicom32plio80_platform_remove,
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+};
-+
-+#ifndef MODULE
-+/*
-+ * ubicom32plio80_setup
-+ *    Process kernel boot options
-+ */
-+static int __init ubicom32plio80_setup(char *options)
-+{
-+      char *this_opt;
-+
-+      if (!options || !*options) {
-+              return 0;
-+      }
-+
-+      while ((this_opt = strsep(&options, ",")) != NULL) {
-+              if (!*this_opt) {
-+                      continue;
-+              }
-+
-+              if (!strncmp(this_opt, "vram_size=", 10)) {
-+                      vram_size = simple_strtoul(this_opt + 10, NULL, 0);
-+                      continue;
-+              }
-+
-+              if (!strncmp(this_opt, "bgr=", 4)) {
-+                      bgr = simple_strtoul(this_opt + 4, NULL, 0);
-+                      continue;
-+              }
-+
-+              if (!strncmp(this_opt, "xres=", 5)) {
-+                      xres = simple_strtoul(this_opt + 5, NULL, 0);
-+                      continue;
-+              }
-+
-+              if (!strncmp(this_opt, "yres=", 5)) {
-+                      yres = simple_strtoul(this_opt + 5, NULL, 0);
-+                      continue;
-+              }
-+      }
-+      return 0;
-+}
-+#endif /* MODULE */
-+
-+/*
-+ * ubicom32plio80_init
-+ */
-+static int __devinit ubicom32plio80_init(void)
-+{
-+      int ret;
-+
-+#ifndef MODULE
-+      /*
-+       * Get kernel boot options (in 'video=ubicom32plio80:<options>')
-+       */
-+      char *option = NULL;
-+
-+      if (fb_get_options(DRIVER_NAME, &option)) {
-+              return -ENODEV;
-+      }
-+      ubicom32plio80_setup(option);
-+#endif /* MODULE */
-+
-+      ret = platform_driver_register(&ubicom32plio80_platform_driver);
-+
-+      if (!ret) {
-+              ubicom32plio80_platform_device = platform_device_alloc(DRIVER_NAME, 0);
-+
-+              if (ubicom32plio80_platform_device)
-+                      ret = platform_device_add(ubicom32plio80_platform_device);
-+              else
-+                      ret = -ENOMEM;
-+
-+              if (ret) {
-+                      platform_device_put(ubicom32plio80_platform_device);
-+                      platform_driver_unregister(&ubicom32plio80_platform_driver);
-+              }
-+      }
-+
-+      return ret;
-+}
-+module_init(ubicom32plio80_init);
-+
-+/*
-+ * ubicom32plio80_exit
-+ */
-+static void __exit ubicom32plio80_exit(void)
-+{
-+      platform_device_unregister(ubicom32plio80_platform_device);
-+      platform_driver_unregister(&ubicom32plio80_platform_driver);
-+}
-+module_exit(ubicom32plio80_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
-+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
---- /dev/null
-+++ b/drivers/video/ubicom32vfb.c
-@@ -0,0 +1,603 @@
-+/*
-+ * drivers/video/ubicom32vfb.c
-+ *    Ubicom32 virtual frame buffer driver
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+/*
-+ * This driver was based on skeletonfb.c, Skeleton for a frame buffer device by
-+ * Geert Uytterhoeven.
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/version.h>
-+#include <linux/errno.h>
-+#include <linux/string.h>
-+#include <linux/mm.h>
-+#include <linux/fb.h>
-+#include <linux/init.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/platform_device.h>
-+#include <linux/device.h>
-+#include <linux/uaccess.h>
-+
-+#define DRIVER_NAME           "ubicom32vfb"
-+#define DRIVER_DESCRIPTION    "Ubicom32 virtual frame buffer driver"
-+
-+#define PALETTE_ENTRIES_NO    16
-+
-+/*
-+ * Option variables
-+ *
-+ * vram_size: VRAM size in kilobytes, subject to alignment
-+ */
-+static int vram_size = 0;
-+module_param(vram_size, int, 0);
-+MODULE_PARM_DESC(vram_size, "VRAM size, in kilobytes to allocate, should be at least the size of one screen, subject to alignment");
-+
-+static int xres = 320;
-+module_param(xres, int, 0);
-+MODULE_PARM_DESC(xres, "x (horizontal) resolution");
-+
-+static int yres = 240;
-+module_param(yres, int, 0);
-+MODULE_PARM_DESC(yres, "y (vertical) resolution");
-+
-+static int bgr = 0;
-+module_param(bgr, int, 0);
-+MODULE_PARM_DESC(bgr, "display is BGR (Blue is MSB)");
-+
-+#define BITS_PER_PIXEL        16
-+
-+/*
-+ * Buffer alignment, must not be 0
-+ */
-+#define UBICOM32VFB_ALIGNMENT 4
-+
-+/*
-+ * fb_fix_screeninfo defines the non-changeable properties of the VDC, depending on what mode it is in.
-+ */
-+static struct fb_fix_screeninfo ubicom32vfb_fix = {
-+      .id =           "Ubicom32",
-+      .type =         FB_TYPE_PACKED_PIXELS,
-+      .visual =       FB_VISUAL_TRUECOLOR,
-+      .accel =        FB_ACCEL_UBICOM32_VFB,
-+};
-+
-+/*
-+ * Filled in at probe time when we find out what the hardware supports
-+ */
-+static struct fb_var_screeninfo ubicom32vfb_var;
-+
-+/*
-+ * Private data structure
-+ */
-+struct ubicom32vfb_drvdata {
-+      struct fb_info                  *fbinfo;
-+      bool                            cmap_alloc;
-+
-+      /*
-+       * The address of the framebuffer in memory
-+       */
-+      void                            *fb;
-+      void                            *fb_aligned;
-+
-+      /*
-+       * Total size of vram including alignment allowance
-+       */
-+      u32                             total_vram_size;
-+
-+      /*
-+       * Fake palette of 16 colors
-+       */
-+      u32                             pseudo_palette[PALETTE_ENTRIES_NO];
-+};
-+
-+static struct platform_device *ubicom32vfb_platform_device;
-+
-+/*
-+ * ubicom32vfb_pan_display
-+ *    Pans the display to a given location.  Supports only y direction panning.
-+ */
-+static int ubicom32vfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
-+{
-+      struct ubicom32vfb_drvdata *ud = (struct ubicom32vfb_drvdata *)fbi->par;
-+      void *new_addr;
-+
-+      /*
-+       * Get the last y line that would be displayed.  Since we don't support YWRAP,
-+       * it must be less than our virtual y size.
-+       */
-+      u32 lasty = var->yoffset + var->yres;
-+      if (lasty > fbi->var.yres_virtual) {
-+              /*
-+               * We would fall off the end of our frame buffer if we panned here.
-+               */
-+              return -EINVAL;
-+      }
-+
-+      if (var->xoffset) {
-+              /*
-+               * We don't support panning in the x direction
-+               */
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Everything looks sane, go ahead and pan
-+       *
-+       * We have to calculate a new address for the VDC to look at
-+       */
-+      new_addr = ud->fb_aligned + (var->yoffset * fbi->fix.line_length);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32vfb_setcolreg
-+ *    Sets a color in our virtual palette
-+ */
-+static int ubicom32vfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *fbi)
-+{
-+      u32 *palette = fbi->pseudo_palette;
-+
-+      if (regno >= PALETTE_ENTRIES_NO) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * We only use 8 bits from each color
-+       */
-+      red >>= 8;
-+      green >>= 8;
-+      blue >>= 8;
-+
-+      /*
-+       * Convert any grayscale values
-+       */
-+      if (fbi->var.grayscale) {
-+              u16 gray = red + green + blue;
-+              gray += (gray >> 2) + (gray >> 3) - (gray >> 7);
-+              gray >>= 2;
-+              if (gray > 255) {
-+                      gray = 255;
-+              }
-+              red = gray;
-+              blue = gray;
-+              green = gray;
-+      }
-+
-+      palette[regno] = (red << fbi->var.red.offset) | (green << fbi->var.green.offset) |
-+                       (blue << fbi->var.blue.offset);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32vfb_mmap
-+ */
-+static int ubicom32vfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-+{
-+      struct ubicom32vfb_drvdata *ud = (struct ubicom32vfb_drvdata *)info->par;
-+
-+      vma->vm_start = (unsigned long)(ud->fb_aligned);
-+
-+      vma->vm_end = vma->vm_start + info->fix.smem_len;
-+
-+      /* For those who don't understand how mmap works, go read
-+       *   Documentation/nommu-mmap.txt.
-+       * For those that do, you will know that the VM_MAYSHARE flag
-+       * must be set in the vma->vm_flags structure on noMMU
-+       *   Other flags can be set, and are documented in
-+       *   include/linux/mm.h
-+       */
-+
-+      vma->vm_flags |=  VM_MAYSHARE | VM_SHARED;
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32vfb_check_var
-+ *    Check the var, tweak it but don't change operational parameters.
-+ */
-+static int ubicom32vfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-+{
-+      struct ubicom32vfb_drvdata *ud = (struct ubicom32vfb_drvdata *)info->par;
-+      u32 line_size = var->xres * (BITS_PER_PIXEL / 8);
-+
-+      /*
-+       * See if we can handle this bpp
-+       */
-+      if (var->bits_per_pixel > BITS_PER_PIXEL) {
-+              return -EINVAL;
-+      }
-+      var->bits_per_pixel = BITS_PER_PIXEL;
-+
-+      /*
-+       * See if we have enough memory to handle this resolution
-+       */
-+      if ((line_size * var->yres * BITS_PER_PIXEL / 8) > ud->total_vram_size) {
-+              return -EINVAL;
-+      }
-+
-+      var->xres_virtual = var->xres;
-+      var->yres_virtual = ud->total_vram_size / line_size;
-+
-+      var->red.length = 5;
-+      var->green.length = 6;
-+      var->green.offset = 5;
-+      var->blue.length = 5;
-+      var->transp.offset = var->transp.length = 0;
-+
-+      if (bgr) {
-+              var->red.offset = 0;
-+              var->blue.offset = 11;
-+      } else {
-+              var->red.offset = 11;
-+              var->blue.offset = 0;
-+      }
-+
-+      var->nonstd = 0;
-+      var->height = -1;
-+      var->width = -1;
-+      var->vmode = FB_VMODE_NONINTERLACED;
-+      var->sync = 0;
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32vfb_set_par
-+ *    Set the video mode according to info->var
-+ */
-+static int ubicom32vfb_set_par(struct fb_info *info)
-+{
-+      /*
-+       * Anything changed?
-+       */
-+      if ((xres == info->var.xres) && (yres == info->var.yres)) {
-+              return 0;
-+      }
-+
-+      /*
-+       * Implement changes
-+       */
-+      xres = info->var.xres;
-+      yres = info->var.yres;
-+      info->fix.visual = FB_VISUAL_TRUECOLOR;
-+      info->fix.xpanstep = 0;
-+      info->fix.ypanstep = 1;
-+      info->fix.line_length = xres * (BITS_PER_PIXEL / 8);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32vfb_ops
-+ *    List of supported operations
-+ */
-+static struct fb_ops ubicom32vfb_ops =
-+{
-+      .owner                  = THIS_MODULE,
-+      .fb_pan_display         = ubicom32vfb_pan_display,
-+      .fb_setcolreg           = ubicom32vfb_setcolreg,
-+      .fb_mmap                = ubicom32vfb_mmap,
-+      .fb_check_var           = ubicom32vfb_check_var,
-+      .fb_set_par             = ubicom32vfb_set_par,
-+      .fb_fillrect            = cfb_fillrect,
-+      .fb_copyarea            = cfb_copyarea,
-+      .fb_imageblit           = cfb_imageblit,
-+};
-+
-+/*
-+ * ubicom32vfb_release
-+ */
-+static int ubicom32vfb_release(struct device *dev)
-+{
-+      struct ubicom32vfb_drvdata *ud = dev_get_drvdata(dev);
-+
-+      unregister_framebuffer(ud->fbinfo);
-+
-+      if (ud->cmap_alloc) {
-+              fb_dealloc_cmap(&ud->fbinfo->cmap);
-+      }
-+
-+      if (ud->fb) {
-+              kfree(ud->fb);
-+      }
-+
-+      framebuffer_release(ud->fbinfo);
-+      dev_set_drvdata(dev, NULL);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubicom32vfb_platform_probe
-+ */
-+static int __init ubicom32vfb_platform_probe(struct platform_device *pdev)
-+{
-+      struct ubicom32vfb_drvdata *ud;
-+      struct fb_info *fbinfo;
-+      int rc;
-+      size_t fbsize;
-+      struct device *dev = &pdev->dev;
-+      int offset;
-+
-+      /*
-+       * This is the minimum VRAM size
-+       */
-+      fbsize = xres * yres * 2;
-+      if (!vram_size) {
-+              vram_size = (fbsize + 1023) / 1024;
-+      } else {
-+              if (fbsize > (vram_size * 1024)) {
-+                      dev_err(dev, "Not enough VRAM for display, need >= %u bytes\n", fbsize);
-+                      return -ENOMEM; // should be ebadparam?
-+              }
-+      }
-+
-+      /*
-+       * Allocate the framebuffer instance + our private data
-+       */
-+      fbinfo = framebuffer_alloc(sizeof(struct ubicom32vfb_drvdata), &pdev->dev);
-+      if (!fbinfo) {
-+              dev_err(dev, "Not enough memory to allocate instance.\n");
-+              return -ENOMEM;
-+      }
-+
-+      /*
-+       * Fill in our private data.
-+       */
-+      ud = (struct ubicom32vfb_drvdata *)fbinfo->par;
-+      ud->fbinfo = fbinfo;
-+      dev_set_drvdata(dev, ud);
-+
-+      /*
-+       * Allocate and align the requested amount of VRAM
-+       */
-+      ud->total_vram_size = (vram_size * 1024) + UBICOM32VFB_ALIGNMENT;
-+      ud->fb = kmalloc(ud->total_vram_size, GFP_KERNEL);
-+      if (ud->fb == NULL) {
-+              dev_err(dev, "Couldn't allocate VRAM\n");
-+              rc = -ENOMEM;
-+              goto fail;
-+      }
-+
-+      offset = (u32_t)ud->fb & (UBICOM32VFB_ALIGNMENT - 1);
-+      if (!offset) {
-+              ud->fb_aligned = ud->fb;
-+      } else {
-+              offset =  UBICOM32VFB_ALIGNMENT - offset;
-+              ud->fb_aligned = ud->fb + offset;
-+      }
-+
-+      /*
-+       * Clear the entire frame buffer
-+       */
-+      memset(ud->fb_aligned, 0, vram_size * 1024);
-+
-+      /*
-+       * Fill in the fb_var_screeninfo structure
-+       */
-+      memset(&ubicom32vfb_var, 0, sizeof(ubicom32vfb_var));
-+      ubicom32vfb_var.bits_per_pixel = BITS_PER_PIXEL;
-+      ubicom32vfb_var.red.length = 5;
-+      ubicom32vfb_var.green.length = 6;
-+      ubicom32vfb_var.green.offset = 5;
-+      ubicom32vfb_var.blue.length = 5;
-+      ubicom32vfb_var.activate = FB_ACTIVATE_NOW;
-+
-+      if (bgr) {
-+              ubicom32vfb_var.red.offset = 0;
-+              ubicom32vfb_var.blue.offset = 11;
-+      } else {
-+              ubicom32vfb_var.red.offset = 11;
-+              ubicom32vfb_var.blue.offset = 0;
-+      }
-+
-+      /*
-+       * Fill in the fb_info structure
-+       */
-+      ud->fbinfo->device = dev;
-+      ud->fbinfo->screen_base = (void *)ud->fb_aligned;
-+      ud->fbinfo->fbops = &ubicom32vfb_ops;
-+      ud->fbinfo->fix = ubicom32vfb_fix;
-+      ud->fbinfo->fix.smem_start = (u32)ud->fb_aligned;
-+      ud->fbinfo->fix.smem_len = vram_size * 1024;
-+      ud->fbinfo->fix.line_length = xres * 2;
-+      ud->fbinfo->fix.mmio_start = (u32)ud;
-+      ud->fbinfo->fix.mmio_len = sizeof(struct ubicom32vfb_drvdata);
-+
-+      /*
-+       * We support panning in the y direction only
-+       */
-+      ud->fbinfo->fix.xpanstep = 0;
-+      ud->fbinfo->fix.ypanstep = 1;
-+
-+      ud->fbinfo->pseudo_palette = ud->pseudo_palette;
-+      ud->fbinfo->flags = FBINFO_DEFAULT;
-+      ud->fbinfo->var = ubicom32vfb_var;
-+      ud->fbinfo->var.xres = xres;
-+      ud->fbinfo->var.yres = yres;
-+
-+      /*
-+       * We cannot pan in the X direction, so xres_virtual is xres
-+       * We can pan in the Y direction, so yres_virtual is vram_size / ud->fbinfo->fix.line_length
-+       */
-+      ud->fbinfo->var.xres_virtual = xres;
-+      ud->fbinfo->var.yres_virtual = (vram_size * 1024) / ud->fbinfo->fix.line_length;
-+
-+      /*
-+       * Allocate a color map
-+       */
-+      rc = fb_alloc_cmap(&ud->fbinfo->cmap, PALETTE_ENTRIES_NO, 0);
-+      if (rc) {
-+              dev_err(dev, "Fail to allocate colormap (%d entries)\n",
-+                      PALETTE_ENTRIES_NO);
-+              goto fail;
-+      }
-+      ud->cmap_alloc = true;
-+
-+      /*
-+       * Register new frame buffer
-+       */
-+      rc = register_framebuffer(ud->fbinfo);
-+      if (rc) {
-+              dev_err(dev, "Could not register frame buffer\n");
-+              goto fail;
-+      }
-+
-+      /*
-+       * Tell the log we are here
-+       */
-+      dev_info(dev, "fbaddr=%p align=%p, size=%uKB screen(%ux%u) virt(%ux%u)\n",
-+              ud->fb, ud->fb_aligned, vram_size, ud->fbinfo->var.xres, ud->fbinfo->var.yres,
-+              ud->fbinfo->var.xres_virtual, ud->fbinfo->var.yres_virtual);
-+
-+      /*
-+       * Success
-+       */
-+      return 0;
-+
-+fail:
-+      ubicom32vfb_release(dev);
-+      return rc;
-+}
-+
-+/*
-+ * ubicom32vfb_platform_remove
-+ */
-+static int ubicom32vfb_platform_remove(struct platform_device *pdev)
-+{
-+      dev_info(&(pdev->dev), "Ubicom32 FB Driver Remove\n");
-+      return ubicom32vfb_release(&pdev->dev);
-+}
-+
-+static struct platform_driver ubicom32vfb_platform_driver = {
-+      .probe          = ubicom32vfb_platform_probe,
-+      .remove         = ubicom32vfb_platform_remove,
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+};
-+
-+#ifndef MODULE
-+/*
-+ * ubicom32vfb_setup
-+ *    Process kernel boot options
-+ */
-+static int __init ubicom32vfb_setup(char *options)
-+{
-+      char *this_opt;
-+
-+      if (!options || !*options) {
-+              return 0;
-+      }
-+
-+      while ((this_opt = strsep(&options, ",")) != NULL) {
-+              if (!*this_opt) {
-+                      continue;
-+              }
-+
-+              if (!strncmp(this_opt, "vram_size=", 10)) {
-+                      vram_size = simple_strtoul(this_opt + 10, NULL, 0);
-+                      continue;
-+              }
-+
-+              if (!strncmp(this_opt, "bgr=", 4)) {
-+                      bgr = simple_strtoul(this_opt + 4, NULL, 0);
-+                      continue;
-+              }
-+
-+              if (!strncmp(this_opt, "xres=", 5)) {
-+                      xres = simple_strtoul(this_opt + 5, NULL, 0);
-+                      continue;
-+              }
-+
-+              if (!strncmp(this_opt, "yres=", 5)) {
-+                      yres = simple_strtoul(this_opt + 5, NULL, 0);
-+                      continue;
-+              }
-+      }
-+      return 0;
-+}
-+#endif /* MODULE */
-+
-+/*
-+ * ubicom32vfb_init
-+ */
-+static int __devinit ubicom32vfb_init(void)
-+{
-+      int ret;
-+
-+#ifndef MODULE
-+      /*
-+       * Get kernel boot options (in 'video=ubicom32vfb:<options>')
-+       */
-+      char *option = NULL;
-+
-+      if (fb_get_options(DRIVER_NAME, &option)) {
-+              return -ENODEV;
-+      }
-+      ubicom32vfb_setup(option);
-+#endif /* MODULE */
-+
-+      ret = platform_driver_register(&ubicom32vfb_platform_driver);
-+
-+#ifdef CONFIG_FB_UBICOM32_VIRTUAL_NOAUTO
-+      return ret;
-+#else
-+      if (!ret) {
-+              ubicom32vfb_platform_device = platform_device_alloc(DRIVER_NAME, 0);
-+
-+              if (ubicom32vfb_platform_device)
-+                      ret = platform_device_add(ubicom32vfb_platform_device);
-+              else
-+                      ret = -ENOMEM;
-+
-+              if (ret) {
-+                      platform_device_put(ubicom32vfb_platform_device);
-+                      platform_driver_unregister(&ubicom32vfb_platform_driver);
-+              }
-+      }
-+
-+      return ret;
-+#endif
-+}
-+module_init(ubicom32vfb_init);
-+
-+/*
-+ * ubicom32vfb_exit
-+ */
-+static void __exit ubicom32vfb_exit(void)
-+{
-+      platform_device_unregister(ubicom32vfb_platform_device);
-+      platform_driver_unregister(&ubicom32vfb_platform_driver);
-+}
-+module_exit(ubicom32vfb_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Patrick Tjin <@ubicom.com>");
-+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
---- a/drivers/watchdog/Kconfig
-+++ b/drivers/watchdog/Kconfig
-@@ -887,6 +887,19 @@ config WATCHDOG_RIO
-         machines.  The watchdog timeout period is normally one minute but
-         can be changed with a boot-time parameter.
-+# Ubicom32
-+
-+config UBI32_WDT
-+      tristate "Ubicom32 Hardware Watchdog support"
-+      depends on UBICOM32
-+      ---help---
-+        If you say yes here you will get support for the Ubicom32 On-Chip
-+        Watchdog Timer. If you have one of these processors and wish to
-+        have watchdog support enabled, say Y, otherwise say N.
-+
-+        To compile this driver as a module, choose M here: the
-+        module will be called ubi32_wdt.
-+
- # XTENSA Architecture
- #
---- a/drivers/watchdog/Makefile
-+++ b/drivers/watchdog/Makefile
-@@ -131,6 +131,9 @@ obj-$(CONFIG_SH_WDT) += shwdt.o
- obj-$(CONFIG_WATCHDOG_RIO)            += riowd.o
- obj-$(CONFIG_WATCHDOG_CP1XXX)         += cpwd.o
-+# Ubicom32 Architecture
-+obj-$(CONFIG_UBI32_WDT)                       += ubi32_wdt.o
-+
- # XTENSA Architecture
- # Architecture Independant
---- /dev/null
-+++ b/drivers/watchdog/ubi32_wdt.c
-@@ -0,0 +1,630 @@
-+/*
-+ * drivers/watchdog/ubi32_wdt.c
-+ *   Ubicom32 Watchdog Driver
-+ *
-+ * Originally based on softdog.c
-+ * Copyright 2006-2007 Analog Devices Inc.
-+ * Copyright 2006-2007 Michele d'Amico
-+ * Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+#include <linux/platform_device.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/types.h>
-+#include <linux/timer.h>
-+#include <linux/miscdevice.h>
-+#include <linux/watchdog.h>
-+#include <linux/fs.h>
-+#include <linux/notifier.h>
-+#include <linux/reboot.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/uaccess.h>
-+#include <asm/ip5000.h>
-+
-+#define WATCHDOG_NAME "ubi32-wdt"
-+#define PFX WATCHDOG_NAME ": "
-+
-+#define OSC1_FREQ 12000000
-+#define WATCHDOG_SEC_TO_CYC(x) (OSC1_FREQ * (x))
-+#define WATCHDOG_MAX_SEC (0xffffffff / OSC1_FREQ)
-+
-+#define MIN_PROCESSOR_ADDRESS 0x03000000
-+
-+static DEFINE_SPINLOCK(ubi32_wdt_spinlock);
-+
-+#define WATCHDOG_TIMEOUT 20
-+
-+#if defined(CONFIG_WATCHDOG_NOWAYOUT)
-+#define WATCHDOG_NOWAYOUT 1
-+#else
-+#define WATCHDOG_NOWAYOUT 0
-+#endif
-+
-+static unsigned int timeout = WATCHDOG_TIMEOUT;
-+static int nowayout = WATCHDOG_NOWAYOUT;
-+static struct watchdog_info ubi32_wdt_info;
-+static unsigned long open_check;
-+static char expect_close;
-+
-+#if !defined(CONFIG_SMP)
-+#define UBI32_WDT_LOCK(lock, flags) local_irq_save(flags)
-+#define UBI32_WDT_UNLOCK(lock, flags) local_irq_restore(flags)
-+#define UBI32_WDT_LOCK_CHECK()
-+#else
-+#define UBI32_WDT_LOCK(lock, flags) spin_lock_irqsave((lock), (flags));
-+#define UBI32_WDT_UNLOCK(lock, flags) spin_unlock_irqrestore((lock), (flags));
-+#define UBI32_WDT_LOCK_CHECK() BUG_ON(!spin_is_locked(&ubi32_wdt_spinlock));
-+#endif
-+
-+/*
-+ * ubi32_wdt_remaining()
-+ *    Return the approximate number of seconds remaining
-+ */
-+static int ubi32_wdt_remaining(void)
-+{
-+      int compare;
-+      int curr;
-+
-+      UBI32_WDT_LOCK_CHECK();
-+
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL);
-+      compare = ubicom32_read_reg(&UBICOM32_IO_TIMER->wdcom);
-+      curr = ubicom32_read_reg(&UBICOM32_IO_TIMER->mptval);
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0);
-+      return (compare - curr) / OSC1_FREQ;
-+
-+}
-+
-+/*
-+ * ubi32_wdt_keepalive()
-+ *    Keep the Userspace Watchdog Alive
-+ *
-+ * The Userspace watchdog got a KeepAlive: schedule the next timeout.
-+ */
-+static int ubi32_wdt_keepalive(void)
-+{
-+      UBI32_WDT_LOCK_CHECK();
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL);
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcom,
-+                      ubicom32_read_reg(&UBICOM32_IO_TIMER->mptval)
-+                      + WATCHDOG_SEC_TO_CYC(timeout));
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0);
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_wdt_stop()
-+ *    Stop the on-chip Watchdog
-+ */
-+static int ubi32_wdt_stop(void)
-+{
-+      UBI32_WDT_LOCK_CHECK();
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL);
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcfg, TIMER_WATCHDOG_DISABLE);
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0);
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_wdt_start()
-+ *    Start the on-chip Watchdog
-+ */
-+static int ubi32_wdt_start(void)
-+{
-+      UBI32_WDT_LOCK_CHECK();
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL);
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcom,
-+                      ubicom32_read_reg(&UBICOM32_IO_TIMER->mptval)
-+                      + WATCHDOG_SEC_TO_CYC(timeout));
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->wdcfg, ~TIMER_WATCHDOG_DISABLE);
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0);
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_wdt_running()
-+ *    Return true if the watchdog is configured
-+ */
-+static int ubi32_wdt_running(void)
-+{
-+      int enabled;
-+
-+      UBI32_WDT_LOCK_CHECK();
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, TIMER_TKEYVAL);
-+      enabled = ubicom32_read_reg(&UBICOM32_IO_TIMER->wdcfg) == ~TIMER_WATCHDOG_DISABLE;
-+      ubicom32_write_reg(&UBICOM32_IO_TIMER->tkey, 0);
-+      return enabled;
-+}
-+
-+/*
-+ * ubi32_wdt_set_timeout()
-+ *    Set the Userspace Watchdog timeout
-+ *
-+ * - @t: new timeout value (in seconds)
-+ */
-+static int ubi32_wdt_set_timeout(unsigned long t)
-+{
-+      UBI32_WDT_LOCK_CHECK();
-+
-+      if (t > WATCHDOG_MAX_SEC) {
-+              printk(KERN_WARNING PFX "request to large: %ld [1-%d] sec)\n", t, WATCHDOG_MAX_SEC);
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * If we are running, then reset the time value so
-+       * that the new value has an immediate effect.
-+       */
-+      timeout = t;
-+      if (ubi32_wdt_running()) {
-+              ubi32_wdt_keepalive();
-+      }
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_wdt_open()
-+ *    Open the Device
-+ */
-+static int ubi32_wdt_open(struct inode *inode, struct file *file)
-+{
-+      unsigned long flags;
-+
-+      if (test_and_set_bit(0, &open_check))
-+              return -EBUSY;
-+
-+      if (nowayout)
-+              __module_get(THIS_MODULE);
-+
-+      spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+      ubi32_wdt_start();
-+      spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+
-+      return nonseekable_open(inode, file);
-+}
-+
-+/*
-+ * ubi32_wdt_close()
-+ *    Close the Device
-+ */
-+static int ubi32_wdt_release(struct inode *inode, struct file *file)
-+{
-+      unsigned long flags;
-+
-+      /*
-+       * If we don't expect a close, then the watchdog continues
-+       * even though the device is closed.  The caller will have
-+       * a full timeout value to reopen the device and continue
-+       * stroking it.
-+       */
-+      if (expect_close != 42) {
-+              printk(KERN_CRIT PFX
-+                      "Unexpected close, not stopping watchdog!\n");
-+              spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+              ubi32_wdt_keepalive();
-+              spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+      } else {
-+              spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+              ubi32_wdt_stop();
-+              spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+      }
-+
-+      expect_close = 0;
-+      clear_bit(0, &open_check);
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_wdt_write()
-+ *    Write to Device
-+ *
-+ * If the user writes nothing, nothing happens.
-+ * If the user writes a V, then we expect a close and allow a release.
-+ * If the user writes anything else, it is ignored.
-+ */
-+static ssize_t ubi32_wdt_write(struct file *file, const char __user *data,
-+                                              size_t len, loff_t *ppos)
-+{
-+      size_t i;
-+      unsigned long flags;
-+
-+      /*
-+       * Every write resets the expect_close.  The last write
-+       * must be a V to allow shutdown on close.
-+       */
-+      expect_close = 0;
-+
-+      /*
-+       * Empty writes still ping.
-+       */
-+      if (!len) {
-+              goto ping;
-+      }
-+
-+      /*
-+       * If nowayout is set, it does not matter if the caller
-+       * is trying to send the magic 'V' we will not allow a
-+       * close to stop us.
-+       */
-+      if (nowayout) {
-+              goto ping;
-+      }
-+
-+      /*
-+       * See if the program wrote a 'V' and if so disable
-+       * the watchdog on release.
-+       */
-+      for (i = 0; i < len; i++) {
-+              char c;
-+              if (get_user(c, data + i)) {
-+                      return -EFAULT;
-+              }
-+
-+              if (c == 'V') {
-+                      expect_close = 42;
-+              }
-+      }
-+
-+ping:
-+      spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+      ubi32_wdt_keepalive();
-+      spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+      return len;
-+}
-+
-+/*
-+ * ubi32_wdt_ioctl()
-+ *    Query the watchdog device.
-+ *
-+ * Query basic information from the device or ping it, as outlined by the
-+ * watchdog API.
-+ */
-+static long ubi32_wdt_ioctl(struct file *file,
-+                              unsigned int cmd, unsigned long arg)
-+{
-+      void __user *argp = (void __user *)arg;
-+      int __user *p = argp;
-+
-+      switch (cmd) {
-+      case WDIOC_GETSUPPORT:
-+              if (copy_to_user(argp, &ubi32_wdt_info, sizeof(ubi32_wdt_info))) {
-+                      return -EFAULT;
-+              }
-+              return 0;
-+
-+      case WDIOC_GETSTATUS: {
-+              unsigned long flags;
-+              int running;
-+
-+              spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+              running = ubi32_wdt_running();
-+              spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+              return running;
-+      }
-+
-+      case WDIOC_GETBOOTSTATUS:
-+              return ubicom32_get_reset_reason();
-+
-+      case WDIOC_SETOPTIONS: {
-+              unsigned long flags;
-+              int options, ret = -EINVAL;
-+
-+              /*
-+               * The sample application does not pass a pointer
-+               * but directly passes a value of 1 or 2; however
-+               * all of the implementations (and thus probably
-+               * the real applications) pass a pointer to a value.
-+               *
-+               * It should be noted that  WDIOC_SETOPTIONS is defined as
-+               * _IOR(WATCHDOG_IOCTL_BASE, 4, int), which means
-+               * that it should be an int and NOT a pointer.
-+               *
-+               * TODO: Examine this code for future chips.
-+               * TODO: Report the sample code defect.
-+               */
-+              if ((int)p < MIN_PROCESSOR_ADDRESS) {
-+                      options = (int)p;
-+              } else {
-+                      if (get_user(options, p))
-+                      return -EFAULT;
-+              }
-+
-+              spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+              if (options & WDIOS_DISABLECARD) {
-+                      ubi32_wdt_stop();
-+                      ret = 0;
-+              }
-+              if (options & WDIOS_ENABLECARD) {
-+                      ubi32_wdt_start();
-+                      ret = 0;
-+              }
-+              spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+              return ret;
-+      }
-+
-+      case WDIOC_KEEPALIVE: {
-+              unsigned long flags;
-+
-+              spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+              ubi32_wdt_keepalive();
-+              spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+              return 0;
-+      }
-+
-+      case WDIOC_SETTIMEOUT: {
-+              int new_timeout;
-+              unsigned long flags;
-+              int ret  = 0;
-+
-+              if (get_user(new_timeout, p))
-+                      return -EFAULT;
-+
-+              spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+              ret = ubi32_wdt_set_timeout(new_timeout);
-+              spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+              return ret;
-+
-+      }
-+
-+      case WDIOC_GETTIMEOUT:
-+              return put_user(timeout, p);
-+
-+      case WDIOC_GETTIMELEFT: {
-+              unsigned long flags;
-+              int remaining = 0;
-+
-+              spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+              remaining = ubi32_wdt_remaining();
-+              spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+              return put_user(remaining, p);
-+      }
-+
-+      default:
-+              return -ENOTTY;
-+      }
-+}
-+
-+/*
-+ * ubi32_wdt_notify_sys()
-+ *    Notification callback function for system events.
-+ *
-+ * Turn off the watchdog during a SYS_DOWN or SYS_HALT.
-+ */
-+static int ubi32_wdt_notify_sys(struct notifier_block *this,
-+                                      unsigned long code, void *unused)
-+{
-+      if (code == SYS_DOWN || code == SYS_HALT) {
-+              unsigned long flags;
-+
-+              spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+              ubi32_wdt_stop();
-+              spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+      }
-+
-+      return NOTIFY_DONE;
-+}
-+
-+#ifdef CONFIG_PM
-+static int state_before_suspend;
-+
-+/*
-+ * ubi32_wdt_suspend()
-+ *    suspend the watchdog
-+ *
-+ * Remember if the watchdog was running and stop it.
-+ */
-+static int ubi32_wdt_suspend(struct platform_device *pdev, pm_message_t state)
-+{
-+      unsigned long flags;
-+      spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+      state_before_suspend = ubi32_wdt_running();
-+      ubi32_wdt_stop();
-+      spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_wdt_resume()
-+ *    Resume the watchdog
-+ *
-+ * If the watchdog was running, turn it back on.
-+ */
-+static int ubi32_wdt_resume(struct platform_device *pdev)
-+{
-+      if (state_before_suspend) {
-+              unsigned long flags;
-+              spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+              ubi32_wdt_set_timeout(timeout);
-+              ubi32_wdt_start();
-+              spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+      }
-+
-+      return 0;
-+}
-+#else
-+# define ubi32_wdt_suspend NULL
-+# define ubi32_wdt_resume NULL
-+#endif
-+
-+static const struct file_operations ubi32_wdt_fops = {
-+      .owner          = THIS_MODULE,
-+      .llseek         = no_llseek,
-+      .write          = ubi32_wdt_write,
-+      .unlocked_ioctl = ubi32_wdt_ioctl,
-+      .open           = ubi32_wdt_open,
-+      .release        = ubi32_wdt_release,
-+};
-+
-+static struct miscdevice ubi32_wdt_miscdev = {
-+      .minor    = WATCHDOG_MINOR,
-+      .name     = "watchdog",
-+      .fops     = &ubi32_wdt_fops,
-+};
-+
-+static struct watchdog_info ubi32_wdt_info = {
-+      .identity = "Ubicom32 Watchdog",
-+      .options  = WDIOF_SETTIMEOUT |
-+                  WDIOF_KEEPALIVEPING |
-+                  WDIOF_MAGICCLOSE,
-+};
-+
-+static struct notifier_block ubi32_wdt_notifier = {
-+      .notifier_call = ubi32_wdt_notify_sys,
-+};
-+
-+/*
-+ * ubi32_wdt_probe()
-+ *    Probe/register the watchdog module
-+ *
-+ * Registers the misc device and notifier handler.  Actual device
-+ * initialization is handled by ubi32_wdt_open().
-+ */
-+static int __devinit ubi32_wdt_probe(struct platform_device *pdev)
-+{
-+      int ret;
-+
-+      ret = register_reboot_notifier(&ubi32_wdt_notifier);
-+      if (ret) {
-+              printk(KERN_ERR PFX
-+                      "cannot register reboot notifier (err=%d)\n", ret);
-+              return ret;
-+      }
-+
-+      ret = misc_register(&ubi32_wdt_miscdev);
-+      if (ret) {
-+              printk(KERN_ERR PFX
-+                      "cannot register miscdev on minor=%d (err=%d)\n",
-+                              WATCHDOG_MINOR, ret);
-+              unregister_reboot_notifier(&ubi32_wdt_notifier);
-+              return ret;
-+      }
-+
-+      printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
-+             timeout, nowayout);
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_wdt_remove()
-+ *    Uninstall the module
-+ *
-+ * Unregisters the misc device and notifier handler.  Actual device
-+ * deinitialization is handled by ubi32_wdt_close().
-+ */
-+static int __devexit ubi32_wdt_remove(struct platform_device *pdev)
-+{
-+      misc_deregister(&ubi32_wdt_miscdev);
-+      unregister_reboot_notifier(&ubi32_wdt_notifier);
-+      return 0;
-+}
-+
-+static struct platform_device *ubi32_wdt_device;
-+
-+static struct platform_driver ubi32_wdt_driver = {
-+      .probe     = ubi32_wdt_probe,
-+      .remove    = __devexit_p(ubi32_wdt_remove),
-+      .suspend   = ubi32_wdt_suspend,
-+      .resume    = ubi32_wdt_resume,
-+      .driver    = {
-+              .name  = WATCHDOG_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+};
-+
-+/*
-+ * ubi32_wdt_init()
-+ *    Initialize the watchdog.
-+ *
-+ * Checks the module params and registers the platform device & driver.
-+ * Real work is in the platform probe function.
-+ */
-+static int __init ubi32_wdt_init(void)
-+{
-+      unsigned long flags;
-+      int ret;
-+
-+      /*
-+       * Check that the timeout value is within range
-+       */
-+      spin_lock_irqsave(&ubi32_wdt_spinlock, flags);
-+      ret = ubi32_wdt_set_timeout(timeout);
-+      spin_unlock_irqrestore(&ubi32_wdt_spinlock, flags);
-+      if (ret) {
-+              return ret;
-+      }
-+
-+      /*
-+       * Since this is an on-chip device and needs no board-specific
-+       * resources, we'll handle all the platform device stuff here.
-+       */
-+      ret = platform_driver_register(&ubi32_wdt_driver);
-+      if (ret) {
-+              printk(KERN_ERR PFX "unable to register driver\n");
-+              return ret;
-+      }
-+
-+      ubi32_wdt_device = platform_device_register_simple(WATCHDOG_NAME, -1, NULL, 0);
-+      if (IS_ERR(ubi32_wdt_device)) {
-+              printk(KERN_ERR PFX "unable to register device\n");
-+              platform_driver_unregister(&ubi32_wdt_driver);
-+              return PTR_ERR(ubi32_wdt_device);
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * ubi32_wdt_exit()
-+ *    Deinitialize module
-+ *
-+ * Back out the platform device & driver steps.  Real work is in the
-+ * platform remove function.
-+ */
-+static void __exit ubi32_wdt_exit(void)
-+{
-+      platform_device_unregister(ubi32_wdt_device);
-+      platform_driver_unregister(&ubi32_wdt_driver);
-+}
-+
-+module_init(ubi32_wdt_init);
-+module_exit(ubi32_wdt_exit);
-+
-+MODULE_AUTHOR("Sol Kavy<sol@ubicom.com>");
-+MODULE_DESCRIPTION("Ubicom32 Watchdog Device Driver");
-+MODULE_LICENSE("GPL");
-+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
-+
-+module_param(timeout, uint, 0);
-+MODULE_PARM_DESC(timeout,
-+      "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default="
-+              __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
-+
-+module_param(nowayout, int, 0);
-+MODULE_PARM_DESC(nowayout,
-+      "Watchdog cannot be stopped once started (default="
-+              __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
---- a/fs/binfmt_flat.c
-+++ b/fs/binfmt_flat.c
-@@ -67,6 +67,11 @@
- #define FLAT_DATA_ALIGN       (sizeof(void *))
- #endif
-+#ifndef ARCH_FLAT_ALIGN
-+#undef FLAT_DATA_ALIGN
-+#define FLAT_DATA_ALIGN       ARCH_FLAT_ALIGN
-+#endif
-+
- #define RELOC_FAILED 0xff00ff01               /* Relocation incorrect somewhere */
- #define UNLOADED_LIB 0x7ff000ff               /* Placeholder for unused library */
-@@ -436,6 +441,7 @@ static int load_flat_file(struct linux_b
-       loff_t fpos;
-       unsigned long start_code, end_code;
-       int ret;
-+      int flush_happened = 0;
-       hdr = ((struct flat_hdr *) bprm->buf);          /* exec-header */
-       inode = bprm->file->f_path.dentry->d_inode;
-@@ -521,6 +527,7 @@ static int load_flat_file(struct linux_b
-               /* OK, This is the point of no return */
-               set_personality(PER_LINUX_32BIT);
-+              flush_happened = 1;
-       }
-       /*
-@@ -535,6 +542,12 @@ static int load_flat_file(struct linux_b
-        * it all together.
-        */
-       if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) {
-+
-+#ifdef ARCH_FLAT_ALIGN_TEXT
-+              printk("Unable to mmap rom with ARCH alignment requirements\n");
-+              ret = -ENOEXEC;
-+              goto err;
-+#endif
-               /*
-                * this should give us a ROM ptr,  but if it doesn't we don't
-                * really care
-@@ -553,7 +566,7 @@ static int load_flat_file(struct linux_b
-                       goto err;
-               }
--              len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
-+              len = data_len + extra + ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), FLAT_DATA_ALIGN);
-               len = PAGE_ALIGN(len);
-               down_write(&current->mm->mmap_sem);
-               realdatastart = do_mmap(0, 0, len,
-@@ -572,6 +585,7 @@ static int load_flat_file(struct linux_b
-               datapos = ALIGN(realdatastart +
-                               MAX_SHARED_LIBS * sizeof(unsigned long),
-                               FLAT_DATA_ALIGN);
-+              //datapos = realdatastart + ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), ARCH_FLAT_ALIGN);
-               DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
-                               (int)(data_len + bss_len + stack_len), (int)datapos);
-@@ -600,7 +614,11 @@ static int load_flat_file(struct linux_b
-               memp_size = len;
-       } else {
--              len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
-+              len = text_len + data_len + extra + ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), FLAT_DATA_ALIGN);
-+#ifdef ARCH_FLAT_ALIGN_TEXT
-+              /* Reserve space for the text alignment. */
-+              len += FLAT_DATA_ALIGN;
-+#endif
-               len = PAGE_ALIGN(len);
-               down_write(&current->mm->mmap_sem);
-               textpos = do_mmap(0, 0, len,
-@@ -616,10 +634,17 @@ static int load_flat_file(struct linux_b
-                       goto err;
-               }
-+              memp = textpos;
-+#ifdef ARCH_FLAT_ALIGN_TEXT
-+              textpos = ALIGN(textpos + sizeof(struct flat_hdr), FLAT_DATA_ALIGN) - sizeof(struct flat_hdr);
-+#endif
-               realdatastart = textpos + ntohl(hdr->data_start);
-               datapos = ALIGN(realdatastart +
-                               MAX_SHARED_LIBS * sizeof(unsigned long),
-                               FLAT_DATA_ALIGN);
-+//            datapos = realdatastart + ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), ARCH_FLAT_ALIGN);
-+//            reloc = (unsigned long *) (textpos + ntohl(hdr->reloc_start) +
-+//                                       ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), ARCH_FLAT_ALIGN));
-               reloc = (unsigned long *)
-                       (datapos + (ntohl(hdr->reloc_start) - text_len));
-@@ -659,7 +684,7 @@ static int load_flat_file(struct linux_b
-               }
-               if (result >= (unsigned long)-4096) {
-                       printk("Unable to read code+data+bss, errno %d\n",(int)-result);
--                      do_munmap(current->mm, textpos, text_len + data_len + extra +
-+                      do_munmap(current->mm, memp, text_len + data_len + extra +
-                               MAX_SHARED_LIBS * sizeof(unsigned long));
-                       ret = result;
-                       goto err;
-@@ -672,6 +697,9 @@ static int load_flat_file(struct linux_b
-       /* The main program needs a little extra setup in the task structure */
-       start_code = textpos + sizeof (struct flat_hdr);
-+#ifdef ARCH_FLAT_ALIGN_TEXT
-+      BUG_ON(ALIGN(start_code, FLAT_DATA_ALIGN) != start_code);
-+#endif
-       end_code = textpos + text_len;
-       if (id == 0) {
-               current->mm->start_code = start_code;
-@@ -800,6 +828,13 @@ static int load_flat_file(struct linux_b
-       return 0;
- err:
-+      if (flush_happened) {
-+              /*
-+               * The parent process has already started running. We cannot allow the child to return back to user space
-+               * as this child is still uning the parent stack and 2 will clobber each other. We are going to kill this child.
-+               */
-+              do_exit(SIGTERM);
-+      }
-       return ret;
- }
---- a/fs/Kconfig.binfmt
-+++ b/fs/Kconfig.binfmt
-@@ -30,7 +30,7 @@ config COMPAT_BINFMT_ELF
- config BINFMT_ELF_FDPIC
-       bool "Kernel support for FDPIC ELF binaries"
-       default y
--      depends on (FRV || BLACKFIN || (SUPERH32 && !MMU))
-+      depends on (FRV || BLACKFIN || (SUPERH32 && !MMU) || UBICOM32)
-       help
-         ELF FDPIC binaries are based on ELF, but allow the individual load
-         segments of a binary to be located in memory independently of each
---- a/include/asm-generic/resource.h
-+++ b/include/asm-generic/resource.h
-@@ -69,13 +69,16 @@
- /*
-  * boot-time rlimit defaults for the init task:
-  */
-+#ifndef       CONFIG_ELF_CORE
-+#define       CONFIG_USER_ELF_CORE_SIZE       0
-+#endif
- #define INIT_RLIMITS                                                  \
- {                                                                     \
-       [RLIMIT_CPU]            = {  RLIM_INFINITY,  RLIM_INFINITY },   \
-       [RLIMIT_FSIZE]          = {  RLIM_INFINITY,  RLIM_INFINITY },   \
-       [RLIMIT_DATA]           = {  RLIM_INFINITY,  RLIM_INFINITY },   \
-       [RLIMIT_STACK]          = {       _STK_LIM,   _STK_LIM_MAX },   \
--      [RLIMIT_CORE]           = {              0,  RLIM_INFINITY },   \
-+      [RLIMIT_CORE]           = { CONFIG_USER_ELF_CORE_SIZE,  RLIM_INFINITY },        \
-       [RLIMIT_RSS]            = {  RLIM_INFINITY,  RLIM_INFINITY },   \
-       [RLIMIT_NPROC]          = {              0,              0 },   \
-       [RLIMIT_NOFILE]         = {       INR_OPEN,       INR_OPEN },   \
---- a/include/linux/elf-em.h
-+++ b/include/linux/elf-em.h
-@@ -41,6 +41,7 @@
-  * up with a final number.
-  */
- #define EM_ALPHA      0x9026
-+#define EM_UBICOM32           0xde3d  /* Ubicom32; no ABI */
- /* Bogus old v850 magic number, used by old tools. */
- #define EM_CYGNUS_V850        0x9080
---- a/include/linux/fb.h
-+++ b/include/linux/fb.h
-@@ -151,6 +151,10 @@ struct dentry;
- #define FB_ACCEL_PROSAVAGE_DDR  0x8d  /* S3 ProSavage DDR             */
- #define FB_ACCEL_PROSAVAGE_DDRK 0x8e  /* S3 ProSavage DDR-K           */
-+#define FB_ACCEL_UBICOM32             0x0100  /* Ubicom32                     */
-+#define FB_ACCEL_UBICOM32_VFB         0x0101  /* Ubicom32 VFB                 */
-+#define FB_ACCEL_UBICOM32_PLIO80      0x0102  /* Ubicom32 PLIO80              */
-+
- struct fb_fix_screeninfo {
-       char id[16];                    /* identification string eg "TT Builtin" */
-       unsigned long smem_start;       /* Start of frame buffer mem */
---- a/include/linux/if_ppp.h
-+++ b/include/linux/if_ppp.h
-@@ -114,14 +114,14 @@ struct pppol2tp_ioc_stats {
-       __u16           tunnel_id;      /* redundant */
-       __u16           session_id;     /* if zero, get tunnel stats */
-       __u32           using_ipsec:1;  /* valid only for session_id == 0 */
--      aligned_u64     tx_packets;
--      aligned_u64     tx_bytes;
--      aligned_u64     tx_errors;
--      aligned_u64     rx_packets;
--      aligned_u64     rx_bytes;
--      aligned_u64     rx_seq_discards;
--      aligned_u64     rx_oos_packets;
--      aligned_u64     rx_errors;
-+      __u64   tx_packets;
-+      __u64   tx_bytes;
-+      __u64   tx_errors;
-+      __u64   rx_packets;
-+      __u64   rx_bytes;
-+      __u64   rx_seq_discards;
-+      __u64   rx_oos_packets;
-+      __u64   rx_errors;
- };
- #define ifr__name       b.ifr_ifrn.ifrn_name
---- a/include/linux/oprofile.h
-+++ b/include/linux/oprofile.h
-@@ -99,6 +99,8 @@ void oprofile_add_sample(struct pt_regs 
-  */
- void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
-                               unsigned long event, int is_kernel);
-+void oprofile_add_ext_sample_cpu(unsigned long pc, struct pt_regs * const regs,
-+                              unsigned long event, int is_kernel, int cpu);
- /* Use this instead when the PC value is not from the regs. Doesn't
-  * backtrace. */
---- a/include/linux/serial_core.h
-+++ b/include/linux/serial_core.h
-@@ -167,6 +167,9 @@
- /* MAX3100 */
- #define PORT_MAX3100    86
-+/* Ubicom32 */
-+#define PORT_UBI32_UARTTIO    87
-+
- #ifdef __KERNEL__
- #include <linux/compiler.h>
---- a/include/linux/slab.h
-+++ b/include/linux/slab.h
-@@ -317,4 +317,14 @@ static inline void *kzalloc_node(size_t 
-       return kmalloc_node(size, flags | __GFP_ZERO, node);
- }
-+struct kmem_cache_size_info {
-+      unsigned short page;
-+      unsigned short order;
-+};
-+
-+/*
-+ * get info on all the memory allocated by slab for this named cache
-+ */
-+extern int kmem_cache_block_info(char *name, struct kmem_cache_size_info *data, int max_data);
-+
- #endif        /* _LINUX_SLAB_H */
---- a/init/Kconfig
-+++ b/init/Kconfig
-@@ -865,6 +865,12 @@ config ELF_CORE
-       help
-         Enable support for generating core dumps. Disabling saves about 4k.
-+config USER_ELF_CORE_SIZE
-+      int "user core dump size (10MB to 32MB)"
-+      range 10485760 33554432
-+      default 16777216
-+      depends on ELF_CORE
-+
- config PCSPKR_PLATFORM
-       bool "Enable PC-Speaker support" if EMBEDDED
-       depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES
---- a/kernel/module.c
-+++ b/kernel/module.c
-@@ -2688,6 +2688,9 @@ static int m_show(struct seq_file *m, vo
-       /* Used by oprofile and other similar tools. */
-       seq_printf(m, " 0x%p", mod->module_core);
-+#ifdef ARCH_PROC_MODULES_EXTRA
-+      ARCH_PROC_MODULES_EXTRA(m, mod);
-+#endif
-       /* Taints info */
-       if (mod->taints)
-               seq_printf(m, " %s", module_flags(mod, buf));
-@@ -2840,8 +2843,12 @@ void print_modules(void)
-       printk("Modules linked in:");
-       /* Most callers should already have preempt disabled, but make sure */
-       preempt_disable();
--      list_for_each_entry_rcu(mod, &modules, list)
-+      list_for_each_entry_rcu(mod, &modules, list) {
-               printk(" %s%s", mod->name, module_flags(mod, buf));
-+#ifdef ARCH_OOPS_MODULE_EXTRA
-+              ARCH_OOPS_MODULE_EXTRA(mod);
-+#endif
-+      }
-       preempt_enable();
-       if (last_unloaded_module[0])
-               printk(" [last unloaded: %s]", last_unloaded_module);
---- a/kernel/sched_clock.c
-+++ b/kernel/sched_clock.c
-@@ -38,8 +38,7 @@
-  */
- unsigned long long __attribute__((weak)) sched_clock(void)
- {
--      return (unsigned long long)(jiffies - INITIAL_JIFFIES)
--                                      * (NSEC_PER_SEC / HZ);
-+      return (get_jiffies_64() - INITIAL_JIFFIES) * (NSEC_PER_SEC / HZ);
- }
- static __read_mostly int sched_clock_running;
---- a/lib/Kconfig.debug
-+++ b/lib/Kconfig.debug
-@@ -621,7 +621,7 @@ config FRAME_POINTER
-       bool "Compile the kernel with frame pointers"
-       depends on DEBUG_KERNEL && \
-               (CRIS || M68K || M68KNOMMU || FRV || UML || \
--               AVR32 || SUPERH || BLACKFIN || MN10300) || \
-+               AVR32 || SUPERH || BLACKFIN || MN10300 || UBICOM32) || \
-               ARCH_WANT_FRAME_POINTERS
-       default y if (DEBUG_INFO && UML) || ARCH_WANT_FRAME_POINTERS
-       help
---- a/mm/Makefile
-+++ b/mm/Makefile
-@@ -38,3 +38,5 @@ obj-$(CONFIG_SMP) += allocpercpu.o
- endif
- obj-$(CONFIG_QUICKLIST) += quicklist.o
- obj-$(CONFIG_CGROUP_MEM_RES_CTLR) += memcontrol.o page_cgroup.o
-+
-+CFLAGS_slab.o := $(PROFILING) -O2
---- a/mm/slab.c
-+++ b/mm/slab.c
-@@ -4100,6 +4100,68 @@ out:
- #ifdef CONFIG_SLABINFO
-+
-+/*
-+ * get info on all the memory allocated by slab for this named cache
-+ */
-+int kmem_cache_block_info(char *name, struct kmem_cache_size_info *data, int max_data)
-+{
-+      int res = 0;
-+      int found = 0;
-+      int node;
-+      struct kmem_cache *cachep;
-+      struct kmem_list3 *l3;
-+      struct slab *slabp;
-+
-+      /* Find the cache in the chain of caches. */
-+      mutex_lock(&cache_chain_mutex);
-+      list_for_each_entry(cachep, &cache_chain, next) {
-+              if (strcmp(cachep->name, name) == 0) {
-+                      found = 1;
-+                      break;
-+              }
-+      }
-+      mutex_unlock(&cache_chain_mutex);
-+      if (!found) {
-+              return 0;
-+      }
-+      for_each_online_node(node) {
-+              l3 = cachep->nodelists[node];
-+              if (!l3)
-+                      continue;
-+              if (res >= max_data)
-+                      break;
-+              check_irq_on();
-+              spin_lock_irq(&l3->list_lock);
-+
-+              list_for_each_entry(slabp, &l3->slabs_full, list) {
-+                      if (res >= max_data)
-+                              break;
-+                      data[res].page = ((unsigned int)slabp->s_mem >> PAGE_SHIFT) & 0xffff;
-+                      data[res].order = cachep->gfporder;
-+                      res++;
-+              }
-+              list_for_each_entry(slabp, &l3->slabs_partial, list) {
-+                      if (res >= max_data)
-+                              break;
-+                      data[res].page = ((unsigned int)slabp->s_mem >> PAGE_SHIFT) & 0xffff;
-+                      data[res].order = cachep->gfporder;
-+                      res++;
-+              }
-+              list_for_each_entry(slabp, &l3->slabs_free, list) {
-+                      if (res >= max_data)
-+                              break;
-+                      data[res].page = ((unsigned int)slabp->s_mem >> PAGE_SHIFT) & 0xffff;
-+                      data[res].order = cachep->gfporder;
-+                      res++;
-+              }
-+
-+              spin_unlock_irq(&l3->list_lock);
-+      }
-+
-+      return res;
-+}
-+
- static void print_slabinfo_header(struct seq_file *m)
- {
-       /*
---- a/scripts/mod/file2alias.c
-+++ b/scripts/mod/file2alias.c
-@@ -774,6 +774,15 @@ void handle_moddevtable(struct module *m
-                       + sym->st_value;
-       }
-+      /*
-+       * somehow our gcc is not generating st_size correctly and set 0 for some symbols.
-+       * and 0 size will break do_table since it adjust size to (size - id_size)
-+       * this is to make sure st_size fall in range.
-+       */
-+      if (sym->st_size == 0 || sym->st_size > info->sechdrs[sym->st_shndx].sh_size) {
-+              sym->st_size = info->sechdrs[sym->st_shndx].sh_size;
-+      }
-+
-       if (sym_is(symname, "__mod_pci_device_table"))
-               do_table(symval, sym->st_size,
-                        sizeof(struct pci_device_id), "pci",
---- a/sound/Kconfig
-+++ b/sound/Kconfig
-@@ -82,6 +82,8 @@ source "sound/parisc/Kconfig"
- source "sound/soc/Kconfig"
-+source "sound/ubicom32/Kconfig"
-+
- endif # SND
- menuconfig SOUND_PRIME
---- a/sound/Makefile
-+++ b/sound/Makefile
-@@ -6,7 +6,7 @@ obj-$(CONFIG_SOUND_PRIME) += sound_firmw
- obj-$(CONFIG_SOUND_PRIME) += oss/
- obj-$(CONFIG_DMASOUND) += oss/
- obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
--      sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/
-+      sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ ubicom32/
- obj-$(CONFIG_SND_AOA) += aoa/
- # This one must be compilable even if sound is configured out
---- /dev/null
-+++ b/sound/ubicom32/Kconfig
-@@ -0,0 +1,42 @@
-+# ALSA Ubicom32 drivers
-+
-+menuconfig SND_UBI32
-+      tristate "Ubicom32 sound devices"
-+      select SND_PCM
-+      default n
-+      help
-+        Say Y here to include support for audio on the Ubicom32 platform.
-+        To compile this driver as a module, say M here: the module will be
-+        called snd_ubi32.
-+
-+if SND_UBI32
-+
-+config SND_UBI32_AUDIO_GENERIC_CAPTURE
-+      bool "Generic Capture Support"
-+      default n
-+      help
-+        Use this option to support ADCs which don't require special drivers.
-+
-+config SND_UBI32_AUDIO_GENERIC
-+      bool "Generic Playback Support"
-+      default n
-+      help
-+        Use this option to support DACs which don't require special drivers.
-+
-+comment "I2C Based Codecs"
-+
-+config SND_UBI32_AUDIO_CS4350
-+      bool "Cirrus Logic CS4350 DAC"
-+      depends on I2C
-+      default n
-+      help
-+        Support for the Cirrus Logic CS4350 DAC.
-+
-+config SND_UBI32_AUDIO_CS4384
-+      bool "Cirrus Logic CS4384 DAC"
-+      depends on I2C
-+      default n
-+      help
-+        Support for the Cirrus Logic CS4384 DAC.
-+
-+endif #SND_UBI32
---- /dev/null
-+++ b/sound/ubicom32/Makefile
-@@ -0,0 +1,41 @@
-+#
-+# sound/ubicom32/Makefile
-+#     Makefile for ALSA
-+#
-+# (C) Copyright 2009, Ubicom, Inc.
-+#
-+# This file is part of the Ubicom32 Linux Kernel Port.
-+#
-+# The Ubicom32 Linux Kernel Port 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.
-+#
-+# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+# see <http://www.gnu.org/licenses/>.
-+#
-+# Ubicom32 implementation derived from (with many thanks):
-+#   arch/m68knommu
-+#   arch/blackfin
-+#   arch/parisc
-+#
-+
-+CFLAGS_ubi32.o += -O2
-+snd-ubi32-pcm-objs := ubi32-pcm.o
-+snd-ubi32-generic-objs := ubi32-generic.o
-+snd-ubi32-generic-capture-objs := ubi32-generic-capture.o
-+snd-ubi32-cs4350-objs := ubi32-cs4350.o
-+snd-ubi32-cs4384-objs := ubi32-cs4384.o
-+
-+# Toplevel Module Dependency
-+obj-$(CONFIG_SND_UBI32) += snd-ubi32-pcm.o
-+obj-$(CONFIG_SND_UBI32_AUDIO_GENERIC) += snd-ubi32-generic.o
-+obj-$(CONFIG_SND_UBI32_AUDIO_GENERIC_CAPTURE) += snd-ubi32-generic-capture.o
-+obj-$(CONFIG_SND_UBI32_AUDIO_CS4350) += snd-ubi32-cs4350.o
-+obj-$(CONFIG_SND_UBI32_AUDIO_CS4384) += snd-ubi32-cs4384.o
---- /dev/null
-+++ b/sound/ubicom32/ubi32-cs4350.c
-@@ -0,0 +1,583 @@
-+/*
-+ * sound/ubicom32/ubi32-cs4350.c
-+ *    Interface to ubicom32 virtual audio peripheral - using CS4350 DAC
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/i2c.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <sound/core.h>
-+#include <sound/tlv.h>
-+#include <sound/control.h>
-+#include <sound/pcm.h>
-+#include <sound/initval.h>
-+#include "ubi32.h"
-+
-+#define DRIVER_NAME "snd-ubi32-cs4350"
-+
-+/*
-+ * Module properties
-+ */
-+static const struct i2c_device_id snd_ubi32_cs4350_id[] = {
-+      {"cs4350", 0 },
-+      { }
-+};
-+MODULE_DEVICE_TABLE(i2c, ubicom32audio_id);
-+
-+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
-+
-+/*
-+ * The dB scale for the Cirrus Logic cs4350.  The output range is from
-+ * -127.5 dB to 0 dB.
-+ */
-+static const DECLARE_TLV_DB_SCALE(snd_ubi32_cs4350_db, -12750, 50, 0);
-+
-+#define ubi32_cs4350_mute_info        snd_ctl_boolean_stereo_info
-+
-+/*
-+ * Private data for cs4350 chip
-+ */
-+struct ubi32_cs4350_priv {
-+      /*
-+       * The current volume settings
-+       */
-+      uint8_t volume[2];
-+
-+      /*
-+       * Bitmask of mutes MSB (unused, ..., unused, right_ch, left_ch) LSB
-+       */
-+      uint8_t mute;
-+
-+      /*
-+       * Lock to protect this struct because callbacks are not atomic.
-+       */
-+      spinlock_t lock;
-+};
-+
-+/*
-+ * The info for the cs4350.  The volume currently has one channel,
-+ * and 255 possible settings.
-+ */
-+static int ubi32_cs4350_volume_info(struct snd_kcontrol *kcontrol,
-+                                  struct snd_ctl_elem_info *uinfo)
-+{
-+      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-+      uinfo->count = 2;
-+      uinfo->value.integer.min = 0;
-+      uinfo->value.integer.max = 255; // 8 bits in cirrus logic cs4350 volume register
-+      return 0;
-+}
-+
-+static int ubi32_cs4350_volume_get(struct snd_kcontrol *kcontrol,
-+                                 struct snd_ctl_elem_value *ucontrol)
-+{
-+      struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol);
-+      struct ubi32_cs4350_priv *cs4350_priv;
-+      unsigned long flags;
-+
-+      cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv);
-+
-+      spin_lock_irqsave(&cs4350_priv->lock, flags);
-+
-+      ucontrol->value.integer.value[0] = cs4350_priv->volume[0];
-+      ucontrol->value.integer.value[1] = cs4350_priv->volume[1];
-+
-+      spin_unlock_irqrestore(&cs4350_priv->lock, flags);
-+
-+      return 0;
-+}
-+
-+static int ubi32_cs4350_volume_put(struct snd_kcontrol *kcontrol,
-+                                 struct snd_ctl_elem_value *ucontrol)
-+{
-+      struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol);
-+      struct i2c_client *client = (struct i2c_client *)ubi32_priv->client;
-+      struct ubi32_cs4350_priv *cs4350_priv;
-+      unsigned long flags;
-+      int ret, changed;
-+      char send[2];
-+      uint8_t volume_reg_value_left, volume_reg_value_right;
-+
-+      changed = 0;
-+
-+      cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv);
-+      volume_reg_value_left = 255 - (ucontrol->value.integer.value[0] & 0xFF);
-+      volume_reg_value_right = 255 - (ucontrol->value.integer.value[1] & 0xFF);
-+
-+#if SND_UBI32_DEBUG
-+      snd_printk(KERN_INFO "Setting volume: writing %d,%d to CS4350 volume registers\n", volume_reg_value_left, volume_reg_value_right);
-+#endif
-+      spin_lock_irqsave(&cs4350_priv->lock, flags);
-+
-+      if (cs4350_priv->volume[0] != ucontrol->value.integer.value[0]) {
-+              send[0] = 0x05; // left channel
-+              send[1] = volume_reg_value_left;
-+              ret = i2c_master_send(client, send, 2);
-+              if (ret != 2) {
-+                      snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n");
-+                      return changed;
-+              }
-+              cs4350_priv->volume[0] = ucontrol->value.integer.value[0];
-+              changed = 1;
-+      }
-+
-+      if (cs4350_priv->volume[1] != ucontrol->value.integer.value[1]) {
-+              send[0] = 0x06; // right channel
-+              send[1] = volume_reg_value_right;
-+              ret = i2c_master_send(client, send, 2);
-+              if (ret != 2) {
-+                      snd_printk(KERN_ERR "Failed to set channel B volume on CS4350\n");
-+                      return changed;
-+              }
-+              cs4350_priv->volume[1] = ucontrol->value.integer.value[1];
-+              changed = 1;
-+      }
-+
-+      spin_unlock_irqrestore(&cs4350_priv->lock, flags);
-+
-+      return changed;
-+}
-+
-+static struct snd_kcontrol_new ubi32_cs4350_volume __devinitdata = {
-+      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+      .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+                SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+      .name = "PCM Playback Volume",
-+      .info = ubi32_cs4350_volume_info,
-+      .get = ubi32_cs4350_volume_get,
-+      .put = ubi32_cs4350_volume_put,
-+      .tlv.p = snd_ubi32_cs4350_db,
-+};
-+
-+static int ubi32_cs4350_mute_get(struct snd_kcontrol *kcontrol,
-+                               struct snd_ctl_elem_value *ucontrol)
-+{
-+      struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol);
-+      struct ubi32_cs4350_priv *cs4350_priv;
-+      unsigned long flags;
-+
-+      cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv);
-+
-+      spin_lock_irqsave(&cs4350_priv->lock, flags);
-+
-+      ucontrol->value.integer.value[0] = cs4350_priv->mute & 1;
-+      ucontrol->value.integer.value[1] = (cs4350_priv->mute & (1 << 1)) ? 1 : 0;
-+
-+      spin_unlock_irqrestore(&cs4350_priv->lock, flags);
-+
-+      return 0;
-+}
-+
-+static int ubi32_cs4350_mute_put(struct snd_kcontrol *kcontrol,
-+                               struct snd_ctl_elem_value *ucontrol)
-+{
-+      struct ubi32_snd_priv *ubi32_priv = snd_kcontrol_chip(kcontrol);
-+      struct i2c_client *client = (struct i2c_client *)ubi32_priv->client;
-+      struct ubi32_cs4350_priv *cs4350_priv;
-+      unsigned long flags;
-+      int ret, changed;
-+      char send[2];
-+      char recv[1];
-+      uint8_t mute;
-+
-+        changed = 0;
-+
-+      cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv);
-+
-+      spin_lock_irqsave(&cs4350_priv->lock, flags);
-+
-+      if ((cs4350_priv->mute & 1) != ucontrol->value.integer.value[0]) {
-+              send[0] = 0x04;
-+              ret = i2c_master_send(client, send, 1);
-+              if (ret != 1) {
-+                      snd_printk(KERN_ERR "Failed to write to mute register: channel 0\n");
-+                      return changed;
-+              }
-+
-+              ret = i2c_master_recv(client, recv, 1);
-+              if (ret != 1) {
-+                      snd_printk(KERN_ERR "Failed to read mute register: channel 0\n");
-+                      return changed;
-+              }
-+
-+              mute = recv[0];
-+
-+              if (ucontrol->value.integer.value[0]) {
-+                      cs4350_priv->mute |= 1;
-+                      mute &= ~(1 << 4);
-+#if SND_UBI32_DEBUG
-+                      snd_printk(KERN_INFO "Unmuted channel A\n");
-+#endif
-+              } else {
-+                      cs4350_priv->mute &= ~1;
-+                      mute |= (1 << 4);
-+#if SND_UBI32_DEBUG
-+                      snd_printk(KERN_INFO "Muted channel A\n");
-+#endif
-+              }
-+
-+              send[0] = 0x04;
-+              send[1] = mute;
-+              ret = i2c_master_send(client, send, 2);
-+              if (ret != 2) {
-+                      snd_printk(KERN_ERR "Failed to set channel A mute on CS4350\n");
-+                      return changed;
-+              }
-+              changed = 1;
-+      }
-+
-+      if (((cs4350_priv->mute & 2) >> 1) != ucontrol->value.integer.value[1]) {
-+              send[0] = 0x04;
-+              ret = i2c_master_send(client, send, 1);
-+              if (ret != 1) {
-+                      snd_printk(KERN_ERR "Failed to write to mute register: channel 1\n");
-+                      return changed;
-+              }
-+
-+              ret = i2c_master_recv(client, recv, 1);
-+              if (ret != 1) {
-+                      snd_printk(KERN_ERR "Failed to read mute register: channel 1\n");
-+                      return changed;
-+              }
-+
-+              mute = recv[0];
-+
-+              if (ucontrol->value.integer.value[1]) {
-+                      cs4350_priv->mute |= (1 << 1);
-+                      mute &= ~(1 << 3);
-+#if SND_UBI32_DEBUG
-+                      snd_printk(KERN_INFO "Unmuted channel B\n");
-+#endif
-+              } else {
-+                      cs4350_priv->mute &= ~(1 << 1);
-+                      mute |= (1 << 3);
-+#if SND_UBI32_DEBUG
-+                      snd_printk(KERN_INFO "Muted channel B\n");
-+#endif
-+              }
-+
-+              send[0] = 0x04;
-+              send[1] = mute;
-+              ret = i2c_master_send(client, send, 2);
-+              if (ret != 2) {
-+                      snd_printk(KERN_ERR "Failed to set channel A mute on CS4350\n");
-+                      return changed;
-+              }
-+              changed = 1;
-+      }
-+
-+      spin_unlock_irqrestore(&cs4350_priv->lock, flags);
-+
-+      return changed;
-+}
-+
-+static struct snd_kcontrol_new ubi32_cs4350_mute __devinitdata = {
-+      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+      .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-+      .name = "PCM Playback Switch",
-+      .info = ubi32_cs4350_mute_info,
-+      .get = ubi32_cs4350_mute_get,
-+      .put = ubi32_cs4350_mute_put,
-+};
-+
-+/*
-+ * snd_ubi32_cs4350_free
-+ *    Card private data free function
-+ */
-+void snd_ubi32_cs4350_free(struct snd_card *card)
-+{
-+      struct ubi32_snd_priv *ubi32_priv;
-+      struct ubi32_cs4350_priv *cs4350_priv;
-+
-+      ubi32_priv = card->private_data;
-+      cs4350_priv = snd_ubi32_priv_get_drv(ubi32_priv);
-+      if (cs4350_priv) {
-+              kfree(cs4350_priv);
-+      }
-+}
-+
-+/*
-+ * snd_ubi32_cs4350_dac_init
-+ */
-+static int snd_ubi32_cs4350_dac_init(struct i2c_client *client, const struct i2c_device_id *id)
-+{
-+      int ret;
-+      char send[2];
-+      char recv[8];
-+
-+      /*
-+       * Initialize the CS4350 DAC over the I2C interface
-+       */
-+      snd_printk(KERN_INFO "Initializing CS4350 DAC\n");
-+
-+      /*
-+       * Register 0x01: device/revid
-+       */
-+      send[0] = 0x01;
-+      ret = i2c_master_send(client, send, 1);
-+      if (ret != 1) {
-+              snd_printk(KERN_ERR "Failed 1st attempt to write to CS4350 register 0x01\n");
-+              goto fail;
-+      }
-+      ret = i2c_master_recv(client, recv, 1);
-+      if (ret != 1) {
-+              snd_printk(KERN_ERR "Failed initial read of CS4350 registers\n");
-+              goto fail;
-+      }
-+      snd_printk(KERN_INFO "CS4350 DAC Device/Rev: %08x\n", recv[0]);
-+
-+      /*
-+       * Register 0x02: Mode control
-+       *      I2S DIF[2:0] = 001, no De-Emphasis, Auto speed mode
-+       */
-+      send[0] = 0x02;
-+      send[1] = 0x10;
-+      ret = i2c_master_send(client, send, 2);
-+      if (ret != 2) {
-+              snd_printk(KERN_ERR "Failed to set CS4350 to I2S mode\n");
-+              goto fail;
-+      }
-+
-+      /*
-+       * Register 0x05/0x06: Volume control
-+       *      Channel A volume set to 0 dB
-+       *      Channel B volume set to 0 dB
-+       */
-+      send[0] = 0x05;
-+      send[1] = 0x00;
-+      ret = i2c_master_send(client, send, 2);
-+      if (ret != 2) {
-+              snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n");
-+              goto fail;
-+      }
-+
-+      send[0] = 0x06;
-+      send[1] = 0x00;
-+      ret = i2c_master_send(client, send, 2);
-+      if (ret != 2) {
-+              snd_printk(KERN_ERR "Failed to set channel A volume on CS4350\n");
-+              goto fail;
-+      }
-+
-+      /*
-+       * Make sure the changes took place, this helps verify we are talking to
-+       * the correct chip.
-+       */
-+      send[0] = 0x81;
-+      ret = i2c_master_send(client, send, 1);
-+      if (ret != 1) {
-+              snd_printk(KERN_ERR "Failed to initiate readback\n");
-+              goto fail;
-+      }
-+
-+      ret = i2c_master_recv(client, recv, 8);
-+      if (ret != 8) {
-+              snd_printk(KERN_ERR "Failed second read of CS4350 registers\n");
-+              goto fail;
-+      }
-+
-+      if ((recv[1] != 0x10) || (recv[4] != 0x00) || (recv[5] != 0x00)) {
-+              snd_printk(KERN_ERR "Failed to initialize CS4350 DAC\n");
-+              goto fail;
-+      }
-+
-+      snd_printk(KERN_INFO "CS4350 DAC Initialized\n");
-+      return 0;
-+
-+fail:
-+      return -ENODEV;
-+}
-+
-+/*
-+ * snd_ubi32_cs4350_i2c_probe
-+ */
-+static int snd_ubi32_cs4350_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
-+{
-+      struct snd_card *card;
-+      struct ubi32_snd_priv *ubi32_priv;
-+      struct ubi32_cs4350_priv *cs4350_priv;
-+      int err, ret;
-+      struct platform_device *pdev;
-+
-+      pdev = client->dev.platform_data;
-+      if (!pdev) {
-+              return -ENODEV;
-+      }
-+
-+      /*
-+       * Initialize the CS4350 DAC
-+       */
-+      ret = snd_ubi32_cs4350_dac_init(client, id);
-+      if (ret < 0) {
-+              /*
-+               * Initialization failed.  Propagate the error.
-+               */
-+              return ret;
-+      }
-+
-+      /*
-+       * Create a snd_card structure
-+       */
-+      card = snd_card_new(index, "Ubi32-CS4350", THIS_MODULE, sizeof(struct ubi32_snd_priv));
-+      if (card == NULL) {
-+              return -ENOMEM;
-+      }
-+
-+      card->private_free = snd_ubi32_cs4350_free; /* Not sure if correct */
-+      ubi32_priv = card->private_data;
-+
-+      /*
-+       * CS4350 DAC has a minimum sample rate of 30khz and an
-+       * upper limit of 216khz for it's auto-detect.
-+       */
-+      ubi32_priv->min_sample_rate = 30000;
-+      ubi32_priv->max_sample_rate = 216000;
-+
-+      /*
-+       * Initialize the snd_card's private data structure
-+       */
-+      ubi32_priv->card = card;
-+      ubi32_priv->client = client;
-+
-+      /*
-+       * Create our private data structure
-+       */
-+      cs4350_priv = kzalloc(sizeof(struct ubi32_cs4350_priv), GFP_KERNEL);
-+      if (!cs4350_priv) {
-+              snd_card_free(card);
-+              return -ENOMEM;
-+      }
-+      snd_ubi32_priv_set_drv(ubi32_priv, cs4350_priv);
-+      spin_lock_init(&cs4350_priv->lock);
-+
-+      /*
-+       * Initial volume is set to max by probe function
-+       */
-+      cs4350_priv->volume[0] = 0xFF;
-+      cs4350_priv->volume[1] = 0xFF;
-+
-+      /*
-+       * The CS4350 starts off unmuted (bit set = not muted)
-+       */
-+      cs4350_priv->mute = 3;
-+
-+      /*
-+       * Create the new PCM instance
-+       */
-+      err = snd_ubi32_pcm_probe(ubi32_priv, pdev);
-+      if (err < 0) {
-+              snd_card_free(card);
-+              return err; /* What is err?  Need to include correct file */
-+      }
-+
-+      strcpy(card->driver, "Ubi32-CS4350");
-+      strcpy(card->shortname, "Ubi32-CS4350");
-+      snprintf(card->longname, sizeof(card->longname),
-+              "%s at sendirq=%d.%d recvirq=%d.%d regs=%p",
-+              card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx,
-+              ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr);
-+
-+      snd_card_set_dev(card, &client->dev);
-+
-+      /*
-+       * Set up the mixer components
-+       */
-+      err = snd_ctl_add(card, snd_ctl_new1(&ubi32_cs4350_volume, ubi32_priv));
-+      if (err) {
-+              snd_printk(KERN_WARNING "Failed to add volume mixer control\n");
-+      }
-+      err = snd_ctl_add(card, snd_ctl_new1(&ubi32_cs4350_mute, ubi32_priv));
-+      if (err) {
-+              snd_printk(KERN_WARNING "Failed to add mute mixer control\n");
-+      }
-+
-+      /*
-+       * Register the sound card
-+       */
-+      if ((err = snd_card_register(card)) != 0) {
-+              snd_printk(KERN_WARNING "snd_card_register error\n");
-+      }
-+
-+      /*
-+       * Store card for access from other methods
-+       */
-+      i2c_set_clientdata(client, card);
-+
-+      return 0;
-+}
-+
-+/*
-+ * snd_ubi32_cs4350_i2c_remove
-+ */
-+static int __devexit snd_ubi32_cs4350_i2c_remove(struct i2c_client *client)
-+{
-+      struct snd_card *card;
-+      struct ubi32_snd_priv *ubi32_priv;
-+
-+      card = i2c_get_clientdata(client);
-+
-+      ubi32_priv = card->private_data;
-+      snd_ubi32_pcm_remove(ubi32_priv);
-+
-+      snd_card_free(i2c_get_clientdata(client));
-+      i2c_set_clientdata(client, NULL);
-+
-+      return 0;
-+}
-+
-+/*
-+ * I2C driver description
-+ */
-+static struct i2c_driver snd_ubi32_cs4350_driver = {
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+      .id_table       = snd_ubi32_cs4350_id,
-+      .probe          = snd_ubi32_cs4350_i2c_probe,
-+      .remove         = __devexit_p(snd_ubi32_cs4350_i2c_remove),
-+};
-+
-+/*
-+ * Driver init
-+ */
-+static int __init snd_ubi32_cs4350_init(void)
-+{
-+      return i2c_add_driver(&snd_ubi32_cs4350_driver);
-+}
-+module_init(snd_ubi32_cs4350_init);
-+
-+/*
-+ * snd_ubi32_cs4350_exit
-+ */
-+static void __exit snd_ubi32_cs4350_exit(void)
-+{
-+      i2c_del_driver(&snd_ubi32_cs4350_driver);
-+}
-+module_exit(snd_ubi32_cs4350_exit);
-+
-+/*
-+ * Module properties
-+ */
-+MODULE_ALIAS("i2c:" DRIVER_NAME);
-+MODULE_AUTHOR("Patrick Tjin");
-+MODULE_DESCRIPTION("Driver for Ubicom32 audio devices CS4350");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/sound/ubicom32/ubi32-cs4384.c
-@@ -0,0 +1,996 @@
-+/*
-+ * sound/ubicom32/ubi32-cs4384.c
-+ *    Interface to ubicom32 virtual audio peripheral - using CS4384 DAC
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/i2c.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/delay.h>
-+#include <sound/core.h>
-+#include <sound/tlv.h>
-+#include <sound/control.h>
-+#include <sound/pcm.h>
-+#include <sound/initval.h>
-+#include <asm/ip5000.h>
-+#include <asm/gpio.h>
-+#include <asm/audio.h>
-+#include <asm/ubi32-cs4384.h>
-+#include "ubi32.h"
-+
-+#define DRIVER_NAME "snd-ubi32-cs4384"
-+
-+/*
-+ * Module properties
-+ */
-+static const struct i2c_device_id snd_ubi32_cs4384_id[] = {
-+      {"cs4384", 0 },
-+      { }
-+};
-+MODULE_DEVICE_TABLE(i2c, ubicom32audio_id);
-+
-+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
-+
-+/*
-+ * Mixer properties
-+ */
-+enum {
-+      /*
-+       * Be careful of changing the order of these IDs, they
-+       * are used to index the volume array.
-+       */
-+      SND_UBI32_CS4384_FRONT_ID,
-+      SND_UBI32_CS4384_SURROUND_ID,
-+      SND_UBI32_CS4384_CENTER_ID,
-+      SND_UBI32_CS4384_LFE_ID,
-+      SND_UBI32_CS4384_REAR_ID,
-+
-+      /*
-+       * This should be the last ID
-+       */
-+      SND_UBI32_CS4384_LAST_ID,
-+};
-+static const u8_t snd_ubi32_cs4384_ch_ofs[] = {0, 2, 4, 5, 6};
-+
-+static const DECLARE_TLV_DB_SCALE(snd_ubi32_cs4384_db, -12750, 50, 0);
-+
-+#define snd_ubi32_cs4384_info_mute    snd_ctl_boolean_stereo_info
-+#define snd_ubi32_cs4384_info_mute_mono       snd_ctl_boolean_mono_info
-+
-+/*
-+ * Mixer controls
-+ */
-+static int snd_ubi32_cs4384_info_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo);
-+static int snd_ubi32_cs4384_get_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-+static int snd_ubi32_cs4384_put_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-+static int snd_ubi32_cs4384_get_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-+static int snd_ubi32_cs4384_put_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol);
-+
-+/*
-+ * Make sure to update these if the structure below is changed
-+ */
-+#define SND_UBI32_MUTE_CTL_START      5
-+#define SND_UBI32_MUTE_CTL_END                9
-+static struct snd_kcontrol_new snd_ubi32_cs4384_controls[] __devinitdata = {
-+      {
-+              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+              .name = "Front Playback Volume",
-+              .info = snd_ubi32_cs4384_info_volume,
-+              .get = snd_ubi32_cs4384_get_volume,
-+              .put = snd_ubi32_cs4384_put_volume,
-+              .private_value = SND_UBI32_CS4384_FRONT_ID,
-+              .tlv = {
-+                      .p = snd_ubi32_cs4384_db,
-+              },
-+      },
-+      {
-+              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+              .name = "Surround Playback Volume",
-+              .info = snd_ubi32_cs4384_info_volume,
-+              .get = snd_ubi32_cs4384_get_volume,
-+              .put = snd_ubi32_cs4384_put_volume,
-+              .private_value = SND_UBI32_CS4384_SURROUND_ID,
-+              .tlv = {
-+                      .p = snd_ubi32_cs4384_db,
-+              },
-+      },
-+      {
-+              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+              .name = "Center Playback Volume",
-+              .info = snd_ubi32_cs4384_info_volume,
-+              .get = snd_ubi32_cs4384_get_volume,
-+              .put = snd_ubi32_cs4384_put_volume,
-+              .private_value = SND_UBI32_CS4384_CENTER_ID,
-+              .tlv = {
-+                      .p = snd_ubi32_cs4384_db,
-+              },
-+      },
-+      {
-+              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+              .name = "LFE Playback Volume",
-+              .info = snd_ubi32_cs4384_info_volume,
-+              .get = snd_ubi32_cs4384_get_volume,
-+              .put = snd_ubi32_cs4384_put_volume,
-+              .private_value = SND_UBI32_CS4384_LFE_ID,
-+              .tlv = {
-+                      .p = snd_ubi32_cs4384_db,
-+              },
-+      },
-+      {
-+              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+              .name = "Rear Playback Volume",
-+              .info = snd_ubi32_cs4384_info_volume,
-+              .get = snd_ubi32_cs4384_get_volume,
-+              .put = snd_ubi32_cs4384_put_volume,
-+              .private_value = SND_UBI32_CS4384_REAR_ID,
-+              .tlv = {
-+                      .p = snd_ubi32_cs4384_db,
-+              },
-+      },
-+      {
-+              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+              .name = "Front Playback Switch",
-+              .info = snd_ubi32_cs4384_info_mute,
-+              .get = snd_ubi32_cs4384_get_mute,
-+              .put = snd_ubi32_cs4384_put_mute,
-+              .private_value = SND_UBI32_CS4384_FRONT_ID,
-+      },
-+      {
-+              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+              .name = "Surround Playback Switch",
-+              .info = snd_ubi32_cs4384_info_mute,
-+              .get = snd_ubi32_cs4384_get_mute,
-+              .put = snd_ubi32_cs4384_put_mute,
-+              .private_value = SND_UBI32_CS4384_SURROUND_ID,
-+      },
-+      {
-+              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+              .name = "Center Playback Switch",
-+              .info = snd_ubi32_cs4384_info_mute_mono,
-+              .get = snd_ubi32_cs4384_get_mute,
-+              .put = snd_ubi32_cs4384_put_mute,
-+              .private_value = SND_UBI32_CS4384_CENTER_ID,
-+      },
-+      {
-+              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+              .name = "LFE Playback Switch",
-+              .info = snd_ubi32_cs4384_info_mute_mono,
-+              .get = snd_ubi32_cs4384_get_mute,
-+              .put = snd_ubi32_cs4384_put_mute,
-+              .private_value = SND_UBI32_CS4384_LFE_ID,
-+      },
-+      {
-+              .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-+              .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-+                        SNDRV_CTL_ELEM_ACCESS_TLV_READ,
-+              .name = "Rear Playback Switch",
-+              .info = snd_ubi32_cs4384_info_mute,
-+              .get = snd_ubi32_cs4384_get_mute,
-+              .put = snd_ubi32_cs4384_put_mute,
-+              .private_value = SND_UBI32_CS4384_REAR_ID,
-+      },
-+};
-+
-+/*
-+ * Our private data
-+ */
-+struct snd_ubi32_cs4384_priv {
-+      /*
-+       * Array of current volumes
-+       *      (L, R, SL, SR, C, LFE, RL, RR)
-+       */
-+      uint8_t volume[8];
-+
-+      /*
-+       * Bitmask of mutes
-+       *      MSB (RR, RL, LFE, C, SR, SL, R, L) LSB
-+       */
-+      uint8_t mute;
-+
-+      /*
-+       * Array of controls
-+       */
-+      struct snd_kcontrol *kctls[ARRAY_SIZE(snd_ubi32_cs4384_controls)];
-+
-+      /*
-+       * Lock to protect our card
-+       */
-+      spinlock_t lock;
-+};
-+
-+/*
-+ * snd_ubi32_cs4384_info_volume
-+ */
-+static int snd_ubi32_cs4384_info_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-+{
-+      unsigned int id = (unsigned int)kcontrol->private_value;
-+
-+      uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-+      uinfo->count = 1;
-+      if ((id != SND_UBI32_CS4384_LFE_ID) &&
-+          (id != SND_UBI32_CS4384_CENTER_ID)) {
-+              uinfo->count = 2;
-+      }
-+      uinfo->value.integer.min = 0;
-+      uinfo->value.integer.max = 255;
-+      return 0;
-+}
-+
-+/*
-+ * snd_ubi32_cs4384_get_volume
-+ */
-+static int snd_ubi32_cs4384_get_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-+{
-+      struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol);
-+      struct snd_ubi32_cs4384_priv *cs4384_priv;
-+      unsigned int id = (unsigned int)kcontrol->private_value;
-+      int ch = snd_ubi32_cs4384_ch_ofs[id];
-+      unsigned long flags;
-+
-+      if (id >= SND_UBI32_CS4384_LAST_ID) {
-+              return -EINVAL;
-+      }
-+
-+      cs4384_priv = snd_ubi32_priv_get_drv(priv);
-+
-+      spin_lock_irqsave(&cs4384_priv->lock, flags);
-+
-+      ucontrol->value.integer.value[0] = cs4384_priv->volume[ch];
-+      if ((id != SND_UBI32_CS4384_LFE_ID) &&
-+          (id != SND_UBI32_CS4384_CENTER_ID)) {
-+              ch++;
-+              ucontrol->value.integer.value[1] = cs4384_priv->volume[ch];
-+      }
-+
-+      spin_unlock_irqrestore(&cs4384_priv->lock, flags);
-+
-+      return 0;
-+}
-+
-+/*
-+ * snd_ubi32_cs4384_put_volume
-+ */
-+static int snd_ubi32_cs4384_put_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-+{
-+      struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol);
-+      struct i2c_client *client = (struct i2c_client *)priv->client;
-+      struct snd_ubi32_cs4384_priv *cs4384_priv;
-+      unsigned int id = (unsigned int)kcontrol->private_value;
-+      int ch = snd_ubi32_cs4384_ch_ofs[id];
-+      unsigned long flags;
-+      unsigned char send[3];
-+      int nch;
-+      int ret = -EINVAL;
-+
-+      if (id >= SND_UBI32_CS4384_LAST_ID) {
-+              return -EINVAL;
-+      }
-+
-+      cs4384_priv = snd_ubi32_priv_get_drv(priv);
-+
-+      spin_lock_irqsave(&cs4384_priv->lock, flags);
-+
-+      send[0] = 0;
-+      switch (id) {
-+      case SND_UBI32_CS4384_REAR_ID:
-+              send[0] = 0x06;
-+
-+              /*
-+               * Fall through
-+               */
-+
-+      case SND_UBI32_CS4384_SURROUND_ID:
-+              send[0] += 0x03;
-+
-+              /*
-+               * Fall through
-+               */
-+
-+      case SND_UBI32_CS4384_FRONT_ID:
-+              send[0] += 0x8B;
-+              nch = 2;
-+              send[1] = 255 - (ucontrol->value.integer.value[0] & 0xFF);
-+              send[2] = 255 - (ucontrol->value.integer.value[1] & 0xFF);
-+              cs4384_priv->volume[ch++] = send[1];
-+              cs4384_priv->volume[ch] = send[2];
-+              break;
-+
-+      case SND_UBI32_CS4384_LFE_ID:
-+              send[0] = 0x81;
-+
-+              /*
-+               * Fall through
-+               */
-+
-+      case SND_UBI32_CS4384_CENTER_ID:
-+              send[0] += 0x11;
-+              nch = 1;
-+              send[1] = 255 - (ucontrol->value.integer.value[0] & 0xFF);
-+              cs4384_priv->volume[ch] = send[1];
-+              break;
-+
-+      default:
-+              spin_unlock_irqrestore(&cs4384_priv->lock, flags);
-+              goto done;
-+
-+      }
-+
-+      /*
-+       * Send the volume to the chip
-+       */
-+      nch++;
-+      ret = i2c_master_send(client, send, nch);
-+      if (ret != nch) {
-+              snd_printk(KERN_ERR "Failed to set volume on CS4384\n");
-+      }
-+
-+done:
-+      spin_unlock_irqrestore(&cs4384_priv->lock, flags);
-+
-+      return ret;
-+}
-+
-+/*
-+ * snd_ubi32_cs4384_get_mute
-+ */
-+static int snd_ubi32_cs4384_get_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-+{
-+      struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol);
-+      struct snd_ubi32_cs4384_priv *cs4384_priv;
-+      unsigned int id = (unsigned int)kcontrol->private_value;
-+      int ch = snd_ubi32_cs4384_ch_ofs[id];
-+      unsigned long flags;
-+
-+      if (id >= SND_UBI32_CS4384_LAST_ID) {
-+              return -EINVAL;
-+      }
-+
-+      cs4384_priv = snd_ubi32_priv_get_drv(priv);
-+
-+      spin_lock_irqsave(&cs4384_priv->lock, flags);
-+
-+      ucontrol->value.integer.value[0] = !(cs4384_priv->mute & (1 << ch));
-+
-+      if ((id != SND_UBI32_CS4384_LFE_ID) &&
-+          (id != SND_UBI32_CS4384_CENTER_ID)) {
-+              ch++;
-+              ucontrol->value.integer.value[1] = !(cs4384_priv->mute & (1 << ch));
-+      }
-+
-+      spin_unlock_irqrestore(&cs4384_priv->lock, flags);
-+
-+      return 0;
-+}
-+
-+/*
-+ * snd_ubi32_cs4384_put_mute
-+ */
-+static int snd_ubi32_cs4384_put_mute(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
-+{
-+      struct ubi32_snd_priv *priv = snd_kcontrol_chip(kcontrol);
-+      struct i2c_client *client = (struct i2c_client *)priv->client;
-+      struct snd_ubi32_cs4384_priv *cs4384_priv;
-+      unsigned int id = (unsigned int)kcontrol->private_value;
-+      int ch = snd_ubi32_cs4384_ch_ofs[id];
-+      unsigned long flags;
-+      unsigned char send[2];
-+      int ret = -EINVAL;
-+
-+      if (id >= SND_UBI32_CS4384_LAST_ID) {
-+              return -EINVAL;
-+      }
-+
-+      cs4384_priv = snd_ubi32_priv_get_drv(priv);
-+
-+      spin_lock_irqsave(&cs4384_priv->lock, flags);
-+
-+      if (ucontrol->value.integer.value[0]) {
-+              cs4384_priv->mute &= ~(1 << ch);
-+      } else {
-+              cs4384_priv->mute |= (1 << ch);
-+      }
-+
-+      if ((id != SND_UBI32_CS4384_LFE_ID) && (id != SND_UBI32_CS4384_CENTER_ID)) {
-+              ch++;
-+              if (ucontrol->value.integer.value[1]) {
-+                      cs4384_priv->mute &= ~(1 << ch);
-+              } else {
-+                      cs4384_priv->mute |= (1 << ch);
-+              }
-+      }
-+
-+      /*
-+       * Update the chip's mute reigster
-+       */
-+      send[0] = 0x09;
-+      send[1] = cs4384_priv->mute;
-+      ret = i2c_master_send(client, send, 2);
-+      if (ret != 2) {
-+              snd_printk(KERN_ERR "Failed to set mute on CS4384\n");
-+      }
-+
-+      spin_unlock_irqrestore(&cs4384_priv->lock, flags);
-+
-+      return ret;
-+}
-+
-+/*
-+ * snd_ubi32_cs4384_mixer
-+ *    Setup the mixer controls
-+ */
-+static int __devinit snd_ubi32_cs4384_mixer(struct ubi32_snd_priv *priv)
-+{
-+      struct snd_card *card = priv->card;
-+      struct snd_ubi32_cs4384_priv *cs4384_priv;
-+      int i;
-+
-+      cs4384_priv = snd_ubi32_priv_get_drv(priv);
-+      for (i = 0; i < ARRAY_SIZE(snd_ubi32_cs4384_controls); i++) {
-+              int err;
-+
-+              cs4384_priv->kctls[i] = snd_ctl_new1(&snd_ubi32_cs4384_controls[i], priv);
-+              err = snd_ctl_add(card, cs4384_priv->kctls[i]);
-+              if (err) {
-+                      snd_printk(KERN_WARNING "Failed to add control %d\n", i);
-+                      return err;
-+              }
-+      }
-+      return 0;
-+}
-+
-+/*
-+ * snd_ubi32_cs4384_free
-+ *    Card private data free function
-+ */
-+void snd_ubi32_cs4384_free(struct snd_card *card)
-+{
-+      struct snd_ubi32_cs4384_priv *cs4384_priv;
-+      struct ubi32_snd_priv *ubi32_priv;
-+
-+      ubi32_priv = card->private_data;
-+      cs4384_priv = snd_ubi32_priv_get_drv(ubi32_priv);
-+      if (cs4384_priv) {
-+              kfree(cs4384_priv);
-+      }
-+}
-+
-+/*
-+ * snd_ubi32_cs4384_setup_mclk
-+ */
-+static int snd_ubi32_cs4384_setup_mclk(struct ubi32_cs4384_platform_data *pdata)
-+{
-+      struct ubicom32_io_port *ioa = (struct ubicom32_io_port *)RA;
-+      struct ubicom32_io_port *ioc = (struct ubicom32_io_port *)RC;
-+      struct ubicom32_io_port *iod = (struct ubicom32_io_port *)RD;
-+      struct ubicom32_io_port *ioe = (struct ubicom32_io_port *)RE;
-+      struct ubicom32_io_port *ioh = (struct ubicom32_io_port *)RH;
-+      unsigned int ctl0;
-+      unsigned int ctlx;
-+      unsigned int div;
-+
-+      div = pdata->mclk_entries[0].div;
-+
-+      ctl0 = (1 << 13);
-+      ctlx = ((div - 1) << 16) | (div / 2);
-+
-+      switch (pdata->mclk_src) {
-+      case UBI32_CS4384_MCLK_PWM_0:
-+              ioc->function |= 2;
-+              ioc->ctl0 |= ctl0;
-+              ioc->ctl1 = ctlx;
-+              if (!ioa->function) {
-+                      ioa->function = 3;
-+              }
-+              return 0;
-+
-+      case UBI32_CS4384_MCLK_PWM_1:
-+              ioc->function |= 2;
-+              ioc->ctl0 |= ctl0 << 16;
-+              ioc->ctl2 = ctlx;
-+              if (!ioe->function) {
-+                      ioe->function = 3;
-+              }
-+              return 0;
-+
-+      case UBI32_CS4384_MCLK_PWM_2:
-+              ioh->ctl0 |= ctl0;
-+              ioh->ctl1 = ctlx;
-+              if (!iod->function) {
-+                      iod->function = 3;
-+              }
-+              return 0;
-+
-+      case UBI32_CS4384_MCLK_CLKDIV_1:
-+              ioa->gpio_mask &= (1 << 7);
-+              ioa->ctl1 &= ~(0x7F << 14);
-+              ioa->ctl1 |= ((div - 1) << 14);
-+              return 0;
-+
-+      case UBI32_CS4384_MCLK_OTHER:
-+              return 0;
-+      }
-+
-+      return 1;
-+}
-+
-+/*
-+ * snd_ubi32_cs4384_set_rate
-+ */
-+static int snd_ubi32_cs4384_set_rate(struct ubi32_snd_priv *priv, int rate)
-+{
-+      struct ubi32_cs4384_platform_data *cpd = priv->pdata->priv_data;
-+      struct ubicom32_io_port *ioa = (struct ubicom32_io_port *)RA;
-+      struct ubicom32_io_port *ioc = (struct ubicom32_io_port *)RC;
-+      struct ubicom32_io_port *ioh = (struct ubicom32_io_port *)RH;
-+      unsigned int ctl;
-+      unsigned int div = 0;
-+      const u16_t mult[] = {64, 96, 128, 192, 256, 384, 512, 768, 1024};
-+      int i;
-+      int j;
-+
-+
-+      for (i = 0; i < sizeof(mult) / sizeof(u16_t); i++) {
-+              for (j = 0; j < cpd->n_mclk; j++) {
-+                      if (((unsigned int)rate * (unsigned int)mult[i]) ==
-+                           cpd->mclk_entries[j].rate) {
-+                              div = cpd->mclk_entries[j].div;
-+                              break;
-+                      }
-+              }
-+      }
-+
-+      ctl = ((div - 1) << 16) | (div / 2);
-+
-+      switch (cpd->mclk_src) {
-+      case UBI32_CS4384_MCLK_PWM_0:
-+              ioc->ctl1 = ctl;
-+              return 0;
-+
-+      case UBI32_CS4384_MCLK_PWM_1:
-+              ioc->ctl2 = ctl;
-+              return 0;
-+
-+      case UBI32_CS4384_MCLK_PWM_2:
-+              ioh->ctl1 = ctl;
-+              return 0;
-+
-+      case UBI32_CS4384_MCLK_CLKDIV_1:
-+              ioa->ctl1 &= ~(0x7F << 14);
-+              ioa->ctl1 |= ((div - 1) << 14);
-+              return 0;
-+
-+      case UBI32_CS4384_MCLK_OTHER:
-+              return 0;
-+      }
-+
-+      return 1;
-+}
-+
-+/*
-+ * snd_ubi32_cs4384_set_channels
-+ *    Mute unused channels
-+ */
-+static int snd_ubi32_cs4384_set_channels(struct ubi32_snd_priv *priv, int channels)
-+{
-+      struct i2c_client *client = (struct i2c_client *)priv->client;
-+      struct snd_ubi32_cs4384_priv *cs4384_priv;
-+      unsigned char send[2];
-+      int ret;
-+      int i;
-+      unsigned long flags;
-+
-+      /*
-+       * Only support 0, 2, 4, 6, 8 channels
-+       */
-+      if ((channels > 8) || (channels & 1)) {
-+              return -EINVAL;
-+      }
-+
-+      cs4384_priv = snd_ubi32_priv_get_drv(priv);
-+      spin_lock_irqsave(&cs4384_priv->lock, flags);
-+
-+      /*
-+       * Address 09h, Mute control
-+       */
-+      send[0] = 0x09;
-+      send[1] = (unsigned char)(0xFF << channels);
-+
-+      ret = i2c_master_send(client, send, 2);
-+
-+      spin_unlock_irqrestore(&cs4384_priv->lock, flags);
-+
-+      /*
-+       * Notify the system that we changed the mutes
-+       */
-+      cs4384_priv->mute = (unsigned char)(0xFF << channels);
-+
-+      for (i = SND_UBI32_MUTE_CTL_START; i < SND_UBI32_MUTE_CTL_END; i++) {
-+              snd_ctl_notify(priv->card, SNDRV_CTL_EVENT_MASK_VALUE,
-+                             &cs4384_priv->kctls[i]->id);
-+      }
-+
-+      if (ret != 2) {
-+              return -ENXIO;
-+      }
-+
-+      return 0;
-+}
-+
-+/*
-+ * snd_ubi32_cs4384_dac_init
-+ */
-+static int snd_ubi32_cs4384_dac_init(struct i2c_client *client, const struct i2c_device_id *id)
-+{
-+      int ret;
-+      unsigned char send[2];
-+      unsigned char recv[2];
-+
-+      /*
-+       * Initialize the CS4384 DAC over the I2C interface
-+       */
-+      snd_printk(KERN_INFO "Initializing CS4384 DAC\n");
-+
-+      /*
-+       * Register 0x01: device/revid
-+       */
-+      send[0] = 0x01;
-+      ret = i2c_master_send(client, send, 1);
-+      if (ret != 1) {
-+              snd_printk(KERN_ERR "Failed 1st attempt to write to CS4384 register 0x01\n");
-+              goto fail;
-+      }
-+      ret = i2c_master_recv(client, recv, 1);
-+      if (ret != 1) {
-+              snd_printk(KERN_ERR "Failed initial read of CS4384 registers\n");
-+              goto fail;
-+      }
-+      snd_printk(KERN_INFO "CS4384 DAC Device/Rev: %08x\n", recv[0]);
-+
-+      /*
-+       * Register 0x02: Mode Control 1
-+       *      Control Port Enable, PCM, All DACs enabled, Power Down
-+       */
-+      send[0] = 0x02;
-+      send[1] = 0x81;
-+      ret = i2c_master_send(client, send, 2);
-+      if (ret != 2) {
-+              snd_printk(KERN_ERR "Failed to set CPEN CS4384\n");
-+              goto fail;
-+      }
-+
-+      /*
-+       * Register 0x08: Ramp and Mute
-+       *      RMP_UP, RMP_DN, PAMUTE, DAMUTE
-+       */
-+      send[0] = 0x08;
-+      send[1] = 0xBC;
-+      ret = i2c_master_send(client, send, 2);
-+      if (ret != 2) {
-+              snd_printk(KERN_ERR "Failed to set CPEN CS4384\n");
-+              goto fail;
-+      }
-+
-+      /*
-+       * Register 0x03: PCM Control
-+       *      I2S DIF[3:0] = 0001, no De-Emphasis, Auto speed mode
-+       */
-+      send[0] = 0x03;
-+      send[1] = 0x13;
-+      ret = i2c_master_send(client, send, 2);
-+      if (ret != 2) {
-+              snd_printk(KERN_ERR "Failed to set CS4384 to I2S mode\n");
-+              goto fail;
-+      }
-+
-+      /*
-+       * Register 0x0B/0x0C: Volume control A1/B1
-+       * Register 0x0E/0x0F: Volume control A2/B2
-+       * Register 0x11/0x12: Volume control A3/B3
-+       * Register 0x14/0x15: Volume control A4/B4
-+       */
-+      send[0] = 0x80 | 0x0B;
-+      send[1] = 0x00;
-+      send[2] = 0x00;
-+      ret = i2c_master_send(client, send, 3);
-+      if (ret != 3) {
-+              snd_printk(KERN_ERR "Failed to set ch1 volume on CS4384\n");
-+              goto fail;
-+      }
-+
-+      send[0] = 0x80 | 0x0E;
-+      send[1] = 0x00;
-+      send[2] = 0x00;
-+      ret = i2c_master_send(client, send, 3);
-+      if (ret != 3) {
-+              snd_printk(KERN_ERR "Failed to set ch2 volume on CS4384\n");
-+              goto fail;
-+      }
-+
-+      send[0] = 0x80 | 0x11;
-+      send[1] = 0x00;
-+      send[2] = 0x00;
-+      ret = i2c_master_send(client, send, 3);
-+      if (ret != 3) {
-+              snd_printk(KERN_ERR "Failed to set ch3 volume on CS4384\n");
-+              goto fail;
-+      }
-+
-+      send[0] = 0x80 | 0x14;
-+      send[1] = 0x00;
-+      send[2] = 0x00;
-+      ret = i2c_master_send(client, send, 3);
-+      if (ret != 3) {
-+              snd_printk(KERN_ERR "Failed to set ch4 volume on CS4384\n");
-+              goto fail;
-+      }
-+
-+      /*
-+       * Register 09h: Mute control
-+       *      Mute all (we will unmute channels as needed)
-+       */
-+      send[0] = 0x09;
-+      send[1] = 0xFF;
-+      ret = i2c_master_send(client, send, 2);
-+      if (ret != 2) {
-+              snd_printk(KERN_ERR "Failed to power up CS4384\n");
-+              goto fail;
-+      }
-+
-+      /*
-+       * Register 0x02: Mode Control 1
-+       *      Control Port Enable, PCM, All DACs enabled, Power Up
-+       */
-+      send[0] = 0x02;
-+      send[1] = 0x80;
-+      ret = i2c_master_send(client, send, 2);
-+      if (ret != 2) {
-+              snd_printk(KERN_ERR "Failed to power up CS4384\n");
-+              goto fail;
-+      }
-+
-+      /*
-+       * Make sure the changes took place, this helps verify we are talking to
-+       * the correct chip.
-+       */
-+      send[0] = 0x80 | 0x03;
-+      ret = i2c_master_send(client, send, 1);
-+      if (ret != 1) {
-+              snd_printk(KERN_ERR "Failed to initiate readback\n");
-+              goto fail;
-+      }
-+
-+      ret = i2c_master_recv(client, recv, 1);
-+      if (ret != 1) {
-+              snd_printk(KERN_ERR "Failed second read of CS4384 registers\n");
-+              goto fail;
-+      }
-+
-+      if (recv[0] != 0x13) {
-+              snd_printk(KERN_ERR "Failed to initialize CS4384 DAC\n");
-+              goto fail;
-+      }
-+
-+      snd_printk(KERN_INFO "CS4384 DAC Initialized\n");
-+      return 0;
-+
-+fail:
-+      return -ENODEV;
-+}
-+
-+/*
-+ * snd_ubi32_cs4384_i2c_probe
-+ */
-+static int snd_ubi32_cs4384_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
-+{
-+      struct snd_card *card;
-+      struct ubi32_snd_priv *ubi32_priv;
-+      int err, ret;
-+      struct platform_device *pdev;
-+      struct ubi32_cs4384_platform_data *pdata;
-+      struct snd_ubi32_cs4384_priv *cs4384_priv;
-+
-+      /*
-+       * pdev is audio device
-+       */
-+      pdev = client->dev.platform_data;
-+      if (!pdev) {
-+              return -ENODEV;
-+      }
-+
-+      /*
-+       * pdev->dev.platform_data is ubi32-pcm platform_data
-+       */
-+      pdata = audio_device_priv(pdev);
-+      if (!pdata) {
-+              return -ENODEV;
-+      }
-+
-+      /*
-+       * Initialize the CS4384 DAC
-+       */
-+      ret = snd_ubi32_cs4384_dac_init(client, id);
-+      if (ret < 0) {
-+              /*
-+               * Initialization failed.  Propagate the error.
-+               */
-+              return ret;
-+      }
-+
-+      if (snd_ubi32_cs4384_setup_mclk(pdata)) {
-+              return -EINVAL;
-+      }
-+
-+      /*
-+       * Create a snd_card structure
-+       */
-+      card = snd_card_new(index, "Ubi32-CS4384", THIS_MODULE, sizeof(struct ubi32_snd_priv));
-+      if (card == NULL) {
-+              return -ENOMEM;
-+      }
-+
-+      card->private_free = snd_ubi32_cs4384_free;
-+      ubi32_priv = card->private_data;
-+
-+      /*
-+       * Initialize the snd_card's private data structure
-+       */
-+      ubi32_priv->card = card;
-+      ubi32_priv->client = client;
-+      ubi32_priv->set_channels = snd_ubi32_cs4384_set_channels;
-+      ubi32_priv->set_rate = snd_ubi32_cs4384_set_rate;
-+
-+      /*
-+       * CS4384 DAC has a minimum sample rate of 4khz and an
-+       * upper limit of 216khz for it's auto-detect.
-+       */
-+      ubi32_priv->min_sample_rate = 4000;
-+      ubi32_priv->max_sample_rate = 216000;
-+
-+      /*
-+       * Create our private data (to manage volume, etc)
-+       */
-+      cs4384_priv = kzalloc(sizeof(struct snd_ubi32_cs4384_priv), GFP_KERNEL);
-+      if (!cs4384_priv) {
-+              snd_card_free(card);
-+              return -ENOMEM;
-+      }
-+      snd_ubi32_priv_set_drv(ubi32_priv, cs4384_priv);
-+      spin_lock_init(&cs4384_priv->lock);
-+
-+      /*
-+       * We start off all muted and max volume
-+       */
-+      cs4384_priv->mute = 0xFF;
-+      memset(cs4384_priv->volume, 0xFF, 8);
-+
-+      /*
-+       * Create the new PCM instance
-+       */
-+      err = snd_ubi32_pcm_probe(ubi32_priv, pdev);
-+      if (err < 0) {
-+              snd_card_free(card);
-+              return err; /* What is err?  Need to include correct file */
-+      }
-+
-+      strcpy(card->driver, "Ubi32-CS4384");
-+      strcpy(card->shortname, "Ubi32-CS4384");
-+      snprintf(card->longname, sizeof(card->longname),
-+              "%s at sendirq=%d.%d recvirq=%d.%d regs=%p",
-+              card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx,
-+              ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr);
-+
-+      snd_card_set_dev(card, &client->dev);
-+
-+      /*
-+       * Set up the mixer
-+       */
-+      snd_ubi32_cs4384_mixer(ubi32_priv);
-+
-+      /*
-+       * Register the sound card
-+       */
-+      if ((err = snd_card_register(card)) != 0) {
-+              snd_printk(KERN_INFO "snd_card_register error\n");
-+      }
-+
-+      /*
-+       * Store card for access from other methods
-+       */
-+      i2c_set_clientdata(client, card);
-+
-+      return 0;
-+}
-+
-+/*
-+ * snd_ubi32_cs4384_i2c_remove
-+ */
-+static int __devexit snd_ubi32_cs4384_i2c_remove(struct i2c_client *client)
-+{
-+      struct snd_card *card;
-+      struct ubi32_snd_priv *ubi32_priv;
-+
-+      card = i2c_get_clientdata(client);
-+
-+      ubi32_priv = card->private_data;
-+      snd_ubi32_pcm_remove(ubi32_priv);
-+
-+      snd_card_free(i2c_get_clientdata(client));
-+      i2c_set_clientdata(client, NULL);
-+
-+      return 0;
-+}
-+
-+/*
-+ * I2C driver description
-+ */
-+static struct i2c_driver snd_ubi32_cs4384_driver = {
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+      .id_table       = snd_ubi32_cs4384_id,
-+      .probe          = snd_ubi32_cs4384_i2c_probe,
-+      .remove         = __devexit_p(snd_ubi32_cs4384_i2c_remove),
-+};
-+
-+/*
-+ * Driver init
-+ */
-+static int __init snd_ubi32_cs4384_init(void)
-+{
-+      return i2c_add_driver(&snd_ubi32_cs4384_driver);
-+}
-+module_init(snd_ubi32_cs4384_init);
-+
-+/*
-+ * snd_ubi32_cs4384_exit
-+ */
-+static void __exit snd_ubi32_cs4384_exit(void)
-+{
-+      i2c_del_driver(&snd_ubi32_cs4384_driver);
-+}
-+module_exit(snd_ubi32_cs4384_exit);
-+
-+/*
-+ * Module properties
-+ */
-+MODULE_ALIAS("i2c:" DRIVER_NAME);
-+MODULE_AUTHOR("Patrick Tjin");
-+MODULE_DESCRIPTION("Driver for Ubicom32 audio devices CS4384");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/sound/ubicom32/ubi32-generic.c
-@@ -0,0 +1,166 @@
-+/*
-+ * sound/ubicom32/ubi32-generic.c
-+ *    Interface to ubicom32 virtual audio peripheral
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/platform_device.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/initval.h>
-+#include "ubi32.h"
-+
-+#define DRIVER_NAME "snd-ubi32-generic"
-+
-+/*
-+ * Module properties
-+ */
-+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
-+
-+/*
-+ * Card private data free function
-+ */
-+void snd_ubi32_generic_free(struct snd_card *card)
-+{
-+      /*
-+       * Free all the fields in the snd_ubi32_priv struct
-+       */
-+      // Nothing to free at this time because ubi32_priv just maintains pointers
-+}
-+
-+/*
-+ * Ubicom audio driver probe() method.  Args change depending on whether we use
-+ * platform_device or i2c_device.
-+ */
-+static int snd_ubi32_generic_probe(struct platform_device *dev)
-+{
-+      struct snd_card *card;
-+      struct ubi32_snd_priv *ubi32_priv;
-+      int err;
-+
-+      /*
-+       * Create a snd_card structure
-+       */
-+      card = snd_card_new(index, "Ubi32-Generic", THIS_MODULE, sizeof(struct ubi32_snd_priv));
-+
-+      if (card == NULL) {
-+              return -ENOMEM;
-+      }
-+
-+      card->private_free = snd_ubi32_generic_free; /* Not sure if correct */
-+      ubi32_priv = card->private_data;
-+
-+      /*
-+       * Initialize the snd_card's private data structure
-+       */
-+      ubi32_priv->card = card;
-+
-+      /*
-+       * Create the new PCM instance
-+       */
-+      err = snd_ubi32_pcm_probe(ubi32_priv, dev);
-+      if (err < 0) {
-+              snd_card_free(card);
-+              return err;
-+      }
-+
-+      strcpy(card->driver, "Ubi32-Generic");
-+      strcpy(card->shortname, "Ubi32-Generic");
-+      snprintf(card->longname, sizeof(card->longname),
-+              "%s at sendirq=%d.%d recvirq=%d.%d regs=%p",
-+              card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx,
-+              ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr);
-+
-+      snd_card_set_dev(card, &dev->dev);
-+
-+      /* Register the sound card */
-+      if ((err = snd_card_register(card)) != 0) {
-+              snd_printk(KERN_INFO "snd_card_register error\n");
-+      }
-+
-+      /* Store card for access from other methods */
-+      platform_set_drvdata(dev, card);
-+
-+      return 0;
-+}
-+
-+/*
-+ * Ubicom audio driver remove() method
-+ */
-+static int __devexit snd_ubi32_generic_remove(struct platform_device *dev)
-+{
-+      struct snd_card *card;
-+      struct ubi32_snd_priv *ubi32_priv;
-+
-+      card = platform_get_drvdata(dev);
-+      ubi32_priv = card->private_data;
-+      snd_ubi32_pcm_remove(ubi32_priv);
-+
-+      snd_card_free(platform_get_drvdata(dev));
-+      platform_set_drvdata(dev, NULL);
-+      return 0;
-+}
-+
-+/*
-+ * Platform driver definition
-+ */
-+static struct platform_driver snd_ubi32_generic_driver = {
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+      .probe = snd_ubi32_generic_probe,
-+      .remove = __devexit_p(snd_ubi32_generic_remove),
-+};
-+
-+/*
-+ * snd_ubi32_generic_init
-+ */
-+static int __init snd_ubi32_generic_init(void)
-+{
-+      return platform_driver_register(&snd_ubi32_generic_driver);
-+}
-+module_init(snd_ubi32_generic_init);
-+
-+/*
-+ * snd_ubi32_generic_exit
-+ */
-+static void __exit snd_ubi32_generic_exit(void)
-+{
-+      platform_driver_unregister(&snd_ubi32_generic_driver);
-+}
-+module_exit(snd_ubi32_generic_exit);
-+
-+/*
-+ * Module properties
-+ */
-+//#if defined(CONFIG_SND_UBI32_AUDIO_I2C)
-+//MODULE_ALIAS("i2c:snd-ubi32");
-+//#endif
-+MODULE_AUTHOR("Aaron Jow, Patrick Tjin");
-+MODULE_DESCRIPTION("Driver for Ubicom32 audio devices");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/sound/ubicom32/ubi32-generic-capture.c
-@@ -0,0 +1,167 @@
-+/*
-+ * sound/ubicom32/ubi32-generic-capture.c
-+ *    Interface to ubicom32 virtual audio peripheral
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/platform_device.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/initval.h>
-+#include "ubi32.h"
-+
-+#define DRIVER_NAME "snd-ubi32-generic-capture"
-+
-+/*
-+ * Module properties
-+ */
-+static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
-+
-+/*
-+ * Card private data free function
-+ */
-+void snd_ubi32_generic_capture_free(struct snd_card *card)
-+{
-+      /*
-+       * Free all the fields in the snd_ubi32_priv struct
-+       */
-+      // Nothing to free at this time because ubi32_priv just maintains pointers
-+}
-+
-+/*
-+ * Ubicom audio driver probe() method.  Args change depending on whether we use
-+ * platform_device or i2c_device.
-+ */
-+static int snd_ubi32_generic_capture_probe(struct platform_device *dev)
-+{
-+      struct snd_card *card;
-+      struct ubi32_snd_priv *ubi32_priv;
-+      int err;
-+
-+      /*
-+       * Create a snd_card structure
-+       */
-+      card = snd_card_new(index, "Ubi32-Generic-C", THIS_MODULE, sizeof(struct ubi32_snd_priv));
-+
-+      if (card == NULL) {
-+              return -ENOMEM;
-+      }
-+
-+      card->private_free = snd_ubi32_generic_capture_free; /* Not sure if correct */
-+      ubi32_priv = card->private_data;
-+
-+      /*
-+       * Initialize the snd_card's private data structure
-+       */
-+      ubi32_priv->card = card;
-+      ubi32_priv->is_capture = 1;
-+
-+      /*
-+       * Create the new PCM instance
-+       */
-+      err = snd_ubi32_pcm_probe(ubi32_priv, dev);
-+      if (err < 0) {
-+              snd_card_free(card);
-+              return err;
-+      }
-+
-+      strcpy(card->driver, "Ubi32-Generic-C");
-+      strcpy(card->shortname, "Ubi32-Generic-C");
-+      snprintf(card->longname, sizeof(card->longname),
-+              "%s at sendirq=%d.%d recvirq=%d.%d regs=%p",
-+              card->shortname, ubi32_priv->tx_irq, ubi32_priv->irq_idx,
-+              ubi32_priv->rx_irq, ubi32_priv->irq_idx, ubi32_priv->adr);
-+
-+      snd_card_set_dev(card, &dev->dev);
-+
-+      /* Register the sound card */
-+      if ((err = snd_card_register(card)) != 0) {
-+              snd_printk(KERN_INFO "snd_card_register error\n");
-+      }
-+
-+      /* Store card for access from other methods */
-+      platform_set_drvdata(dev, card);
-+
-+      return 0;
-+}
-+
-+/*
-+ * Ubicom audio driver remove() method
-+ */
-+static int __devexit snd_ubi32_generic_capture_remove(struct platform_device *dev)
-+{
-+      struct snd_card *card;
-+      struct ubi32_snd_priv *ubi32_priv;
-+
-+      card = platform_get_drvdata(dev);
-+      ubi32_priv = card->private_data;
-+      snd_ubi32_pcm_remove(ubi32_priv);
-+
-+      snd_card_free(platform_get_drvdata(dev));
-+      platform_set_drvdata(dev, NULL);
-+      return 0;
-+}
-+
-+/*
-+ * Platform driver definition
-+ */
-+static struct platform_driver snd_ubi32_generic_capture_driver = {
-+      .driver = {
-+              .name = DRIVER_NAME,
-+              .owner = THIS_MODULE,
-+      },
-+      .probe = snd_ubi32_generic_capture_probe,
-+      .remove = __devexit_p(snd_ubi32_generic_capture_remove),
-+};
-+
-+/*
-+ * snd_ubi32_generic_capture_init
-+ */
-+static int __init snd_ubi32_generic_capture_init(void)
-+{
-+      return platform_driver_register(&snd_ubi32_generic_capture_driver);
-+}
-+module_init(snd_ubi32_generic_capture_init);
-+
-+/*
-+ * snd_ubi32_generic_capture_exit
-+ */
-+static void __exit snd_ubi32_generic_capture_exit(void)
-+{
-+      platform_driver_unregister(&snd_ubi32_generic_capture_driver);
-+}
-+module_exit(snd_ubi32_generic_capture_exit);
-+
-+/*
-+ * Module properties
-+ */
-+//#if defined(CONFIG_SND_UBI32_AUDIO_I2C)
-+//MODULE_ALIAS("i2c:snd-ubi32");
-+//#endif
-+MODULE_AUTHOR("Patrick Tjin");
-+MODULE_DESCRIPTION("Driver for Ubicom32 audio devices");
-+MODULE_LICENSE("GPL");
---- /dev/null
-+++ b/sound/ubicom32/ubi32.h
-@@ -0,0 +1,102 @@
-+/*
-+ * sound/ubicom32/ubi32.h
-+ *    Common header file for all ubi32- sound drivers
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#ifndef _UBI32_H
-+#define _UBI32_H
-+
-+#define SND_UBI32_DEBUG 0 // Debug flag
-+
-+#include <linux/platform_device.h>
-+#include <asm/devtree.h>
-+#include <asm/audio.h>
-+#include <asm/ubi32-pcm.h>
-+
-+struct ubi32_snd_priv;
-+
-+typedef int (*set_channels_t)(struct ubi32_snd_priv *priv, int channels);
-+typedef int (*set_rate_t)(struct ubi32_snd_priv *priv, int rate);
-+
-+struct ubi32_snd_priv {
-+      /*
-+       * Any variables that are needed locally here but NOT in
-+       * the VP itself should go in here.
-+       */
-+      struct snd_card *card;
-+      struct snd_pcm *pcm;
-+
-+      /*
-+       * capture (1) or playback (0)
-+       */
-+      int is_capture;
-+      /*
-+       * DAC parameters.  These are the parameters for the specific
-+       * DAC we are driving.  The I2S component can run at a range
-+       * of frequencies, but the DAC may be limited.  We may want
-+       * to make this an array of some sort in the future?
-+       *
-+       * min/max_sample_rate if set to 0 are ignored.
-+       */
-+      int max_sample_rate;
-+      int min_sample_rate;
-+
-+      /*
-+       * The size a period (group) of audio samples.  The VP does
-+       * not need to know this; each DMA transfer is made to be
-+       * one period.
-+       */
-+      u32_t period_size;
-+
-+      spinlock_t ubi32_lock;
-+
-+      struct audio_regs *ar;
-+      struct audio_dev_regs *adr;
-+      u32 irq_idx;
-+      u8 tx_irq;
-+      u8 rx_irq;
-+
-+      void *client;
-+
-+      /*
-+       * Operations which the base DAC driver can implement
-+       */
-+      set_channels_t set_channels;
-+      set_rate_t set_rate;
-+
-+      /*
-+       * platform data
-+       */
-+      struct ubi32pcm_platform_data *pdata;
-+
-+      /*
-+       * Private driver data (used for DAC driver control, etc)
-+       */
-+      void *drvdata;
-+};
-+
-+#define snd_ubi32_priv_get_drv(priv) ((priv)->drvdata)
-+#define snd_ubi32_priv_set_drv(priv, data) (((priv)->drvdata) = (void *)(data))
-+
-+extern int snd_ubi32_pcm_probe(struct ubi32_snd_priv *ubi32_priv, struct platform_device *pdev);
-+extern void snd_ubi32_pcm_remove(struct ubi32_snd_priv *ubi32_priv);
-+
+               musb_writew(ep->regs, MUSB_TXCSR, txcsr);
+       } else {
+               txcsr = MUSB_CSR0_H_SETUPPKT | MUSB_CSR0_TXPKTRDY;
+@@ -223,6 +227,8 @@ musb_start_urb(struct musb *musb, int is
+               break;
+       default:                /* bulk, interrupt */
+               /* actual_length may be nonzero on retry paths */
++              if (urb->actual_length)
++                      DBG(3 ,"musb_start_urb: URB %p retried, len: %d\n", urb, urb->actual_length);
+               buf = urb->transfer_buffer + urb->actual_length;
+               len = urb->transfer_buffer_length - urb->actual_length;
+       }
+@@ -342,13 +348,13 @@ musb_save_toggle(struct musb_hw_ep *ep, 
+       if (!is_in) {
+               csr = musb_readw(epio, MUSB_TXCSR);
+               usb_settoggle(udev, qh->epnum, 1,
+-                      (csr & MUSB_TXCSR_H_DATATOGGLE)
+-                              ? 1 : 0);
++                      ((csr & MUSB_TXCSR_H_DATATOGGLE)
++                              ? 1 : 0));
+       } else {
+               csr = musb_readw(epio, MUSB_RXCSR);
+               usb_settoggle(udev, qh->epnum, 0,
+-                      (csr & MUSB_RXCSR_H_DATATOGGLE)
+-                              ? 1 : 0);
++                      ((csr & MUSB_RXCSR_H_DATATOGGLE)
++                              ? 1 : 0));
+       }
+ }
+@@ -556,7 +562,11 @@ musb_host_packet_rx(struct musb *musb, s
+       musb_read_fifo(hw_ep, length, buf);
+       csr = musb_readw(epio, MUSB_RXCSR);
++#ifndef CONFIG_UBICOM32
+       csr |= MUSB_RXCSR_H_WZC_BITS;
++#else
++      csr &= ~MUSB_RXCSR_H_WZC_BITS;
 +#endif
---- /dev/null
-+++ b/sound/ubicom32/ubi32-pcm.c
-@@ -0,0 +1,711 @@
-+/*
-+ * sound/ubicom32/ubi32-pcm.c
-+ *    Interface to ubicom32 virtual audio peripheral
-+ *
-+ * (C) Copyright 2009, Ubicom, Inc.
-+ *
-+ * This file is part of the Ubicom32 Linux Kernel Port.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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.
-+ *
-+ * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port.  If not,
-+ * see <http://www.gnu.org/licenses/>.
-+ *
-+ * Ubicom32 implementation derived from (with many thanks):
-+ *   arch/m68knommu
-+ *   arch/blackfin
-+ *   arch/parisc
-+ */
-+
-+#include <linux/interrupt.h>
-+#include <sound/core.h>
-+#include <sound/pcm.h>
-+#include <sound/pcm_params.h>
-+#include <asm/ip5000.h>
-+#include <asm/ubi32-pcm.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/delay.h>
-+#include "ubi32.h"
-+
-+struct ubi32_snd_runtime_data {
-+      dma_addr_t dma_buffer;          /* Physical address of DMA buffer */
-+      dma_addr_t dma_buffer_end;      /* First address beyond end of DMA buffer */
-+      size_t period_size;
-+      dma_addr_t period_ptr;          /* Physical address of next period */
-+      unsigned int flags;
-+};
-+
-+static void snd_ubi32_vp_int_set(struct snd_pcm *pcm)
-+{
-+      struct ubi32_snd_priv *ubi32_priv = pcm->private_data;
-+      ubi32_priv->ar->int_req |= (1 << ubi32_priv->irq_idx);
-+      ubicom32_set_interrupt(ubi32_priv->tx_irq);
-+}
-+
-+static snd_pcm_uframes_t snd_ubi32_pcm_pointer(struct snd_pcm_substream *substream)
-+{
-+
-+      struct ubi32_snd_priv *ubi32_priv = snd_pcm_substream_chip(substream);
-+      struct audio_dev_regs *adr = ubi32_priv->adr;
-+      struct snd_pcm_runtime *runtime = substream->runtime;
-+      struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data;
-+
-+      dma_addr_t read_pos;
-+
-+      snd_pcm_uframes_t frames;
-+      if (!adr->primary_os_buffer_ptr) {
-+              /*
-+               * If primary_os_buffer_ptr is NULL (e.g. right after the HW is started or
-+               * when the HW is stopped), then handle this case separately.
-+               */
-+              return 0;
-+      }
-+
-+      read_pos = (dma_addr_t)adr->primary_os_buffer_ptr;
-+      frames = bytes_to_frames(runtime, read_pos - ubi32_rd->dma_buffer);
-+      if (frames == runtime->buffer_size) {
-+              frames = 0;
-+      }
-+      return frames;
-+}
+       if (unlikely(do_flush))
+               musb_h_flush_rxfifo(hw_ep, csr);
+       else {
+@@ -590,6 +600,7 @@ musb_rx_reinit(struct musb *musb, struct
+       /* if programmed for Tx, put it in RX mode */
+       if (ep->is_shared_fifo) {
++#ifndef  CONFIG_UBICOM32
+               csr = musb_readw(ep->regs, MUSB_TXCSR);
+               if (csr & MUSB_TXCSR_MODE) {
+                       musb_h_tx_flush_fifo(ep);
+@@ -604,7 +615,18 @@ musb_rx_reinit(struct musb *musb, struct
+                */
+               if (csr & MUSB_TXCSR_DMAMODE)
+                       musb_writew(ep->regs, MUSB_TXCSR, MUSB_TXCSR_DMAMODE);
 +
-+/*
-+ * Audio trigger
-+ */
-+static int snd_ubi32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-+{
-+      struct ubi32_snd_priv *ubi32_priv = substream->pcm->private_data;
-+      struct audio_dev_regs *adr = ubi32_priv->adr;
-+      struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data;
-+      int ret = 0;
++#else
++              /* clear mode (and everything else) to enable Rx */
+               musb_writew(ep->regs, MUSB_TXCSR, 0);
++              /* scrub all previous state, clearing toggle */
++              csr = musb_readw(ep->regs, MUSB_RXCSR);
++              if (csr & MUSB_RXCSR_RXPKTRDY)
++                      WARNING("rx%d, packet/%d ready?\n", ep->epnum,
++                              musb_readw(ep->regs, MUSB_RXCOUNT));
 +
-+#ifdef CONFIG_SND_DEBUG
-+      snd_printk(KERN_INFO "snd_ubi32_pcm_trigger cmd=%d=", cmd);
++              musb_h_flush_rxfifo(ep, MUSB_RXCSR_CLRDATATOG);
 +#endif
-+
-+      if (adr->command != AUDIO_CMD_NONE) {
-+              snd_printk(KERN_WARNING "Can't send command to audio device at this time\n");
-+              // Set a timer to call this function back later.  How to do this?
-+              return 0;
+       /* scrub all previous state, clearing toggle */
+       } else {
+@@ -1138,8 +1160,18 @@ void musb_host_tx(struct musb *musb, u8 
+       void __iomem            *mbase = musb->mregs;
+       struct dma_channel      *dma;
++#ifdef CONFIG_UBICOM32
++      if (hw_ep->is_shared_fifo) {
++              qh = hw_ep->in_qh;
 +      }
-+
-+      /*
-+       * Set interrupt flag to indicate that we interrupted audio device
-+       * to send a command
-+       */
-+
-+      switch (cmd) {
-+      case SNDRV_PCM_TRIGGER_START:
-+
-+#ifdef CONFIG_SND_DEBUG
-+              snd_printk(KERN_INFO "START\n");
++#ifdef CONFIG_USB_SERIAL_SIERRAWIRELESS
++      printk(KERN_DEBUG "OUT/TX%d end, csr %04x%s\n", epnum, tx_csr,
++                      dma ? ", dma" : "");
 +#endif
-+              /*
-+               * Ready the DMA transfer
-+               */
-+              ubi32_rd->period_ptr = ubi32_rd->dma_buffer;
-+
-+#ifdef CONFIG_SND_DEBUG
-+              snd_printk(KERN_INFO "trigger period_ptr=%lx\n", (unsigned long)ubi32_rd->period_ptr);
 +#endif
-+              adr->dma_xfer_requests[0].ptr = (void *)ubi32_rd->period_ptr;
-+              adr->dma_xfer_requests[0].ctr = ubi32_rd->period_size;
-+              adr->dma_xfer_requests[0].active = 1;
+       urb = next_urb(qh);
 +
-+#ifdef CONFIG_SND_DEBUG
-+              snd_printk(KERN_INFO "xfer_request 0 ptr=0x%x ctr=%u\n", ubi32_rd->period_ptr, ubi32_rd->period_size);
+       musb_ep_select(mbase, epnum);
+       tx_csr = musb_readw(epio, MUSB_TXCSR);
+@@ -1180,9 +1212,14 @@ void musb_host_tx(struct musb *musb, u8 
+                * we have a candidate... NAKing is *NOT* an error
+                */
+               musb_ep_select(mbase, epnum);
++#ifndef CONFIG_UBICOM32
+               musb_writew(epio, MUSB_TXCSR,
+                               MUSB_TXCSR_H_WZC_BITS
+                               | MUSB_TXCSR_TXPKTRDY);
++#else
++              musb_writew(epio, MUSB_TXCSR,
++                               MUSB_TXCSR_TXPKTRDY);
 +#endif
-+
-+              ubi32_rd->period_ptr += ubi32_rd->period_size;
-+              adr->dma_xfer_requests[1].ptr = (void *)ubi32_rd->period_ptr;
-+              adr->dma_xfer_requests[1].ctr = ubi32_rd->period_size;
-+              adr->dma_xfer_requests[1].active = 1;
-+
-+#ifdef CONFIG_SND_DEBUG
-+              snd_printk(KERN_INFO "xfer_request 1 ptr=0x%x ctr=%u\n", ubi32_rd->period_ptr, ubi32_rd->period_size);
+               return;
+       }
+@@ -1353,8 +1390,14 @@ void musb_host_tx(struct musb *musb, u8 
+       qh->segsize = length;
+       musb_ep_select(mbase, epnum);
++#ifndef CONFIG_UBICOM32
++      musb_writew(epio, MUSB_TXCSR,
++                  MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
++#else
+       musb_writew(epio, MUSB_TXCSR,
+-                      MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
++                  MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY);
 +#endif
 +
-+              /*
-+               * Tell the VP that we want to begin playback by filling in the
-+               * command field and then interrupting the audio VP
-+               */
-+              adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
-+              adr->command = AUDIO_CMD_START;
-+              snd_ubi32_vp_int_set(substream->pcm);
-+              break;
-+
-+      case SNDRV_PCM_TRIGGER_STOP:
+ }
+@@ -1414,7 +1457,11 @@ static void musb_bulk_rx_nak_timeout(str
+       /* clear nak timeout bit */
+       rx_csr = musb_readw(epio, MUSB_RXCSR);
++#ifndef CONFIG_UBICOM32
+       rx_csr |= MUSB_RXCSR_H_WZC_BITS;
++#else
++      rx_csr &= ~MUSB_RXCSR_H_WZC_BITS;
++#endif
+       rx_csr &= ~MUSB_RXCSR_DATAERROR;
+       musb_writew(epio, MUSB_RXCSR, rx_csr);
+@@ -1483,6 +1530,13 @@ void musb_host_rx(struct musb *musb, u8 
+       pipe = urb->pipe;
++#ifdef CONFIG_UBICOM32
++#ifdef CONFIG_USB_SERIAL_SIERRAWIRELESS
++              printk(KERN_DEBUG  "RXCSR%d %04x, reqpkt, len %zu%s\n", epnum, rx_csr,
++                              xfer_len, dma ? ", dma" : "");
++#endif
++#endif
 +
-+#ifdef CONFIG_SND_DEBUG
-+              snd_printk(KERN_INFO "STOP\n");
+       DBG(5, "<== hw %d rxcsr %04x, urb actual %d (+dma %zu)\n",
+               epnum, rx_csr, urb->actual_length,
+               dma ? dma->actual_len : 0);
+@@ -1521,8 +1575,15 @@ void musb_host_rx(struct musb *musb, u8 
+                               return;
+                       }
+                       musb_ep_select(mbase, epnum);
++#ifndef CONFIG_UBICOM32
+                       rx_csr |= MUSB_RXCSR_H_WZC_BITS;
+                       rx_csr &= ~MUSB_RXCSR_DATAERROR;
++#else
++                      /* NEED TO EVALUATE CHANGE */
++                      rx_csr &= ~MUSB_RXCSR_H_WZC_BITS;
++                      rx_csr &= ~MUSB_RXCSR_DATAERROR;
++//                    musb_writew(epio, MUSB_RXCSR, (~(MUSB_RXCSR_H_WZC_BITS))| MUSB_RXCSR_H_REQPKT);
++#endif
+                       musb_writew(epio, MUSB_RXCSR, rx_csr);
+                       goto finish;
+@@ -1579,8 +1640,13 @@ void musb_host_rx(struct musb *musb, u8 
+               rx_csr &= ~MUSB_RXCSR_H_REQPKT;
+               musb_ep_select(mbase, epnum);
++#ifndef CONFIG_UBICOM32
+               musb_writew(epio, MUSB_RXCSR,
+                               MUSB_RXCSR_H_WZC_BITS | rx_csr);
++#else
++              musb_writew(epio, MUSB_RXCSR,
++                              (~MUSB_RXCSR_H_WZC_BITS) & rx_csr);
++#endif
+       }
+ #endif
+       if (dma && (rx_csr & MUSB_RXCSR_DMAENAB)) {
+@@ -1610,7 +1676,7 @@ void musb_host_rx(struct musb *musb, u8 
+                       else
+                               done = false;
+-              } else  {
++              } else {
+               /* done if urb buffer is full or short packet is recd */
+               done = (urb->actual_length + xfer_len >=
+                               urb->transfer_buffer_length
+@@ -1823,7 +1889,11 @@ static int musb_schedule(
+               } else  if (hw_ep->out_qh != NULL)
+                       continue;
++#ifndef CONFIG_UBICOM32
+               if (hw_ep == musb->bulk_ep)
++#else
++              if ((hw_ep == musb->bulk_ep_in) || (hw_ep == musb->bulk_ep_out)) /* Ubicom */
 +#endif
+                       continue;
+               if (is_in)
+@@ -1836,7 +1906,14 @@ static int musb_schedule(
+                       best_end = epnum;
+               }
+       }
 +
-+              /*
-+               * Tell the VP that we want to stop playback by filling in the
-+               * command field and then interrupting the audio VP
-+               */
-+              adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
-+              adr->command = AUDIO_CMD_STOP;
-+              snd_ubi32_vp_int_set(substream->pcm);
-+              break;
++#ifdef CONFIG_UBICOM32
++      if (((best_diff >= qh->maxpacket)) && ((qh->type == USB_ENDPOINT_XFER_BULK) && (!is_in)))
++              best_end = -1;
++#endif
 +
-+      case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+       /* use bulk reserved ep1 if no other ep is free */
++#ifndef CONFIG_UBICOM32
+       if (best_end < 0 && qh->type == USB_ENDPOINT_XFER_BULK) {
+               hw_ep = musb->bulk_ep;
+               if (is_in)
+@@ -1858,6 +1935,22 @@ static int musb_schedule(
+       } else if (best_end < 0) {
+               return -ENOSPC;
+       }
++#else
++      if (best_end < 0 && qh->type == USB_ENDPOINT_XFER_BULK) {
++              /* hw_ep = musb->bulk_ep; */
++              if (is_in) {
++                      head = &musb->in_bulk;
++                      hw_ep = musb->bulk_ep_in; /* UBICOM */
++              }
++              else {
++                      head = &musb->out_bulk;
++                      hw_ep = musb->bulk_ep_out; /* UBICOM */
++              }
++              goto success;
++      } else if (best_end < 0) {
++              return -ENOSPC;
++      }
++#endif
+       idle = 1;
+       qh->mux = 0;
+@@ -1869,6 +1962,13 @@ success:
+               list_add_tail(&qh->ring, head);
+               qh->mux = 1;
+       }
++      /*
++       * It's not make sense to set NAK timeout when qh->mux = 0,
++       * There is nothing else to schedule
++       */
++      if ((qh->type == USB_ENDPOINT_XFER_BULK) && (qh->mux == 0))
++              qh->intv_reg = 0;
 +
-+#ifdef CONFIG_SND_DEBUG
-+              snd_printk(KERN_INFO "PAUSE_PUSH\n");
+       qh->hw_ep = hw_ep;
+       qh->hep->hcpriv = qh;
+       if (idle)
+@@ -1975,6 +2075,15 @@ static int musb_urb_enqueue(
+               /* ISO always uses logarithmic encoding */
+               interval = min_t(u8, epd->bInterval, 16);
+               break;
++#ifdef COMFIG_UBICOM32
++      case USB_ENDPOINT_XFER_BULK:
++               if (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
++                      interval = (USB_SPEED_HIGH == urb->dev->speed) ? 16: 2;
++               else
++                      interval = 0;
++               break;
 +#endif
 +
-+              /*
-+               * Tell the VP that we want to pause playback by filling in the
-+               * command field and then interrupting the audio VP
-+               */
-+              adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
-+              adr->command = AUDIO_CMD_PAUSE;
-+              snd_ubi32_vp_int_set(substream->pcm);
-+              break;
-+
-+      case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-+
-+#ifdef CONFIG_SND_DEBUG
-+              snd_printk(KERN_INFO "PAUSE_RELEASE\n");
-+#endif
-+              /*
-+               * Tell the VP that we want to resume paused playback by filling
-+               * in the command field and then interrupting the audio VP
-+               */
-+              adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
-+              adr->command = AUDIO_CMD_RESUME;
-+              snd_ubi32_vp_int_set(substream->pcm);
-+              break;
+       default:
+               /* REVISIT we actually want to use NAK limits, hinting to the
+                * transfer scheduling logic to try some other qh, e.g. try
+--- a/drivers/usb/musb/musb_io.h
++++ b/drivers/usb/musb/musb_io.h
+@@ -58,6 +58,7 @@ static inline void writesb(const void __
+ #ifndef CONFIG_BLACKFIN
++#ifndef CONFIG_UBICOM32
+ /* NOTE:  these offsets are all in bytes */
+ static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
+@@ -72,7 +73,37 @@ static inline void musb_writew(void __io
+ static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
+       { __raw_writel(data, addr + offset); }
++#else
++#include <asm/ubicom32-tio.h>
++static inline u16 musb_readw(const void __iomem *addr, unsigned offset)
++{
++        u16 data;
++        usb_tio_read_u16((u32)(addr + offset), &data);
++        return data;
++}
++static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
++{
++        u8 data;
++        usb_tio_read_u8((u32)(addr + offset), &data);
++        return data;
++}
 +
-+      default:
-+              snd_printk(KERN_WARNING "Unhandled trigger\n");
-+              ret = -EINVAL;
-+              break;
-+      }
++static inline void musb_writew(void __iomem *addr, unsigned offset, u16 data)
++{
++        usb_tio_write_u16((u32)(addr + offset), data);
++}
 +
-+      return ret;
++static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
++{
++        usb_tio_write_u8((u32)(addr + offset), data);
 +}
 +
-+/*
-+ * Prepare to transfer an audio stream to the codec
-+ */
-+static int snd_ubi32_pcm_prepare(struct snd_pcm_substream *substream)
++static inline void  musb_read_int_status(u8_t *int_usb, u16_t *int_tx, u16_t *int_rx)
 +{
-+      /*
-+       * Configure registers and setup the runtime instance for DMA transfers
-+       */
-+      struct ubi32_snd_priv *ubi32_priv = substream->pcm->private_data;
-+      struct audio_dev_regs *adr = ubi32_priv->adr;
++      return usb_tio_read_int_status(int_usb, int_tx, int_rx);
++}
++#endif /* CONFIG_UBICOM32 */
+ #ifdef CONFIG_USB_TUSB6010
+@@ -106,7 +137,7 @@ static inline void musb_writeb(void __io
+       __raw_writew(tmp, addr + (offset & ~1));
+ }
+-#else
++#elif !defined(CONFIG_UBICOM32)
+ static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
+       { return __raw_readb(addr + offset); }
+--- a/drivers/usb/musb/musb_regs.h
++++ b/drivers/usb/musb/musb_regs.h
+@@ -167,6 +167,7 @@
+       (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \
+       | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY)
 +
-+#ifdef CONFIG_SND_DEBUG
-+      snd_printk(KERN_INFO "snd_ubi32_pcm_prepare: sending STOP command to audio device\n");
-+#endif
+ /* RXCSR in Peripheral and Host mode */
+ #define MUSB_RXCSR_AUTOCLEAR          0x8000
+ #define MUSB_RXCSR_DMAENAB            0x2000
+--- a/drivers/video/backlight/Kconfig
++++ b/drivers/video/backlight/Kconfig
+@@ -93,6 +93,63 @@ config LCD_HP700
+         If you have an HP Jornada 700 series handheld (710/720/728)
+         say Y to enable LCD control driver.
++config LCD_UBICOM32POWER
++      tristate "Ubicom LCD power Driver"
++      depends on LCD_CLASS_DEVICE && UBICOM32
++      default n
++      help
++        If you have a Ubicom32 based system with an LCD panel that requires
++        power control, say Y to enable the power control driver for it.
 +
-+      /*
-+       * Make sure the audio device is stopped
-+       */
++config LCD_UBICOM32
++      tristate "Ubicom Backlight Driver"
++      depends on LCD_CLASS_DEVICE && UBICOM32
++      default n
++      help
++        This driver takes care of initialization of LCD panels with
++        built in controllers.
 +
-+      /*
-+       * Set interrupt flag to indicate that we interrupted audio device
-+       * to send a command
-+       */
-+      adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
-+      adr->command = AUDIO_CMD_STOP;
-+      snd_ubi32_vp_int_set(substream->pcm);
++menu "Ubicom32 LCD Panel Support"
++      depends on UBICOM32 && LCD_UBICOM32
 +
-+      return 0;
-+}
++config LCD_UBICOM32_TFT2N0369E_P
++      bool "TFT2N0369E (Portrait)"
++      default n
++      help
++        Support for TFT2N0369 in portrait mode
 +
-+/*
-+ * Allocate DMA buffers from preallocated memory.
-+ * Preallocation was done in snd_ubi32_pcm_new()
-+ */
-+static int snd_ubi32_pcm_hw_params(struct snd_pcm_substream *substream,
-+                                      struct snd_pcm_hw_params *hw_params)
-+{
-+      struct snd_pcm_runtime *runtime = substream->runtime;
-+      struct ubi32_snd_priv *ubi32_priv = substream->pcm->private_data;
-+      struct audio_dev_regs *adr = ubi32_priv->adr;
-+      struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data;
++config LCD_UBICOM32_TFT2N0369E_L
++      bool "TFT2N0369E (Landscape)"
++      default n
++      help
++        Support for TFT2N0369 in landscape mode
 +
-+      /*
-+       * Use pre-allocated memory from ubi32_snd_pcm_new() to satisfy
-+       * this memory request.
-+       */
-+      int ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
-+      if (ret < 0) {
-+              return ret;
-+      }
++config LCD_UBICOM32_CFAF240320KTTS
++      bool "CFAF240320KTTS"
++      default n
++      help
++        Support for CFAF240320KTTS
 +
-+#ifdef CONFIG_SND_DEBUG
-+      snd_printk(KERN_INFO "snd_ubi32_pcm_hw_params\n");
-+#endif
++config LCD_UBICOM32_CFAF240320KTTS_180
++      bool "CFAF240320KTTS (180 rotation)"
++      default n
++      help
++        Support for CFAF240320KTTS rotated 180 degrees
 +
-+      if (!(adr->channel_mask & (1 << params_channels(hw_params)))) {
-+              snd_printk(KERN_INFO "snd_ubi32_pcm_hw_params unsupported number of channels %d mask %08x\n", params_channels(hw_params), adr->channel_mask);
-+              return -EINVAL;
-+      }
++config LCD_UBICOM32_CFAF240320D
++      bool "CFAF240320D"
++      default n
++      help
++        Support for CFAF240320D
 +
-+      if (ubi32_priv->set_channels) {
-+              int ret = ubi32_priv->set_channels(ubi32_priv, params_channels(hw_params));
-+              if (ret) {
-+                      snd_printk(KERN_WARNING "Unable to set channels to %d, ret=%d\n", params_channels(hw_params), ret);
-+                      return ret;
-+              }
-+      }
++config LCD_UBICOM32_CFAF320240F
++      bool "CFAF320240F"
++      default n
++      help
++        Support for CFAF320240F
 +
-+      if (ubi32_priv->set_rate) {
-+              int ret = ubi32_priv->set_rate(ubi32_priv, params_rate(hw_params));
-+              if (ret) {
-+                      snd_printk(KERN_WARNING "Unable to set rate to %d, ret=%d\n", params_rate(hw_params), ret);
-+                      return ret;
-+              }
-+      }
++endmenu
 +
-+      if (ubi32_priv->pdata->set_rate) {
-+              int ret = ubi32_priv->pdata->set_rate(ubi32_priv->pdata->appdata, params_rate(hw_params));
-+              if (ret) {
-+                      snd_printk(KERN_WARNING "Unable to set rate to %d, ret=%d\n", params_rate(hw_params), ret);
-+                      return ret;
-+              }
-+      }
+ #
+ # Backlight
+ #
+@@ -229,3 +286,11 @@ config BACKLIGHT_SAHARA
+       help
+         If you have a Tabletkiosk Sahara Touch-iT, say y to enable the
+         backlight driver.
 +
-+      if (adr->command != AUDIO_CMD_NONE) {
-+              snd_printk(KERN_WARNING "snd_ubi32_pcm_hw_params: tio busy\n");
-+              return -EAGAIN;
-+      }
++config BACKLIGHT_UBICOM32
++      tristate "Ubicom Backlight Driver"
++      depends on BACKLIGHT_CLASS_DEVICE && UBICOM32
++      default n
++      help
++        If you have a Ubicom32 based system with a backlight say Y to enable the
++        backlight driver.
+--- a/drivers/video/backlight/Makefile
++++ b/drivers/video/backlight/Makefile
+@@ -9,6 +9,9 @@ obj-$(CONFIG_LCD_PLATFORM)        += platfor
+ obj-$(CONFIG_LCD_VGG2432A4)      += vgg2432a4.o
+ obj-$(CONFIG_LCD_TDO24M)         += tdo24m.o
+ obj-$(CONFIG_LCD_TOSA)                   += tosa_lcd.o
++obj-$(CONFIG_LCD_LTV350QV)       += ltv350qv.o
++obj-$(CONFIG_LCD_UBICOM32POWER)          += ubicom32lcdpower.o
++obj-$(CONFIG_LCD_UBICOM32)       += ubicom32lcd.o
+ obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
+ obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o
+@@ -24,4 +27,4 @@ obj-$(CONFIG_BACKLIGHT_DA903X)       += da903x
+ obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o
+ obj-$(CONFIG_BACKLIGHT_TOSA)  += tosa_bl.o
+ obj-$(CONFIG_BACKLIGHT_SAHARA)        += kb3886_bl.o
+-
++obj-$(CONFIG_BACKLIGHT_UBICOM32) += ubicom32bl.o
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -609,6 +609,50 @@ config FB_BFIN_T350MCQB
+        This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI
+        It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK.
++config FB_UBICOM32
++      tristate "Ubicom32 Frame Buffer driver"
++      depends on FB && UBICOM32
++      select FB_CFB_FILLRECT
++      select FB_CFB_COPYAREA
++      select FB_CFB_IMAGEBLIT
++      select FONT_6x11 if FRAMEBUFFER_CONSOLE
++      help
++       This is the framebuffer device driver for the Ubicom32 architecture.
++       You can configure video memory by using kernel command line parameters, for example:
++              video=ubicomfb:vram_size=512,init_value=0xffff
 +
-+      if (params_format(hw_params) == SNDRV_PCM_FORMAT_S16_LE) {
-+              adr->flags |= CMD_START_FLAG_LE;
-+      } else {
-+              adr->flags &= ~CMD_START_FLAG_LE;
-+      }
-+      adr->channels = params_channels(hw_params);
-+      adr->sample_rate = params_rate(hw_params);
-+      adr->command = AUDIO_CMD_SETUP;
-+      adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
-+      snd_ubi32_vp_int_set(substream->pcm);
++config FB_UBICOM32_PLIO80
++      tristate "Ubicom32 80 Bus PLIO Frame Buffer driver"
++      depends on FB && UBICOM32
++      select FB_CFB_FILLRECT
++      select FB_CFB_COPYAREA
++      select FB_CFB_IMAGEBLIT
++      select FONT_6x11 if FRAMEBUFFER_CONSOLE
++      select UBICOM32_PLIO
++      help
++       This is a framebuffer device driver for the Ubicom32 architecture.
++       You can configure the xres, yres and vram size (in kilobytes) by using
++       kernel command line parameters, for example:
++              video=ubicom32vfb:xres=320,yres=240,vram_size=512
 +
-+      /*
-+       * Wait for the command to complete
-+       */
-+      while (adr->command != AUDIO_CMD_NONE) {
-+              udelay(1);
-+      }
++config FB_UBICOM32_VIRTUAL
++      tristate "Ubicom32 Virtual Frame Buffer driver"
++      depends on FB && UBICOM32
++      select FB_CFB_FILLRECT
++      select FB_CFB_COPYAREA
++      select FB_CFB_IMAGEBLIT
++      select FONT_6x11 if FRAMEBUFFER_CONSOLE
++      help
++       This is a virtual framebuffer device driver for the Ubicom32 architecture.
++       You can configure the xres, yres and vram size (in kilobytes) by using
++       kernel command line parameters, for example:
++              video=ubicom32vfb:xres=320,yres=240,vram_size=512
 +
-+      /*
-+       * Put the DMA info into the DMA descriptor that we will
-+       * use to do transfers to our audio VP "hardware"
-+       */
++config FB_UBICOM32_VIRTUAL_NOAUTO
++      bool "Do not automatically load"
++      depends on FB_UBICOM32_VIRTUAL
++      help
++       Select this option to prevent the VFB from automatically loading at boot.
+ config FB_STI
+       tristate "HP STI frame buffer device support"
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -136,6 +136,10 @@ obj-$(CONFIG_FB_BF54X_LQ043)        += bf54x-
+ obj-$(CONFIG_FB_BFIN_T350MCQB)          += bfin-t350mcqb-fb.o
+ obj-$(CONFIG_FB_MX3)            += mx3fb.o
++obj-$(CONFIG_FB_UBICOM32)         += ubicom32fb.o
++obj-$(CONFIG_FB_UBICOM32_PLIO80)  += ubicom32plio80.o
++obj-$(CONFIG_FB_UBICOM32_VIRTUAL) += ubicom32vfb.o
++
+ # the test framebuffer is last
+ obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
+--- a/drivers/watchdog/Kconfig
++++ b/drivers/watchdog/Kconfig
+@@ -887,6 +887,19 @@ config WATCHDOG_RIO
+         machines.  The watchdog timeout period is normally one minute but
+         can be changed with a boot-time parameter.
++# Ubicom32
 +
-+      /*
-+       * Mark both DMA transfers as not ready/inactive
-+       */
-+      adr->dma_xfer_requests[0].active = 0;
-+      adr->dma_xfer_requests[1].active = 0;
++config UBI32_WDT
++      tristate "Ubicom32 Hardware Watchdog support"
++      depends on UBICOM32
++      ---help---
++        If you say yes here you will get support for the Ubicom32 On-Chip
++        Watchdog Timer. If you have one of these processors and wish to
++        have watchdog support enabled, say Y, otherwise say N.
 +
-+      /*
-+       * Put the location of the buffer into the runtime data instance
-+       */
-+      ubi32_rd->dma_buffer = (dma_addr_t)runtime->dma_area;
-+      ubi32_rd->dma_buffer_end = (dma_addr_t)(runtime->dma_area + runtime->dma_bytes);
++        To compile this driver as a module, choose M here: the
++        module will be called ubi32_wdt.
 +
-+      /*
-+       * Get the period size
-+       */
-+      ubi32_rd->period_size = params_period_bytes(hw_params);
+ # XTENSA Architecture
+ #
+--- a/drivers/watchdog/Makefile
++++ b/drivers/watchdog/Makefile
+@@ -131,6 +131,9 @@ obj-$(CONFIG_SH_WDT) += shwdt.o
+ obj-$(CONFIG_WATCHDOG_RIO)            += riowd.o
+ obj-$(CONFIG_WATCHDOG_CP1XXX)         += cpwd.o
++# Ubicom32 Architecture
++obj-$(CONFIG_UBI32_WDT)                       += ubi32_wdt.o
 +
-+#ifdef CONFIG_SND_DEBUG
-+      snd_printk(KERN_INFO "DMA for ubi32 audio initialized dma_area=0x%x dma_bytes=%d, period_size=%d\n", (unsigned int)runtime->dma_area, (unsigned int)runtime->dma_bytes, ubi32_rd->period_size);
-+      snd_printk(KERN_INFO "Private buffer ubi32_rd: dma_buffer=0x%x dma_buffer_end=0x%x ret=%d\n", ubi32_rd->dma_buffer, ubi32_rd->dma_buffer_end, ret);
+ # XTENSA Architecture
+ # Architecture Independant
+--- a/fs/binfmt_flat.c
++++ b/fs/binfmt_flat.c
+@@ -67,6 +67,11 @@
+ #define FLAT_DATA_ALIGN       (sizeof(void *))
+ #endif
++#ifndef ARCH_FLAT_ALIGN
++#undef FLAT_DATA_ALIGN
++#define FLAT_DATA_ALIGN       ARCH_FLAT_ALIGN
 +#endif
 +
-+      return ret;
-+}
+ #define RELOC_FAILED 0xff00ff01               /* Relocation incorrect somewhere */
+ #define UNLOADED_LIB 0x7ff000ff               /* Placeholder for unused library */
+@@ -436,6 +441,7 @@ static int load_flat_file(struct linux_b
+       loff_t fpos;
+       unsigned long start_code, end_code;
+       int ret;
++      int flush_happened = 0;
+       hdr = ((struct flat_hdr *) bprm->buf);          /* exec-header */
+       inode = bprm->file->f_path.dentry->d_inode;
+@@ -521,6 +527,7 @@ static int load_flat_file(struct linux_b
+               /* OK, This is the point of no return */
+               set_personality(PER_LINUX_32BIT);
++              flush_happened = 1;
+       }
+       /*
+@@ -535,6 +542,12 @@ static int load_flat_file(struct linux_b
+        * it all together.
+        */
+       if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) {
 +
-+/*
-+ * This is the reverse of snd_ubi32_pcm_hw_params
-+ */
-+static int snd_ubi32_pcm_hw_free(struct snd_pcm_substream *substream)
-+{
-+#ifdef CONFIG_SND_DEBUG
-+      snd_printk(KERN_INFO "snd_ubi32_pcm_hw_free\n");
++#ifdef ARCH_FLAT_ALIGN_TEXT
++              printk("Unable to mmap rom with ARCH alignment requirements\n");
++              ret = -ENOEXEC;
++              goto err;
 +#endif
-+      return snd_pcm_lib_free_pages(substream);
-+}
-+
-+/*
-+ * Audio virtual peripheral capabilities (capture and playback are identical)
-+ */
-+static struct snd_pcm_hardware snd_ubi32_pcm_hw =
-+{
-+      .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
-+               SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
-+      .buffer_bytes_max = (64*1024),
-+      .period_bytes_min       = 64,
-+      .period_bytes_max       = 8184,//8184,//8176,
-+      .periods_min = 2,
-+      .periods_max = 255,
-+      .fifo_size = 0, // THIS IS IGNORED BY ALSA
-+};
-+
-+/*
-+ * We fill this in later
-+ */
-+static struct snd_pcm_hw_constraint_list ubi32_pcm_rates;
-+
-+/*
-+ * snd_ubi32_pcm_close
-+ */
-+static int snd_ubi32_pcm_close(struct snd_pcm_substream *substream)
-+{
-+      /* Disable codec, stop DMA, free private data structures */
-+      //struct ubi32_snd_priv *ubi32_priv = snd_pcm_substream_chip(substream);
-+      struct ubi32_snd_runtime_data *ubi32_rd = substream->runtime->private_data;
-+
-+#ifdef CONFIG_SND_DEBUG
-+      snd_printk(KERN_INFO "snd_ubi32_pcm_close\n");
+               /*
+                * this should give us a ROM ptr,  but if it doesn't we don't
+                * really care
+@@ -553,7 +566,7 @@ static int load_flat_file(struct linux_b
+                       goto err;
+               }
+-              len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
++              len = data_len + extra + ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), FLAT_DATA_ALIGN);
+               len = PAGE_ALIGN(len);
+               down_write(&current->mm->mmap_sem);
+               realdatastart = do_mmap(0, 0, len,
+@@ -572,6 +585,7 @@ static int load_flat_file(struct linux_b
+               datapos = ALIGN(realdatastart +
+                               MAX_SHARED_LIBS * sizeof(unsigned long),
+                               FLAT_DATA_ALIGN);
++              //datapos = realdatastart + ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), ARCH_FLAT_ALIGN);
+               DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
+                               (int)(data_len + bss_len + stack_len), (int)datapos);
+@@ -600,7 +614,11 @@ static int load_flat_file(struct linux_b
+               memp_size = len;
+       } else {
+-              len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long);
++              len = text_len + data_len + extra + ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), FLAT_DATA_ALIGN);
++#ifdef ARCH_FLAT_ALIGN_TEXT
++              /* Reserve space for the text alignment. */
++              len += FLAT_DATA_ALIGN;
 +#endif
-+
-+      substream->runtime->private_data = NULL;
-+
-+      kfree(ubi32_rd);
-+
-+      return 0;
-+}
-+
-+/*
-+ * snd_ubi32_pcm_open
-+ */
-+static int snd_ubi32_pcm_open(struct snd_pcm_substream *substream)
-+{
-+      struct snd_pcm_runtime *runtime = substream->runtime;
-+      struct ubi32_snd_runtime_data *ubi32_rd;
-+      int ret = 0;
-+
-+#ifdef CONFIG_SND_DEBUG
-+      snd_printk(KERN_INFO "ubi32 pcm open\n");
+               len = PAGE_ALIGN(len);
+               down_write(&current->mm->mmap_sem);
+               textpos = do_mmap(0, 0, len,
+@@ -616,10 +634,17 @@ static int load_flat_file(struct linux_b
+                       goto err;
+               }
++              memp = textpos;
++#ifdef ARCH_FLAT_ALIGN_TEXT
++              textpos = ALIGN(textpos + sizeof(struct flat_hdr), FLAT_DATA_ALIGN) - sizeof(struct flat_hdr);
 +#endif
-+
-+      /* Associate capabilities with component */
-+      runtime->hw = snd_ubi32_pcm_hw;
-+
-+      /*
-+       * Inform ALSA about constraints of the audio device
-+       */
-+      ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &ubi32_pcm_rates);
-+      if (ret < 0) {
-+              snd_printk(KERN_INFO "invalid rate\n");
-+              goto out;
-+      }
-+
-+      /* Force the buffer size to be an integer multiple of period size */
-+      ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
-+      if (ret < 0) {
-+              snd_printk(KERN_INFO "invalid period\n");
-+              goto out;
-+      }
-+      /* Initialize structures/registers */
-+      ubi32_rd = kzalloc(sizeof(struct ubi32_snd_runtime_data), GFP_KERNEL);
-+      if (ubi32_rd == NULL) {
-+              ret = -ENOMEM;
-+              goto out;
-+      }
-+
-+      runtime->private_data = ubi32_rd;
-+
-+#ifdef CONFIG_SND_DEBUG
-+      snd_printk(KERN_INFO "snd_ubi32_pcm_open returned 0\n");
+               realdatastart = textpos + ntohl(hdr->data_start);
+               datapos = ALIGN(realdatastart +
+                               MAX_SHARED_LIBS * sizeof(unsigned long),
+                               FLAT_DATA_ALIGN);
++//            datapos = realdatastart + ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), ARCH_FLAT_ALIGN);
++//            reloc = (unsigned long *) (textpos + ntohl(hdr->reloc_start) +
++//                                       ALIGN(MAX_SHARED_LIBS * sizeof(unsigned long), ARCH_FLAT_ALIGN));
+               reloc = (unsigned long *)
+                       (datapos + (ntohl(hdr->reloc_start) - text_len));
+@@ -659,7 +684,7 @@ static int load_flat_file(struct linux_b
+               }
+               if (result >= (unsigned long)-4096) {
+                       printk("Unable to read code+data+bss, errno %d\n",(int)-result);
+-                      do_munmap(current->mm, textpos, text_len + data_len + extra +
++                      do_munmap(current->mm, memp, text_len + data_len + extra +
+                               MAX_SHARED_LIBS * sizeof(unsigned long));
+                       ret = result;
+                       goto err;
+@@ -672,6 +697,9 @@ static int load_flat_file(struct linux_b
+       /* The main program needs a little extra setup in the task structure */
+       start_code = textpos + sizeof (struct flat_hdr);
++#ifdef ARCH_FLAT_ALIGN_TEXT
++      BUG_ON(ALIGN(start_code, FLAT_DATA_ALIGN) != start_code);
 +#endif
-+
-+      return 0;
-+out:
-+#ifdef CONFIG_SND_DEBUG
-+      snd_printk(KERN_INFO "snd_ubi32_pcm_open returned %d\n", ret);
+       end_code = textpos + text_len;
+       if (id == 0) {
+               current->mm->start_code = start_code;
+@@ -800,6 +828,13 @@ static int load_flat_file(struct linux_b
+       return 0;
+ err:
++      if (flush_happened) {
++              /*
++               * The parent process has already started running. We cannot allow the child to return back to user space
++               * as this child is still uning the parent stack and 2 will clobber each other. We are going to kill this child.
++               */
++              do_exit(SIGTERM);
++      }
+       return ret;
+ }
+--- a/fs/Kconfig.binfmt
++++ b/fs/Kconfig.binfmt
+@@ -30,7 +30,7 @@ config COMPAT_BINFMT_ELF
+ config BINFMT_ELF_FDPIC
+       bool "Kernel support for FDPIC ELF binaries"
+       default y
+-      depends on (FRV || BLACKFIN || (SUPERH32 && !MMU))
++      depends on (FRV || BLACKFIN || (SUPERH32 && !MMU) || UBICOM32)
+       help
+         ELF FDPIC binaries are based on ELF, but allow the individual load
+         segments of a binary to be located in memory independently of each
+--- a/include/asm-generic/resource.h
++++ b/include/asm-generic/resource.h
+@@ -69,13 +69,16 @@
+ /*
+  * boot-time rlimit defaults for the init task:
+  */
++#ifndef       CONFIG_ELF_CORE
++#define       CONFIG_USER_ELF_CORE_SIZE       0
 +#endif
+ #define INIT_RLIMITS                                                  \
+ {                                                                     \
+       [RLIMIT_CPU]            = {  RLIM_INFINITY,  RLIM_INFINITY },   \
+       [RLIMIT_FSIZE]          = {  RLIM_INFINITY,  RLIM_INFINITY },   \
+       [RLIMIT_DATA]           = {  RLIM_INFINITY,  RLIM_INFINITY },   \
+       [RLIMIT_STACK]          = {       _STK_LIM,   _STK_LIM_MAX },   \
+-      [RLIMIT_CORE]           = {              0,  RLIM_INFINITY },   \
++      [RLIMIT_CORE]           = { CONFIG_USER_ELF_CORE_SIZE,  RLIM_INFINITY },        \
+       [RLIMIT_RSS]            = {  RLIM_INFINITY,  RLIM_INFINITY },   \
+       [RLIMIT_NPROC]          = {              0,              0 },   \
+       [RLIMIT_NOFILE]         = {       INR_OPEN,       INR_OPEN },   \
+--- a/include/linux/elf-em.h
++++ b/include/linux/elf-em.h
+@@ -41,6 +41,7 @@
+  * up with a final number.
+  */
+ #define EM_ALPHA      0x9026
++#define EM_UBICOM32           0xde3d  /* Ubicom32; no ABI */
+ /* Bogus old v850 magic number, used by old tools. */
+ #define EM_CYGNUS_V850        0x9080
+--- a/include/linux/fb.h
++++ b/include/linux/fb.h
+@@ -151,6 +151,10 @@ struct dentry;
+ #define FB_ACCEL_PROSAVAGE_DDR  0x8d  /* S3 ProSavage DDR             */
+ #define FB_ACCEL_PROSAVAGE_DDRK 0x8e  /* S3 ProSavage DDR-K           */
++#define FB_ACCEL_UBICOM32             0x0100  /* Ubicom32                     */
++#define FB_ACCEL_UBICOM32_VFB         0x0101  /* Ubicom32 VFB                 */
++#define FB_ACCEL_UBICOM32_PLIO80      0x0102  /* Ubicom32 PLIO80              */
 +
-+      return ret;
-+}
+ struct fb_fix_screeninfo {
+       char id[16];                    /* identification string eg "TT Builtin" */
+       unsigned long smem_start;       /* Start of frame buffer mem */
+--- a/include/linux/if_ppp.h
++++ b/include/linux/if_ppp.h
+@@ -114,14 +114,14 @@ struct pppol2tp_ioc_stats {
+       __u16           tunnel_id;      /* redundant */
+       __u16           session_id;     /* if zero, get tunnel stats */
+       __u32           using_ipsec:1;  /* valid only for session_id == 0 */
+-      aligned_u64     tx_packets;
+-      aligned_u64     tx_bytes;
+-      aligned_u64     tx_errors;
+-      aligned_u64     rx_packets;
+-      aligned_u64     rx_bytes;
+-      aligned_u64     rx_seq_discards;
+-      aligned_u64     rx_oos_packets;
+-      aligned_u64     rx_errors;
++      __u64   tx_packets;
++      __u64   tx_bytes;
++      __u64   tx_errors;
++      __u64   rx_packets;
++      __u64   rx_bytes;
++      __u64   rx_seq_discards;
++      __u64   rx_oos_packets;
++      __u64   rx_errors;
+ };
+ #define ifr__name       b.ifr_ifrn.ifrn_name
+--- a/include/linux/oprofile.h
++++ b/include/linux/oprofile.h
+@@ -99,6 +99,8 @@ void oprofile_add_sample(struct pt_regs 
+  */
+ void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs,
+                               unsigned long event, int is_kernel);
++void oprofile_add_ext_sample_cpu(unsigned long pc, struct pt_regs * const regs,
++                              unsigned long event, int is_kernel, int cpu);
+ /* Use this instead when the PC value is not from the regs. Doesn't
+  * backtrace. */
+--- a/include/linux/serial_core.h
++++ b/include/linux/serial_core.h
+@@ -167,6 +167,9 @@
+ /* MAX3100 */
+ #define PORT_MAX3100    86
++/* Ubicom32 */
++#define PORT_UBI32_UARTTIO    87
 +
-+static struct snd_pcm_ops snd_ubi32_pcm_ops = {
-+      .open =         snd_ubi32_pcm_open, /* Open */
-+      .close =        snd_ubi32_pcm_close, /* Close */
-+      .ioctl =        snd_pcm_lib_ioctl, /* Generic IOCTL handler */
-+      .hw_params =    snd_ubi32_pcm_hw_params, /* Hardware parameters/capabilities */
-+      .hw_free =      snd_ubi32_pcm_hw_free, /* Free function for hw_params */
-+      .prepare =      snd_ubi32_pcm_prepare,
-+      .trigger =      snd_ubi32_pcm_trigger,
-+      .pointer =      snd_ubi32_pcm_pointer,
+ #ifdef __KERNEL__
+ #include <linux/compiler.h>
+--- a/include/linux/slab.h
++++ b/include/linux/slab.h
+@@ -317,4 +317,14 @@ static inline void *kzalloc_node(size_t 
+       return kmalloc_node(size, flags | __GFP_ZERO, node);
+ }
++struct kmem_cache_size_info {
++      unsigned short page;
++      unsigned short order;
 +};
 +
 +/*
-+ * Interrupt handler that gets called when the audio device
-+ * interrupts Linux
++ * get info on all the memory allocated by slab for this named cache
 + */
-+static irqreturn_t snd_ubi32_pcm_interrupt(int irq, void *appdata)
-+{
-+      struct snd_pcm *pcm = (struct snd_pcm *)appdata;
-+      struct ubi32_snd_priv *ubi32_priv = pcm->private_data;
-+      struct audio_dev_regs *adr = ubi32_priv->adr;
-+      struct snd_pcm_substream *substream;
-+      struct ubi32_snd_runtime_data *ubi32_rd;
-+      int dma_to_fill = 0;
-+
-+      /*
-+       * Check to see if the interrupt is for us
-+       */
-+      if (!(ubi32_priv->ar->int_status & (1 << ubi32_priv->irq_idx))) {
-+              return IRQ_NONE;
-+      }
-+
-+      /*
-+       * Clear the interrupt
-+       */
-+      ubi32_priv->ar->int_status &= ~(1 << ubi32_priv->irq_idx);
-+
-+      /*
-+       * We only have one stream since we don't mix.  Therefore
-+       * we don't need to search through substreams.
-+       */
-+      if (ubi32_priv->is_capture) {
-+              substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
-+      } else {
-+              substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
-+      }
-+
-+      if (!substream->runtime) {
-+              snd_printk(KERN_WARNING "No runtime data\n");
-+              return IRQ_NONE;
-+      }
++extern int kmem_cache_block_info(char *name, struct kmem_cache_size_info *data, int max_data);
 +
-+      ubi32_rd = substream->runtime->private_data;
+ #endif        /* _LINUX_SLAB_H */
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -865,6 +865,12 @@ config ELF_CORE
+       help
+         Enable support for generating core dumps. Disabling saves about 4k.
++config USER_ELF_CORE_SIZE
++      int "user core dump size (10MB to 32MB)"
++      range 10485760 33554432
++      default 16777216
++      depends on ELF_CORE
 +
-+#ifdef CONFIG_SND_DEBUG
-+      snd_printk(KERN_INFO "Ubi32 ALSA interrupt\n");
+ config PCSPKR_PLATFORM
+       bool "Enable PC-Speaker support" if EMBEDDED
+       depends on ALPHA || X86 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -2688,6 +2688,9 @@ static int m_show(struct seq_file *m, vo
+       /* Used by oprofile and other similar tools. */
+       seq_printf(m, " 0x%p", mod->module_core);
++#ifdef ARCH_PROC_MODULES_EXTRA
++      ARCH_PROC_MODULES_EXTRA(m, mod);
 +#endif
-+
-+      if (ubi32_rd == NULL) {
-+              snd_printk(KERN_WARNING "No private data\n");
-+              return IRQ_NONE;
-+      }
-+
-+      // Check interrupt cause
-+      if (0) {
-+              // Handle the underflow case
-+      } else if ((adr->status & AUDIO_STATUS_PLAY_DMA0_REQUEST) ||
-+                 (adr->status & AUDIO_STATUS_PLAY_DMA1_REQUEST)) {
-+              if (adr->status & AUDIO_STATUS_PLAY_DMA0_REQUEST) {
-+                      dma_to_fill = 0;
-+                      adr->status &= ~AUDIO_STATUS_PLAY_DMA0_REQUEST;
-+              } else if (adr->status & AUDIO_STATUS_PLAY_DMA1_REQUEST) {
-+                      dma_to_fill = 1;
-+                      adr->status &= ~AUDIO_STATUS_PLAY_DMA1_REQUEST;
-+              }
-+              ubi32_rd->period_ptr += ubi32_rd->period_size;
-+              if (ubi32_rd->period_ptr >= ubi32_rd->dma_buffer_end) {
-+                      ubi32_rd->period_ptr = ubi32_rd->dma_buffer;
-+              }
-+              adr->dma_xfer_requests[dma_to_fill].ptr = (void *)ubi32_rd->period_ptr;
-+              adr->dma_xfer_requests[dma_to_fill].ctr = ubi32_rd->period_size;
-+              adr->dma_xfer_requests[dma_to_fill].active = 1;
-+#ifdef CONFIG_SND_DEBUG
-+              snd_printk(KERN_INFO "xfer_request %d ptr=0x%x ctr=%u\n", dma_to_fill, ubi32_rd->period_ptr, ubi32_rd->period_size);
+       /* Taints info */
+       if (mod->taints)
+               seq_printf(m, " %s", module_flags(mod, buf));
+@@ -2840,8 +2843,12 @@ void print_modules(void)
+       printk("Modules linked in:");
+       /* Most callers should already have preempt disabled, but make sure */
+       preempt_disable();
+-      list_for_each_entry_rcu(mod, &modules, list)
++      list_for_each_entry_rcu(mod, &modules, list) {
+               printk(" %s%s", mod->name, module_flags(mod, buf));
++#ifdef ARCH_OOPS_MODULE_EXTRA
++              ARCH_OOPS_MODULE_EXTRA(mod);
 +#endif
-+              adr->int_flags |= AUDIO_INT_FLAG_MORE_SAMPLES;
-+              snd_ubi32_vp_int_set(substream->pcm);
 +      }
-+      // If we are interrupted by the VP, that means we completed
-+      // processing one period of audio.  We need to inform the upper
-+      // layers of ALSA of this.
-+      snd_pcm_period_elapsed(substream);
-+
-+      return IRQ_HANDLED;
-+}
-+
-+void __devexit snd_ubi32_pcm_remove(struct ubi32_snd_priv *ubi32_priv)
-+{
-+      struct snd_pcm *pcm = ubi32_priv->pcm;
-+      free_irq(ubi32_priv->rx_irq, pcm);
-+}
+       preempt_enable();
+       if (last_unloaded_module[0])
+               printk(" [last unloaded: %s]", last_unloaded_module);
+--- a/kernel/sched_clock.c
++++ b/kernel/sched_clock.c
+@@ -38,8 +38,7 @@
+  */
+ unsigned long long __attribute__((weak)) sched_clock(void)
+ {
+-      return (unsigned long long)(jiffies - INITIAL_JIFFIES)
+-                                      * (NSEC_PER_SEC / HZ);
++      return (get_jiffies_64() - INITIAL_JIFFIES) * (NSEC_PER_SEC / HZ);
+ }
+ static __read_mostly int sched_clock_running;
+--- a/lib/Kconfig.debug
++++ b/lib/Kconfig.debug
+@@ -621,7 +621,7 @@ config FRAME_POINTER
+       bool "Compile the kernel with frame pointers"
+       depends on DEBUG_KERNEL && \
+               (CRIS || M68K || M68KNOMMU || FRV || UML || \
+-               AVR32 || SUPERH || BLACKFIN || MN10300) || \
++               AVR32 || SUPERH || BLACKFIN || MN10300 || UBICOM32) || \
+               ARCH_WANT_FRAME_POINTERS
+       default y if (DEBUG_INFO && UML) || ARCH_WANT_FRAME_POINTERS
+       help
+--- a/mm/Makefile
++++ b/mm/Makefile
+@@ -38,3 +38,5 @@ obj-$(CONFIG_SMP) += allocpercpu.o
+ endif
+ obj-$(CONFIG_QUICKLIST) += quicklist.o
+ obj-$(CONFIG_CGROUP_MEM_RES_CTLR) += memcontrol.o page_cgroup.o
 +
-+#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12
-+#error "Change this table to match pcm.h"
-+#endif
-+static unsigned int rates[] __initdata = {5512, 8000, 11025, 16000, 22050,
-+                                        32000, 44100, 48000, 64000, 88200,
-+                                        96000, 176400, 192000};
++CFLAGS_slab.o := $(PROFILING) -O2
+--- a/mm/slab.c
++++ b/mm/slab.c
+@@ -4100,6 +4100,68 @@ out:
+ #ifdef CONFIG_SLABINFO
 +
 +/*
-+ * snd_ubi32_pcm_probe
++ * get info on all the memory allocated by slab for this named cache
 + */
-+int __devinit snd_ubi32_pcm_probe(struct ubi32_snd_priv *ubi32_priv, struct platform_device *pdev)
++int kmem_cache_block_info(char *name, struct kmem_cache_size_info *data, int max_data)
 +{
-+      struct snd_pcm *pcm;
-+      int ret, err;
-+      int i;
-+      int j;
-+      int nrates;
-+      unsigned int rate_max = 0;
-+      unsigned int rate_min = 0xFFFFFFFF;
-+      unsigned int rate_mask = 0;
-+      struct audio_dev_regs *adr;
-+      struct resource *res_adr;
-+      struct resource *res_irq_tx;
-+      struct resource *res_irq_rx;
-+      struct ubi32pcm_platform_data *pdata;
-+
-+      pdata = pdev->dev.platform_data;
-+      if (!pdata) {
-+              return -ENODEV;
-+      }
++      int res = 0;
++      int found = 0;
++      int node;
++      struct kmem_cache *cachep;
++      struct kmem_list3 *l3;
++      struct slab *slabp;
 +
-+      /*
-+       * Get our resources, adr is the hardware driver base address
-+       * and the tx and rx irqs are used to communicate with the
-+       * hardware driver.
-+       */
-+      res_adr = platform_get_resource(pdev, IORESOURCE_MEM, AUDIO_MEM_RESOURCE);
-+      res_irq_tx = platform_get_resource(pdev, IORESOURCE_IRQ, AUDIO_TX_IRQ_RESOURCE);
-+      res_irq_rx = platform_get_resource(pdev, IORESOURCE_IRQ, AUDIO_RX_IRQ_RESOURCE);
-+      if (!res_adr || !res_irq_tx || !res_irq_rx) {
-+              snd_printk(KERN_WARNING "Could not get resources");
-+              return -ENODEV;
++      /* Find the cache in the chain of caches. */
++      mutex_lock(&cache_chain_mutex);
++      list_for_each_entry(cachep, &cache_chain, next) {
++              if (strcmp(cachep->name, name) == 0) {
++                      found = 1;
++                      break;
++              }
 +      }
-+
-+      ubi32_priv->ar = (struct audio_regs *)res_adr->start;
-+      ubi32_priv->tx_irq = res_irq_tx->start;
-+      ubi32_priv->rx_irq = res_irq_rx->start;
-+      ubi32_priv->irq_idx = pdata->inst_num;
-+      ubi32_priv->adr = &(ubi32_priv->ar->adr[pdata->inst_num]);
-+
-+      /*
-+       * Check the version
-+       */
-+      adr = ubi32_priv->adr;
-+      if (adr->version != AUDIO_DEV_REGS_VERSION) {
-+              snd_printk(KERN_WARNING "This audio_dev_reg is not compatible with this driver\n");
-+              return -ENODEV;
++      mutex_unlock(&cache_chain_mutex);
++      if (!found) {
++              return 0;
 +      }
++      for_each_online_node(node) {
++              l3 = cachep->nodelists[node];
++              if (!l3)
++                      continue;
++              if (res >= max_data)
++                      break;
++              check_irq_on();
++              spin_lock_irq(&l3->list_lock);
 +
-+      /*
-+       * Find out the standard rates, also find max and min rates
-+       */
-+      for (i = 0; i < ARRAY_SIZE(rates); i++) {
-+              int found = 0;
-+              for (j = 0; j < adr->n_sample_rates; j++) {
-+                      if (rates[i] == adr->sample_rates[j]) {
-+                              /*
-+                               * Check to see if it is supported by the dac
-+                               */
-+                              if ((rates[i] >= ubi32_priv->min_sample_rate) &&
-+                                  (!ubi32_priv->max_sample_rate ||
-+                                   (ubi32_priv->max_sample_rate && (rates[i] <= ubi32_priv->max_sample_rate)))) {
-+                                      found = 1;
-+                                      rate_mask |= (1 << i);
-+                                      nrates++;
-+                                      if (rates[i] < rate_min) {
-+                                              rate_min = rates[i];
-+                                      }
-+                                      if (rates[i] > rate_max) {
-+                                              rate_max = rates[i];
-+                                      }
-+                                      break;
-+                              }
-+                      }
++              list_for_each_entry(slabp, &l3->slabs_full, list) {
++                      if (res >= max_data)
++                              break;
++                      data[res].page = ((unsigned int)slabp->s_mem >> PAGE_SHIFT) & 0xffff;
++                      data[res].order = cachep->gfporder;
++                      res++;
 +              }
-+              if (!found) {
-+                      rate_mask |= SNDRV_PCM_RATE_KNOT;
++              list_for_each_entry(slabp, &l3->slabs_partial, list) {
++                      if (res >= max_data)
++                              break;
++                      data[res].page = ((unsigned int)slabp->s_mem >> PAGE_SHIFT) & 0xffff;
++                      data[res].order = cachep->gfporder;
++                      res++;
 +              }
-+      }
-+
-+      snd_ubi32_pcm_hw.rates = rate_mask;
-+      snd_ubi32_pcm_hw.rate_min = rate_min;
-+      snd_ubi32_pcm_hw.rate_max = rate_max;
-+      ubi32_pcm_rates.count = adr->n_sample_rates;
-+      ubi32_pcm_rates.list = (unsigned int *)adr->sample_rates;
-+      ubi32_pcm_rates.mask = 0;
-+
-+      for (i = 0; i < 32; i++) {
-+              if (adr->channel_mask & (1 << i)) {
-+                      if (!snd_ubi32_pcm_hw.channels_min) {
-+                              snd_ubi32_pcm_hw.channels_min = i;
-+                      }
-+                      snd_ubi32_pcm_hw.channels_max = i;
++              list_for_each_entry(slabp, &l3->slabs_free, list) {
++                      if (res >= max_data)
++                              break;
++                      data[res].page = ((unsigned int)slabp->s_mem >> PAGE_SHIFT) & 0xffff;
++                      data[res].order = cachep->gfporder;
++                      res++;
 +              }
-+      }
-+      snd_printk(KERN_INFO "Ubi32PCM: channels_min:%u channels_max:%u\n",
-+                 snd_ubi32_pcm_hw.channels_min,
-+                 snd_ubi32_pcm_hw.channels_max);
-+
-+      if (adr->caps & AUDIONODE_CAP_BE) {
-+              snd_ubi32_pcm_hw.formats |= SNDRV_PCM_FMTBIT_S16_BE;
-+      }
-+      if (adr->caps & AUDIONODE_CAP_LE) {
-+              snd_ubi32_pcm_hw.formats |= SNDRV_PCM_FMTBIT_S16_LE;
-+      }
-+
-+      snd_printk(KERN_INFO "Ubi32PCM: rates:%08x min:%u max:%u count:%d fmts:%016llx (%s)\n",
-+                 snd_ubi32_pcm_hw.rates,
-+                 snd_ubi32_pcm_hw.rate_min,
-+                 snd_ubi32_pcm_hw.rate_max,
-+                 ubi32_pcm_rates.count,
-+                 snd_ubi32_pcm_hw.formats,
-+                 ubi32_priv->is_capture ? "capture" : "playback");
-+
-+      if (ubi32_priv->is_capture) {
-+              ret = snd_pcm_new(ubi32_priv->card, "Ubi32 PCM", 0, 0, 1, &pcm);
-+      } else {
-+              ret = snd_pcm_new(ubi32_priv->card, "Ubi32 PCM", 0, 1, 0, &pcm);
-+      }
-+
-+      if (ret < 0) {
-+              return ret;
-+      }
 +
-+      pcm->private_data = ubi32_priv;
-+      ubi32_priv->pcm = pcm;
-+      ubi32_priv->pdata = pdata;
-+
-+      pcm->info_flags = 0;
-+
-+      strcpy(pcm->name, "Ubi32-PCM");
-+
-+      snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
-+                                            snd_dma_continuous_data(GFP_KERNEL),
-+                                            45*1024, 64*1024);
-+
-+      if (ubi32_priv->is_capture) {
-+              snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ubi32_pcm_ops);
-+      } else {
-+              snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ubi32_pcm_ops);
++              spin_unlock_irq(&l3->list_lock);
 +      }
 +
-+      /*
-+       * Start up the audio device
-+       */
-+      adr->int_flags |= AUDIO_INT_FLAG_COMMAND;
-+      adr->command = AUDIO_CMD_ENABLE;
-+      snd_ubi32_vp_int_set(pcm);
++      return res;
++}
 +
+ static void print_slabinfo_header(struct seq_file *m)
+ {
+       /*
+--- a/scripts/mod/file2alias.c
++++ b/scripts/mod/file2alias.c
+@@ -774,6 +774,15 @@ void handle_moddevtable(struct module *m
+                       + sym->st_value;
+       }
 +      /*
-+       * Request IRQ
++       * somehow our gcc is not generating st_size correctly and set 0 for some symbols.
++       * and 0 size will break do_table since it adjust size to (size - id_size)
++       * this is to make sure st_size fall in range.
 +       */
-+      err = request_irq(ubi32_priv->rx_irq, snd_ubi32_pcm_interrupt, IRQF_SHARED | IRQF_DISABLED, pcm->name, pcm);
-+      if (err) {
-+              snd_printk(KERN_WARNING "request_irq failed: irq=%d err=%d\n", ubi32_priv->rx_irq, err);
-+              return -ENODEV;
++      if (sym->st_size == 0 || sym->st_size > info->sechdrs[sym->st_shndx].sh_size) {
++              sym->st_size = info->sechdrs[sym->st_shndx].sh_size;
 +      }
 +
-+      return ret;
+       if (sym_is(symname, "__mod_pci_device_table"))
+               do_table(symval, sym->st_size,
+                        sizeof(struct pci_device_id), "pci",
+--- a/sound/Kconfig
++++ b/sound/Kconfig
+@@ -82,6 +82,8 @@ source "sound/parisc/Kconfig"
+ source "sound/soc/Kconfig"
++source "sound/ubicom32/Kconfig"
 +
-+}
+ endif # SND
+ menuconfig SOUND_PRIME
+--- a/sound/Makefile
++++ b/sound/Makefile
+@@ -6,7 +6,7 @@ obj-$(CONFIG_SOUND_PRIME) += sound_firmw
+ obj-$(CONFIG_SOUND_PRIME) += oss/
+ obj-$(CONFIG_DMASOUND) += oss/
+ obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
+-      sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/
++      sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ ubicom32/
+ obj-$(CONFIG_SND_AOA) += aoa/
+ # This one must be compilable even if sound is configured out