1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2024-11-27 17:11:53 +02:00

Merge branch 'adm8668'

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@23900 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
florian 2010-11-06 18:54:20 +00:00
parent bedf12ad6b
commit d633f6be97
46 changed files with 5162 additions and 0 deletions

View File

@ -0,0 +1,25 @@
#
# 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
LINUX_VERSION:=2.6.36
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))

View File

@ -0,0 +1,3 @@
#define Package/base-files/install-target
# rm -f $(1)/etc/config/network
#endef

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -0,0 +1,9 @@
#!/bin/sh
set_preinit_ifname() {
ifname=eth0
}
boot_hook_add preinit_main set_preinit_ifname

View File

@ -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
}

View File

@ -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()

View File

@ -0,0 +1,4 @@
#!/bin/sh
case "$1" in
button) kill -USR1 1;;
esac

View File

@ -0,0 +1,36 @@
CONFIG_ADM8668=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_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HW_HAS_PCI=y
CONFIG_IRQ_CPU=y
CONFIG_MIPS=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
CONFIG_MIPS_MT_DISABLED=y
CONFIG_MTD_ADM8668_NOR=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
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_ZONE_DMA_FLAG=0

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,134 @@
/*
* 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>
void enable_adm8668_irq(unsigned int irq);
void disable_adm8668_irq(unsigned int irq);
void adm8668_irq_cascade(void);
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();
}
/*
* System irq dispatch
*/
void adm8668_irq_cascade()
{
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);
}
/*
* irq enable
*/
static __inline void _irq_enable(int irql)
{
ADM8668_INTC_REG(IRQ_ENABLE_REG) = (1 << irql);
}
/*
* irq disable
*/
static __inline void _irq_disable(int irql)
{
ADM8668_INTC_REG(IRQ_DISABLE_REG) = (1 << irql);
}
/*
* enable 8668 irq
*/
void enable_adm8668_irq(unsigned int irq)
{
if ((irq < 0) || (irq > NR_IRQS))
return;
_irq_enable(irq);
}
/*
* disable 8668 irq
*/
void disable_adm8668_irq(unsigned int irq)
{
if ((irq < 0) || (irq > NR_IRQS))
return;
_irq_disable(irq);
}
static inline void ack_adm8668_irq(unsigned int irq_nr)
{
ADM8668_INTC_REG(IRQ_DISABLE_REG) = (1 << irq_nr);
}
/*
* system irq type
*/
static struct irq_chip adm8668_irq_type = {
.name = "adm8668",
.ack = ack_adm8668_irq,
.mask = disable_adm8668_irq,
.unmask = enable_adm8668_irq
};
/*
* irq init
*/
void __init init_adm8668_irqs(void)
{
int i;
for (i = 0; i <= INT_LVL_MAX; i++)
set_irq_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();
}

View File

@ -0,0 +1,276 @@
/*
* 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/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 <asm/unaligned.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.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__ */

View File

@ -0,0 +1,617 @@
/*
* 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, IRQF_SHARED, 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_multicast_list = 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->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);

View File

@ -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;
}

View File

@ -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);

View File

@ -0,0 +1,154 @@
/*
* 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>
extern char _end;
#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
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) = BIT_1|BIT_13;
ADM8668_LAN_REG(NETCSR7) = 0;
ADM8668_WAN_REG(NETCSR6) = BIT_1|BIT_13;
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) = BIT_0;
}
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);

View File

@ -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 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");

View File

@ -0,0 +1,138 @@
/*
* 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 do this ... */
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(" Board ID: %#lx\n", bd->bi_arch_number);
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);
}

View File

@ -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");

View File

@ -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_ */

View File

