diff options
author | blogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-10-05 10:12:53 +0000 |
---|---|---|
committer | blogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-10-05 10:12:53 +0000 |
commit | 5c105d9f3fd086aff195d3849dcf847d6b0bd927 (patch) | |
tree | 1229a11f725bfa58aa7c57a76898553bb5f6654a /target/linux/adm8668 | |
download | openwrt-5c105d9f3fd086aff195d3849dcf847d6b0bd927.tar.gz openwrt-5c105d9f3fd086aff195d3849dcf847d6b0bd927.zip |
branch Attitude Adjustment
git-svn-id: svn://svn.openwrt.org/openwrt/branches/attitude_adjustment@33625 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/adm8668')
44 files changed, 4997 insertions, 0 deletions
diff --git a/target/linux/adm8668/Makefile b/target/linux/adm8668/Makefile new file mode 100644 index 000000000..8ad2e71ea --- /dev/null +++ b/target/linux/adm8668/Makefile @@ -0,0 +1,26 @@ +# +# Copyright (C) 2010 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk + +ARCH:=mipsel +BOARD:=adm8668 +BOARDNAME:=Infineon WildPass ADM8668 +FEATURES:=squashfs +MAINTAINER:=Florian Fainelli <florian@openwrt.org> + +LINUX_VERSION:=3.3.8 + +include $(INCLUDE_DIR)/target.mk +DEFAULT_PACKAGES += wpad-mini kmod-rt61-pci +# kmod-switch kmod-diag nvram + +define Target/Description + Build firmware images for Infineon WildPass (ADM8668) based routers + (e.g. T-Mobile branded Linksys WRTU54G-TM) +endef + +$(eval $(call BuildTarget)) diff --git a/target/linux/adm8668/base-files.mk b/target/linux/adm8668/base-files.mk new file mode 100644 index 000000000..a09623604 --- /dev/null +++ b/target/linux/adm8668/base-files.mk @@ -0,0 +1,3 @@ +#define Package/base-files/install-target +# rm -f $(1)/etc/config/network +#endef diff --git a/target/linux/adm8668/base-files/etc/config/network b/target/linux/adm8668/base-files/etc/config/network new file mode 100644 index 000000000..120db236f --- /dev/null +++ b/target/linux/adm8668/base-files/etc/config/network @@ -0,0 +1,16 @@ +config interface loopback + option ifname lo + option proto static + option ipaddr 127.0.0.1 + option netmask 255.0.0.0 + +config interface lan + option ifname eth0 + option type bridge + option proto static + option ipaddr 192.168.1.1 + option netmask 255.255.255.0 + +config interface wan + option ifname eth1 + option proto dhcp diff --git a/target/linux/adm8668/base-files/etc/diag.sh b/target/linux/adm8668/base-files/etc/diag.sh new file mode 100644 index 000000000..edcc7536a --- /dev/null +++ b/target/linux/adm8668/base-files/etc/diag.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# Copyright (C) 2010 OpenWrt.org + +set_led() { + local state="$1" + [ -f "/proc/adm8668/sesled" ] && echo "$state" > "/proc/adm8668/sesled" +} + +set_state() { + case "$1" in + preinit) + set_led 1 + ;; + failsafe) + set_led 2 + ;; + done) + set_led 0 + ;; + esac +} diff --git a/target/linux/adm8668/base-files/lib/preinit/03_init_hotplug_failsafe_adm8668 b/target/linux/adm8668/base-files/lib/preinit/03_init_hotplug_failsafe_adm8668 new file mode 100644 index 000000000..b0f4a4efa --- /dev/null +++ b/target/linux/adm8668/base-files/lib/preinit/03_init_hotplug_failsafe_adm8668 @@ -0,0 +1,9 @@ +#!/bin/sh + +init_hotplug_failsafe() { + echo '/sbin/hotplug.failsafe' > /proc/sys/kernel/hotplug +} + +boot_hook_add preinit_main init_hotplug_failsafe + + diff --git a/target/linux/adm8668/base-files/lib/preinit/05_set_preinit_face_adm8668 b/target/linux/adm8668/base-files/lib/preinit/05_set_preinit_face_adm8668 new file mode 100644 index 000000000..ac2a7cbb6 --- /dev/null +++ b/target/linux/adm8668/base-files/lib/preinit/05_set_preinit_face_adm8668 @@ -0,0 +1,9 @@ +#!/bin/sh + +set_preinit_ifname() { + ifname=eth0 +} + +boot_hook_add preinit_main set_preinit_ifname + + diff --git a/target/linux/adm8668/base-files/lib/preinit/45_failsafe_adm8668 b/target/linux/adm8668/base-files/lib/preinit/45_failsafe_adm8668 new file mode 100644 index 000000000..c54aaed1e --- /dev/null +++ b/target/linux/adm8668/base-files/lib/preinit/45_failsafe_adm8668 @@ -0,0 +1,11 @@ +#!/bin/sh + +failsafe_wait() { + FAILSAFE= + grep -q 'SES: UP FLIP' /proc/adm8668/buttons && FAILSAFE=true && export FAILSAFE + grep -q 'SES: DOWN' /proc/adm8668/buttons && FAILSAFE=true && export FAILSAFE + if [ "$FAILSAFE" != "true" ]; then + preinit_net_echo "Please press button now to enter failsafe" + fs_wait_for_key f 'to enter failsafe mode' $fs_failsafe_wait_timeout && FAILSAFE=true && export FAILSAFE + fi +} diff --git a/target/linux/adm8668/base-files/lib/upgrade/platform.sh b/target/linux/adm8668/base-files/lib/upgrade/platform.sh new file mode 100644 index 000000000..583fa2e1d --- /dev/null +++ b/target/linux/adm8668/base-files/lib/upgrade/platform.sh @@ -0,0 +1,15 @@ +PART_NAME=linux +platform_check_image() { + [ "$ARGC" -gt 1 ] && return 1 + + case "$(get_magic_word "$1")" in + # u-boot + 2705) return 0;; + *) + echo "Invalid image type. Please use only u-boot files" + return 1 + ;; + esac +} + +# use default for platform_do_upgrade() diff --git a/target/linux/adm8668/base-files/sbin/hotplug.failsafe b/target/linux/adm8668/base-files/sbin/hotplug.failsafe new file mode 100644 index 000000000..0544339de --- /dev/null +++ b/target/linux/adm8668/base-files/sbin/hotplug.failsafe @@ -0,0 +1,4 @@ +#!/bin/sh +case "$1" in + button) kill -USR1 1;; +esac diff --git a/target/linux/adm8668/config-3.3 b/target/linux/adm8668/config-3.3 new file mode 100644 index 000000000..c5e486053 --- /dev/null +++ b/target/linux/adm8668/config-3.3 @@ -0,0 +1,77 @@ +CONFIG_ADM8668=y +CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y +CONFIG_ARCH_DISCARD_MEMBLOCK=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_BCMA_POSSIBLE=y +CONFIG_CEVT_R4K=y +CONFIG_CEVT_R4K_LIB=y +CONFIG_CPU_HAS_PREFETCH=y +CONFIG_CPU_HAS_SYNC=y +CONFIG_CPU_LITTLE_ENDIAN=y +CONFIG_CPU_MIPS32=y +CONFIG_CPU_MIPS32_R1=y +CONFIG_CPU_MIPSR1=y +CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y +CONFIG_CPU_SUPPORTS_HIGHMEM=y +CONFIG_CSRC_R4K=y +CONFIG_CSRC_R4K_LIB=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DMA_NONCOHERENT=y +CONFIG_EEPROM_93CX6=m +CONFIG_GENERIC_ATOMIC64=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_HARDWARE_WATCHPOINTS=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_KGDB=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_DMA_API_DEBUG=y +CONFIG_HAVE_DMA_ATTRS=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_HAVE_GENERIC_HARDIRQS=y +CONFIG_HAVE_IDE=y +CONFIG_HAVE_IRQ_WORK=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_HAVE_MEMBLOCK_NODE_MAP=y +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_HW_HAS_PCI=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_IRQ_CPU=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_MIPS=y +CONFIG_MIPS_L1_CACHE_SHIFT=5 +# CONFIG_MIPS_MACHINE is not set +CONFIG_MIPS_MT_DISABLED=y +CONFIG_MTD_ADM8668_NOR=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NEED_PER_CPU_KM=y +CONFIG_NO_EXCEPT_FILL=y +CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PERF_USE_VMALLOC=y +# CONFIG_PREEMPT_RCU is not set +# CONFIG_SCSI_DMA is not set +CONFIG_SERIAL_ADM8668=y +CONFIG_SERIAL_ADM8668_CONSOLE=y +CONFIG_SWAP_IO_SPACE=y +CONFIG_SYS_HAS_CPU_MIPS32_R1=y +CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y +CONFIG_SYS_SUPPORTS_ARBIT_HZ=y +CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y +CONFIG_XZ_DEC=y +CONFIG_ZONE_DMA_FLAG=0 diff --git a/target/linux/adm8668/files/arch/mips/adm8668/Makefile b/target/linux/adm8668/files/arch/mips/adm8668/Makefile new file mode 100644 index 000000000..0b31b97d4 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/Makefile @@ -0,0 +1,5 @@ +# +# something witty --neutronscott +# + +obj-y := irq.o pci.o prom.o platform.o serial.o proc.o net_core.o net_intr.o diff --git a/target/linux/adm8668/files/arch/mips/adm8668/Platform b/target/linux/adm8668/files/arch/mips/adm8668/Platform new file mode 100644 index 000000000..c70cd270b --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/Platform @@ -0,0 +1,6 @@ +# +# Infineon ADM8668 WildPass +# +platform-$(CONFIG_ADM8668) += adm8668/ +cflags-$(CONFIG_ADM8668) += -I$(srctree)/arch/mips/include/asm/mach-adm8668 +load-$(CONFIG_ADM8668) += 0xffffffff80002000 diff --git a/target/linux/adm8668/files/arch/mips/adm8668/irq.c b/target/linux/adm8668/files/arch/mips/adm8668/irq.c new file mode 100644 index 000000000..e048c15c8 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/irq.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/pm.h> +#include <linux/irq.h> +#include <asm/mipsregs.h> +#include <asm/irq_cpu.h> +#include <asm/irq.h> +#include <adm8668.h> + +static void adm8668_irq_cascade(void) +{ + int i; + unsigned long intsrc; + + intsrc = ADM8668_INTC_REG(IRQ_STATUS_REG) & IRQ_MASK; + for (i = 0; intsrc; intsrc >>= 1, i++) + if (intsrc & 0x1) + do_IRQ(i); +} + +/* + * System irq dispatch + */ +void plat_irq_dispatch(void) +{ + unsigned int pending; + + pending = read_c0_cause() & read_c0_status() & ST0_IM; + + /* timer interrupt, that we renumbered */ + if (pending & STATUSF_IP7) + do_IRQ(MIPS_CPU_IRQ_BASE + 7); + if (pending & STATUSF_IP2) + adm8668_irq_cascade(); +} + +/* + * enable 8668 irq + */ +static void enable_adm8668_irq(struct irq_data *d) +{ + int irq = d->irq; + + if ((irq < 0) || (irq > NR_IRQS)) + return; + + ADM8668_INTC_REG(IRQ_ENABLE_REG) = (1 << irq); +} + + +/* + * disable 8668 irq + */ +static void disable_adm8668_irq(struct irq_data *d) +{ + int irq = d->irq; + + if ((irq < 0) || (irq > NR_IRQS)) + return; + + ADM8668_INTC_REG(IRQ_DISABLE_REG) = (1 << irq); +} + +static void ack_adm8668_irq(struct irq_data *d) +{ + int irq = d->irq; + + ADM8668_INTC_REG(IRQ_DISABLE_REG) = (1 << irq); +} + +/* + * system irq type + */ + +static struct irq_chip adm8668_irq_type = { + .name = "adm8668", + .irq_ack = ack_adm8668_irq, + .irq_mask = disable_adm8668_irq, + .irq_unmask = enable_adm8668_irq +}; + +/* + * irq init + */ +static void __init init_adm8668_irqs(void) +{ + int i; + + for (i = 0; i <= INT_LVL_MAX; i++) + irq_set_chip_and_handler(i, &adm8668_irq_type, + handle_level_irq); + + /* hw0 is where our interrupts are uh.. interrupted at. */ + set_c0_status(IE_IRQ0); +} + +/* + * system init + */ +void __init arch_init_irq(void) +{ + mips_cpu_irq_init(); + init_adm8668_irqs(); +} diff --git a/target/linux/adm8668/files/arch/mips/adm8668/net.h b/target/linux/adm8668/files/arch/mips/adm8668/net.h new file mode 100644 index 000000000..c7aef8cf6 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/net.h @@ -0,0 +1,277 @@ +/* + * originally drivers/net/tulip/tulip.h + * Copyright 2000,2001 The Linux Kernel Team + * Written/copyright 1994-2001 by Donald Becker. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#ifndef __NET_TULIP_H__ +#define __NET_TULIP_H__ + +#include <linux/module.h> +#include <linux/export.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/mii.h> +#include <linux/crc32.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/netdevice.h> +#include <linux/ethtool.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/etherdevice.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <asm/unaligned.h> +#include <asm/uaccess.h> + +/* undefine, or define to various debugging levels (>4 == obscene levels) */ +#define TULIP_DEBUG 1 +#define VALID_INTR 0x0001a451 +#define ADM8668_WAN_IRQ 8 +#define ADM8668_LAN_IRQ 7 +#define ADM8668_WAN_MACADDR 0xb00205ac +#define ADM8668_LAN_MACADDR 0xb0020404 + +/* Offsets to the Command and Status Registers, "CSRs". All accesses + must be longword instructions and quadword aligned. */ +enum tulip_offsets { + CSR0 = 0, + CSR1 = 0x08, + CSR2 = 0x10, + CSR3 = 0x18, + CSR4 = 0x20, + CSR5 = 0x28, + CSR6 = 0x30, + CSR7 = 0x38, + CSR8 = 0x40, + CSR9 = 0x48, + CSR10 = 0x50, + CSR11 = 0x58, + CSR12 = 0x60, + CSR13 = 0x68, + CSR14 = 0x70, + CSR15 = 0x78, + CSR18 = 0x88, + CSR19 = 0x8c, + CSR20 = 0x90, + CSR27 = 0xAC, + CSR28 = 0xB0, +}; + +#define RxPollInt (RxIntr|RxNoBuf|RxDied|RxJabber) + +/* The bits in the CSR5 status registers, mostly interrupt sources. */ +enum status_bits { + TimerInt = 0x800, + SystemError = 0x2000, + TPLnkFail = 0x1000, + TPLnkPass = 0x10, + NormalIntr = 0x10000, + AbnormalIntr = 0x8000, + RxJabber = 0x200, + RxDied = 0x100, + RxNoBuf = 0x80, + RxIntr = 0x40, + TxFIFOUnderflow = 0x20, + RxErrIntr = 0x10, + TxJabber = 0x08, + TxNoBuf = 0x04, + TxDied = 0x02, + TxIntr = 0x01, +}; + +/* bit mask for CSR5 TX/RX process state */ +#define CSR5_TS 0x00700000 +#define CSR5_RS 0x000e0000 + +enum tulip_mode_bits { + TxThreshold = (1 << 22), + FullDuplex = (1 << 9), + TxOn = 0x2000, + AcceptBroadcast = 0x0100, + AcceptAllMulticast = 0x0080, + AcceptAllPhys = 0x0040, + AcceptRunt = 0x0008, + RxOn = 0x0002, + RxTx = (TxOn | RxOn), +}; + +/* The Tulip Rx and Tx buffer descriptors. */ +struct tulip_rx_desc { + __le32 status; + __le32 length; + __le32 buffer1; + __le32 buffer2; +}; + +struct tulip_tx_desc { + __le32 status; + __le32 length; + __le32 buffer1; + __le32 buffer2; /* We use only buffer 1. */ +}; + +enum desc_status_bits { + DescOwned = 0x80000000, + DescWholePkt = 0x60000000, + DescEndPkt = 0x40000000, + DescStartPkt = 0x20000000, + DescEndRing = 0x02000000, + DescUseLink = 0x01000000, + + /* + * Error summary flag is logical or of 'CRC Error', 'Collision Seen', + * 'Frame Too Long', 'Runt' and 'Descriptor Error' flags generated + * within tulip chip. + */ + RxDescErrorSummary = 0x8000, + RxDescCRCError = 0x0002, + RxDescCollisionSeen = 0x0040, + + /* + * 'Frame Too Long' flag is set if packet length including CRC exceeds + * 1518. However, a full sized VLAN tagged frame is 1522 bytes + * including CRC. + * + * The tulip chip does not block oversized frames, and if this flag is + * set on a receive descriptor it does not indicate the frame has been + * truncated. The receive descriptor also includes the actual length. + * Therefore we can safety ignore this flag and check the length + * ourselves. + */ + RxDescFrameTooLong = 0x0080, + RxDescRunt = 0x0800, + RxDescDescErr = 0x4000, + RxWholePkt = 0x00000300, + /* + * Top three bits of 14 bit frame length (status bits 27-29) should + * never be set as that would make frame over 2047 bytes. The Receive + * Watchdog flag (bit 4) may indicate the length is over 2048 and the + * length field is invalid. + */ + RxLengthOver2047 = 0x38000010 +}; + +/* Keep the ring sizes a power of two for efficiency. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ + +#define TX_RING_SIZE 32 +#define RX_RING_SIZE 128 + +/* The receiver on the DC21143 rev 65 can fail to close the last + * receive descriptor in certain circumstances (see errata) when + * using MWI. This can only occur if the receive buffer ends on + * a cache line boundary, so the "+ 4" below ensures it doesn't. + */ +#define PKT_BUF_SZ (1536 + 4) /* Size of each temporary Rx buffer. */ + +/* Ring-wrap flag in length field, use for last ring entry. + 0x01000000 means chain on buffer2 address, + 0x02000000 means use the ring start address in CSR2/3. + Note: Some work-alike chips do not function correctly in chained mode. + The ASIX chip works only in chained mode. + Thus we indicates ring mode, but always write the 'next' field for + chained mode as well. +*/ +#define DESC_RING_WRAP 0x02000000 + +struct ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + +struct tulip_private { + struct tulip_rx_desc *rx_ring; + struct tulip_tx_desc *tx_ring; + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct ring_info tx_buffers[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct ring_info rx_buffers[RX_RING_SIZE]; + struct napi_struct napi; + struct net_device_stats stats; + struct timer_list oom_timer; /* Out of memory timer. */ + u32 mc_filter[2]; + spinlock_t lock; + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + unsigned int csr0; /* CSR0 setting. */ + unsigned int csr6; /* Current CSR6 control settings. */ + void (*link_change) (struct net_device * dev, int csr5); + struct platform_device *pdev; + unsigned long nir; + void __iomem *base_addr; + int pad0; /* Used for 8-byte alignment */ + struct net_device *dev; +}; + + +/* interrupt.c */ +irqreturn_t tulip_interrupt(int irq, void *dev_instance); +int tulip_refill_rx(struct net_device *dev); +int tulip_poll(struct napi_struct *napi, int budget); + +/* tulip_core.c */ +extern int tulip_debug; +void oom_timer(unsigned long data); + +static inline void tulip_start_rxtx(struct tulip_private *tp) +{ + void __iomem *ioaddr = tp->base_addr; + iowrite32(tp->csr6 | RxTx, ioaddr + CSR6); + barrier(); + (void) ioread32(ioaddr + CSR6); /* mmio sync */ +} + +static inline void tulip_stop_rxtx(struct tulip_private *tp) +{ + void __iomem *ioaddr = tp->base_addr; + u32 csr6 = ioread32(ioaddr + CSR6); + + if (csr6 & RxTx) { + unsigned i=1300/10; + iowrite32(csr6 & ~RxTx, ioaddr + CSR6); + barrier(); + /* wait until in-flight frame completes. + * Max time @ 10BT: 1500*8b/10Mbps == 1200us (+ 100us margin) + * Typically expect this loop to end in < 50 us on 100BT. + */ + while (--i && (ioread32(ioaddr + CSR5) & (CSR5_TS|CSR5_RS))) + udelay(10); + + if (!i) + printk(KERN_DEBUG "fixme: tulip_stop_rxtx() failed" + " (CSR5 0x%x CSR6 0x%x)\n", + ioread32(ioaddr + CSR5), + ioread32(ioaddr + CSR6)); + } +} + +static inline void tulip_restart_rxtx(struct tulip_private *tp) +{ + tulip_stop_rxtx(tp); + udelay(5); + tulip_start_rxtx(tp); +} + +static inline void tulip_tx_timeout_complete(struct tulip_private *tp, void __iomem *ioaddr) +{ + /* Stop and restart the chip's Tx processes. */ + tulip_restart_rxtx(tp); + /* Trigger an immediate transmit demand. */ + iowrite32(0, ioaddr + CSR1); + + tp->stats.tx_errors++; +} + +#endif /* __NET_TULIP_H__ */ diff --git a/target/linux/adm8668/files/arch/mips/adm8668/net_core.c b/target/linux/adm8668/files/arch/mips/adm8668/net_core.c new file mode 100644 index 000000000..3348c224b --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/net_core.c @@ -0,0 +1,618 @@ +/* + * originally drivers/net/tulip_core.c + * Copyright 2000,2001 The Linux Kernel Team + * Written/copyright 1994-2001 by Donald Becker. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#define DRV_NAME "tulip" +#define DRV_VERSION "1.1.15-NAPI" /* Keep at least for test */ +#define DRV_RELDATE "Feb 27, 2007" + +#include "net.h" + +static char version[] __devinitdata = + "ADM8668net driver version " DRV_VERSION " (" DRV_RELDATE ")\n"; + +#define MAX_UNITS 2 + +/* + Set the bus performance register. + Typical: Set 16 longword cache alignment, no burst limit. + Cache alignment bits 15:14 Burst length 13:8 + 0000 No alignment 0x00000000 unlimited 0800 8 longwords + 4000 8 longwords 0100 1 longword 1000 16 longwords + 8000 16 longwords 0200 2 longwords 2000 32 longwords + C000 32 longwords 0400 4 longwords + Warning: many older 486 systems are broken and require setting 0x00A04800 + 8 longword cache alignment, 8 longword burst. + ToDo: Non-Intel setting could be better. +*/ + +//static int csr0 = 0x00200000 | 0x4000; +static int csr0 = 0; + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) + +MODULE_AUTHOR("Scott Nicholas <neutronscott@scottn.us>"); +MODULE_DESCRIPTION("ADM8668 new ethernet driver."); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +#ifdef TULIP_DEBUG +int tulip_debug = TULIP_DEBUG; +#else +int tulip_debug = 1; +#endif + +static void tulip_tx_timeout(struct net_device *dev); +static void tulip_init_ring(struct net_device *dev); +static void tulip_free_ring(struct net_device *dev); +static netdev_tx_t tulip_start_xmit(struct sk_buff *skb, + struct net_device *dev); +static int tulip_open(struct net_device *dev); +static int tulip_close(struct net_device *dev); +static void tulip_up(struct net_device *dev); +static void tulip_down(struct net_device *dev); +static struct net_device_stats *tulip_get_stats(struct net_device *dev); +//static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void set_rx_mode(struct net_device *dev); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void poll_tulip(struct net_device *dev); +#endif + +static void tulip_up(struct net_device *dev) +{ + struct tulip_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->base_addr; + + napi_enable(&tp->napi); + + /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ + iowrite32(0x00000001, ioaddr + CSR0); + + /* Deassert reset. + Wait the specified 50 PCI cycles after a reset by initializing + Tx and Rx queues and the address filter list. */ + iowrite32(tp->csr0, ioaddr + CSR0); + + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: tulip_up(), irq==%d\n", + dev->name, dev->irq); + + iowrite32(tp->rx_ring_dma, ioaddr + CSR3); + iowrite32(tp->tx_ring_dma, ioaddr + CSR4); + tp->cur_rx = tp->cur_tx = 0; + tp->dirty_rx = tp->dirty_tx = 0; + + /* set mac address */ + iowrite32(get_unaligned_le32(dev->dev_addr), ioaddr + 0xA4); + iowrite32(get_unaligned_le16(dev->dev_addr + 4), ioaddr + 0xA8); + iowrite32(0, ioaddr + CSR27); + iowrite32(0, ioaddr + CSR28); + + tp->csr6 = 0; + + /* Enable automatic Tx underrun recovery. */ + iowrite32(ioread32(ioaddr + CSR18) | 1, ioaddr + CSR18); + tp->csr6 = 0x00040000; + + /* Start the chip's Tx to process setup frame. */ + tulip_stop_rxtx(tp); + barrier(); + udelay(5); + iowrite32(tp->csr6 | TxOn, ioaddr + CSR6); + + /* Enable interrupts by setting the interrupt mask. */ + iowrite32(VALID_INTR, ioaddr + CSR5); + iowrite32(VALID_INTR, ioaddr + CSR7); + tulip_start_rxtx(tp); + iowrite32(0, ioaddr + CSR2); /* Rx poll demand */ + + if (tulip_debug > 2) { + printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %08x, CSR5 %08x CSR6 %08x\n", + dev->name, ioread32(ioaddr + CSR0), + ioread32(ioaddr + CSR5), + ioread32(ioaddr + CSR6)); + } + + init_timer(&tp->oom_timer); + tp->oom_timer.data = (unsigned long)dev; + tp->oom_timer.function = oom_timer; +} + +static int +tulip_open(struct net_device *dev) +{ + int retval; + + tulip_init_ring (dev); + + retval = request_irq(dev->irq, tulip_interrupt, 0, dev->name, dev); + if (retval) + goto free_ring; + + tulip_up (dev); + + netif_start_queue (dev); + + return 0; + +free_ring: + tulip_free_ring (dev); + return retval; +} + + +static void tulip_tx_timeout(struct net_device *dev) +{ + struct tulip_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->base_addr; + unsigned long flags; + + spin_lock_irqsave (&tp->lock, flags); + + dev_warn(&dev->dev, + "Transmit timed out, status %08x, CSR12 %08x, resetting...\n", + ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12)); + + tulip_tx_timeout_complete(tp, ioaddr); + + spin_unlock_irqrestore (&tp->lock, flags); + dev->trans_start = jiffies; /* prevent tx timeout */ + netif_wake_queue (dev); +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void tulip_init_ring(struct net_device *dev) +{ + struct tulip_private *tp = netdev_priv(dev); + int i; + + tp->nir = 0; + + for (i = 0; i < RX_RING_SIZE; i++) { + tp->rx_ring[i].status = 0x00000000; + tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ); + tp->rx_ring[i].buffer2 = cpu_to_le32(tp->rx_ring_dma + sizeof(struct tulip_rx_desc) * (i + 1)); + tp->rx_buffers[i].skb = NULL; + tp->rx_buffers[i].mapping = 0; + } + /* Mark the last entry as wrapping the ring. */ + tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP); + tp->rx_ring[i-1].buffer2 = cpu_to_le32(tp->rx_ring_dma); + + for (i = 0; i < RX_RING_SIZE; i++) { + dma_addr_t mapping; + /* Note the receive buffer must be longword aligned. + dev_alloc_skb() provides 16 byte alignment. But do *not* + use skb_reserve() to align the IP header! */ + struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ); + tp->rx_buffers[i].skb = skb; + if (skb == NULL) + break; + mapping = dma_map_single(&dev->dev, skb->data, + PKT_BUF_SZ, DMA_FROM_DEVICE); + tp->rx_buffers[i].mapping = mapping; + skb->dev = dev; /* Mark as being used by this device. */ + tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */ + tp->rx_ring[i].buffer1 = cpu_to_le32(mapping); + } + tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + /* The Tx buffer descriptor is filled in as needed, but we + do need to clear the ownership bit. */ + for (i = 0; i < TX_RING_SIZE; i++) { + tp->tx_buffers[i].skb = NULL; + tp->tx_buffers[i].mapping = 0; + tp->tx_ring[i].status = 0x00000000; + tp->tx_ring[i].buffer2 = cpu_to_le32(tp->tx_ring_dma + sizeof(struct tulip_tx_desc) * (i + 1)); + } + tp->tx_ring[i-1].buffer2 = cpu_to_le32(tp->tx_ring_dma); +} + +static netdev_tx_t +tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct tulip_private *tp = netdev_priv(dev); + int entry; + u32 flag; + dma_addr_t mapping; + unsigned long flags; + + spin_lock_irqsave(&tp->lock, flags); + + /* Calculate the next Tx descriptor entry. */ + entry = tp->cur_tx % TX_RING_SIZE; + + tp->tx_buffers[entry].skb = skb; + mapping = dma_map_single(&tp->pdev->dev, skb->data, skb->len, + DMA_TO_DEVICE); + tp->tx_buffers[entry].mapping = mapping; + tp->tx_ring[entry].buffer1 = cpu_to_le32(mapping); + + if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ + flag = 0x60000000; /* No interrupt */ + } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { + flag = 0xe0000000; /* Tx-done intr. */ + } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { + flag = 0x60000000; /* No Tx-done intr. */ + } else { /* Leave room for set_rx_mode() to fill entries. */ + flag = 0xe0000000; /* Tx-done intr. */ + netif_stop_queue(dev); + } + if (entry == TX_RING_SIZE-1) + flag = 0xe0000000 | DESC_RING_WRAP; + + tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag); + /* if we were using Transmit Automatic Polling, we would need a + * wmb() here. */ + tp->tx_ring[entry].status = cpu_to_le32(DescOwned); + wmb(); + + tp->cur_tx++; + + /* Trigger an immediate transmit demand. */ + iowrite32(0, tp->base_addr + CSR1); + + spin_unlock_irqrestore(&tp->lock, flags); + + return NETDEV_TX_OK; +} + +static void tulip_clean_tx_ring(struct tulip_private *tp) +{ + unsigned int dirty_tx; + + for (dirty_tx = tp->dirty_tx ; tp->cur_tx - dirty_tx > 0; + dirty_tx++) { + int entry = dirty_tx % TX_RING_SIZE; + int status = le32_to_cpu(tp->tx_ring[entry].status); + + if (status < 0) { + tp->stats.tx_errors++; /* It wasn't Txed */ + tp->tx_ring[entry].status = 0; + } + + dma_unmap_single(&tp->pdev->dev, tp->tx_buffers[entry].mapping, + tp->tx_buffers[entry].skb->len, + DMA_TO_DEVICE); + + /* Free the original skb. */ + dev_kfree_skb_irq(tp->tx_buffers[entry].skb); + tp->tx_buffers[entry].skb = NULL; + tp->tx_buffers[entry].mapping = 0; + } +} + +static void tulip_down (struct net_device *dev) +{ + struct tulip_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->base_addr; + unsigned long flags; + + napi_disable(&tp->napi); + del_timer_sync (&tp->oom_timer); + spin_lock_irqsave (&tp->lock, flags); + + /* Disable interrupts by clearing the interrupt mask. */ + iowrite32 (0x00000000, ioaddr + CSR7); + + /* Stop the Tx and Rx processes. */ + tulip_stop_rxtx(tp); + + /* prepare receive buffers */ + tulip_refill_rx(dev); + + /* release any unconsumed transmit buffers */ + tulip_clean_tx_ring(tp); + + if (ioread32 (ioaddr + CSR6) != 0xffffffff) + tp->stats.rx_missed_errors += ioread32 (ioaddr + CSR8) & 0xffff; + + spin_unlock_irqrestore (&tp->lock, flags); +} + +static void tulip_free_ring (struct net_device *dev) +{ + struct tulip_private *tp = netdev_priv(dev); + int i; + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = tp->rx_buffers[i].skb; + dma_addr_t mapping = tp->rx_buffers[i].mapping; + + tp->rx_buffers[i].skb = NULL; + tp->rx_buffers[i].mapping = 0; + + tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ + tp->rx_ring[i].length = 0; + /* An invalid address. */ + tp->rx_ring[i].buffer1 = cpu_to_le32(0xBADF00D0); + if (skb) { + dma_unmap_single(&tp->pdev->dev, mapping, PKT_BUF_SZ, + DMA_FROM_DEVICE); + dev_kfree_skb (skb); + } + } + + for (i = 0; i < TX_RING_SIZE; i++) { + struct sk_buff *skb = tp->tx_buffers[i].skb; + + if (skb != NULL) { + dma_unmap_single(&tp->pdev->dev, + tp->tx_buffers[i].mapping, skb->len, DMA_TO_DEVICE); + dev_kfree_skb (skb); + } + tp->tx_buffers[i].skb = NULL; + tp->tx_buffers[i].mapping = 0; + } +} + +static int tulip_close (struct net_device *dev) +{ + struct tulip_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->base_addr; + + netif_stop_queue (dev); + + tulip_down (dev); + + if (tulip_debug > 1) + dev_printk(KERN_DEBUG, &dev->dev, + "Shutting down ethercard, status was %02x\n", + ioread32 (ioaddr + CSR5)); + + free_irq (dev->irq, dev); + + tulip_free_ring (dev); + + return 0; +} + +static struct net_device_stats *tulip_get_stats(struct net_device *dev) +{ + struct tulip_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->base_addr; + + if (netif_running(dev)) { + unsigned long flags; + + spin_lock_irqsave (&tp->lock, flags); + + tp->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff; + + spin_unlock_irqrestore(&tp->lock, flags); + } + + return &tp->stats; +} + + +static void tulip_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, "mmio"); +} + +static const struct ethtool_ops ops = { + .get_drvinfo = tulip_get_drvinfo +}; + +static void set_rx_mode(struct net_device *dev) +{ + struct tulip_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->base_addr; + int csr6; + + csr6 = ioread32(ioaddr + CSR6) & ~0x00D5; + + tp->csr6 &= ~0x00D5; + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + tp->csr6 |= AcceptAllMulticast | AcceptAllPhys; + csr6 |= AcceptAllMulticast | AcceptAllPhys; + } else if ((netdev_mc_count(dev) > 1000) || + (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter well -- accept all multicasts. */ + tp->csr6 |= AcceptAllMulticast; + csr6 |= AcceptAllMulticast; + } else { + /* Some work-alikes have only a 64-entry hash filter table. */ + /* Should verify correctness on big-endian/__powerpc__ */ + struct netdev_hw_addr *ha; + if (netdev_mc_count(dev) > 64) { + /* Arbitrary non-effective limit. */ + tp->csr6 |= AcceptAllMulticast; + csr6 |= AcceptAllMulticast; + } else { + u32 mc_filter[2] = {0, 0}; /* Multicast hash filter */ + int filterbit; + netdev_for_each_mc_addr(ha, dev) { + filterbit = ether_crc_le(ETH_ALEN, ha->addr); + filterbit &= 0x3f; + mc_filter[filterbit >> 5] |= 1 << (filterbit & 31); + if (tulip_debug > 2) + dev_info(&dev->dev, + "Added filter for %pM %08x bit %d\n", + ha->addr, + ether_crc(ETH_ALEN, ha->addr), + filterbit); + } + if (mc_filter[0] == tp->mc_filter[0] && + mc_filter[1] == tp->mc_filter[1]) + ; /* No change. */ + iowrite32(mc_filter[0], ioaddr + CSR27); + iowrite32(mc_filter[1], ioaddr + CSR28); + tp->mc_filter[0] = mc_filter[0]; + tp->mc_filter[1] = mc_filter[1]; + } + } + + if (dev->irq == ADM8668_LAN_IRQ) + csr6 |= (1 << 9); /* force 100Mbps full duplex */ +// csr6 |= 1; /* pad 2 bytes. vlan? */ + + iowrite32(csr6, ioaddr + CSR6); +} + +static const struct net_device_ops tulip_netdev_ops = { + .ndo_open = tulip_open, + .ndo_start_xmit = tulip_start_xmit, + .ndo_tx_timeout = tulip_tx_timeout, + .ndo_stop = tulip_close, + .ndo_get_stats = tulip_get_stats, + .ndo_set_rx_mode = set_rx_mode, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = poll_tulip, +#endif +}; + +static int __devinit adm8668net_probe(struct platform_device *pdev) +{ + struct tulip_private *tp; + struct net_device *dev; + struct resource *res; + void __iomem *ioaddr; + int irq; + + if (pdev->id < 0 || pdev->id >= MAX_UNITS) + return -EINVAL; + + if (!(res = platform_get_resource(pdev, IORESOURCE_IRQ, 0))) + return -ENODEV; + irq = res->start; + if (!(res = platform_get_resource(pdev, IORESOURCE_MEM, 0))) + return -ENODEV; + if (!(ioaddr = ioremap(res->start, res->end - res->start))) + return -ENODEV; + if (!(dev = alloc_etherdev(sizeof (*tp)))) + return -ENOMEM; + + /* setup net dev */ + dev->base_addr = (unsigned long)res->start; + dev->irq = irq; + SET_NETDEV_DEV(dev, &pdev->dev); + + /* tulip private struct */ + tp = netdev_priv(dev); + tp->dev = dev; + tp->base_addr = ioaddr; + tp->csr0 = csr0; + tp->pdev = pdev; + tp->rx_ring = dma_alloc_coherent(&pdev->dev, + sizeof(struct tulip_rx_desc) * RX_RING_SIZE + + sizeof(struct tulip_tx_desc) * TX_RING_SIZE, + &tp->rx_ring_dma, GFP_KERNEL); + if (!tp->rx_ring) + return -ENODEV; + tp->tx_ring = (struct tulip_tx_desc *)(tp->rx_ring + RX_RING_SIZE); + tp->tx_ring_dma = tp->rx_ring_dma + sizeof(struct tulip_rx_desc) * RX_RING_SIZE; + + spin_lock_init(&tp->lock); + + /* Stop the chip's Tx and Rx processes. */ + tulip_stop_rxtx(tp); + + /* Clear the missed-packet counter. */ + ioread32(ioaddr + CSR8); + + /* Addresses are stored in BSP area of NOR flash */ + if (irq == ADM8668_WAN_IRQ) + memcpy(dev->dev_addr, (char *)ADM8668_WAN_MACADDR, 6); + else + memcpy(dev->dev_addr, (char *)ADM8668_LAN_MACADDR, 6); + + /* The Tulip-specific entries in the device structure. */ + dev->netdev_ops = &tulip_netdev_ops; + dev->watchdog_timeo = TX_TIMEOUT; + netif_napi_add(dev, &tp->napi, tulip_poll, 16); + SET_ETHTOOL_OPS(dev, &ops); + + if (register_netdev(dev)) + goto err_out_free_ring; + + dev_info(&dev->dev, + "ADM8668net at MMIO %#lx %pM, IRQ %d\n", + (unsigned long)dev->base_addr, dev->dev_addr, irq); + + platform_set_drvdata(pdev, dev); + return 0; + +err_out_free_ring: + dma_free_coherent(&pdev->dev, + sizeof (struct tulip_rx_desc) * RX_RING_SIZE + + sizeof (struct tulip_tx_desc) * TX_RING_SIZE, + tp->rx_ring, tp->rx_ring_dma); + return -ENODEV; +} + +static int __devexit adm8668net_remove(struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata (pdev); + struct tulip_private *tp; + + if (!dev) + return -ENODEV; + + tp = netdev_priv(dev); + unregister_netdev(dev); + dma_free_coherent(&pdev->dev, + sizeof (struct tulip_rx_desc) * RX_RING_SIZE + + sizeof (struct tulip_tx_desc) * TX_RING_SIZE, + tp->rx_ring, tp->rx_ring_dma); + iounmap(tp->base_addr); + free_netdev(dev); + platform_set_drvdata(pdev, NULL); + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void poll_tulip (struct net_device *dev) +{ + /* disable_irq here is not very nice, but with the lockless + interrupt handler we have no other choice. */ + disable_irq(dev->irq); + tulip_interrupt(dev->irq, dev); + enable_irq(dev->irq); +} +#endif + +static struct platform_driver adm8668net_platform_driver = { + .probe = adm8668net_probe, + .remove = __devexit_p(adm8668net_remove), + .driver = { + .owner = THIS_MODULE, + .name = "adm8668_eth" + }, +}; + +static int __init adm8668net_init(void) +{ + pr_info("%s", version); + return platform_driver_register(&adm8668net_platform_driver); +} + +static void __exit adm8668net_exit(void) +{ + platform_driver_unregister(&adm8668net_platform_driver); +} + +module_init(adm8668net_init); +module_exit(adm8668net_exit); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/net_intr.c b/target/linux/adm8668/files/arch/mips/adm8668/net_intr.c new file mode 100644 index 000000000..113dbaebd --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/net_intr.c @@ -0,0 +1,446 @@ +/* + * originally drivers/net/tulip/interrupt.c + * Copyright 2000,2001 The Linux Kernel Team + * Written/copyright 1994-2001 by Donald Becker. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include "net.h" + +int tulip_refill_rx(struct net_device *dev) +{ + struct tulip_private *tp = netdev_priv(dev); + int entry; + int refilled = 0; + + /* Refill the Rx ring buffers. */ + for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { + entry = tp->dirty_rx % RX_RING_SIZE; + if (tp->rx_buffers[entry].skb == NULL) { + struct sk_buff *skb; + dma_addr_t mapping; + + skb = tp->rx_buffers[entry].skb = dev_alloc_skb(PKT_BUF_SZ); + if (skb == NULL) + break; + + mapping = dma_map_single(&dev->dev, skb->data, + PKT_BUF_SZ, DMA_FROM_DEVICE); + tp->rx_buffers[entry].mapping = mapping; + + skb->dev = dev; /* Mark as being used by this device. */ + tp->rx_ring[entry].buffer1 = cpu_to_le32(mapping); + refilled++; + } + tp->rx_ring[entry].status = cpu_to_le32(DescOwned); + } + return refilled; +} + +void oom_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct tulip_private *tp = netdev_priv(dev); + napi_schedule(&tp->napi); +} + +int tulip_poll(struct napi_struct *napi, int budget) +{ + struct tulip_private *tp = container_of(napi, struct tulip_private, napi); + struct net_device *dev = tp->dev; + int entry = tp->cur_rx % RX_RING_SIZE; + int work_done = 0; + + if (tulip_debug > 4) + printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n", + entry, tp->rx_ring[entry].status); + + do { + if (ioread32(tp->base_addr + CSR5) == 0xffffffff) { + printk(KERN_DEBUG " In tulip_poll(), hardware disappeared\n"); + break; + } + /* Acknowledge current RX interrupt sources. */ + iowrite32((RxIntr | RxNoBuf), tp->base_addr + CSR5); + + + /* If we own the next entry, it is a new packet. Send it up. */ + while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { + s32 status = le32_to_cpu(tp->rx_ring[entry].status); + short pkt_len; + + if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) + break; + + if (tulip_debug > 5) + printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n", + dev->name, entry, status); + + if (++work_done >= budget) + goto not_done; + + /* + * Omit the four octet CRC from the length. + * (May not be considered valid until we have + * checked status for RxLengthOver2047 bits) + */ + pkt_len = ((status >> 16) & 0x7ff) - 4; + +#if 0 + csr6 = ioread32(tp->base_addr + CSR6); + if (csr6 & 0x1) + pkt_len += 2; + +#endif + /* + * Maximum pkt_len is 1518 (1514 + vlan header) + * Anything higher than this is always invalid + * regardless of RxLengthOver2047 bits + */ + + if ((status & (RxLengthOver2047 | + RxDescCRCError | + RxDescCollisionSeen | + RxDescRunt | + RxDescDescErr | + RxWholePkt)) != RxWholePkt || + pkt_len > 1518) { + if ((status & (RxLengthOver2047 | + RxWholePkt)) != RxWholePkt) { + /* Ingore earlier buffers. */ + if ((status & 0xffff) != 0x7fff) { + if (tulip_debug > 1) + dev_warn(&dev->dev, + "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", + status); + tp->stats.rx_length_errors++; + } + } else { + /* There was a fatal error. */ + if (tulip_debug > 2) + printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n", + dev->name, status); + tp->stats.rx_errors++; /* end of a packet.*/ + if (pkt_len > 1518 || + (status & RxDescRunt)) + tp->stats.rx_length_errors++; + + if (status & 0x0004) tp->stats.rx_frame_errors++; + if (status & 0x0002) tp->stats.rx_crc_errors++; + if (status & 0x0001) tp->stats.rx_fifo_errors++; + } + } else { + struct sk_buff *skb = tp->rx_buffers[entry].skb; + char *temp = skb_put(skb, pkt_len); + +#if 0 + if (csr6 & 1) + skb_pull(skb, 2); +#endif +#ifndef final_version + if (tp->rx_buffers[entry].mapping != + le32_to_cpu(tp->rx_ring[entry].buffer1)) { + dev_err(&dev->dev, + "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %08llx %p / %p\n", + le32_to_cpu(tp->rx_ring[entry].buffer1), + (unsigned long long)tp->rx_buffers[entry].mapping, + skb->head, temp); + } +#endif + + tp->rx_buffers[entry].skb = NULL; + tp->rx_buffers[entry].mapping = 0; + skb->protocol = eth_type_trans(skb, dev); + + netif_receive_skb(skb); + + tp->stats.rx_packets++; + tp->stats.rx_bytes += pkt_len; + } + entry = (++tp->cur_rx) % RX_RING_SIZE; + if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4) + tulip_refill_rx(dev); + + } + + /* New ack strategy... irq does not ack Rx any longer + hopefully this helps */ + + /* Really bad things can happen here... If new packet arrives + * and an irq arrives (tx or just due to occasionally unset + * mask), it will be acked by irq handler, but new thread + * is not scheduled. It is major hole in design. + * No idea how to fix this if "playing with fire" will fail + * tomorrow (night 011029). If it will not fail, we won + * finally: amount of IO did not increase at all. */ + } while ((ioread32(tp->base_addr + CSR5) & RxIntr)); + + tulip_refill_rx(dev); + + /* If RX ring is not full we are out of memory. */ + if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) + goto oom; + + /* Remove us from polling list and enable RX intr. */ + napi_complete(napi); + iowrite32(VALID_INTR, tp->base_addr+CSR7); + + /* The last op happens after poll completion. Which means the following: + * 1. it can race with disabling irqs in irq handler + * 2. it can race with dise/enabling irqs in other poll threads + * 3. if an irq raised after beginning loop, it will be immediately + * triggered here. + * + * Summarizing: the logic results in some redundant irqs both + * due to races in masking and due to too late acking of already + * processed irqs. But it must not result in losing events. + */ + + return work_done; + + not_done: + if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || + tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) + tulip_refill_rx(dev); + + if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) + goto oom; + + return work_done; + + oom: /* Executed with RX ints disabled */ + + /* Start timer, stop polling, but do not enable rx interrupts. */ + mod_timer(&tp->oom_timer, jiffies+1); + + /* Think: timer_pending() was an explicit signature of bug. + * Timer can be pending now but fired and completed + * before we did napi_complete(). See? We would lose it. */ + + /* remove ourselves from the polling list */ + napi_complete(napi); + + return work_done; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +irqreturn_t tulip_interrupt(int irq, void *dev_instance) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct tulip_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->base_addr; + int csr5; + int missed; + int rx = 0; + int tx = 0; + int oi = 0; + int maxrx = RX_RING_SIZE; + int maxtx = TX_RING_SIZE; + int maxoi = TX_RING_SIZE; + int rxd = 0; + unsigned int work_count = 25; + unsigned int handled = 0; + + /* Let's see whether the interrupt really is for us */ + csr5 = ioread32(ioaddr + CSR5); + + if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) + return IRQ_RETVAL(handled); + + tp->nir++; + + do { + + if (!rxd && (csr5 & (RxIntr | RxNoBuf))) { + rxd++; + /* Mask RX intrs and add the device to poll list. */ + iowrite32(VALID_INTR&~RxPollInt, ioaddr + CSR7); + napi_schedule(&tp->napi); + + if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) + break; + } + + /* Acknowledge the interrupt sources we handle here ASAP + the poll function does Rx and RxNoBuf acking */ + + iowrite32(csr5 & 0x0001ff3f, ioaddr + CSR5); + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x\n", + dev->name, csr5, ioread32(ioaddr + CSR5)); + + + if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { + unsigned int dirty_tx; + + spin_lock(&tp->lock); + + for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; + dirty_tx++) { + int entry = dirty_tx % TX_RING_SIZE; + int status = le32_to_cpu(tp->tx_ring[entry].status); + + if (status < 0) + break; /* It still has not been Txed */ + + if (status & 0x8000) { + /* There was an major error, log it. */ +#ifndef final_version + if (tulip_debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n", + dev->name, status); +#endif + tp->stats.tx_errors++; + if (status & 0x4104) tp->stats.tx_aborted_errors++; + if (status & 0x0C00) tp->stats.tx_carrier_errors++; + if (status & 0x0200) tp->stats.tx_window_errors++; + if (status & 0x0002) tp->stats.tx_fifo_errors++; + if (status & 0x0080) tp->stats.tx_heartbeat_errors++; + } else { + tp->stats.tx_bytes += + tp->tx_buffers[entry].skb->len; + tp->stats.collisions += (status >> 3) & 15; + tp->stats.tx_packets++; + } + + dma_unmap_single(&tp->pdev->dev, tp->tx_buffers[entry].mapping, + tp->tx_buffers[entry].skb->len, DMA_TO_DEVICE); + /* Free the original skb. */ + dev_kfree_skb_irq(tp->tx_buffers[entry].skb); + tp->tx_buffers[entry].skb = NULL; + tp->tx_buffers[entry].mapping = 0; + tx++; + } + +#ifndef final_version + if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { + dev_err(&dev->dev, + "Out-of-sync dirty pointer, %d vs. %d\n", + dirty_tx, tp->cur_tx); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) + netif_wake_queue(dev); + + tp->dirty_tx = dirty_tx; + if (csr5 & TxDied) { + if (tulip_debug > 2) + dev_warn(&dev->dev, + "The transmitter stopped. CSR5 is %x, CSR6 %x, new CSR6 %x\n", + csr5, ioread32(ioaddr + CSR6), + tp->csr6); + tulip_restart_rxtx(tp); + } + spin_unlock(&tp->lock); + } + + /* Log errors. */ + if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ + if (csr5 == 0xffffffff) + break; + if (csr5 & TxJabber) tp->stats.tx_errors++; + if (csr5 & TxFIFOUnderflow) { + if ((tp->csr6 & 0xC000) != 0xC000) + tp->csr6 += 0x4000; /* Bump up the Tx threshold */ + else + tp->csr6 |= 0x00200000; /* Store-n-forward. */ + /* Restart the transmit process. */ + tulip_restart_rxtx(tp); + iowrite32(0, ioaddr + CSR1); + } + if (csr5 & (RxDied | RxNoBuf)) { + iowrite32(tp->mc_filter[0], ioaddr + CSR27); + iowrite32(tp->mc_filter[1], ioaddr + CSR28); + } + if (csr5 & RxDied) { /* Missed a Rx frame. */ + tp->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff; + tp->stats.rx_errors++; + tulip_start_rxtx(tp); + } + /* + * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this + * call is ever done under the spinlock + */ + if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { + if (tp->link_change) + (tp->link_change)(dev, csr5); + } + if (csr5 & SystemError) { + int error = (csr5 >> 23) & 7; + /* oops, we hit a PCI error. The code produced corresponds + * to the reason: + * 0 - parity error + * 1 - master abort + * 2 - target abort + * Note that on parity error, we should do a software reset + * of the chip to get it back into a sane state (according + * to the 21142/3 docs that is). + * -- rmk + */ + dev_err(&dev->dev, + "(%lu) System Error occurred (%d)\n", + tp->nir, error); + } + /* Clear all error sources, included undocumented ones! */ + iowrite32(0x0800f7ba, ioaddr + CSR5); + oi++; + } + if (csr5 & TimerInt) { + + if (tulip_debug > 2) + dev_err(&dev->dev, + "Re-enabling interrupts, %08x\n", + csr5); + iowrite32(VALID_INTR, ioaddr + CSR7); + oi++; + } + if (tx > maxtx || rx > maxrx || oi > maxoi) { + if (tulip_debug > 1) + dev_warn(&dev->dev, "Too much work during an interrupt, csr5=0x%08x. (%lu) (%d,%d,%d)\n", + csr5, tp->nir, tx, rx, oi); + + /* Acknowledge all interrupt sources. */ + iowrite32(0x8001ffff, ioaddr + CSR5); + /* Mask all interrupting sources, set timer to + re-enable. */ + iowrite32(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7); + iowrite32(0x0012, ioaddr + CSR11); + break; + } + + work_count--; + if (work_count == 0) + break; + + csr5 = ioread32(ioaddr + CSR5); + + if (rxd) + csr5 &= ~RxPollInt; + } while ((csr5 & (TxNoBuf | + TxDied | + TxIntr | + TimerInt | + /* Abnormal intr. */ + RxDied | + TxFIFOUnderflow | + TxJabber | + TPLnkFail | + SystemError )) != 0); + + if ((missed = ioread32(ioaddr + CSR8) & 0x1ffff)) { + tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; + } + + if (tulip_debug > 4) + printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#04x\n", + dev->name, ioread32(ioaddr + CSR5)); + + return IRQ_HANDLED; +} diff --git a/target/linux/adm8668/files/arch/mips/adm8668/pci.c b/target/linux/adm8668/files/arch/mips/adm8668/pci.c new file mode 100644 index 000000000..2bf119297 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/pci.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <asm/byteorder.h> +#include <asm/pci.h> +#include <adm8668.h> + +volatile u32* pci_config_address_reg = (volatile u32*)KSEG1ADDR(PCICFG_BASE); +volatile u32* pci_config_data_reg = (volatile u32*)KSEG1ADDR(PCIDAT_BASE); + +#define PCI_ENABLE 0x80000000 +#define ADMPCI_IO_BASE 0x12600000 +#define ADMPCI_IO_SIZE 0x1fffff +#define ADMPCI_MEM_BASE 0x16000000 +#define ADMPCI_MEM_SIZE 0x7ffffff +#define PCI_CMM_IOACC_EN 0x1 +#define PCI_CMM_MEMACC_EN 0x2 +#define PCI_CMM_MASTER_EN 0x4 +#define PCI_CMM_DEF (PCI_CMM_IOACC_EN | PCI_CMM_MEMACC_EN | PCI_CMM_MASTER_EN) + +#define PCI_DEF_CACHE_LINE_SZ 0 +#define PCI_DEF_LATENCY_TIMER 0x20 +#define PCI_DEF_CACHE_LATENCY ((PCI_DEF_LATENCY_TIMER << 8) | PCI_DEF_CACHE_LINE_SZ) + + +#define cfgaddr(bus, devfn, where) ( \ + (bus ? ((bus->number & 0xff) << 0x10) : 0) | \ + ((devfn & 0xff) << 0x08) | \ + (where & 0xfc)) | PCI_ENABLE + +/* assumed little endian */ +static int adm8668_read_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + switch (size) + { + case 1: + *pci_config_address_reg = cfgaddr(bus, devfn, where); + *val = (le32_to_cpu(*pci_config_data_reg) >> ((where&3)<<3)) & 0xff; + break; + case 2: + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + *pci_config_address_reg = cfgaddr(bus, devfn, where); + *val = (le32_to_cpu(*pci_config_data_reg) >> ((where&3)<<3)) & 0xffff; + break; + case 4: + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + *pci_config_address_reg = cfgaddr(bus, devfn, where); + *val = le32_to_cpu(*pci_config_data_reg); + break; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int adm8668_write_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + switch (size) + { + case 1: + *pci_config_address_reg = cfgaddr(bus, devfn, where); + *(volatile u8 *)(((int)pci_config_data_reg) + (where & 3)) = val; + break; + case 2: + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + *pci_config_address_reg = cfgaddr(bus, devfn, where); + *(volatile u16 *)(((int)pci_config_data_reg) + (where & 2)) = val; + break; + case 4: + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + *pci_config_address_reg = cfgaddr(bus, devfn, where); + *pci_config_data_reg = (val); + } + + return PCIBIOS_SUCCESSFUL; +} + + +struct pci_ops adm8668_pci_ops = { + .read = adm8668_read_config, + .write = adm8668_write_config +}; + + +struct resource pciioport_resource = { + .name = "adm8668_pci", + .start = ADMPCI_IO_BASE, + .end = ADMPCI_IO_BASE + ADMPCI_IO_SIZE, + .flags = IORESOURCE_IO +}; + + +struct resource pciiomem_resource = { + .name = "adm8668_pci", + .start = ADMPCI_MEM_BASE, + .end = ADMPCI_MEM_BASE + ADMPCI_MEM_SIZE, + .flags = IORESOURCE_MEM +}; + +#ifdef CONFIG_ADM8668_DISABLE_PCI +struct pci_controller mips_pci_channels[] = { + { NULL, NULL, NULL , NULL , NULL} +}; +#else +struct pci_controller mips_pci_channels = { + .pci_ops = &adm8668_pci_ops, + .io_resource = &pciioport_resource, + .mem_resource = &pciiomem_resource, +}; +#endif + +int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + switch (slot) + { + case 1: + return 14; + case 2: + return 13; + case 3: + return 12; + default: + return dev->irq; + } +} + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} + +static int __init adm8668_pci_init(void) +{ + void __iomem *io_map_base; + + printk("adm8668_pci_init()\n"); + + /* what's an io port? this is MIPS... *shrug* */ + ioport_resource.start = ADMPCI_IO_BASE; + ioport_resource.end = ADMPCI_IO_BASE + ADMPCI_IO_SIZE; + + io_map_base = ioremap(ADMPCI_IO_BASE, ADMPCI_IO_SIZE); + if (!io_map_base) + printk("io_map_base didn't work.\n"); + mips_pci_channels.io_map_base = (unsigned long)io_map_base; + register_pci_controller(&mips_pci_channels); + + /* this needed? linksys' gpl 2.4 did it... */ + adm8668_write_config(NULL, 0, PCI_CACHE_LINE_SIZE, 2, 0); + adm8668_write_config(NULL, 0, PCI_BASE_ADDRESS_0, 4, 0); + adm8668_write_config(NULL, 0, PCI_BASE_ADDRESS_1, 4, 0); + adm8668_write_config(NULL, 0, PCI_COMMAND, 4, PCI_CMM_DEF); + + return 0; +} + +arch_initcall(adm8668_pci_init); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/platform.c b/target/linux/adm8668/files/arch/mips/adm8668/platform.c new file mode 100644 index 000000000..803af09aa --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/platform.c @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <linux/ioport.h> +#include <asm/reboot.h> +#include <asm/time.h> +#include <asm/addrspace.h> +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <adm8668.h> + +static struct resource uart_resources[] = { + { + .start = ADM8668_UART0_BASE, + .end = ADM8668_UART0_BASE + 0xF, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_LVL_UART0, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device adm8668_uart_device = { + .name = "adm8668_uart", + .id = 0, + .resource = uart_resources, + .num_resources = ARRAY_SIZE(uart_resources), +}; + +static struct resource eth0_resources[] = { + { + .start = ADM8668_LAN_BASE, + .end = ADM8668_LAN_BASE + 256, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_LVL_LAN, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device adm8668_eth0_device = { + .name = "adm8668_eth", + .id = 0, + .resource = eth0_resources, + .num_resources = ARRAY_SIZE(eth0_resources), +}; + +static struct resource eth1_resources[] = { + { + .start = ADM8668_WAN_BASE, + .end = ADM8668_WAN_BASE + 256, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_LVL_WAN, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device adm8668_eth1_device = { + .name = "adm8668_eth", + .id = 1, + .resource = eth1_resources, + .num_resources = ARRAY_SIZE(eth1_resources), +}; + +static void adm8668_restart(char *cmd) +{ + int i; + + /* stop eth0 and eth1 */ + ADM8668_LAN_REG(NETCSR6) = (1 << 13) | (1 << 1); + ADM8668_LAN_REG(NETCSR7) = 0; + ADM8668_WAN_REG(NETCSR6) = (1 << 13) | (1 << 1); + ADM8668_WAN_REG(NETCSR7) = 0; + + /* reset PHY */ + ADM8668_WAN_REG(NETCSR37) = 0x20; + for (i = 0; i < 10000; i++) + ; + ADM8668_WAN_REG(NETCSR37) = 0; + for (i = 0; i < 10000; i++) + ; + + *(volatile unsigned int *)0xB1600000 = 1; /* reset eth0 mac */ + *(volatile unsigned int *)0xB1A00000 = 1; /* reset eth1 mac */ + *(volatile unsigned int *)0xB1800000 = 1; /* reset wlan0 mac */ + + /* the real deal */ + for (i = 0; i < 1000; i++) + ; + ADM8668_CONFIG_REG(ADM8668_CR1) = 1; +} + +int __devinit adm8668_devs_register(void) +{ + _machine_restart = adm8668_restart; + platform_device_register(&adm8668_uart_device); + platform_device_register(&adm8668_eth0_device); + platform_device_register(&adm8668_eth1_device); + + return 0; +} + +void __init plat_time_init(void) +{ + int adj = (ADM8668_CONFIG_REG(ADM8668_CR3) >> 11) & 0xf; + + /* adjustable clock selection + CR3 bit 14~11, 0000 -> 175MHz, 0001 -> 180MHz, etc... */ + + mips_hpt_frequency = (SYS_CLOCK + adj * 5000000) / 2; + printk("ADM8668 CPU clock: %d MHz\n", 2*mips_hpt_frequency / 1000000); +} + +void __init plat_mem_setup(void) +{ + /* prom_init seemed like easier place for this. it's tooo simple */ +} + +const char *get_system_type(void) +{ + unsigned long chipid = ADM8668_CONFIG_REG(ADM8668_CR0); + int adj = (ADM8668_CONFIG_REG(ADM8668_CR3) >> 11) & 0xf; + int product, revision, mhz; + static char ret[32]; + + product = chipid >> 16; + revision = chipid & 0xffff; + mhz = (SYS_CLOCK/1000000) + (adj * 5); + + /* i getting fancy :\ */ + snprintf(ret, sizeof(ret), "ADM%xr%x %dMHz", product, revision, mhz); + + return ret; +} + +arch_initcall(adm8668_devs_register); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/proc.c b/target/linux/adm8668/files/arch/mips/adm8668/proc.c new file mode 100644 index 000000000..77dbb1faf --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/proc.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <asm/uaccess.h> +#include <adm8668.h> + +int adm8668_sesled_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) +{ + char buf[8]; + int num; + + num = (count < 8) ? count : 8; + + if (copy_from_user(buf, buffer, num)) + { + printk("copy_from_user failed"); + return -EFAULT; + } + num = simple_strtoul(buf, NULL, 16); + switch (num) + { + case 0: + GPIO_SET_LOW(0); + CRGPIO_SET_LOW(2); + break; + case 1: + GPIO_SET_LOW(0); + CRGPIO_SET_HI(2); + break; + case 2: + GPIO_SET_HI(0); + CRGPIO_SET_HI(2); + break; + default: + break; + } + + return count; +} + +int adm8668_sesled_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data) +{ + int len = 0; + int led_state = 0; + + led_state = (ADM8668_CONFIG_REG(CRGPIO_REG) & 0x100) ? 1 : 0; + led_state += (ADM8668_WLAN_REG(GPIO_REG) & 0x40) ? 2 : 0; + len += sprintf(buf+len, "%s\n", + (led_state&1) ? + ((led_state&2) ? "ORANGE" : "GREEN") : "OFF"); + + return len; +} + +int adm8668_button_read_proc(char *buf, char **start, off_t offset, + int count, int *eof, void *data) +{ + int len = 0; + int read_once = ADM8668_CONFIG_REG(CRGPIO_REG); + int button_flip = (read_once >> 20) & 0x3; + int button_state = read_once & 0x3; + + len += sprintf(buf+len, "SES: %s %s\nRESET: %s %s\n", + (button_state&2) ? "UP" : "DOWN", + (button_flip&2) ? "FLIP" : "", + (button_state&1) ? "UP" : "DOWN", + (button_flip&1) ? "FLIP" : ""); + + return len; +} + +int __init adm8668_init_proc(void) +{ + struct proc_dir_entry *adm8668_proc_dir = NULL; + struct proc_dir_entry *sesled = NULL; + int __maybe_unused bogus; + + /* these are known to be lights. rest are input...? */ + ADM8668_CONFIG_REG(CRGPIO_REG) = GPIO2_OUTPUT_ENABLE; + ADM8668_WLAN_REG(GPIO_REG) = GPIO0_OUTPUT_ENABLE; + + /* inital read off of the flipper switcher on the button thingie */ + bogus = ADM8668_CONFIG_REG(CRGPIO_REG); + + adm8668_proc_dir = proc_mkdir("adm8668", 0); + if (adm8668_proc_dir == NULL) { + printk(KERN_ERR "ADM8668 proc: unable to create proc dir.\n"); + return 0; + } + create_proc_read_entry("buttons", 0444, adm8668_proc_dir, + adm8668_button_read_proc, NULL); + sesled = create_proc_entry("sesled", S_IRUGO|S_IWUGO, adm8668_proc_dir); + if (sesled) { + sesled->read_proc = adm8668_sesled_read_proc; + sesled->write_proc = adm8668_sesled_write_proc; + } + + return 0; +} + +module_init(adm8668_init_proc); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Scott Nicholas <neutronscott@scottn.us>"); +MODULE_DESCRIPTION("ADM8668 ghetto button driver"); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/prom.c b/target/linux/adm8668/files/arch/mips/adm8668/prom.c new file mode 100644 index 000000000..7187f2982 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/prom.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * + * based on work of rb532 prom.c + * Copyright (C) 2003, Peter Sadik <peter.sadik@idt.com> + * Copyright (C) 2005-2006, P.Christeas <p_christ@hol.gr> + * Copyright (C) 2007, Gabor Juhos <juhosg@openwrt.org> + * Felix Fietkau <nbd@openwrt.org> + * Florian Fainelli <florian@openwrt.org> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/console.h> +#include <linux/string.h> +#include <linux/serial_core.h> +#include <asm/bootinfo.h> +#include <adm8668.h> +#include "u-boot.h" + +register volatile struct global_data *gd asm ("k0"); + +#ifdef CONFIG_SERIAL_ADM8668_CONSOLE +static inline unsigned int adm_uart_readl(unsigned int offset) +{ + return (*(volatile unsigned int *)(0xbe400000 + offset)); +} + +static inline void adm_uart_writel(unsigned int value, unsigned int offset) +{ + (*((volatile unsigned int *)(0xbe400000 + offset))) = value; +} + +static void prom_putchar(char c) +{ + adm_uart_writel(c, UART_DR_REG); + while ((adm_uart_readl(UART_FR_REG) & UART_TX_FIFO_FULL) != 0) + ; +} + +static void __init +early_console_write(struct console *con, const char *s, unsigned n) +{ + while (n-- && *s) { + if (*s == '\n') + prom_putchar('\r'); + prom_putchar(*s); + s++; + } +} + +static struct console early_console __initdata = { + .name = "early", + .write = early_console_write, + .flags = CON_BOOT, + .index = -1 +}; + +#endif + +void __init prom_free_prom_memory(void) +{ + /* No prom memory to free */ +} + +static inline int match_tag(char *arg, const char *tag) +{ + return strncmp(arg, tag, strlen(tag)) == 0; +} + +static inline unsigned long tag2ul(char *arg, const char *tag) +{ + char *num; + + num = arg + strlen(tag); + return simple_strtoul(num, 0, 10); +} + +void __init prom_setup_cmdline(void) +{ + char *cp; + int prom_argc; + char **prom_argv; + int i; + + prom_argc = fw_arg0; + prom_argv = (char **)KSEG0ADDR(fw_arg1); + + cp = &(arcs_cmdline[0]); + for (i = 1; i < prom_argc; i++) { + prom_argv[i] = (char *)KSEG0ADDR(prom_argv[i]); + + /* default bootargs has "console=/dev/ttyS0" yet console won't + * show up at all if you include the '/dev/' nowadays ... */ + if (match_tag(prom_argv[i], "console=/dev/")) { + char *ptr = prom_argv[i] + strlen("console=/dev/"); + + strcpy(cp, "console="); + cp += strlen("console="); + strcpy(cp, ptr); + cp += strlen(ptr); + *cp++ = ' '; + continue; + } + strcpy(cp, prom_argv[i]); + cp += strlen(prom_argv[i]); + *cp++ = ' '; + } + if (prom_argc > 1) + --cp; /* trailing space */ + + *cp = '\0'; +} + +void __init prom_init(void) +{ + bd_t *bd = gd->bd; + int memsize; + +#ifdef CONFIG_SERIAL_ADM8668_CONSOLE + register_console(&early_console); +#endif + + memsize = bd->bi_memsize; + printk("Board info:\n"); + printk(" RAM size: %d MB\n", (int)memsize/(1024*1024)); + printk(" NOR start: %#lx\n", bd->bi_flashstart); + printk(" NOR size: %#lx\n", bd->bi_flashsize); + + prom_setup_cmdline(); + add_memory_region(0, memsize, BOOT_MEM_RAM); +} diff --git a/target/linux/adm8668/files/arch/mips/adm8668/serial.c b/target/linux/adm8668/files/arch/mips/adm8668/serial.c new file mode 100644 index 000000000..7d684b810 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/serial.c @@ -0,0 +1,638 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * ADM8668 serial driver, totally ripped the source from BCM63xx and changed + * all the registers to fit our hardware, and removed all the features that + * I didn't know because our GPL'd serial driver was way lame. + * + * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * Derived directly from bcm63xx_uart + * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> + * + */ + +#if defined(CONFIG_SERIAL_ADM8668_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/console.h> +#include <linux/clk.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/sysrq.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <adm8668.h> + +#define ADM8668_NR_UARTS 1 + +static struct uart_port ports[ADM8668_NR_UARTS]; + +/* + * handy uart register accessor + */ +static inline unsigned int adm_uart_readl(struct uart_port *port, + unsigned int offset) +{ + return (*(volatile unsigned int *)(port->membase + offset)); +} + +static inline void adm_uart_writel(struct uart_port *port, + unsigned int value, unsigned int offset) +{ + (*((volatile unsigned int *)(port->membase + offset))) = value; +} + +/* + * serial core request to check if uart tx fifo is empty + */ +static unsigned int adm_uart_tx_empty(struct uart_port *port) +{ + /* we always wait for completion, no buffer is made... */ + return 1; +} + +/* + * serial core request to set RTS and DTR pin state and loopback mode + */ +static void adm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +/* + * serial core request to return RI, CTS, DCD and DSR pin state + */ +static unsigned int adm_uart_get_mctrl(struct uart_port *port) +{ + return 0; +} + +/* + * serial core request to disable tx ASAP (used for flow control) + */ +static void adm_uart_stop_tx(struct uart_port *port) +{ + unsigned int val; + + val = adm_uart_readl(port, UART_CR_REG); + val &= ~(UART_TX_INT_EN); + adm_uart_writel(port, val, UART_CR_REG); +} + +/* + * serial core request to (re)enable tx + */ +static void adm_uart_start_tx(struct uart_port *port) +{ + unsigned int val; + + val = adm_uart_readl(port, UART_CR_REG); + val |= UART_TX_INT_EN; + adm_uart_writel(port, val, UART_CR_REG); +} + +/* + * serial core request to stop rx, called before port shutdown + */ +static void adm_uart_stop_rx(struct uart_port *port) +{ + unsigned int val; + + val = adm_uart_readl(port, UART_CR_REG); + val &= ~UART_RX_INT_EN; + adm_uart_writel(port, val, UART_CR_REG); +} + +/* + * serial core request to enable modem status interrupt reporting + */ +static void adm_uart_enable_ms(struct uart_port *port) +{ +} + +/* + * serial core request to start/stop emitting break char + */ +static void adm_uart_break_ctl(struct uart_port *port, int ctl) +{ +} + +/* + * return port type in string format + */ +static const char *adm_uart_type(struct uart_port *port) +{ + return (port->type == PORT_ADM8668) ? "adm8668_uart" : NULL; +} + +/* + * read all chars in rx fifo and send them to core + */ +static void adm_uart_do_rx(struct uart_port *port) +{ + struct tty_struct *tty; + unsigned int max_count; + + /* limit number of char read in interrupt, should not be + * higher than fifo size anyway since we're much faster than + * serial port */ + max_count = 32; + tty = port->state->port.tty; + do { + unsigned int iestat, c, cstat; + char flag; + + /* get overrun/fifo empty information from ier + * register */ + iestat = adm_uart_readl(port, UART_FR_REG); + if (iestat & UART_RX_FIFO_EMPTY) + break; + + /* recieve status */ + cstat = adm_uart_readl(port, UART_RSR_REG); + /* clear errors */ + adm_uart_writel(port, cstat, UART_RSR_REG); + + c = adm_uart_readl(port, UART_DR_REG); + port->icount.rx++; + flag = TTY_NORMAL; + + if (unlikely((cstat & UART_RX_STATUS_MASK))) { + /* do stats first */ + if (cstat & UART_BREAK_ERR) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } + + if (cstat & UART_PARITY_ERR) + port->icount.parity++; + if (cstat & UART_FRAMING_ERR) + port->icount.frame++; + if (cstat & UART_OVERRUN_ERR) { + port->icount.overrun++; + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + + /* update flag wrt read_status_mask */ + cstat &= port->read_status_mask; + if (cstat & UART_BREAK_ERR) + flag = TTY_BREAK; + if (cstat & UART_FRAMING_ERR) + flag = TTY_FRAME; + if (cstat & UART_PARITY_ERR) + flag = TTY_PARITY; + } + + if (uart_handle_sysrq_char(port, c)) + continue; + + /* fixthis */ + if ((cstat & port->ignore_status_mask) == 0) + tty_insert_flip_char(tty, c, flag); + } while (max_count--); + + tty_flip_buffer_push(tty); +} + +/* + * fill tx fifo with chars to send, stop when fifo is about to be full + * or when all chars have been sent. + */ +static void adm_uart_do_tx(struct uart_port *port) +{ + struct circ_buf *xmit; + + if (port->x_char) { + adm_uart_writel(port, port->x_char, UART_DR_REG); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_tx_stopped(port)) + adm_uart_stop_tx(port); + + xmit = &port->state->xmit; + + if (uart_circ_empty(xmit)) + goto txq_empty; + do + { + while ((adm_uart_readl(port, UART_FR_REG) & UART_TX_FIFO_FULL) != 0) + ; + adm_uart_writel(port, xmit->buf[xmit->tail], UART_DR_REG); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (1); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + goto txq_empty; + + return; + +txq_empty: + adm_uart_stop_tx(port); +} + +/* + * process uart interrupt + */ +static irqreturn_t adm_uart_interrupt(int irq, void *dev_id) +{ + struct uart_port *port; + unsigned int irqstat; + + port = dev_id; + spin_lock(&port->lock); + + irqstat = adm_uart_readl(port, UART_IIR_REG); + + if (irqstat & (UART_RX_INT|UART_RX_TIMEOUT_INT)) { + adm_uart_do_rx(port); + } + + if (irqstat & UART_TX_INT) { + adm_uart_do_tx(port); + } + spin_unlock(&port->lock); + return IRQ_HANDLED; +} + +/* + * enable rx & tx operation on uart + */ +static void adm_uart_enable(struct uart_port *port) +{ + unsigned int val; + + val = adm_uart_readl(port, UART_CR_REG); + // BREAK_INT too + val |= (UART_RX_INT_EN | UART_RX_TIMEOUT_INT_EN); + adm_uart_writel(port, val, UART_CR_REG); +} + +/* + * disable rx & tx operation on uart + */ +static void adm_uart_disable(struct uart_port *port) +{ + unsigned int val; + + val = adm_uart_readl(port, UART_CR_REG); + val &= ~(UART_TX_INT_EN | UART_RX_INT_EN | UART_RX_TIMEOUT_INT_EN); + adm_uart_writel(port, val, UART_CR_REG); +} + +/* + * clear all unread data in rx fifo and unsent data in tx fifo + */ +static void adm_uart_flush(struct uart_port *port) +{ + /* read any pending char to make sure all irq status are + * cleared */ + (void)adm_uart_readl(port, UART_DR_REG); +} + +/* + * serial core request to initialize uart and start rx operation + */ +static int adm_uart_startup(struct uart_port *port) +{ + int ret; + + /* clear any pending external input interrupt */ + (void)adm_uart_readl(port, UART_IIR_REG); + + /* register irq and enable rx interrupts */ + ret = request_irq(port->irq, adm_uart_interrupt, 0, + adm_uart_type(port), port); + if (ret) + return ret; + + adm_uart_enable(port); + + return 0; +} + +/* + * serial core request to flush & disable uart + */ +static void adm_uart_shutdown(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); +// adm_uart_writel(port, 0, UART_CR_REG); + spin_unlock_irqrestore(&port->lock, flags); + + adm_uart_disable(port); + adm_uart_flush(port); + free_irq(port->irq, port); +} + +/* + * serial core request to change current uart setting + */ +static void adm_uart_set_termios(struct uart_port *port, + struct ktermios *new, + struct ktermios *old) +{ + port->ignore_status_mask = 0; + uart_update_timeout(port, new->c_cflag, 115200); +} + +/* + * serial core request to claim uart iomem + */ +static int adm_uart_request_port(struct uart_port *port) +{ + unsigned int size = 0xf; + if (!request_mem_region(port->mapbase, size, "adm8668")) { + dev_err(port->dev, "Memory region busy\n"); + return -EBUSY; + } + + port->membase = ioremap(port->mapbase, size); + if (!port->membase) { + dev_err(port->dev, "Unable to map registers\n"); + release_mem_region(port->mapbase, size); + return -EBUSY; + } + return 0; +} + +/* + * serial core request to release uart iomem + */ +static void adm_uart_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, 0xf); + iounmap(port->membase); +} + +/* + * serial core request to do any port required autoconfiguration + */ +static void adm_uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + if (adm_uart_request_port(port)) + return; + port->type = PORT_ADM8668; + } +} + +/* + * serial core request to check that port information in serinfo are + * suitable + */ +static int adm_uart_verify_port(struct uart_port *port, + struct serial_struct *serinfo) +{ + if (port->type != PORT_ADM8668) + return -EINVAL; + if (port->irq != serinfo->irq) + return -EINVAL; + if (port->iotype != serinfo->io_type) + return -EINVAL; + if (port->mapbase != (unsigned long)serinfo->iomem_base) + return -EINVAL; + return 0; +} + +/* serial core callbacks */ +static struct uart_ops adm_uart_ops = { + .tx_empty = adm_uart_tx_empty, + .get_mctrl = adm_uart_get_mctrl, + .set_mctrl = adm_uart_set_mctrl, + .start_tx = adm_uart_start_tx, + .stop_tx = adm_uart_stop_tx, + .stop_rx = adm_uart_stop_rx, + .enable_ms = adm_uart_enable_ms, + .break_ctl = adm_uart_break_ctl, + .startup = adm_uart_startup, + .shutdown = adm_uart_shutdown, + .set_termios = adm_uart_set_termios, + .type = adm_uart_type, + .release_port = adm_uart_release_port, + .request_port = adm_uart_request_port, + .config_port = adm_uart_config_port, + .verify_port = adm_uart_verify_port, +}; + +#ifdef CONFIG_SERIAL_ADM8668_CONSOLE +static inline void wait_for_xmitr(struct uart_port *port) +{ + while ((adm_uart_readl(port, UART_FR_REG) & UART_TX_FIFO_FULL) != 0) + ; +} + +/* + * output given char + */ +static void adm_console_putchar(struct uart_port *port, int ch) +{ + wait_for_xmitr(port); + adm_uart_writel(port, ch, UART_DR_REG); +} + +/* + * console core request to output given string + */ +static void adm_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *port; + unsigned long flags; + int locked; + + port = &ports[co->index]; + + local_irq_save(flags); + if (port->sysrq) { + /* adm_uart_interrupt() already took the lock */ + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&port->lock); + } else { + spin_lock(&port->lock); + locked = 1; + } + + /* call helper to deal with \r\n */ + uart_console_write(port, s, count, adm_console_putchar); + + /* and wait for char to be transmitted */ + wait_for_xmitr(port); + + if (locked) + spin_unlock(&port->lock); + local_irq_restore(flags); +} + +/* + * console core request to setup given console, find matching uart + * port and setup it. + */ +static int adm_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= ADM8668_NR_UARTS) + return -EINVAL; + port = &ports[co->index]; + if (!port->membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver adm_uart_driver; + +static struct console adm8668_console = { + .name = "ttyS", + .write = adm_console_write, + .device = uart_console_device, + .setup = adm_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &adm_uart_driver, +}; + +static int __init adm8668_console_init(void) +{ + register_console(&adm8668_console); + return 0; +} + +console_initcall(adm8668_console_init); + +#define ADM8668_CONSOLE (&adm8668_console) +#else +#define ADM8668_CONSOLE NULL +#endif /* CONFIG_SERIAL_ADM8668_CONSOLE */ + +static struct uart_driver adm_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "adm8668_uart", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = 1, + .cons = ADM8668_CONSOLE, +}; + +/* + * platform driver probe/remove callback + */ +static int __devinit adm_uart_probe(struct platform_device *pdev) +{ + struct resource *res_mem, *res_irq; + struct uart_port *port; + int ret; + + if (pdev->id < 0 || pdev->id >= ADM8668_NR_UARTS) + return -EINVAL; + + if (ports[pdev->id].membase) + return -EBUSY; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mem) + return -ENODEV; + + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res_irq) + return -ENODEV; + + port = &ports[pdev->id]; + memset(port, 0, sizeof(*port)); + port->iotype = UPIO_MEM; + port->mapbase = res_mem->start; + port->irq = res_irq->start; + port->ops = &adm_uart_ops; + port->flags = UPF_BOOT_AUTOCONF; + port->dev = &pdev->dev; + port->fifosize = 8; + port->uartclk = ADM8668_UARTCLK_FREQ; + + ret = uart_add_one_port(&adm_uart_driver, port); + if (ret) { + ports[pdev->id].membase = 0; + return ret; + } + platform_set_drvdata(pdev, port); + return 0; +} + +static int __devexit adm_uart_remove(struct platform_device *pdev) +{ + struct uart_port *port; + + port = platform_get_drvdata(pdev); + uart_remove_one_port(&adm_uart_driver, port); + platform_set_drvdata(pdev, NULL); + /* mark port as free */ + ports[pdev->id].membase = 0; + return 0; +} + +/* + * platform driver stuff + */ +static struct platform_driver adm_uart_platform_driver = { + .probe = adm_uart_probe, + .remove = __devexit_p(adm_uart_remove), + .driver = { + .owner = THIS_MODULE, + .name = "adm8668_uart", + }, +}; + +static int __init adm_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&adm_uart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&adm_uart_platform_driver); + if (ret) + uart_unregister_driver(&adm_uart_driver); + + return ret; +} + +static void __exit adm_uart_exit(void) +{ + platform_driver_unregister(&adm_uart_platform_driver); + uart_unregister_driver(&adm_uart_driver); +} + +module_init(adm_uart_init); +module_exit(adm_uart_exit); + +MODULE_AUTHOR("Scott Nicholas <neutronscott@scottn.us>"); +MODULE_DESCRIPTION("ADM8668 integrated uart driver"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/u-boot.h b/target/linux/adm8668/files/arch/mips/adm8668/u-boot.h new file mode 100644 index 000000000..d9d226889 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/u-boot.h @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _U_BOOT_H_ +#define _U_BOOT_H_ 1 + +typedef struct bd_info { + int bi_baudrate; /* serial console baudrate */ + unsigned long bi_ip_addr; /* IP Address */ + unsigned char bi_enetaddr[6]; /* Ethernet adress */ + unsigned long bi_arch_number; /* unique id for this board */ + unsigned long bi_boot_params; /* where this board expects params */ + unsigned long bi_memstart; /* start of DRAM memory */ + unsigned long bi_memsize; /* size of DRAM memory in bytes */ + unsigned long bi_flashstart; /* start of FLASH memory */ + unsigned long bi_flashsize; /* size of FLASH memory */ + unsigned long bi_flashoffset; /* reserved area for startup monitor */ +} bd_t; + +struct global_data { + bd_t *bd; /* board data... */ + unsigned long flags; + unsigned long baudrate; + unsigned long have_console; /* serial_init() was called */ + unsigned long ram_size; /* RAM size */ + unsigned long reloc_off; /* Relocation Offset */ + unsigned long env_addr; /* Address of Environment struct */ + unsigned long env_valid; /* Checksum of Environment valid? */ + void **jt; /* jump table */ +}; + +#endif /* _U_BOOT_H_ */ diff --git a/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/adm8668.h b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/adm8668.h new file mode 100644 index 000000000..2cf65d81a --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/adm8668.h @@ -0,0 +1,139 @@ +/************************************************************************ + * + * Copyright (c) 2005 + * Infineon Technologies AG + * St. Martin Strasse 53; 81669 Muenchen; Germany + * + ************************************************************************/ + +#ifndef __ADM8668_H__ +#define __ADM8668_H__ + +#define SYS_CLOCK 175000000 + +/*======================= Physical Memory Map ============================*/ +#define ADM8668_SDRAM_BASE 0 +#define ADM8668_SMEM1_BASE 0x10000000 +#define ADM8668_MPMC_BASE 0x11000000 +#define ADM8668_USB_BASE 0x11200000 +#define ADM8668_CONFIG_BASE 0x11400000 +#define ADM8668_WAN_BASE 0x11600000 +#define ADM8668_WLAN_BASE 0x11800000 +#define ADM8668_LAN_BASE 0x11A00000 +#define ADM8668_INTC_BASE 0x1E000000 +#define ADM8668_TMR_BASE 0x1E200000 +#define ADM8668_UART0_BASE 0x1E400000 +#define ADM8668_SMEM0_BASE 0x1FC00000 +#define ADM8668_NAND_BASE 0x1FFFFF00 + +#define PCICFG_BASE 0x12200000 +#define PCIDAT_BASE 0x12400000 + +/** onboard uart **/ +#define ADM8668_UARTCLK_FREQ 62500000 +/* registers */ +#define UART_DR_REG 0x00 +#define UART_RSR_REG 0x04 +#define UART_CR_REG 0x14 +#define UART_FR_REG 0x18 +#define UART_IIR_REG 0x1C + +/* rsr reg */ +#define UART_FRAMING_ERR 0x01 +#define UART_PARITY_ERR 0x02 +#define UART_BREAK_ERR 0x04 +#define UART_OVERRUN_ERR 0x08 +#define UART_RX_STATUS_MASK 0x0F + +/* cr reg */ +#define UART_RX_INT_EN 0x10 +#define UART_TX_INT_EN 0x20 +#define UART_RX_TIMEOUT_INT_EN 0x40 + +/* fr reg */ +#define UART_RX_FIFO_EMPTY 0x10 +#define UART_TX_FIFO_FULL 0x20 + +/* iir reg */ +#define UART_RX_INT 0x02 +#define UART_TX_INT 0x04 +#define UART_RX_TIMEOUT_INT 0x08 + +/* interrupt controller */ +#define IRQ_STATUS_REG 0x00 /* Read */ +#define IRQ_ENABLE_REG 0x08 /* Read/Write */ +#define IRQ_DISABLE_REG 0x0C /* Write */ + +/* interrupt levels */ +#define INT_LVL_SWI 1 +#define INT_LVL_COMMS_RX 2 +#define INT_LVL_COMMS_TX 3 +#define INT_LVL_TIMERINT0 4 +#define INT_LVL_TIMERINT1 5 +#define INT_LVL_UART0 6 +#define INT_LVL_LAN 7 +#define INT_LVL_WAN 8 +#define INT_LVL_WLAN 9 +#define INT_LVL_GPIO 10 +#define INT_LVL_IDE 11 +#define INT_LVL_PCI2 12 +#define INT_LVL_PCI1 13 +#define INT_LVL_PCI0 14 +#define INT_LVL_USB 15 +#define INT_LVL_MAX INT_LVL_USB + +/* register access macros */ +#define ADM8668_INTC_REG(_reg) \ + (*((volatile unsigned long *)(KSEG1ADDR(ADM8668_INTC_BASE + (_reg))))) +#define ADM8668_LAN_REG(_reg) \ + (*((volatile unsigned int *)(KSEG1ADDR(ADM8668_LAN_BASE + (_reg))))) +#define ADM8668_WAN_REG(_reg) \ + (*((volatile unsigned int *)(KSEG1ADDR(ADM8668_WAN_BASE + (_reg))))) +#define ADM8668_WLAN_REG(_reg) \ + (*((volatile unsigned int *)(KSEG1ADDR(ADM8668_WLAN_BASE + (_reg))))) +#define ADM8668_CONFIG_REG(_reg) \ + (*((volatile unsigned int *)(KSEG1ADDR(ADM8668_CONFIG_BASE + (_reg))))) + +/* lan registers */ +#define NETCSR6 0x30 +#define NETCSR7 0x38 +#define NETCSR37 0xF8 + +/* known/used CPU configuration registers */ +#define ADM8668_CR0 0x00 +#define ADM8668_CR1 0x04 +#define ADM8668_CR3 0x0C + +/** For GPIO control **/ +#define GPIO_REG 0x5C /* on WLAN */ +#define CRGPIO_REG 0x20 /* on CPU */ +#define GPIO0_OUTPUT_ENABLE 0x1000 +#define GPIO1_OUTPUT_ENABLE 0x2000 +#define GPIO2_OUTPUT_ENABLE 0x4000 +#define GPIO_OUTPUT_ENABLE_ALL 0x7000 +#define GPIO0_OUTPUT_1 0x40 +#define GPIO1_OUTPUT_1 0x80 +#define GPIO2_OUTPUT_1 0x100 +#define GPIO0_INPUT_1 0x1 +#define GPIO1_INPUT_1 0x2 +#define GPIO2_INPUT_1 0x4 + +#define GPIO_SET_HI(num) \ + ADM8668_WLAN_REG(GPIO_REG) |= (1 << (6 + num)) + +#define GPIO_SET_LOW(num) \ + ADM8668_WLAN_REG(GPIO_REG) &= ~(1 << (6 + num)) + +#define GPIO_TOGGLE(num) \ + ADM8668_WLAN_REG(GPIO_REG) ^= (1 << (6 + num)) + +#define CRGPIO_SET_HI(num) \ + ADM8668_CONFIG_REG(CRGPIO_REG) |= (1 << (6 + num)) + +#define CRGPIO_SET_LOW(num) \ + ADM8668_CONFIG_REG(CRGPIO_REG) &= ~(1 << (6 + num)) + +#define CRGPIO_TOGGLE(num) \ + ADM8668_CONFIG_REG(CRGPIO_REG) ^= (1 << (6 + num)) + +#endif /* __ADM8668_H__ */ diff --git a/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/irq.h b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/irq.h new file mode 100644 index 000000000..1341309f2 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/irq.h @@ -0,0 +1,16 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2003 by Ralf Baechle + */ +#ifndef __ASM_MACH_ADM8668_IRQ_H +#define __ASM_MACH_ADM8668_IRQ_H + +#define NR_IRQS 32 +#define MIPS_CPU_IRQ_BASE 16 + +#define IRQ_MASK 0xffff + +#endif /* __ASM_MACH_ADM8668_IRQ_H */ diff --git a/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/war.h b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/war.h new file mode 100644 index 000000000..7180043d3 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/war.h @@ -0,0 +1,25 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org> + */ +#ifndef __ASM_MIPS_MACH_ADM8668_WAR_H +#define __ASM_MIPS_MACH_ADM8668_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_ADM8668_WAR_H */ diff --git a/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c b/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c new file mode 100644 index 000000000..e360a0d78 --- /dev/null +++ b/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> + * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> + * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) + * + * original functions for finding root filesystem from Mike Baker + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Copyright 2004, 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. + * + * Flash mapping for adm8668 boards + * + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/slab.h> +#include <linux/mtd/partitions.h> +#include <linux/crc32.h> +#include <linux/magic.h> +#include <asm/io.h> + +#define WINDOW_ADDR 0x10000000 +#define WINDOW_SIZE 0x800000 +#define BANKWIDTH 2 + +/* first a little bit about the headers i need.. */ + +/* just interested in part of the full struct */ +struct squashfs_super_block { + __le32 s_magic; + __le32 pad0[9]; /* it's not really padding */ + __le64 bytes_used; +}; + +#define IH_MAGIC 0x56190527 /* Image Magic Number */ +struct uboot_header { + uint32_t ih_magic; /* Image Header Magic Number */ + uint32_t ih_hcrc; /* Image Header CRC Checksum */ + uint32_t ih_time; /* Image Creation Timestamp */ + uint32_t ih_size; /* Image Data Size */ + uint32_t ih_load; /* Data Load Address */ + uint32_t ih_ep; /* Entry Point Address */ + uint32_t ih_dcrc; /* Image Data CRC Checksum */ + uint8_t ih_os; /* Operating System */ + uint8_t ih_arch; /* CPU architecture */ + uint8_t ih_type; /* Image Type */ + uint8_t ih_comp; /* Compression Type */ + char ih_name[32]; /* image name */ +}; + +/************************************************/ + +static struct mtd_info *adm8668_mtd; + +struct map_info adm8668_map = { + name: "adm8668-nor", + size: WINDOW_SIZE, + phys: WINDOW_ADDR, + bankwidth: BANKWIDTH, +}; + +/* + * Copied from mtdblock.c + * + * Cache stuff... + * + * Since typical flash erasable sectors are much larger than what Linux's + * buffer cache can handle, we must implement read-modify-write on flash + * sectors for each block write requests. To avoid over-erasing flash sectors + * and to speed things up, we locally cache a whole flash sector while it is + * being written to until a different sector is required. + */ + +static void erase_callback(struct erase_info *done) +{ + wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; + wake_up(wait_q); +} + +static int erase_write (struct mtd_info *mtd, unsigned long pos, + int len, const char *buf) +{ + struct erase_info erase; + DECLARE_WAITQUEUE(wait, current); + wait_queue_head_t wait_q; + size_t retlen; + int ret; + + /* + * First, let's erase the flash block. + */ + + init_waitqueue_head(&wait_q); + erase.mtd = mtd; + erase.callback = erase_callback; + erase.addr = pos; + erase.len = len; + erase.priv = (u_long)&wait_q; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&wait_q, &wait); + + ret = mtd->erase(mtd, &erase); + if (ret) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&wait_q, &wait); + printk (KERN_WARNING "erase of region [0x%lx, 0x%x] " + "on \"%s\" failed\n", + pos, len, mtd->name); + return ret; + } + + schedule(); /* Wait for erase to finish. */ + remove_wait_queue(&wait_q, &wait); + + /* + * Next, write data to flash. + */ + + ret = mtd->write (mtd, pos, len, &retlen, buf); + if (ret) + return ret; + if (retlen != len) + return -EIO; + return 0; +} + +/* decent defaults in case... shrug */ +static struct mtd_partition adm8668_parts[] = { + { name: "linux", offset: 0x40000, size: WINDOW_SIZE-0x40000, }, + { name: "rootfs", offset: 0xe0000, size: 0x140000, }, + { name: "uboot_env", offset: 0x20000, size: 0x20000, }, + { name: NULL, }, +}; + +/* in case i wanna change stuff later, and to clarify the math section... */ +#define PART_LINUX 0 +#define PART_ROOTFS 1 +#define NR_PARTS 3 + +static int __init +init_mtd_partitions(struct mtd_info *mtd, size_t size) +{ + struct uboot_header uhdr; + int off, blocksize; + size_t len, linux_len; + struct squashfs_super_block shdr; + + blocksize = mtd->erasesize; + if (blocksize < 0x10000) + blocksize = 0x10000; + + /* now find squashfs */ + memset(&shdr, 0xe5, sizeof(shdr)); + for (off = adm8668_parts[PART_LINUX].offset; off < size; off += blocksize) { + /* + * Read into buffer + */ + if (mtd->read(mtd, off, sizeof(shdr), &len, (char *)&shdr) || + len != sizeof(shdr)) + continue; + + if (shdr.s_magic == SQUASHFS_MAGIC) { + uint32_t fs_size = (uint32_t)shdr.bytes_used; + + printk(KERN_INFO "%s: Filesystem type: squashfs, size=%dkB\n", + mtd->name, fs_size>>10); + + /* Update rootfs based on the superblock info, and + * stretch to end of MTD. rootfs_split will split it */ + adm8668_parts[PART_ROOTFS].offset = off; + adm8668_parts[PART_ROOTFS].size = mtd->size - + adm8668_parts[PART_ROOTFS].offset; + + /* kernel ends where rootfs starts + * but we'll keep it full-length for upgrades */ + linux_len = adm8668_parts[PART_LINUX+1].offset - + adm8668_parts[PART_LINUX].offset; +#if 1 + adm8668_parts[PART_LINUX].size = mtd->size - + adm8668_parts[PART_LINUX].offset; +#else + adm8668_parts[PART_LINUX].size = linux_len; +#endif + goto found; + } + } + + printk(KERN_NOTICE + "%s: Couldn't find root filesystem\n", + mtd->name); + return NR_PARTS; + + found: + if (mtd->read(mtd, adm8668_parts[PART_LINUX].offset, sizeof(uhdr), &len, (char *)&uhdr) || + len != sizeof(uhdr)) + return NR_PARTS; + + /* that's odd. how'd ya boot it then */ + if (uhdr.ih_magic != IH_MAGIC) + return NR_PARTS; + + if (be32_to_cpu(uhdr.ih_size) != (linux_len - sizeof(uhdr))) { + unsigned char *block, *data; + unsigned int offset; + + offset = adm8668_parts[PART_LINUX].offset + + sizeof(struct uboot_header); + data = (unsigned char *)(WINDOW_ADDR | 0xA0000000 | offset); + + printk(KERN_NOTICE "Updating U-boot image:\n"); + printk(KERN_NOTICE " old: [size: %8d crc32: 0x%08x]\n", + be32_to_cpu(uhdr.ih_size), be32_to_cpu(uhdr.ih_dcrc)); + + /* Update the data length & crc32 */ + uhdr.ih_size = cpu_to_be32(linux_len - sizeof(uhdr)); + uhdr.ih_dcrc = crc32_le(~0, data, linux_len - sizeof(uhdr)) ^ (~0); + uhdr.ih_dcrc = cpu_to_be32(uhdr.ih_dcrc); + + printk(KERN_NOTICE " new: [size: %8d crc32: 0x%08x]\n", + be32_to_cpu(uhdr.ih_size), be32_to_cpu(uhdr.ih_dcrc)); + + /* update header's crc... */ + uhdr.ih_hcrc = 0; + uhdr.ih_hcrc = crc32_le(~0, (unsigned char *)&uhdr, + sizeof(uhdr)) ^ (~0); + uhdr.ih_hcrc = cpu_to_be32(uhdr.ih_hcrc); + + /* read first eraseblock from the image */ + block = kmalloc(mtd->erasesize, GFP_KERNEL); + if (mtd->read(mtd, adm8668_parts[PART_LINUX].offset, mtd->erasesize, &len, block) || len != mtd->erasesize) { + printk("Error copying first eraseblock\n"); + return 0; + } + + /* Write updated header to the flash */ + memcpy(block, &uhdr, sizeof(uhdr)); + if (mtd->unlock) + mtd->unlock(mtd, off, mtd->erasesize); + erase_write(mtd, adm8668_parts[PART_LINUX].offset, mtd->erasesize, block); + if (mtd->sync) + mtd->sync(mtd); + kfree(block); + printk(KERN_NOTICE "Done\n"); + } + + return NR_PARTS; +} + +int __init init_adm8668_map(void) +{ + int nr_parts, ret; + + adm8668_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); + + if (!adm8668_map.virt) { + printk(KERN_ERR "Failed to ioremap\n"); + return -EIO; + } + + simple_map_init(&adm8668_map); + if (!(adm8668_mtd = do_map_probe("cfi_probe", &adm8668_map))) { + printk(KERN_ERR "cfi_probe failed\n"); + iounmap((void *)adm8668_map.virt); + return -ENXIO; + } + + adm8668_mtd->owner = THIS_MODULE; + + nr_parts = init_mtd_partitions(adm8668_mtd, adm8668_mtd->size); + ret = mtd_device_register(adm8668_mtd, adm8668_parts, nr_parts); + if (ret) { + printk(KERN_ERR "Flash: mtd_device_register failed\n"); + goto fail; + } + + return 0; + + fail: + if (adm8668_mtd) + map_destroy(adm8668_mtd); + if (adm8668_map.virt) + iounmap((void *) adm8668_map.virt); + adm8668_map.virt = 0; + return ret; +} + +void __exit cleanup_adm8668_map(void) +{ + mtd_device_unregister(adm8668_mtd); + map_destroy(adm8668_mtd); + iounmap((void *) adm8668_map.virt); + adm8668_map.virt = 0; +} + +module_init(init_adm8668_map); +module_exit(cleanup_adm8668_map); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Scott Nicholas <neutronscott@scottn.us>"); +MODULE_DESCRIPTION("MTD map driver for ADM8668 NOR Flash"); diff --git a/target/linux/adm8668/image/Makefile b/target/linux/adm8668/image/Makefile new file mode 100644 index 000000000..bc412a609 --- /dev/null +++ b/target/linux/adm8668/image/Makefile @@ -0,0 +1,58 @@ +# +# Copyright (C) 2010 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/image.mk + +VMLINUX:=$(BIN_DIR)/$(IMG_PREFIX)-vmlinux +UIMAGE:=$(IMG_PREFIX)-uImage +ifeq ($(CONFIG_TARGET_ROOTFS_INITRAMFS),y) + VMLINUX:=$(BIN_DIR)/$(IMG_PREFIX)-vmlinux-initramfs + UIMAGE:=$(IMG_PREFIX)-uImage-initramfs +endif + +define kernel_entry +-a 0x80002000 -e 0x80002000 +endef + + +define CompressGzip + gzip -9 -c $(1) > $(2) +endef + +define MkImage + mkimage -A mips -O linux -T kernel $(call kernel_entry) -C $(1) $(2) \ + -n "ADM8668 Linux Kernel(2.4.31)" \ + -d $(3) $(4) +endef + +define Build/Clean + $(MAKE) -C lzma-loader clean +endef + +define Image/Prepare + cat $(KDIR)/vmlinux | $(STAGING_DIR_HOST)/bin/lzma e -si -so -eos -lc1 -lp2 -pb2 > $(KDIR)/vmlinux.lzma + $(MAKE) -C lzma-loader \ + KDIR="$(KDIR)" \ + clean compile + rm -f $(KDIR)/fs_mark + touch $(KDIR)/fs_mark + $(call prepare_generic_squashfs,$(KDIR)/fs_mark) +endef + +define Image/Build + ./my-mkimage $(KDIR)/loader.bin $(KDIR)/root.squashfs \ + $(KDIR)/fs_mark $(BIN_DIR)/$(IMG_PREFIX)-$(1).bin +endef + +define Image/BuildKernel + cp $(KDIR)/vmlinux.elf $(VMLINUX).elf + cp $(KDIR)/vmlinux $(VMLINUX).bin + $(call CompressGzip,$(KDIR)/vmlinux,$(KDIR)/vmlinux.bin.gz) + $(call MkImage,gzip,,$(KDIR)/vmlinux.bin.gz,$(BIN_DIR)/$(UIMAGE)-gzip.bin) +endef + +$(eval $(call BuildImage)) diff --git a/target/linux/adm8668/image/lzma-loader/Makefile b/target/linux/adm8668/image/lzma-loader/Makefile new file mode 100644 index 000000000..f6bc7cef3 --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/Makefile @@ -0,0 +1,41 @@ +# +# Copyright (C) 2010 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME := loader +PKG_VERSION := 0.05 + +PKG_BUILD_DIR := $(KDIR)/$(PKG_NAME)-$(PKG_VERSION)$(LOADER_TYPE) + +$(PKG_BUILD_DIR)/.prepared: + mkdir $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ + touch $@ + +$(PKG_BUILD_DIR)/lzma.elf: $(PKG_BUILD_DIR)/.prepared $(PKG_BUILD_DIR)/vmlinux.lzma + PATH="$(TARGET_PATH)" $(MAKE) -C $(PKG_BUILD_DIR) \ + CC="$(TARGET_CC)" CROSS_COMPILE="$(TARGET_CROSS)" + +$(PKG_BUILD_DIR)/vmlinux.lzma: $(KDIR)/vmlinux.lzma + $(CP) $< $@ + +$(KDIR)/loader$(LOADER_TYPE).elf: $(PKG_BUILD_DIR)/lzma.elf + $(CP) $< $@ + +$(KDIR)/loader$(LOADER_TYPE).bin: $(PKG_BUILD_DIR)/lzma.bin + $(CP) $< $@ + +download: +prepare: $(PKG_BUILD_DIR)/.prepared +compile: $(KDIR)/loader$(LOADER_TYPE).elf $(KDIR)/loader$(LOADER_TYPE).bin +install: + +clean: + rm -rf $(PKG_BUILD_DIR) + rm -f $(KDIR)/loader.elf + rm -f $(KDIR)/loader.bin diff --git a/target/linux/adm8668/image/lzma-loader/src/LzmaDecode.c b/target/linux/adm8668/image/lzma-loader/src/LzmaDecode.c new file mode 100644 index 000000000..8c863efe5 --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/src/LzmaDecode.c @@ -0,0 +1,590 @@ +/* + LzmaDecode.c + LZMA Decoder (optimized for Speed version) + + LZMA SDK 4.22 Copyright (c) 1999-2005 Igor Pavlov (2005-06-10) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this Code, expressly permits you to + statically or dynamically link your Code (or bind by name) to the + interfaces of this file without subjecting your linked Code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#include "LzmaDecode.h" + +#ifndef Byte +#define Byte unsigned char +#endif + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_READ_BYTE (*Buffer++) + +#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \ + { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }} + +#ifdef _LZMA_IN_CB + +#define RC_TEST { if (Buffer == BufferLim) \ + { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \ + BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }} + +#define RC_INIT Buffer = BufferLim = 0; RC_INIT2 + +#else + +#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; } + +#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2 + +#endif + +#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; } + +#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound) +#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits; +#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits; + +#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \ + { UpdateBit0(p); mi <<= 1; A0; } else \ + { UpdateBit1(p); mi = (mi + mi) + 1; A1; } + +#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;) + +#define RangeDecoderBitTreeDecode(probs, numLevels, res) \ + { int i = numLevels; res = 1; \ + do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \ + res -= (1 << numLevels); } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +#if 0 +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size) +{ + unsigned char prop0; + if (size < LZMA_PROPERTIES_SIZE) + return LZMA_RESULT_DATA_ERROR; + prop0 = propsData[0]; + if (prop0 >= (9 * 5 * 5)) + return LZMA_RESULT_DATA_ERROR; + { + for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5)); + for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9); + propsRes->lc = prop0; + /* + unsigned char remainder = (unsigned char)(prop0 / 9); + propsRes->lc = prop0 % 9; + propsRes->pb = remainder / 5; + propsRes->lp = remainder % 5; + */ + } + + #ifdef _LZMA_OUT_READ + { + int i; + propsRes->DictionarySize = 0; + for (i = 0; i < 4; i++) + propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8); + if (propsRes->DictionarySize == 0) + propsRes->DictionarySize = 1; + } + #endif + return LZMA_RESULT_OK; +} +#endif + +#define kLzmaStreamWasFinishedId (-1) + +int LzmaDecode(CLzmaDecoderState *vs, + #ifdef _LZMA_IN_CB + ILzmaInCallback *InCallback, + #else + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + #endif + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed) +{ + CProb *p = vs->Probs; + SizeT nowPos = 0; + Byte previousByte = 0; + UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1; + UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1; + int lc = vs->Properties.lc; + + #ifdef _LZMA_OUT_READ + + UInt32 Range = vs->Range; + UInt32 Code = vs->Code; + #ifdef _LZMA_IN_CB + const Byte *Buffer = vs->Buffer; + const Byte *BufferLim = vs->BufferLim; + #else + const Byte *Buffer = inStream; + const Byte *BufferLim = inStream + inSize; + #endif + int state = vs->State; + UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3]; + int len = vs->RemainLen; + UInt32 globalPos = vs->GlobalPos; + UInt32 distanceLimit = vs->DistanceLimit; + + Byte *dictionary = vs->Dictionary; + UInt32 dictionarySize = vs->Properties.DictionarySize; + UInt32 dictionaryPos = vs->DictionaryPos; + + Byte tempDictionary[4]; + + #ifndef _LZMA_IN_CB + *inSizeProcessed = 0; + #endif + *outSizeProcessed = 0; + if (len == kLzmaStreamWasFinishedId) + return LZMA_RESULT_OK; + + if (dictionarySize == 0) + { + dictionary = tempDictionary; + dictionarySize = 1; + tempDictionary[0] = vs->TempDictionary[0]; + } + + if (len == kLzmaNeedInitId) + { + { + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); + UInt32 i; + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + rep0 = rep1 = rep2 = rep3 = 1; + state = 0; + globalPos = 0; + distanceLimit = 0; + dictionaryPos = 0; + dictionary[dictionarySize - 1] = 0; + #ifdef _LZMA_IN_CB + RC_INIT; + #else + RC_INIT(inStream, inSize); + #endif + } + len = 0; + } + while(len != 0 && nowPos < outSize) + { + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos]; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + len--; + } + if (dictionaryPos == 0) + previousByte = dictionary[dictionarySize - 1]; + else + previousByte = dictionary[dictionaryPos - 1]; + + #else /* if !_LZMA_OUT_READ */ + + int state = 0; + UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; + int len = 0; + const Byte *Buffer; + const Byte *BufferLim; + UInt32 Range; + UInt32 Code; + + #ifndef _LZMA_IN_CB + *inSizeProcessed = 0; + #endif + *outSizeProcessed = 0; + + { + UInt32 i; + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp)); + for (i = 0; i < numProbs; i++) + p[i] = kBitModelTotal >> 1; + } + + #ifdef _LZMA_IN_CB + RC_INIT; + #else + RC_INIT(inStream, inSize); + #endif + + #endif /* _LZMA_OUT_READ */ + + while(nowPos < outSize) + { + CProb *prob; + UInt32 bound; + int posState = (int)( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & posStateMask); + + prob = p + IsMatch + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + int symbol = 1; + UpdateBit0(prob) + prob = p + Literal + (LZMA_LIT_SIZE * + ((( + (nowPos + #ifdef _LZMA_OUT_READ + + globalPos + #endif + ) + & literalPosMask) << lc) + (previousByte >> (8 - lc)))); + + if (state >= kNumLitStates) + { + int matchByte; + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + matchByte = dictionary[pos]; + #else + matchByte = outStream[nowPos - rep0]; + #endif + do + { + int bit; + CProb *probLit; + matchByte <<= 1; + bit = (matchByte & 0x100); + probLit = prob + 0x100 + bit + symbol; + RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break) + } + while (symbol < 0x100); + } + while (symbol < 0x100) + { + CProb *probLit = prob + symbol; + RC_GET_BIT(probLit, symbol) + } + previousByte = (Byte)symbol; + + outStream[nowPos++] = previousByte; + #ifdef _LZMA_OUT_READ + if (distanceLimit < dictionarySize) + distanceLimit++; + + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #endif + if (state < 4) state = 0; + else if (state < 10) state -= 3; + else state -= 6; + } + else + { + UpdateBit1(prob); + prob = p + IsRep + state; + IfBit0(prob) + { + UpdateBit0(prob); + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + state = state < kNumLitStates ? 0 : 3; + prob = p + LenCoder; + } + else + { + UpdateBit1(prob); + prob = p + IsRepG0 + state; + IfBit0(prob) + { + UpdateBit0(prob); + prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState; + IfBit0(prob) + { + #ifdef _LZMA_OUT_READ + UInt32 pos; + #endif + UpdateBit0(prob); + + #ifdef _LZMA_OUT_READ + if (distanceLimit == 0) + #else + if (nowPos == 0) + #endif + return LZMA_RESULT_DATA_ERROR; + + state = state < kNumLitStates ? 9 : 11; + #ifdef _LZMA_OUT_READ + pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + outStream[nowPos++] = previousByte; + #ifdef _LZMA_OUT_READ + if (distanceLimit < dictionarySize) + distanceLimit++; + #endif + + continue; + } + else + { + UpdateBit1(prob); + } + } + else + { + UInt32 distance; + UpdateBit1(prob); + prob = p + IsRepG1 + state; + IfBit0(prob) + { + UpdateBit0(prob); + distance = rep1; + } + else + { + UpdateBit1(prob); + prob = p + IsRepG2 + state; + IfBit0(prob) + { + UpdateBit0(prob); + distance = rep2; + } + else + { + UpdateBit1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = p + RepLenCoder; + } + { + int numBits, offset; + CProb *probLen = prob + LenChoice; + IfBit0(probLen) + { + UpdateBit0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + numBits = kLenNumLowBits; + } + else + { + UpdateBit1(probLen); + probLen = prob + LenChoice2; + IfBit0(probLen) + { + UpdateBit0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + numBits = kLenNumMidBits; + } + else + { + UpdateBit1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + numBits = kLenNumHighBits; + } + } + RangeDecoderBitTreeDecode(probLen, numBits, len); + len += offset; + } + + if (state < 4) + { + int posSlot; + state += kNumLitStates; + prob = p + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + rep0 = (2 | ((UInt32)posSlot & 1)); + if (posSlot < kEndPosModelIndex) + { + rep0 <<= numDirectBits; + prob = p + SpecPos + rep0 - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + RC_NORMALIZE + Range >>= 1; + rep0 <<= 1; + if (Code >= Range) + { + Code -= Range; + rep0 |= 1; + } + } + while (--numDirectBits != 0); + prob = p + Align; + rep0 <<= kNumAlignBits; + numDirectBits = kNumAlignBits; + } + { + int i = 1; + int mi = 1; + do + { + CProb *prob3 = prob + mi; + RC_GET_BIT2(prob3, mi, ; , rep0 |= i); + i <<= 1; + } + while(--numDirectBits != 0); + } + } + else + rep0 = posSlot; + if (++rep0 == (UInt32)(0)) + { + /* it's for stream version */ + len = kLzmaStreamWasFinishedId; + break; + } + } + + len += kMatchMinLen; + #ifdef _LZMA_OUT_READ + if (rep0 > distanceLimit) + #else + if (rep0 > nowPos) + #endif + return LZMA_RESULT_DATA_ERROR; + + #ifdef _LZMA_OUT_READ + if (dictionarySize - distanceLimit > (UInt32)len) + distanceLimit += len; + else + distanceLimit = dictionarySize; + #endif + + do + { + #ifdef _LZMA_OUT_READ + UInt32 pos = dictionaryPos - rep0; + if (pos >= dictionarySize) + pos += dictionarySize; + previousByte = dictionary[pos]; + dictionary[dictionaryPos] = previousByte; + if (++dictionaryPos == dictionarySize) + dictionaryPos = 0; + #else + previousByte = outStream[nowPos - rep0]; + #endif + len--; + outStream[nowPos++] = previousByte; + } + while(len != 0 && nowPos < outSize); + } + } + RC_NORMALIZE; + + #ifdef _LZMA_OUT_READ + vs->Range = Range; + vs->Code = Code; + vs->DictionaryPos = dictionaryPos; + vs->GlobalPos = globalPos + (UInt32)nowPos; + vs->DistanceLimit = distanceLimit; + vs->Reps[0] = rep0; + vs->Reps[1] = rep1; + vs->Reps[2] = rep2; + vs->Reps[3] = rep3; + vs->State = state; + vs->RemainLen = len; + vs->TempDictionary[0] = tempDictionary[0]; + #endif + + #ifdef _LZMA_IN_CB + vs->Buffer = Buffer; + vs->BufferLim = BufferLim; + #else + *inSizeProcessed = (SizeT)(Buffer - inStream); + #endif + *outSizeProcessed = nowPos; + return LZMA_RESULT_OK; +} diff --git a/target/linux/adm8668/image/lzma-loader/src/LzmaDecode.h b/target/linux/adm8668/image/lzma-loader/src/LzmaDecode.h new file mode 100644 index 000000000..abc02d7ed --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/src/LzmaDecode.h @@ -0,0 +1,131 @@ +/* + LzmaDecode.h + LZMA Decoder interface + + LZMA SDK 4.21 Copyright (c) 1999-2005 Igor Pavlov (2005-06-08) + http://www.7-zip.org/ + + LZMA SDK is licensed under two licenses: + 1) GNU Lesser General Public License (GNU LGPL) + 2) Common Public License (CPL) + It means that you can select one of these two licenses and + follow rules of that license. + + SPECIAL EXCEPTION: + Igor Pavlov, as the author of this code, expressly permits you to + statically or dynamically link your code (or bind by name) to the + interfaces of this file without subjecting your linked code to the + terms of the CPL or GNU LGPL. Any modifications or additions + to this file, however, are subject to the LGPL or CPL terms. +*/ + +#ifndef __LZMADECODE_H +#define __LZMADECODE_H + +/* #define _LZMA_IN_CB */ +/* Use callback for input data */ + +/* #define _LZMA_OUT_READ */ +/* Use read function for output data */ + +/* #define _LZMA_PROB32 */ +/* It can increase speed on some 32-bit CPUs, + but memory usage will be doubled in that case */ + +/* #define _LZMA_LOC_OPT */ +/* Enable local speed optimizations inside code */ + +/* #define _LZMA_SYSTEM_SIZE_T */ +/* Use system's size_t. You can use it to enable 64-bit sizes supporting*/ + +#ifndef UInt32 +#ifdef _LZMA_UINT32_IS_ULONG +#define UInt32 unsigned long +#else +#define UInt32 unsigned int +#endif +#endif + +#ifndef SizeT +#ifdef _LZMA_SYSTEM_SIZE_T +#include <stddef.h> +#define SizeT size_t +#else +#define SizeT UInt32 +#endif +#endif + +#ifdef _LZMA_PROB32 +#define CProb UInt32 +#else +#define CProb unsigned short +#endif + +#define LZMA_RESULT_OK 0 +#define LZMA_RESULT_DATA_ERROR 1 + +#ifdef _LZMA_IN_CB +typedef struct _ILzmaInCallback +{ + int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize); +} ILzmaInCallback; +#endif + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LZMA_PROPERTIES_SIZE 5 + +typedef struct _CLzmaProperties +{ + int lc; + int lp; + int pb; + #ifdef _LZMA_OUT_READ + UInt32 DictionarySize; + #endif +}CLzmaProperties; + +int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size); + +#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp))) + +#define kLzmaNeedInitId (-2) + +typedef struct _CLzmaDecoderState +{ + CLzmaProperties Properties; + CProb *Probs; + + #ifdef _LZMA_IN_CB + const unsigned char *Buffer; + const unsigned char *BufferLim; + #endif + + #ifdef _LZMA_OUT_READ + unsigned char *Dictionary; + UInt32 Range; + UInt32 Code; + UInt32 DictionaryPos; + UInt32 GlobalPos; + UInt32 DistanceLimit; + UInt32 Reps[4]; + int State; + int RemainLen; + unsigned char TempDictionary[4]; + #endif +} CLzmaDecoderState; + +#ifdef _LZMA_OUT_READ +#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; } +#endif + +int LzmaDecode(CLzmaDecoderState *vs, + #ifdef _LZMA_IN_CB + ILzmaInCallback *inCallback, + #else + const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed, + #endif + unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed); + +#endif diff --git a/target/linux/adm8668/image/lzma-loader/src/Makefile b/target/linux/adm8668/image/lzma-loader/src/Makefile new file mode 100644 index 000000000..998e39081 --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/src/Makefile @@ -0,0 +1,47 @@ +# +# Copyright (C) 2010 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +RAMSTART = 0x80000000 +RAMSIZE = 0x00800000 # 8MB +LOADADDR = 0x80400000 # RAM start + 4M +KERNEL_ENTRY = 0x80002000 + +CROSS_COMPILE = mipsel-openwrt-linux- + +OBJCOPY:= $(CROSS_COMPILE)objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S +CFLAGS := -I./include -fno-builtin -Os -G 0 -ffunction-sections -mno-abicalls -fno-pic -mabi=32 -march=mips32 -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap -Wall -DRAMSTART=${RAMSTART} -DRAMSIZE=${RAMSIZE} -DKERNEL_ENTRY=${KERNEL_ENTRY} + +.c.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +CC = $(CROSS_COMPILE)gcc +LD = $(CROSS_COMPILE)ld +OBJDUMP = $(CROSS_COMPILE)objdump + +O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32) + +# Drop some uninteresting sections in the kernel. +# This is only relevant for ELF kernels but doesn't hurt a.out +drop-sections = .reginfo .mdebug .comment +strip-flags = $(addprefix --remove-section=,$(drop-sections)) + +all : lzma.elf lzma.bin + +lzma.lds: lzma.lds.in + sed -e 's,@LOADADDR@,$(LOADADDR),g' $< >$@ + +kernel.o: vmlinux.lzma lzma.lds + $(LD) -r -b binary --oformat $(O_FORMAT) -o $@ $< + +lzma.bin: lzma.elf + $(OBJCOPY) $< $@ + +lzma.elf: decompress.o stubs.o LzmaDecode.o kernel.o lzma.lds + $(LD) -T lzma.lds -o $@ $^ +#-s ^ + +clean: + rm -f *.o lzma.elf lzma.bin *.tmp *.lds diff --git a/target/linux/adm8668/image/lzma-loader/src/decompress.c b/target/linux/adm8668/image/lzma-loader/src/decompress.c new file mode 100644 index 000000000..f328058a1 --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/src/decompress.c @@ -0,0 +1,118 @@ +/* + * LZMA compressed kernel decompressor for bcm947xx boards + * + * Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * Please note, this was code based on the bunzip2 decompressor code + * by Manuel Novoa III (mjn3@codepoet.org), although the only thing left + * is an idea and part of original vendor code + * + * + * 12-Mar-2005 Mineharu Takahara <mtakahar@yahoo.com> + * pass actual output size to decoder (stream mode + * compressed input is not a requirement anymore) + * + * 24-Apr-2005 Oleg I. Vdovikin + * reordered functions using lds script, removed forward decl + * + * ??-Nov-2005 Mike Baker + * reorder the script as an lzma wrapper; do not depend on flash access + */ + +#include "LzmaDecode.h" +#include <exports.h> + +#define KSEG0ADDR(addr) (0x80000000|addr) + +register volatile gd_t *gd asm ("k0"); +unsigned char *data; + +static __inline__ unsigned char get_byte() +{ + unsigned char *buffer; + + buffer = data; + data++; + + return *buffer; +} + +/* This puts lzma workspace 128k below RAM end. + * That should be enough for both lzma and stack + */ +static char *buffer = (char *)(RAMSTART + RAMSIZE - 0x00020000); +extern char _binary_vmlinux_lzma_start[]; +extern char _binary_vmlinux_lzma_end[]; +extern char lzma_start[]; +extern char lzma_end[]; + +/* should be the first function */ +void entry(unsigned int arg0, unsigned int arg1, + unsigned int arg2, unsigned int arg3) +{ + unsigned int i; /* temp value */ + unsigned int isize; /* compressed size */ + unsigned int osize; /* uncompressed size */ + int argc = arg0; + char **argv = (char **)arg1; + char **envp = (char **)arg2; + + CLzmaDecoderState vs; + + data = (unsigned char *)_binary_vmlinux_lzma_start; + isize = _binary_vmlinux_lzma_end - _binary_vmlinux_lzma_start + 1; + + puts("\nLZMA kernel loader\n"); + + printf("lzma data @ %#x - %#x\n", _binary_vmlinux_lzma_start, _binary_vmlinux_lzma_end); + printf("load addr @ %#x\n\n", KERNEL_ENTRY); + printf("jump table @ %#x\n", gd->jt[3]); + + /* lzma args */ + i = get_byte(); + vs.Properties.lc = i % 9, i = i / 9; + vs.Properties.lp = i % 5, vs.Properties.pb = i / 5; + + vs.Probs = (CProb *)buffer; + + /* skip rest of the LZMA coder property */ + data += 4; + + /* read the lower half of uncompressed size in the header */ + osize = ((unsigned int)get_byte()) + + ((unsigned int)get_byte() << 8) + + ((unsigned int)get_byte() << 16) + + ((unsigned int)get_byte() << 24); + + /* skip rest of the header (upper half of uncompressed size) */ + data += 4; + + /* decompress kernel */ + puts("\nDecompressing kernel..."); + if ((i = LzmaDecode(&vs, + (unsigned char*)data, isize, &isize, + (unsigned char*)KERNEL_ENTRY, osize, &osize)) == LZMA_RESULT_OK) + { + puts("success!\n"); + + /* Jump to load address */ +// ((void (*)(int a0, int a1, int a2, int a3))KERNEL_ENTRY)(0,0,0,0); + ((void (*)(int a0, int a1, int a2, int a3))KERNEL_ENTRY)(arg0, arg1, arg2, arg3); + } + puts("failure!\n"); +} diff --git a/target/linux/adm8668/image/lzma-loader/src/include/_exports.h b/target/linux/adm8668/image/lzma-loader/src/include/_exports.h new file mode 100644 index 000000000..61dcaaf33 --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/src/include/_exports.h @@ -0,0 +1,18 @@ +EXPORT_FUNC(get_version) +EXPORT_FUNC(getc) +EXPORT_FUNC(tstc) +EXPORT_FUNC(putc) +EXPORT_FUNC(puts) +EXPORT_FUNC(printf) +EXPORT_FUNC(install_hdlr) +EXPORT_FUNC(free_hdlr) +EXPORT_FUNC(malloc) +EXPORT_FUNC(free) +EXPORT_FUNC(udelay) +EXPORT_FUNC(get_timer) +EXPORT_FUNC(vprintf) +EXPORT_FUNC(do_reset) +#if (CONFIG_COMMANDS & CFG_CMD_I2C) +EXPORT_FUNC(i2c_write) +EXPORT_FUNC(i2c_read) +#endif /* CFG_CMD_I2C */ diff --git a/target/linux/adm8668/image/lzma-loader/src/include/asm/global_data.h b/target/linux/adm8668/image/lzma-loader/src/include/asm/global_data.h new file mode 100644 index 000000000..a024194ba --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/src/include/asm/global_data.h @@ -0,0 +1,60 @@ +/* + * (C) Copyright 2002-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_GBL_DATA_H +#define __ASM_GBL_DATA_H + +#include <asm/regdef.h> + +/* + * The following data structure is placed in some memory wich is + * available very early after boot (like DPRAM on MPC8xx/MPC82xx, or + * some locked parts of the data cache) to allow for a minimum set of + * global variables during system initialization (until we have set + * up the memory controller so that we can use RAM). + * + * Keep it *SMALL* and remember to set CFG_GBL_DATA_SIZE > sizeof(gd_t) + */ + +typedef struct global_data { + bd_t *bd; + unsigned long flags; + unsigned long baudrate; + unsigned long have_console; /* serial_init() was called */ + unsigned long ram_size; /* RAM size */ + unsigned long reloc_off; /* Relocation Offset */ + unsigned long env_addr; /* Address of Environment struct */ + unsigned long env_valid; /* Checksum of Environment valid? */ + void **jt; /* jump table */ +} gd_t; + +/* + * Global Data Flags + */ +#define GD_FLG_RELOC 0x00001 /* Code was relocated to RAM */ +#define GD_FLG_DEVINIT 0x00002 /* Devices have been initialized */ +#define GD_FLG_SILENT 0x00004 /* Silent mode */ + +#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("k0") + +#endif /* __ASM_GBL_DATA_H */ diff --git a/target/linux/adm8668/image/lzma-loader/src/include/asm/u-boot.h b/target/linux/adm8668/image/lzma-loader/src/include/asm/u-boot.h new file mode 100644 index 000000000..0de0b4da8 --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/src/include/asm/u-boot.h @@ -0,0 +1,42 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _U_BOOT_H_ +#define _U_BOOT_H_ 1 + +typedef struct bd_info { + int bi_baudrate; /* serial console baudrate */ + unsigned long bi_ip_addr; /* IP Address */ + unsigned char bi_enetaddr[6]; /* Ethernet adress */ + unsigned long bi_arch_number; /* unique id for this board */ + unsigned long bi_boot_params; /* where this board expects params */ + unsigned long bi_memstart; /* start of DRAM memory */ + unsigned long bi_memsize; /* size of DRAM memory in bytes */ + unsigned long bi_flashstart; /* start of FLASH memory */ + unsigned long bi_flashsize; /* size of FLASH memory */ + unsigned long bi_flashoffset; /* reserved area for startup monitor */ +} bd_t; +#define bi_env_data bi_env->data +#define bi_env_crc bi_env->crc + +#endif /* _U_BOOT_H_ */ diff --git a/target/linux/adm8668/image/lzma-loader/src/include/common.h b/target/linux/adm8668/image/lzma-loader/src/include/common.h new file mode 100644 index 000000000..5d957af6a --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/src/include/common.h @@ -0,0 +1,48 @@ +/* + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __COMMON_H_ +#define __COMMON_H_ 1 + +#undef _LINUX_CONFIG_H +#define _LINUX_CONFIG_H 1 /* avoid reading Linux autoconf.h file */ + +typedef unsigned char uchar; +typedef volatile unsigned long vu_long; +typedef volatile unsigned short vu_short; +typedef volatile unsigned char vu_char; + +#include <inttypes.h> +#include <linux/types.h> +#include <linux/string.h> +#include <asm/ptrace.h> +#include <stdarg.h> +#include <image.h> + +typedef void (interrupt_handler_t)(void *); + +#include <asm/u-boot.h> /* boot information for Linux kernel */ +#include <asm/global_data.h> /* global data used for startup functions */ + + +#endif /* __COMMON_H_ */ diff --git a/target/linux/adm8668/image/lzma-loader/src/include/exports.h b/target/linux/adm8668/image/lzma-loader/src/include/exports.h new file mode 100644 index 000000000..4cdc36e37 --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/src/include/exports.h @@ -0,0 +1,38 @@ +#ifndef __EXPORTS_H__ +#define __EXPORTS_H__ +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#ifndef __ASSEMBLY__ + +#include <common.h> + +/* These are declarations of exported functions available in C code */ +unsigned long get_version(void); +int getc(void); +int tstc(void); +void putc(const char); +void puts(const char*); +void printf(const char* fmt, ...); +void install_hdlr(int, interrupt_handler_t*, void*); +void free_hdlr(int); +void *malloc(size_t); +void free(void*); +void udelay(unsigned long); +unsigned long get_timer(unsigned long); +void vprintf(const char *, va_list); +void do_reset (void); + +void app_startup(char **); + +#endif /* ifndef __ASSEMBLY__ */ + +enum { +#define EXPORT_FUNC(x) XF_ ## x , +#include <_exports.h> +#undef EXPORT_FUNC + + XF_MAX +}; + +#define XF_VERSION 2 + +#endif /* __EXPORTS_H__ */ diff --git a/target/linux/adm8668/image/lzma-loader/src/include/image.h b/target/linux/adm8668/image/lzma-loader/src/include/image.h new file mode 100644 index 000000000..69c73b71d --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/src/include/image.h @@ -0,0 +1,157 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __IMAGE_H__ +#define __IMAGE_H__ + +/* + * Operating System Codes + */ +#define IH_OS_INVALID 0 /* Invalid OS */ +#define IH_OS_OPENBSD 1 /* OpenBSD */ +#define IH_OS_NETBSD 2 /* NetBSD */ +#define IH_OS_FREEBSD 3 /* FreeBSD */ +#define IH_OS_4_4BSD 4 /* 4.4BSD */ +#define IH_OS_LINUX 5 /* Linux */ +#define IH_OS_SVR4 6 /* SVR4 */ +#define IH_OS_ESIX 7 /* Esix */ +#define IH_OS_SOLARIS 8 /* Solaris */ +#define IH_OS_IRIX 9 /* Irix */ +#define IH_OS_SCO 10 /* SCO */ +#define IH_OS_DELL 11 /* Dell */ +#define IH_OS_NCR 12 /* NCR */ +#define IH_OS_LYNXOS 13 /* LynxOS */ +#define IH_OS_VXWORKS 14 /* VxWorks */ +#define IH_OS_PSOS 15 /* pSOS */ +#define IH_OS_QNX 16 /* QNX */ +#define IH_OS_U_BOOT 17 /* Firmware */ +#define IH_OS_RTEMS 18 /* RTEMS */ +#define IH_OS_ARTOS 19 /* ARTOS */ +#define IH_OS_UNITY 20 /* Unity OS */ + +/* + * CPU Architecture Codes (supported by Linux) + */ +#define IH_CPU_INVALID 0 /* Invalid CPU */ +#define IH_CPU_ALPHA 1 /* Alpha */ +#define IH_CPU_ARM 2 /* ARM */ +#define IH_CPU_I386 3 /* Intel x86 */ +#define IH_CPU_IA64 4 /* IA64 */ +#define IH_CPU_MIPS 5 /* MIPS */ +#define IH_CPU_MIPS64 6 /* MIPS 64 Bit */ +#define IH_CPU_PPC 7 /* PowerPC */ +#define IH_CPU_S390 8 /* IBM S390 */ +#define IH_CPU_SH 9 /* SuperH */ +#define IH_CPU_SPARC 10 /* Sparc */ +#define IH_CPU_SPARC64 11 /* Sparc 64 Bit */ +#define IH_CPU_M68K 12 /* M68K */ +#define IH_CPU_NIOS 13 /* Nios-32 */ +#define IH_CPU_MICROBLAZE 14 /* MicroBlaze */ +#define IH_CPU_NIOS2 15 /* Nios-II */ + +/* + * Image Types + * + * "Standalone Programs" are directly runnable in the environment + * provided by U-Boot; it is expected that (if they behave + * well) you can continue to work in U-Boot after return from + * the Standalone Program. + * "OS Kernel Images" are usually images of some Embedded OS which + * will take over control completely. Usually these programs + * will install their own set of exception handlers, device + * drivers, set up the MMU, etc. - this means, that you cannot + * expect to re-enter U-Boot except by resetting the CPU. + * "RAMDisk Images" are more or less just data blocks, and their + * parameters (address, size) are passed to an OS kernel that is + * being started. + * "Multi-File Images" contain several images, typically an OS + * (Linux) kernel image and one or more data images like + * RAMDisks. This construct is useful for instance when you want + * to boot over the network using BOOTP etc., where the boot + * server provides just a single image file, but you want to get + * for instance an OS kernel and a RAMDisk image. + * + * "Multi-File Images" start with a list of image sizes, each + * image size (in bytes) specified by an "uint32_t" in network + * byte order. This list is terminated by an "(uint32_t)0". + * Immediately after the terminating 0 follow the images, one by + * one, all aligned on "uint32_t" boundaries (size rounded up to + * a multiple of 4 bytes - except for the last file). + * + * "Firmware Images" are binary images containing firmware (like + * U-Boot or FPGA images) which usually will be programmed to + * flash memory. + * + * "Script files" are command sequences that will be executed by + * U-Boot's command interpreter; this feature is especially + * useful when you configure U-Boot to use a real shell (hush) + * as command interpreter (=> Shell Scripts). + */ + +#define IH_TYPE_INVALID 0 /* Invalid Image */ +#define IH_TYPE_STANDALONE 1 /* Standalone Program */ +#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ +#define IH_TYPE_RAMDISK 3 /* RAMDisk Image */ +#define IH_TYPE_MULTI 4 /* Multi-File Image */ +#define IH_TYPE_FIRMWARE 5 /* Firmware Image */ +#define IH_TYPE_SCRIPT 6 /* Script file */ +#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */ + +/* + * Compression Types + */ +#define IH_COMP_NONE 0 /* No Compression Used */ +#define IH_COMP_GZIP 1 /* gzip Compression Used */ +#define IH_COMP_BZIP2 2 /* bzip2 Compression Used */ + +#define IH_MAGIC 0x27051956 /* Image Magic Number */ +#define IH_NMLEN 32 /* Image Name Length */ + +#define IH_NAMEMAGIC 0x86680001 /* Name Magic Number */ +#define IH_SIZEMAX 5800000 /* Max image size */ +/* + * all data in network byte order (aka natural aka bigendian) + */ + +typedef struct image_header { + uint32_t ih_magic; /* Image Header Magic Number */ + uint32_t ih_hcrc; /* Image Header CRC Checksum */ + uint32_t ih_time; /* Image Creation Timestamp */ + uint32_t ih_size; /* Image Data Size */ + uint32_t ih_load; /* Data Load Address */ + uint32_t ih_ep; /* Entry Point Address */ + uint32_t ih_dcrc; /* Image Data CRC Checksum */ + uint8_t ih_os; /* Operating System */ + uint8_t ih_arch; /* CPU architecture */ + uint8_t ih_type; /* Image Type */ + uint8_t ih_comp; /* Compression Type */ +#ifdef NEW_IMAGE_HEADER + uint32_t ih_namemagic; /* image name CRC */ + uint8_t ih_name[IH_NMLEN-4]; /* image name */ +#else + uint8_t ih_name[IH_NMLEN]; /* Image Name */ +#endif +} image_header_t; + + +#endif /* __IMAGE_H__ */ diff --git a/target/linux/adm8668/image/lzma-loader/src/lzma.lds.in b/target/linux/adm8668/image/lzma-loader/src/lzma.lds.in new file mode 100644 index 000000000..d6c60ca0d --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/src/lzma.lds.in @@ -0,0 +1,24 @@ +OUTPUT_ARCH(mips) +ENTRY(entry) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = @LOADADDR@; + .text : + { + _ftext = . ; + *(.text.entry) + *(.text) + lzma_start = .; + kernel.o + lzma_end = .; + *(.rodata) + } =0 + + .reginfo : { *(.reginfo) } + + .bss : + { + *(.bss) + } +} diff --git a/target/linux/adm8668/image/lzma-loader/src/stubs.c b/target/linux/adm8668/image/lzma-loader/src/stubs.c new file mode 100644 index 000000000..468e5a1fd --- /dev/null +++ b/target/linux/adm8668/image/lzma-loader/src/stubs.c @@ -0,0 +1,52 @@ +#include <exports.h> + +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +#endif /* GCC_VERSION */ + +/* + * k0 ($26) holds the pointer to the global_data; t9 ($25) is a call- + * clobbered register that is also used to set gp ($26). Note that the + * jr instruction also executes the instruction immediately following + * it; however, GCC/mips generates an additional `nop' after each asm + * statement + */ +#define EXPORT_FUNC(x) \ + asm volatile ( \ +" .globl " #x "\n" \ +#x ":\n" \ +" lw $25, %0($26)\n" \ +" lw $25, %1($25)\n" \ +" jr $25\n" \ + : : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "t9"); + +/* This function is necessary to prevent the compiler from + * generating prologue/epilogue, preparing stack frame etc. + * The stub functions are special, they do not use the stack + * frame passed to them, but pass it intact to the actual + * implementation. On the other hand, asm() statements with + * arguments can be used only inside the functions (gcc limitation) + */ +#if GCC_VERSION < 3004 +static +#endif /* GCC_VERSION */ +void __attribute__((unused)) dummy(void) +{ +#include <_exports.h> +} + +#if 0 +extern unsigned long __bss_start, _end; + +void app_startup(char **argv) +{ + unsigned long * cp = &__bss_start; + + /* Zero out BSS */ + while (cp < &_end) { + *cp++ = 0; + } +} +#endif + +#undef EXPORT_FUNC diff --git a/target/linux/adm8668/image/my-mkimage b/target/linux/adm8668/image/my-mkimage new file mode 100755 index 000000000..7ed6666e7 --- /dev/null +++ b/target/linux/adm8668/image/my-mkimage @@ -0,0 +1,32 @@ +#!/bin/sh +# my-mkimage +# This will pad given files to 64k boundaries to make a single u-boot image. +# we have to be fancy because u-boot mkimage is going to add 64 byte header, ... +# and i only know basic arithmetic.. ;) +# +# Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> +[ $# -lt 2 ] && { + echo usage: $0 loader.bin [rootfs.squashfs [fs_mark [...]]] output.bin +} + +OLDSIZE=$(stat -c%s $1) +NEWSIZE=$(((OLDSIZE / 65536 + 1) * 65536 - 64)) + +dd if=$1 of=vmlinuz.tmp bs=$NEWSIZE conv=sync >/dev/null 2>&1 +shift +appends=$(($# - 1)) +echo +while [ $appends -gt 0 ]; do + dd if=$1 of=temp bs=64k conv=sync >/dev/null 2>&1 + printf "### '%s' starts at 0x%x\n" "`basename $1`" "$((NEWSIZE+64))" + cat temp >>vmlinuz.tmp + shift + appends=$((appends-1)) + NEWSIZE=$(stat -c%s vmlinuz.tmp) +done +echo +../../../../staging_dir/host/bin/mkimage -A mips -O linux -T kernel \ +-C none -a 0x80400000 -e 0x80400000 -n "ADM8668 Linux Kernel(2.4.31)" \ +-d vmlinuz.tmp $1 + +rm temp vmlinuz.tmp diff --git a/target/linux/adm8668/patches-3.3/001-adm8668_arch.patch b/target/linux/adm8668/patches-3.3/001-adm8668_arch.patch new file mode 100644 index 000000000..c00188cf0 --- /dev/null +++ b/target/linux/adm8668/patches-3.3/001-adm8668_arch.patch @@ -0,0 +1,39 @@ +--- a/arch/mips/Kbuild.platforms ++++ b/arch/mips/Kbuild.platforms +@@ -30,6 +30,7 @@ platforms += sni + platforms += txx9 + platforms += vr41xx + platforms += wrppmc ++platforms += adm8668 + + # include the platform specific files + include $(patsubst %, $(srctree)/arch/mips/%/Platform, $(platforms)) +--- a/arch/mips/Kconfig ++++ b/arch/mips/Kconfig +@@ -105,6 +105,26 @@ config BCM47XX + help + Support for BCM47XX based boards + ++config ADM8668 ++ bool "WildPass ADM8668" ++ select SYS_HAS_CPU_MIPS32_R1 ++ select BOOT_RAW ++ select NO_EXCEPT_FILL ++ select IRQ_CPU ++ select CEVT_R4K ++ select CSRC_R4K ++ select HW_HAS_PCI ++ select PCI ++ select SYS_SUPPORTS_LITTLE_ENDIAN ++ select SYS_SUPPORTS_32BIT_KERNEL ++ select DMA_NONCOHERENT ++ select SWAP_IO_SPACE ++ select SERIAL_ADM8668 ++ select SERIAL_ADM8668_CONSOLE ++ help ++ ADM8668 board support by neutronscott ++ Scott Nicholas <neutronscott@scottn.us> ++ + config BCM63XX + bool "Broadcom BCM63XX based boards" + select CEVT_R4K diff --git a/target/linux/adm8668/patches-3.3/002-adm8668_uart.patch b/target/linux/adm8668/patches-3.3/002-adm8668_uart.patch new file mode 100644 index 000000000..ed55cbbaa --- /dev/null +++ b/target/linux/adm8668/patches-3.3/002-adm8668_uart.patch @@ -0,0 +1,40 @@ +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -1192,6 +1192,25 @@ config SERIAL_BCM63XX_CONSOLE + If you have enabled the serial port on the bcm63xx CPU + you can make it the console by answering Y to this option. + ++config SERIAL_ADM8668 ++ tristate "ADM8668 serial port support" ++ select SERIAL_CORE ++ depends on ADM8668 ++ help ++ If you have an adm8668 CPU, you can enable its onboard ++ serial port by enabling this options. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called adm8668_uart. ++ ++config SERIAL_ADM8668_CONSOLE ++ bool "Console on adm8668 serial port" ++ depends on SERIAL_ADM8668=y ++ select SERIAL_CORE_CONSOLE ++ help ++ If you have enabled the serial port on the adm8668 CPU ++ you can make it the console by answering Y to this option. ++ + config SERIAL_GRLIB_GAISLER_APBUART + tristate "GRLIB APBUART serial support" + depends on OF && SPARC +--- a/include/linux/serial_core.h ++++ b/include/linux/serial_core.h +@@ -211,6 +211,9 @@ + #define PORT_AR933X 99 + + ++/* ADM8668 UART */ ++#define PORT_ADM8668 100 ++ + #ifdef __KERNEL__ + + #include <linux/compiler.h> diff --git a/target/linux/adm8668/patches-3.3/003-adm8668_nor_map.patch b/target/linux/adm8668/patches-3.3/003-adm8668_nor_map.patch new file mode 100644 index 000000000..eca9bc468 --- /dev/null +++ b/target/linux/adm8668/patches-3.3/003-adm8668_nor_map.patch @@ -0,0 +1,25 @@ +--- a/drivers/mtd/maps/Kconfig ++++ b/drivers/mtd/maps/Kconfig +@@ -96,6 +96,12 @@ config MSP_FLASH_MAP_LIMIT + default "0x02000000" + depends on MSP_FLASH_MAP_LIMIT_32M + ++config MTD_ADM8668_NOR ++ tristate "ADM8668 NOR mapping" ++ depends on ADM8668 && MTD_CFI ++ help ++ mapping driver for ADM8668 NOR ++ + config MTD_SUN_UFLASH + tristate "Sun Microsystems userflash support" + depends on SPARC && MTD_CFI && PCI +--- a/drivers/mtd/maps/Makefile ++++ b/drivers/mtd/maps/Makefile +@@ -7,6 +7,7 @@ obj-$(CONFIG_MTD) += map_funcs.o + endif + + # Chip mappings ++obj-$(CONFIG_MTD_ADM8668_NOR) += adm8668.o + obj-$(CONFIG_MTD_CDB89712) += cdb89712.o + obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o + obj-$(CONFIG_MTD_DC21285) += dc21285.o |