@ -0,0 +1,416 @@
/************************************************************************
*
* Copyright (c) 2005
* Infineon Technologies AG
* St. Martin Strasse 53; 81669 Muenchen; Germany
*
************************************************************************/
#ifndef __ADM8668_H__
#define __ADM8668_H__
#include <asm/addrspace.h>
#include "bsp_sup.h"
#define MEM_KSEG0_BASE 0x80000000
#define MEM_KSEG1_BASE 0xA0000000
#define MEM_SEG_MASK 0xE0000000
#define KVA2PA(_addr) ((unsigned long)(_addr) & ~MEM_SEG_MASK)
#define MIPS_KSEG0A(_addr) (KVA2PA(_addr) | MEM_KSEG0_BASE)
#define MIPS_KSEG1A(_addr) (KVA2PA(_addr) | MEM_KSEG1_BASE)
#define PA2VA(_addr) (KVA2PA(_addr) | MEM_KSEG1_BASE)
#define PA2CACHEVA(_addr) (KVA2PA(_addr) | MEM_KSEG0_BASE)
/*======================= 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
/* for PCI bridge fixup ! */
#define PCI_BRIDGE_MASK 0x40
/* WLAN registers */
#define WCSR0 0x00
#define WCSR11A 0x5c
#define GPIO_REG WCSR11A
#define ADM8668_WLAN_REG(_reg) \
(*((volatile unsigned int *)(PA2VA(ADM8668_WLAN_BASE + (_reg)))))
/* configuration registers */
#define ADM8668_CR0 0x00
#define ADM8668_CR1 0x04
#define ADM8668_CR2 0x08
#define ADM8668_CR3 0x0C
#define ADM8668_CR8 0x20
#define ADM8668_CR10 0x28
#define ADM8668_CR11 0x2C
#define ADM8668_CR12 0x30
#define ADM8668_CR13 0x34
#define ADM8668_CR14 0x38
#define ADM8668_CR15 0x3C
#define ADM8668_CR16 0x40
#define ADM8668_CR17 0x44
#define ADM8668_CR18 0x48
#define ADM8668_CR19 0x4C
#define ADM8668_CR20 0x50
#define ADM8668_CR21 0x54
#define ADM8668_CR22 0x58
#define ADM8668_CR23 0x5C
#define ADM8668_CR24 0x60
#define ADM8668_CR25 0x64
#define ADM8668_CR26 0x68
#define ADM8668_CR27 0x6C
#define ADM8668_CR28 0x70
#define ADM8668_CR29 0x74
#define ADM8668_CR30 0x78
#define ADM8668_CR31 0x7C
#define ADM8668_CR32 0x80
#define ADM8668_CR33 0x84
#define ADM8668_CR34 0x88
#define ADM8668_CR35 0x8C
#define ADM8668_CR36 0x90
#define ADM8668_CR37 0x94
#define ADM8668_CR38 0x98
#define ADM8668_CR39 0x9C
#define ADM8668_CR40 0xA0
#define ADM8668_CR41 0xA4
#define ADM8668_CR42 0xA8
#define ADM8668_CR43 0xAC
#define ADM8668_CR44 0xB0
#define ADM8668_CR45 0xB4
#define ADM8668_CR46 0xB8
#define ADM8668_CR47 0xBC
#define ADM8668_CR48 0xC0
#define ADM8668_CR49 0xC4
#define ADM8668_CR50 0xC8
#define ADM8668_CR51 0xCC
#define ADM8668_CR52 0xD0
#define ADM8668_CR53 0xD4
#define ADM8668_CR54 0xD8
#define ADM8668_CR55 0xDC
#define ADM8668_CR56 0xE0
#define ADM8668_CR57 0xE4
#define ADM8668_CR58 0xE8
#define ADM8668_CR59 0xEC
#define ADM8668_CR60 0xF0
#define ADM8668_CR61 0xF4
#define ADM8668_CR62 0xF8
#define ADM8668_CR63 0xFC
#define ADM8668_CR64 0x100
#define ADM8668_CR65 0x104
#define ADM8668_CR66 0x108
#define ADM8668_CR67 0x10C
#define ADM8668_CR68 0x110
#define CRGPIO_REG ADM8668_CR8
#define ADM8668_CONFIG_REG(_reg) \
(*((volatile unsigned int *)(PA2VA(ADM8668_CONFIG_BASE + (_reg)))))
#define ADM8668_MPMC_REG(_reg) \
(*((volatile unsigned int *)(PA2VA(ADM8668_MPMC_BASE + (_reg)))))
/*========================== Interrupt Controller ==========================*/
/* registers offset */
#define IRQ_STATUS_REG 0x00 /* Read */
#define IRQ_RAW_STATUS_REG 0x04 /* Read */
#define IRQ_ENABLE_REG 0x08 /* Read/Write */
#define IRQ_DISABLE_REG 0x0C /* Write */
#define IRQ_SOFT_REG 0x10 /* Write */
#define FIQ_STATUS_REG 0x100 /* Read */
#define FIQ_RAW_STATUS_REG 0x104
#define FIQ_ENABLE_REG 0x108
#define FIQ_DISABLE_REG 0x10c
/* Macro for accessing Interrupt controller register */
#define ADM8668_INTC_REG(_reg) \
(*((volatile unsigned long *)(PA2VA(ADM8668_INTC_BASE + (_reg)))))
/* 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
#define IRQ_MASK 0xffff
#define IRQ_SWI (0x1<<INT_LVL_SWI)
#define IRQ_TIMERINT0 (0x1<<INT_LVL_TIMERINT0)
#define IRQ_TIMERINT1 (0x1<<INT_LVL_TIMERINT1)
#define IRQ_UART0 (0x1<<INT_LVL_UART0)
#define IRQ_LAN (0x1<<INT_LVL_LAN)
#define IRQ_WAN (0x1<<INT_LVL_WAN)
#define IRQ_WLAN (0x1<<INT_LVL_WLAN)
#define IRQ_GPIO (0x1<<INT_LVL_GPIO)
#define IRQ_IDEINT (0x1<<INT_LVL_IDE)
#define IRQ_PCI2 (0x1<<INT_LVL_PCI2)
#define IRQ_PCI1 (0x1<<INT_LVL_PCI1)
#define IRQ_PCI0 (0x1<<INT_LVL_PCI0)
#define IRQ_USB (0x1<<INT_LVL_USB)
/*=========================== UART Control Register ========================*/
#define UART_DR_REG 0x00
#define UART_RSR_REG 0x04
#define UART_ECR_REG 0x04
#define UART_LCR_H_REG 0x08
#define UART_LCR_M_REG 0x0c
#define UART_LCR_L_REG 0x10
#define UART_CR_REG 0x14
#define UART_FR_REG 0x18
#define UART_IIR_REG 0x1c
#define UART_ICR_REG 0x1C
#define UART_ILPR_REG 0x20
/* rsr/ecr reg */
#define UART_OVERRUN_ERR 0x08
#define UART_BREAK_ERR 0x04
#define UART_PARITY_ERR 0x02
#define UART_FRAMING_ERR 0x01
#define UART_RX_STATUS_MASK 0x0f
#define UART_RX_ERROR ( UART_BREAK_ERR \
| UART_PARITY_ERR \
| UART_FRAMING_ERR)
/* lcr_h reg */
#define UART_SEND_BREAK 0x01
#define UART_PARITY_EN 0x02
#define UART_EVEN_PARITY 0x04
#define UART_TWO_STOP_BITS 0x08
#define UART_ENABLE_FIFO 0x10
#define UART_WLEN_5BITS 0x00
#define UART_WLEN_6BITS 0x20
#define UART_WLEN_7BITS 0x40
#define UART_WLEN_8BITS 0x60
#define UART_WLEN_MASK 0x60
/* cr reg */
#define UART_PORT_EN 0x01
#define UART_SIREN 0x02
#define UART_SIRLP 0x04
#define UART_MODEM_STATUS_INT_EN 0x08
#define UART_RX_INT_EN 0x10
#define UART_TX_INT_EN 0x20
#define UART_RX_TIMEOUT_INT_EN 0x40
#define UART_LOOPBACK_EN 0x80
/* fr reg */
#define UART_CTS 0x01
#define UART_DSR 0x02
#define UART_DCD 0x04
#define UART_BUSY 0x08
#define UART_RX_FIFO_EMPTY 0x10
#define UART_TX_FIFO_FULL 0x20
#define UART_RX_FIFO_FULL 0x40
#define UART_TX_FIFO_EMPTY 0x80
/* iir/icr reg */
#define UART_MODEM_STATUS_INT 0x01
#define UART_RX_INT 0x02
#define UART_TX_INT 0x04
#define UART_RX_TIMEOUT_INT 0x08
#define UART_INT_MASK 0x0f
#ifdef _FPGA_
#define ADM8668_UARTCLK_FREQ 3686400
#else
#define ADM8668_UARTCLK_FREQ 62500000
#endif
#define UART_BAUDDIV(_rate) \
((unsigned long)(ADM8668_UARTCLK_FREQ/(16*(_rate)) - 1))
/* uart_baudrate */
#define UART_230400bps_DIVISOR UART_BAUDDIV(230400)
#define UART_115200bps_DIVISOR UART_BAUDDIV(115200)
#define UART_76800bps_DIVISOR UART_BAUDDIV(76800)
#define UART_57600bps_DIVISOR UART_BAUDDIV(57600)
#define UART_38400bps_DIVISOR UART_BAUDDIV(38400)
#define UART_19200bps_DIVISOR UART_BAUDDIV(19200)
#define UART_14400bps_DIVISOR UART_BAUDDIV(14400)
#define UART_9600bps_DIVISOR UART_BAUDDIV(9600)
#define UART_2400bps_DIVISOR UART_BAUDDIV(2400)
#define UART_1200bps_DIVISOR UART_BAUDDIV(1200)
/*=========================== Counter Timer ==============================*/
#define TIMER0_REG_BASE ADM8668_TMR_BASE
#define TIMER1_REG_BASE ADM8668_TMR_BASE+0x20
#define TIMER_LOAD_REG 0x00
#define TIMER_VALUE_REG 0x04
#define TIMER_CTRL_REG 0x08
#define TIMER_CLR_REG 0x0c
/* TIMER_LOAD_REG */
#ifdef _FPGA_
#define SYS_CLOCK 56000000
#else
#define SYS_CLOCK 175000000
#endif
#define SYS_PRESCALE 256
#define TMR_10MS_TICKS (SYS_CLOCK/SYS_PRESCALE/100)
/* TIMER_CTRL_REG */
#define TMR_PRESCALE_1 0x00
#define TMR_PRESCALE_16 0x04
#define TMR_PRESCALE_256 0x08
#define TMR_MODE_PERIODIC 0x40
#define TMR_ENABLE 0x80
/* TIMER_CLR_REG */
#define TMR_CLEAR_BIT 1
/* Macro for access MPMC register */
#define ADM8668_TMR_REG(base, _offset) \
(*((volatile unsigned long *)(PA2VA(base + (_offset)))))
/* For GPIO control */
#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))
/*==========================================================================*/
/* Cache Controller */
#define ADM8668_CACHE_LINE_SIZE 16
#define BIT_0 0x00000001
#define BIT_1 0x00000002
#define BIT_2 0x00000004
#define BIT_3 0x00000008
#define BIT_4 0x00000010
#define BIT_5 0x00000020
#define BIT_6 0x00000040
#define BIT_7 0x00000080
#define BIT_8 0x00000100
#define BIT_9 0x00000200
#define BIT_10 0x00000400
#define BIT_11 0x00000800
#define BIT_12 0x00001000
#define BIT_13 0x00002000
#define BIT_14 0x00004000
#define BIT_15 0x00008000
#define BIT_16 0x00010000
#define BIT_17 0x00020000
#define BIT_18 0x00040000
#define BIT_19 0x00080000
#define BIT_20 0x00100000
#define BIT_21 0x00200000
#define BIT_22 0x00400000
#define BIT_23 0x00800000
#define BIT_24 0x01000000
#define BIT_25 0x02000000
#define BIT_26 0x04000000
#define BIT_27 0x08000000
#define BIT_28 0x10000000
#define BIT_29 0x20000000
#define BIT_30 0x40000000
#define BIT_31 0x80000000
/* network regs */
#define NETCSR0 0x0
#define NETCSR1 0x08
#define NETCSR2 0x10
#define NETCSR3 0x18
#define NETCSR4 0x20
#define NETCSR5 0x28
#define NETCSR6 0x30
#define NETCSR7 0x38
#define NETCSR8 0x40
#define NETCSR9 0x48
#define NETCSR10 0x50
#define NETCSR11 0x58
#define NETCSR12 0x60
#define NETCSR13 0x68
#define NETCSR14 0x70
#define NETCSR15 0x78
#define NETCSR36 0xD0
#define NETCSR36A 0xD4
#define NETCSR36B 0xD8
#define NETCSR36C 0xDC // dummy
#define NETCSR36D 0xE0
#define NETCSR36E 0xE4
#define NETCSR36F 0xE8
#define NETCSR36G 0xEC
#define NETCSR36H 0xF0
#define NETCSR36I 0xF4
#define NETCSR37 0xF8
/* for descriptor skip DWs */
#define NETDESCSKIP_1DW BIT_2
#define NETDESCSKIP_2DW BIT_3
#define NETDESCSKIP_3DW (BIT_3|BIT_2)
#define NETDESCSKIP_4DW BIT_4
#define ADM8668_LAN_REG(_reg) \
(*((volatile unsigned int *)(PA2VA(ADM8668_LAN_BASE + (_reg)))))
#define ADM8668_WAN_REG(_reg) \
(*((volatile unsigned int *)(PA2VA(ADM8668_WAN_BASE + (_reg)))))
#endif /* __ADM8668_H__ */

View File

@ -0,0 +1,84 @@
/************************************************************************
*
* Copyright (c) 2005
* Infineon Technologies AG
* St. Martin Strasse 53; 81669 Muenchen; Germany
*
************************************************************************/
#ifndef _BSP_SUP_H_
#define _BSP_SUP_H_
#define ADD_WAN_MAC
#define CONFIG_IFX_GAN
#define UBOOT_CFG_ENV_SIZE (0x400-4)
#define ADM8668_BL_MAGIC 0x6c62676d
#define ADM8668_MAC_MAGIC 0x69666164
#define ADM8668_VER_MAGIC 0x7276676d
#define ADM8668_ID_MAGIC 0x6469676d
#define ADM8668_IF_MAGIC 0x6669676d
#define ADM8668_WANMAC_MAGIC 0x69666164
#define ADM8668_IMEI_MAGIC 0x6669676e
#define BSP_IFNAME_MAX_LEN 15
#define BOOT_LINE_SIZE 255
#define BSP_STR_LEN 79
/*
* Boot mode configuration
*/
typedef struct BTMODE_CFG_S
{
unsigned long btmode;
unsigned long dlmethod;
} BTMODE_CFG_T;
/*
* Interface configuration
*/
typedef struct IF_CFG_S
{
char ifname[BSP_IFNAME_MAX_LEN+1];
unsigned long ip;
unsigned long mask;
unsigned long gateway;
} IF_CFG_T;
/*
* Board configuration
*/
typedef struct BOARD_CFG_S
{
unsigned long blmagic;
unsigned char blreserved[UBOOT_CFG_ENV_SIZE];
unsigned long macmagic;
unsigned char mac[8];
unsigned long macnum;
unsigned long idmagic;
unsigned char serial[BSP_STR_LEN+1];
unsigned long vermagic;
unsigned char ver[BSP_STR_LEN+1];
unsigned long ifmagic;
IF_CFG_T ifcfg[8];
unsigned long btmagic;
BTMODE_CFG_T bootmode;
unsigned long wanmagic;
unsigned char wanmac[8];
unsigned long imeimagic;
unsigned char imei0[16];
unsigned char imei1[16];
} BOARD_CFG_T, *PBOARD_CFG_T;
#define ADM8668_BOARD_CFG_ADDR (ADM8668_SMEM0_BASE + CONFIG_ADM8668_BSP_OFFSET*1024)
#define ADM8668_BOARD_CFG_SIZE (CONFIG_ADM8668_BSP_SIZE*1024)
#endif /* _BSP_SUP_H_ */

View File

@ -0,0 +1,35 @@
/*
* 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
#ifndef NR_IRQS
#define NR_IRQS 32
#endif
#ifdef CONFIG_IRQ_CPU
#ifndef MIPS_CPU_IRQ_BASE
#define MIPS_CPU_IRQ_BASE 16
#endif
#ifdef CONFIG_IRQ_CPU_RM7K
#ifndef RM7K_CPU_IRQ_BASE
#define RM7K_CPU_IRQ_BASE (MIPS_CPU_IRQ_BASE+8)
#endif
#endif
#ifdef CONFIG_IRQ_CPU_RM9K
#ifndef RM9K_CPU_IRQ_BASE
#define RM9K_CPU_IRQ_BASE (MIPS_CPU_IRQ_BASE+12)
#endif
#endif
#endif /* CONFIG_IRQ_CPU */
#endif /* __ASM_MACH_ADM8668_IRQ_H */

View File

@ -0,0 +1,55 @@
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
*
* ########################################################################
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* ########################################################################
*
* MIPS boards bootprom interface for the Linux kernel.
*
*/
/************************************************************************
*
* Copyright (c) 2005
* Infineon Technologies AG
* St. Martin Strasse 53; 81669 Muenchen; Germany
*
************************************************************************/
#ifndef _MIPS_PROM_H
#define _MIPS_PROM_H
extern char *prom_getcmdline(void);
extern char *prom_getenv(char *name);
extern void setup_prom_printf(int tty_no);
extern void prom_printf(char *fmt, ...);
extern void prom_init_cmdline(void);
extern void prom_meminit(void);
extern void prom_fixup_mem_map(unsigned long start_mem, unsigned long end_mem);
extern void prom_free_prom_memory (void);
extern void mips_display_message(const char *str);
extern void mips_display_word(unsigned int num);
extern int get_ethernet_addr(char *ethernet_addr);
/* Memory descriptor management. */
#define PROM_MAX_PMEMBLOCKS 32
struct prom_pmemblock {
unsigned long base; /* Within KSEG0. */
unsigned int size; /* In bytes. */
unsigned int type; /* free or prom memory */
};
#endif /* !(_MIPS_PROM_H) */

View File

@ -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 */

View File

@ -0,0 +1,126 @@
/*
* Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/magic.h>
#include <asm/io.h>
#define FLASH_SIZE 0x800000
#define FLASH_PHYS_ADDR 0x10000000
/* 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;
};
static struct mtd_info *mymtd;
static struct map_info nor_map = {
name: "adm8668-nor",
size: FLASH_SIZE,
phys: FLASH_PHYS_ADDR,
bankwidth: 2,
};
static struct mtd_partition nor_parts[] = {
{ name: "linux", offset: 0x40000, size: FLASH_SIZE - 0x40000, },
{ name: "rootfs", offset: 0x200000, size: 0x400000, },
{ name: NULL, },
};
int __init init_mtd_partitions(struct mtd_info *mtd, size_t size)
{
int blocksize, off;
size_t len;
struct squashfs_super_block hdr;
blocksize = mtd->erasesize;
if (blocksize < 0x10000)
blocksize = 0x10000;
memset(&hdr, 0xe5, sizeof(hdr));
/* find and size squashfs */
for (off = (128*1024); off < size; off += blocksize) {
if (mtd->read(mtd, off, sizeof(hdr), &len, (char *)&hdr) ||
len != sizeof(hdr))
continue;
if (hdr.s_magic == SQUASHFS_MAGIC) {
printk(KERN_INFO "%s: Filesystem type: squashfs, off=%#x size=%#x\n",
mtd->name, off, (unsigned int)hdr.bytes_used);
/* Update the squashfs start address only! */
nor_parts[1].offset = off;
nor_parts[1].size = FLASH_SIZE - off;
return 2;
}
}
return 2;
}
int __init init_nor(void)
{
int nr_parts;
printk(KERN_NOTICE "ADM8668 NOR flash device: %#x at %#x\n",
FLASH_SIZE, FLASH_PHYS_ADDR);
nor_map.virt = ioremap(FLASH_PHYS_ADDR, FLASH_SIZE);
if (!nor_map.virt) {
printk("Failed to ioremap\n");
return -EIO;
}
simple_map_init(&nor_map);
mymtd = do_map_probe("cfi_probe", &nor_map);
if (!mymtd) {
iounmap((void *)nor_map.virt);
return -ENXIO;
}
mymtd->owner = THIS_MODULE;
nr_parts = init_mtd_partitions(mymtd, mymtd->size);
add_mtd_partitions(mymtd, nor_parts, nr_parts);
return 0;
}
static void __exit cleanup_nor(void)
{
if (mymtd) {
del_mtd_partitions(mymtd);
map_destroy(mymtd);
}
if (nor_map.virt) {
iounmap((void *)nor_map.virt);
nor_map.virt = 0;
}
}
module_init(init_nor);
module_exit(cleanup_nor);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Scott Nicholas <neutronscott@scottn.us>");
MODULE_DESCRIPTION("MTD map driver for ADM8668 NOR Flash");

View File

@ -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
include $(INCLUDE_DIR)/image.mk
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
endef
define Image/Build
./my-mkimage $(KDIR)/loader.bin $(KDIR)/root.squashfs \
$(BIN_DIR)/$(IMG_PREFIX)-$(1).bin
endef
$(eval $(call BuildImage))

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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 # 1MB
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

View File

@ -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");
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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)
}
}

View File

@ -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

View File

@ -0,0 +1,26 @@
#!/bin/sh
# my-mkimage
# This will just pad the kernel partition to 64k boundary, then add rootfs.
# but we have to be fancy because u-boot mkimage is going to add 64 byte header.
#
# Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us>
PATH_LOADER=$1
PATH_ROOTFS=$2
OUTPUT=$3
# todo - check arguments...? nah...
if [ -x $OUTPUT ]; then
echo usage: $0 loader.bin root.squashfs output.bin
exit
fi
OLDSIZE=$(stat -c%s $PATH_LOADER)
NEWSIZE=$(((OLDSIZE / 65536 + 1) * 65536 - 64))
dd if=$PATH_LOADER of=vmlinuz.tmp bs=$NEWSIZE conv=sync
cat $PATH_ROOTFS >>vmlinuz.tmp
../../../../staging_dir/host/bin/mkimage -A mips -O linux -T kernel -C none -a 0x400000 -e 0x400000 -n "ADM8668 Linux Kernel(2.4.31)" -d vmlinuz.tmp $OUTPUT
rm vmlinuz.tmp
printf '\n\nOk done, now your squashfs starts on an erase boundary of %x :)\n\n' $((NEWSIZE+64))

View File

@ -0,0 +1,37 @@
--- a/arch/mips/Kbuild.platforms 2010-10-20 16:30:22.000000000 -0400
+++ b/arch/mips/Kbuild.platforms 2010-10-22 08:42:06.228968083 -0400
@@ -27,6 +27,7 @@
platforms += txx9
platforms += vr41xx
platforms += wrppmc
+platforms += adm8668
# include the platform specific files
include $(patsubst %, $(srctree)/arch/mips/%/Platform, $(platforms))
--- a/arch/mips/Kconfig 2010-10-20 16:30:22.000000000 -0400
+++ b/arch/mips/Kconfig 2010-10-22 08:37:31.016965108 -0400
@@ -82,6 +82,24 @@
help
Support for BCM47XX based boards
+config ADM8668
+ bool "WildPass ADM8668"
+ select SYS_HAS_CPU_MIPS32_R1
+ 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

View File

@ -0,0 +1,41 @@
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1510,6 +1510,25 @@
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
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -196,6 +196,9 @@
/* High Speed UART for Medfield */
#define PORT_MFD 95
+/* ADM8668 UART */
+#define PORT_ADM8668 93
+
#ifdef __KERNEL__
#include <linux/compiler.h>

View File

@ -0,0 +1,25 @@
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -103,6 +103,12 @@
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 @@
endif
# Chip mappings
+obj-$(CONFIG_MTD_ADM8668_NOR) += adm8668.o
obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o