Add preliminary RouterBoard RB1xx support

SVN-Revision: 6839
This commit is contained in:
Florian Fainelli 2007-04-02 16:59:59 +00:00
parent 75262124ba
commit 3e8d73d762
45 changed files with 6688 additions and 0 deletions

View file

@ -0,0 +1,24 @@
#
# Copyright (C) 2006 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:=rb1xx
BOARDNAME:=Microtik RouterBoard 1xx
FEATURES:=squashfs jffs2 broken
define Target/Description
Build firmware images for ADMTek ADM5120 based boards
(e.g : RouterBoard RB1xx (111,112,133,153)
endef
include $(INCLUDE_DIR)/kernel-build.mk
# include the profiles
-include profiles/*.mk
$(eval $(call BuildKernel))

View file

@ -0,0 +1,251 @@
CONFIG_32BIT=y
# CONFIG_64BIT is not set
# CONFIG_64BIT_PHYS_ADDR is not set
CONFIG_ADM5120_GPIO=y
CONFIG_ADM5120_NR_UARTS=2
CONFIG_BASE_SMALL=0
CONFIG_BAYCOM_SER_FDX=m
CONFIG_BAYCOM_SER_HDX=m
CONFIG_BINFMT_MISC=m
# CONFIG_BLK_DEV_CF_MIPS is not set
CONFIG_CIFS_DEBUG2=y
CONFIG_CIFS_EXPERIMENTAL=y
CONFIG_CIFS_STATS2=y
CONFIG_CIFS_WEAK_PW_HASH=y
CONFIG_CIFS_XATTR=y
CONFIG_CMDLINE="console=ttyS0,115200 rootfs=jffs2,squashfs init=/etc/preinit"
# CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_CPU_HAS_LLSC=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_MIPS32_R2 is not set
# CONFIG_CPU_MIPS64_R1 is not set
# CONFIG_CPU_MIPS64_R2 is not set
CONFIG_CPU_MIPSR1=y
# CONFIG_CPU_NEVADA is not set
# CONFIG_CPU_R10000 is not set
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_R8000 is not set
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_RM9000 is not set
# CONFIG_CPU_SB1 is not set
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
# CONFIG_CPU_TX39XX is not set
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_VR41XX is not set
CONFIG_CRYPTO_SHA1=y
# CONFIG_DDB5477 is not set
# CONFIG_DM9000 is not set
CONFIG_DMA_NEED_PCI_MAP_STATE=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_ELF_CORE=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
# CONFIG_EXT3_FS_SECURITY is not set
CONFIG_EXT3_FS_XATTR=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FS_MBCACHE=m
CONFIG_FS_POSIX_ACL=y
CONFIG_GENERIC_ACL=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
# CONFIG_GEN_RTC is not set
CONFIG_HWMON=y
# CONFIG_HWMON_DEBUG_CHIP is not set
CONFIG_HW_HAS_PCI=y
CONFIG_HW_RANDOM=y
CONFIG_HZ=250
# CONFIG_HZ_100 is not set
# CONFIG_HZ_1024 is not set
# CONFIG_HZ_128 is not set
CONFIG_HZ_250=y
# CONFIG_HZ_256 is not set
# CONFIG_HZ_48 is not set
# CONFIG_I2C is not set
# CONFIG_IDE is not set
CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
CONFIG_INET_XFRM_MODE_BEET=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_INITRAMFS_SOURCE=""
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
CONFIG_INPUT=y
# CONFIG_INPUT_EVDEV is not set
CONFIG_IPV6_MIP6=y
CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_TUNNEL=m
CONFIG_IP_NF_NAT_SNMP_BASIC=m
CONFIG_IP_NF_NETBIOS_NS=m
CONFIG_IP_NF_TARGET_CLUSTERIP=m
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_POSIX_ACL=y
CONFIG_JFFS2_FS_SECURITY=y
CONFIG_JFFS2_FS_XATTR=y
CONFIG_JFFS2_SUMMARY=y
# CONFIG_JOLIET is not set
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_MACH_VR41XX is not set
CONFIG_MII=m
# CONFIG_MINIX_FS is not set
CONFIG_MINI_FO=y
CONFIG_MIPS=y
CONFIG_MIPS_ADM5120=y
CONFIG_MIPS_ADM5120_ENET=y
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_BOSPORUS is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_MIPS_DB1000 is not set
# CONFIG_MIPS_DB1100 is not set
# CONFIG_MIPS_DB1200 is not set
# CONFIG_MIPS_DB1500 is not set
# CONFIG_MIPS_DB1550 is not set
# CONFIG_MIPS_EV64120 is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
# CONFIG_MIPS_MALTA is not set
# CONFIG_MIPS_MIRAGE is not set
# CONFIG_MIPS_MTX1 is not set
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_MT_SMP is not set
# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_PB1000 is not set
# CONFIG_MIPS_PB1100 is not set
# CONFIG_MIPS_PB1200 is not set
# CONFIG_MIPS_PB1500 is not set
# CONFIG_MIPS_PB1550 is not set
# CONFIG_MIPS_SEAD is not set
# CONFIG_MIPS_SIM is not set
# CONFIG_MIPS_VPE_LOADER is not set
# CONFIG_MIPS_XXS1500 is not set
CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_MOMENCO_JAGUAR_ATX is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_MOMENCO_OCELOT_3 is not set
# CONFIG_MOMENCO_OCELOT_C is not set
# CONFIG_MOMENCO_OCELOT_G is not set
CONFIG_MTD=y
# CONFIG_MTD_ABSENT is not set
# CONFIG_MTD_ADM5120 is not set
CONFIG_MTD_BLOCK=y
# CONFIG_MTD_BLOCK2MTD is not set
# CONFIG_MTD_CFI is not set
CONFIG_MTD_CFI_I1=y
CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I4 is not set
# CONFIG_MTD_CFI_I8 is not set
CONFIG_MTD_CHAR=y
# CONFIG_MTD_CMDLINE_PARTS is not set
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# CONFIG_MTD_CONCAT is not set
# CONFIG_MTD_DEBUG is not set
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
# CONFIG_MTD_JEDECPROBE is not set
CONFIG_MTD_MAP_BANK_WIDTH_1=y
# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
CONFIG_MTD_MAP_BANK_WIDTH_2=y
# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
CONFIG_MTD_MAP_BANK_WIDTH_4=y
# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
# CONFIG_MTD_MTDRAM is not set
# CONFIG_MTD_MYLOADER_PARTS is not set
CONFIG_MTD_NAND=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_ECC_SMC is not set
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_NANDSIM is not set
CONFIG_MTD_NAND_RB500=y
CONFIG_MTD_NAND_VERIFY_WRITE=y
# CONFIG_MTD_OBSOLETE_CHIPS is not set
# CONFIG_MTD_ONENAND is not set
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_PLATRAM is not set
# CONFIG_MTD_PMC551 is not set
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_SLRAM is not set
CONFIG_NETFILTER_XT_MATCH_QUOTA=m
CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
CONFIG_NET_ACT_SIMP=m
CONFIG_NET_KEY=y
# CONFIG_NET_PCI is not set
# CONFIG_NET_PKTGEN is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_PAGE_SIZE_16KB is not set
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_64KB is not set
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PARTITION_ADVANCED is not set
# CONFIG_PCIPCWATCHDOG is not set
CONFIG_PCI_ADM5120=y
# CONFIG_PMC_YOSEMITE is not set
# CONFIG_PNX8550_JBS is not set
# CONFIG_PNX8550_V2PCI is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_RTC is not set
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_F71805F is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SERIAL_8250 is not set
CONFIG_SERIAL_ADM5120=y
CONFIG_SERIO=y
# CONFIG_SERIO_I8042 is not set
# CONFIG_SERIO_LIBPS2 is not set
# CONFIG_SERIO_PCIPS2 is not set
# CONFIG_SERIO_RAW is not set
CONFIG_SERIO_SERPORT=y
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP27 is not set
# CONFIG_SGI_IP32 is not set
# CONFIG_SIBYTE_BIGSUR is not set
# CONFIG_SIBYTE_CARMEL is not set
# CONFIG_SIBYTE_CRHINE is not set
# CONFIG_SIBYTE_CRHONE is not set
# CONFIG_SIBYTE_LITTLESUR is not set
# CONFIG_SIBYTE_PTSWARM is not set
# CONFIG_SIBYTE_RHONE is not set
# CONFIG_SIBYTE_SENTOSA is not set
# CONFIG_SIBYTE_SWARM is not set
CONFIG_SOFT_WATCHDOG=m
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SYN_COOKIES=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_TMPFS_POSIX_ACL=y
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
CONFIG_TRAD_SIGNALS=y
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_USB is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED=y
CONFIG_YAFFS_AUTO_YAFFS2=y
# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
CONFIG_YAFFS_DOES_ECC=y
CONFIG_YAFFS_ECC_WRONG_ORDER=y
CONFIG_YAFFS_FS=y
CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
CONFIG_YAFFS_YAFFS1=y
CONFIG_YAFFS_YAFFS2=y

View file

@ -0,0 +1,7 @@
#
# Makefile for the ADMtek ADM5120 SoC specific parts of the kernel
#
obj-y := setup.o prom.o irq.o memory.o mipsIRQ.o adm5120_info.o
EXTRA_AFLAGS := $(CFLAGS)

View file

@ -0,0 +1,186 @@
/*
* $Id$
*
* Copyright (C) 2007 OpenWrt.org
* Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/types.h>
#include <linux/autoconf.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/addrspace.h>
#include <adm5120_info.h>
#include <adm5120_defs.h>
#include <adm5120_switch.h>
#include <myloader.h>
/* boot loaders specific definitions */
#define CFE_EPTSEAL 0x43464531 /* CFE1 is the magic number to recognize CFE from other bootloaders */
struct adm5120_info adm5120_info = {
.cpu_speed = CPU_SPEED_175,
.cpu_package = CPU_PACKAGE_PQFP,
.boot_loader = BOOT_LOADER_UNKNOWN,
.board_type = BOARD_TYPE_UNKNOWN
};
static char *boot_loader_names[BOOT_LOADER_LAST+1] = {
[BOOT_LOADER_UNKNOWN] = "Unknown",
[BOOT_LOADER_CFE] = "CFE",
[BOOT_LOADER_UBOOT] = "U-Boot",
[BOOT_LOADER_MYLOADER] = "MyLoader"
};
/*
* CPU settings detection
*/
#define CODE_GET_PC(c) ((c) & CODE_PC_MASK)
#define CODE_GET_REV(c) (((c) >> CODE_REV_SHIFT) & CODE_REV_MASK)
#define CODE_GET_PK(c) (((c) >> CODE_PK_SHIFT) & CODE_PK_MASK)
#define CODE_GET_CLKS(c) (((c) >> CODE_CLKS_SHIFT) & CODE_CLKS_MASK)
#define CODE_GET_NAB(c) (((c) & CODE_NAB) != 0)
static void __init detect_cpu_info(void)
{
uint32_t *reg;
uint32_t code;
uint32_t clks;
reg = (uint32_t *)KSEG1ADDR(ADM5120_SWITCH_BASE+SWITCH_REG_CODE);
code = *reg;
clks = CODE_GET_CLKS(code);
adm5120_info.product_code = CODE_GET_PC(code);
adm5120_info.revision = CODE_GET_REV(code);
adm5120_info.cpu_speed = CPU_SPEED_175;
if (clks & 1)
adm5120_info.cpu_speed += 25000000;
if (clks & 2)
adm5120_info.cpu_speed += 50000000;
adm5120_info.cpu_package = (CODE_GET_PK(code) == CODE_PK_BGA) ?
CPU_PACKAGE_BGA : CPU_PACKAGE_PQFP;
adm5120_info.nand_boot = CODE_GET_NAB(code);
}
/*
* Boot loader detection routines
*/
static int __init detect_cfe(void)
{
/*
* This method only works, when we are booted directly from the CFE.
*/
uint32_t cfe_handle = (uint32_t) fw_arg0;
uint32_t cfe_a1_val = (uint32_t) fw_arg1;
uint32_t cfe_entry = (uint32_t) fw_arg2;
uint32_t cfe_seal = (uint32_t) fw_arg3;
/* Check for CFE by finding the CFE magic number */
if (cfe_seal != CFE_EPTSEAL) {
/* We are not booted from CFE */
return 0;
}
/* cfe_a1_val must be 0, because only one CPU present in the ADM5120 SoC */
if (cfe_a1_val != 0) {
return 0;
}
/* The cfe_handle, and the cfe_entry must be kernel mode addresses */
if ((cfe_handle < KSEG0) || (cfe_entry < KSEG0)) {
return 0;
}
return 1;
}
static int __init detect_uboot(void)
{
/* FIXME: not yet implemented */
return 0;
}
static int __init detect_myloader(void)
{
struct mylo_system_params *sysp;
struct mylo_board_params *boardp;
struct mylo_partition_table *parts;
sysp = (struct mylo_system_params *)(MYLO_MIPS_SYS_PARAMS);
boardp = (struct mylo_board_params *)(MYLO_MIPS_BOARD_PARAMS);
parts = (struct mylo_partition_table *)(MYLO_MIPS_PARTITIONS);
/* Check for some magic numbers */
if ((sysp->magic != MYLO_MAGIC_SYS_PARAMS) ||
(boardp->magic != MYLO_MAGIC_BOARD_PARAMS) ||
(parts->magic != MYLO_MAGIC_PARTITIONS))
return 0;
return 1;
}
static int __init detect_routerboot(void)
{
/* FIXME: not yet implemented */
return 0;
}
static int __init detect_bootloader(void)
{
if (detect_cfe())
return BOOT_LOADER_CFE;
if (detect_uboot())
return BOOT_LOADER_UBOOT;
if (detect_myloader())
return BOOT_LOADER_MYLOADER;
if (detect_routerboot())
return BOOT_LOADER_ROUTERBOOT;
return BOOT_LOADER_UNKNOWN;
}
/*
* Board detection
*/
static void __init detect_board_type(void)
{
/* FIXME: not yet implemented */
}
void __init adm5120_info_show(void)
{
printk("ADM%04X%s revision %d, running at %ldMHz\n",
adm5120_info.product_code,
(adm5120_info.cpu_package == CPU_PACKAGE_BGA) ? "" : "P",
adm5120_info.revision,
(adm5120_info.cpu_speed / 1000000)
);
printk("Boot loader is: %s\n", boot_loader_names[adm5120_info.boot_loader]);
printk("Booted from : %s flash\n", adm5120_info.nand_boot ? "NAND" : "NOR");
}
void __init adm5120_info_init(void)
{
detect_cpu_info();
adm5120_info.boot_loader = detect_bootloader();
detect_board_type();
adm5120_info_show();
}

View file

@ -0,0 +1,156 @@
/*
* Copyright (C) ADMtek Incorporated.
* Creator : daniell@admtek.com.tw
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000, 2001 MIPS Technologies, Inc.
* Copyright (C) 2001 Ralf Baechle
* Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org)
*/
#include <linux/autoconf.h>
#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 <asm/irq.h>
#include <asm/time.h>
#include <asm/mipsregs.h>
#include <asm/gdb-stub.h>
#include <asm/irq_cpu.h>
#define MIPS_CPU_TIMER_IRQ 7
extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
extern irq_desc_t irq_desc[];
extern asmlinkage void mipsIRQ(void);
int mips_int_lock(void);
void mips_int_unlock(int);
unsigned int mips_counter_frequency;
#define ADM5120_INTC_REG(reg) (*(volatile u32 *)(KSEG1ADDR(0x12200000+(reg))))
#define ADM5120_INTC_STATUS ADM5120_INTC_REG(0x00)
#define ADM5120_INTC_ENABLE ADM5120_INTC_REG(0x08)
#define ADM5120_INTC_DISABLE ADM5120_INTC_REG(0x0c)
#define ADM5120_IRQ_MAX 9
#define ADM5120_IRQ_MASK 0x3ff
void adm5120_hw0_irqdispatch(struct pt_regs *regs)
{
unsigned long intsrc;
int i;
intsrc = ADM5120_INTC_STATUS & ADM5120_IRQ_MASK;
for (i = 0; intsrc; intsrc >>= 1, i++)
if (intsrc & 0x1)
do_IRQ(i);
else
spurious_interrupt();
}
void mips_timer_interrupt(struct pt_regs *regs)
{
write_c0_compare(read_c0_count()+ mips_counter_frequency/HZ);
ll_timer_interrupt(MIPS_CPU_TIMER_IRQ);
}
/* Main interrupt dispatcher */
asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
unsigned int cp0_cause = read_c0_cause() & read_c0_status();
if (cp0_cause & CAUSEF_IP7) {
mips_timer_interrupt( regs);
} else if (cp0_cause & CAUSEF_IP2) {
adm5120_hw0_irqdispatch( regs);
}
}
void enable_adm5120_irq(unsigned int irq)
{
int s;
/* Disable all interrupts (FIQ/IRQ) */
s = mips_int_lock();
if ((irq < 0) || (irq > ADM5120_IRQ_MAX))
goto err_exit;
ADM5120_INTC_ENABLE = (1<<irq);
err_exit:
/* Restore the interrupts states */
mips_int_unlock(s);
}
void disable_adm5120_irq(unsigned int irq)
{
int s;
/* Disable all interrupts (FIQ/IRQ) */
s = mips_int_lock();
if ((irq < 0) || (irq > ADM5120_IRQ_MAX))
goto err_exit;
ADM5120_INTC_DISABLE = (1<<irq);
err_exit:
/* Restore the interrupts states */
mips_int_unlock(s);
}
unsigned int startup_adm5120_irq(unsigned int irq)
{
enable_adm5120_irq(irq);
return 0;
}
void shutdown_adm5120_irq(unsigned int irq)
{
disable_adm5120_irq(irq);
}
static inline void ack_adm5120_irq(unsigned int irq_nr)
{
ADM5120_INTC_DISABLE = (1 << irq_nr);
}
static void end_adm5120_irq(unsigned int irq_nr)
{
ADM5120_INTC_ENABLE = (1 << irq_nr);
}
static hw_irq_controller adm5120_irq_type = {
.typename = "MIPS",
.startup = startup_adm5120_irq,
.shutdown = shutdown_adm5120_irq,
.enable = enable_adm5120_irq,
.disable = disable_adm5120_irq,
.ack = ack_adm5120_irq,
.end = end_adm5120_irq,
.set_affinity = NULL,
};
void __init arch_init_irq(void)
{
int i;
for (i = 0; i <= ADM5120_IRQ_MAX; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[i].depth = 1;
irq_desc[i].chip = &adm5120_irq_type;
}
}

View file

@ -0,0 +1,135 @@
/*****************************************************************************
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
* Copyright (C) 2003 ADMtek Incorporated.
* daniell@admtek.com.tw
* Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org)
*
* ########################################################################
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* ########################################################################
*
*****************************************************************************/
#include <linux/autoconf.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
#include <linux/pfn.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
#include <asm/page.h>
#include <asm/sections.h>
#include <asm-mips/mips-boards/prom.h>
extern char *prom_getenv(char *envname);
#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
#define ADM5120_MEMCTRL 0x1200001c
#define ADM5120_MEMCTRL_SDRAM_MASK 0x7
static const unsigned long adm_sdramsize[] __initdata = {
0x0, /* Reserved */
0x0400000, /* 4Mb */
0x0800000, /* 8Mb */
0x1000000, /* 16Mb */
0x4000000, /* 64Mb */
0x8000000, /* 128Mb */
};
/* determined physical memory size, not overridden by command line args */
unsigned long physical_memsize = 0L;
struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
struct prom_pmemblock * __init prom_getmdesc(void)
{
char *memsize_str;
unsigned int memsize;
char cmdline[CL_SIZE], *ptr;
memsize_str = prom_getenv("memsize");
if (!memsize_str)
{
prom_printf("memsize not set in boot prom, set to default (8Mb)\n");
physical_memsize = 0x00800000;
}
else
#ifdef DEBUG
prom_printf("prom_memsize = %s\n", memsize_str);
#endif
physical_memsize = simple_strtol(memsize_str, NULL, 0);
/* Check the command line for a memsize directive that overrides
* the physical/default amount */
strcpy(cmdline, arcs_cmdline);
ptr = strstr(cmdline, "memsize=");
if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' '))
ptr = strstr(ptr, " memsize=");
if (ptr)
memsize = memparse(ptr + 8, &ptr);
else
memsize = physical_memsize;
memset(mdesc, 0, sizeof(mdesc));
mdesc[0].type = BOOT_MEM_RAM;
mdesc[0].base = CPHYSADDR(PFN_ALIGN(&_end));
mdesc[0].size = memsize - mdesc[0].base;
return &mdesc[0];
}
void __init prom_meminit(void)
{
struct prom_pmemblock *p;
p = prom_getmdesc();
while (p->size)
{
long type;
unsigned long base, size;
base = p->base;
type = p->type,
size = p->size;
add_memory_region(base, size, type);
p++;
}
}
#if 0
void __init prom_meminit(void)
{
unsigned long base = CPHYSADDR(PFN_ALIGN(&_end));
unsigned long size;
u32 memctrl = *(u32*)KSEG1ADDR(ADM5120_MEMCTRL);
size = adm_sdramsize[memctrl & ADM5120_MEMCTRL_SDRAM_MASK];
add_memory_region(base, size-base, BOOT_MEM_RAM);
}
#endif
unsigned long __init prom_free_prom_memory(void)
{
/* We do not have to prom memory to free */
return 0;
}

View file

@ -0,0 +1,135 @@
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999, 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.
*
* ########################################################################
*
* Interrupt exception dispatch code.
*
*/
#include <linux/autoconf.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#define STATUS_IE 0x00000001
/* A lot of complication here is taken away because:
*
* 1) We handle one interrupt and return, sitting in a loop and moving across
* all the pending IRQ bits in the cause register is _NOT_ the answer, the
* common case is one pending IRQ so optimize in that direction.
*
* 2) We need not check against bits in the status register IRQ mask, that
* would make this routine slow as hell.
*
* 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
* between like BSD spl() brain-damage.
*
* Furthermore, the IRQs on the MIPS board look basically (barring software
* IRQs which we don't use at all and all external interrupt sources are
* combined together on hardware interrupt 0 (MIPS IRQ 2)) like:
*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 Combined hardware interrupt (hw0)
* 3 Hardware (ignored)
* 4 Hardware (ignored)
* 5 Hardware (ignored)
* 6 Hardware (ignored)
* 7 R4k timer (what we use)
*
* Note: On the SEAD board thing are a little bit different.
* Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired
* wired to UART1.
*
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
* Lowest ---- Combined hardware interrupt
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
.text
.set noreorder
.set noat
.align 5
NESTED(mipsIRQ, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 s0, CP0_CAUSE
mfc0 s1, CP0_STATUS
and s0, s0, s1
/* First we check for r4k counter/timer IRQ. */
andi a0, s0, CAUSEF_IP7
beq a0, zero, 1f
nop
move a0, sp
jal mips_timer_interrupt
nop
j ret_from_irq
nop
1:
andi a0, s0, CAUSEF_IP2
beq a0, zero, 1f
nop
move a0, sp
jal adm5120_hw0_irqdispatch
nop
1:
j ret_from_irq
nop
END(mipsIRQ)
LEAF(mips_int_lock)
.set noreorder
mfc0 v0, CP0_STATUS
li v1, ~STATUS_IE
and v1, v1, v0
mtc0 v1, CP0_STATUS
j ra
and v0, v0, STATUS_IE
.set reorder
END(mips_int_lock)
LEAF(mips_int_unlock)
mfc0 v0, CP0_STATUS
and a0, a0, STATUS_IE
or v0, v0, a0
mtc0 v0, CP0_STATUS
j ra
nop
END(mips_int_unlock)

View file

@ -0,0 +1,118 @@
/*****************************************************************************
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
* Copyright (C) 2003 ADMtek Incorporated.
* daniell@admtek.com.tw
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*****************************************************************************/
#include <linux/init.h>
#include <linux/autoconf.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
#include <asm/bootinfo.h>
#include <asm/addrspace.h>
#include <adm5120_info.h>
void setup_prom_printf(int);
void prom_printf(char *, ...);
void prom_meminit(void);
#define ADM5120_ENVC 1
char *adm5120_envp[2*ADM5120_ENVC] = {"memsize","0x001000000"};
#define READCSR(r) *(volatile unsigned long *)(0xB2600000+(r))
#define WRITECSR(r,v) *(volatile unsigned long *)(0xB2600000+(r)) = v
#define UART_DR_REG 0x00
#define UART_FR_REG 0x18
#define UART_TX_FIFO_FULL 0x20
int putPromChar(char c)
{
WRITECSR(UART_DR_REG, c);
while ( (READCSR(UART_FR_REG) & UART_TX_FIFO_FULL) );
return 0;
}
/*
* Ugly prom_printf used for debugging
*/
void prom_printf(char *fmt, ...)
{
va_list args;
int l;
char *p, *buf_end;
char buf[1024];
va_start(args, fmt);
l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */
va_end(args);
buf_end = buf + l;
for (p = buf; p < buf_end; p++) {
/* Crude cr/nl handling is better than none */
if (*p == '\n')
putPromChar('\r');
putPromChar(*p);
}
}
char *prom_getenv(char *envname)
{
int i, index=0;
i = strlen(envname);
printk(KERN_INFO "GETENV: envname is %s\n", envname);
while(index < (2*ADM5120_ENVC)) {
if(strncmp(envname, adm5120_envp[index], i) == 0) {
printk(KERN_INFO "GETENV: returning %s\n", adm5120_envp[index+1]);
return(adm5120_envp[index+1]);
}
index += 2;
}
printk(KERN_INFO "GETENV: not found.\n");
return(NULL);
}
/*
* initialize the prom module.
*/
void __init prom_init(void)
{
/* you should these macros defined in include/asm/bootinfo.h */
mips_machgroup = MACH_GROUP_ADM_GW;
mips_machtype = MACH_ADM_GW_5120;
adm5120_info_init();
/* init command line, register a default kernel command line */
strcpy(&(arcs_cmdline[0]), "console=ttyS0,115200 rootfstype=squashfs,jffs2 init=/etc/preinit");
/* init memory map */
prom_meminit();
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (C) ADMtek Incorporated.
* Creator : daniell@admtek.com.tw
* Copyright 1999, 2000 MIPS Technologies, Inc.
* Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005
*/
#include <linux/autoconf.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <asm/reboot.h>
#include <asm/io.h>
#include <asm/time.h>
#include <adm5120_info.h>
#define ADM5120_SOFTRESET 0x12000004
#define STATUS_IE 0x00000001
#define ALLINTS (IE_IRQ0 | IE_IRQ5 | STATUS_IE)
void mips_time_init(void);
extern unsigned int mips_counter_frequency;
void adm5120_restart(char *command)
{
*(u32*)KSEG1ADDR(ADM5120_SOFTRESET)=1;
}
void adm5120_halt(void)
{
printk(KERN_NOTICE "\n** You can safely turn off the power\n");
while (1);
}
void adm5120_power_off(void)
{
adm5120_halt();
}
void __init adm5120_time_init(void)
{
mips_counter_frequency = adm5120_info.cpu_speed >> 1;
}
void __init plat_timer_setup(struct irqaction *irq)
{
/* to generate the first timer interrupt */
write_c0_compare(read_c0_count()+ mips_counter_frequency/HZ);
clear_c0_status(ST0_BEV);
set_c0_status(ALLINTS);
}
void __init plat_mem_setup(void)
{
printk(KERN_INFO "ADM5120 board setup\n");
board_time_init = adm5120_time_init;
//board_timer_setup = mips_timer_setup;
_machine_restart = adm5120_restart;
_machine_halt = adm5120_halt;
pm_power_off = adm5120_power_off;
set_io_port_base(KSEG1);
}
const char *get_system_type(void)
{
return "ADM5120 Board";
}
static struct resource adm5120_hcd_resources[] = {
[0] = {
.start = 0x11200000,
.end = 0x11200084,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 0x3,
.end = 0x3,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device adm5120hcd_device = {
.name = "adm5120-hcd",
.id = -1,
.num_resources = ARRAY_SIZE(adm5120_hcd_resources),
.resource = adm5120_hcd_resources,
};
static struct platform_device *devices[] __initdata = {
&adm5120hcd_device,
};
static int __init adm5120_init(void)
{
return platform_add_devices(devices, ARRAY_SIZE(devices));
}
subsys_initcall(adm5120_init);

View file

@ -0,0 +1,63 @@
/*
* Copyright (C) ADMtek Incorporated.
* Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org)
* Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu>
* Copyright (C) 2007 OpenWrt.org
*/
#include <linux/autoconf.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <adm5120_defs.h>
volatile u32* pci_config_address_reg = (volatile u32*)KSEG1ADDR(ADM5120_PCICFG_ADDR);
volatile u32* pci_config_data_reg = (volatile u32*)KSEG1ADDR(ADM5120_PCICFG_DATA);
#define PCI_ENABLE 0x80000000
static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where,
int size, uint32_t *val)
{
*pci_config_address_reg = ((bus->number & 0xff) << 0x10) |
((devfn & 0xff) << 0x08) | (where & 0xfc) | PCI_ENABLE;
switch (size) {
case 1:
*val = ((*pci_config_data_reg)>>((where&3)<<3))&0xff;
break;
case 2:
*val = ((*pci_config_data_reg)>>((where&3)<<3))&0xffff;
break;
default:
*val = (*pci_config_data_reg);
}
return PCIBIOS_SUCCESSFUL;
}
static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where,
int size, uint32_t val)
{
*pci_config_address_reg = ((bus->number & 0xff) << 0x10) |
((devfn & 0xff) << 0x08) | (where & 0xfc) | PCI_ENABLE;
switch (size) {
case 1:
*(volatile u8 *)(((int)pci_config_data_reg) +
(where & 3)) = val;
break;
case 2:
*(volatile u16 *)(((int)pci_config_data_reg) +
(where & 2)) = (val);
break;
default:
*pci_config_data_reg = (val);
}
return PCIBIOS_SUCCESSFUL;
}
struct pci_ops adm5120_pci_ops = {
.read = pci_config_read,
.write = pci_config_write,
};

View file

@ -0,0 +1,96 @@
/*
* Copyright (C) ADMtek Incorporated.
* Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org)
* Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu>
* Copyright (C) 2007 OpenWrt.org
*/
#include <linux/autoconf.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <adm5120_info.h>
#include <adm5120_defs.h>
extern struct pci_ops adm5120_pci_ops;
#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 4
struct resource pci_io_resource = {
.name = "ADM5120 PCI I/O",
.start = ADM5120_PCIIO_BASE,
.end = ADM5120_PCICFG_ADDR-1,
.flags = IORESOURCE_IO
};
struct resource pci_mem_resource = {
.name = "ADM5120 PCI MEM",
.start = ADM5120_PCIMEM_BASE,
.end = ADM5120_PCIIO_BASE-1,
.flags = IORESOURCE_MEM
};
static struct pci_controller adm5120_controller = {
.pci_ops = &adm5120_pci_ops,
.io_resource = &pci_io_resource,
.mem_resource = &pci_mem_resource,
};
int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
if (slot < 2 || slot > 4)
return -1;
return slot + 4;
}
static void adm5120_pci_fixup(struct pci_dev *dev)
{
if (dev->devfn == 0) {
pci_write_config_word(dev, PCI_COMMAND, PCI_CMM_DEF);
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
PCI_DEF_CACHE_LINE_SZ);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0);
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, adm5120_pci_fixup);
int pcibios_plat_dev_init(struct pci_dev *dev)
{
return 0;
}
static int __init adm5120_pci_setup(void)
{
int pci_bios;
pci_bios = adm5120_has_pci();
printk("adm5120: system has %sPCI BIOS\n", pci_bios ? "" : "no ");
if (pci_bios == 0)
return 1;
/* Avoid ISA compat ranges. */
PCIBIOS_MIN_IO = 0x00000000;
PCIBIOS_MIN_MEM = 0x00000000;
/* Set I/O resource limits. */
ioport_resource.end = 0x1fffffff;
iomem_resource.end = 0xffffffff;
register_pci_controller(&adm5120_controller);
return 0;
}
subsys_initcall(adm5120_pci_setup);

View file

@ -0,0 +1,58 @@
/*
* ADM5120 LED (GPIO) driver
*
* Copyright (C) Jeroen Vreeken (pe1rxq@amsat.org), 2005
*/
#include <linux/autoconf.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#define LED_MINOR 151
#define GPIO_IO ((unsigned long *)0xb20000b8)
static ssize_t adm5120_led_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
unsigned char val;
if (!len || get_user(val, data))
return -EFAULT;
*GPIO_IO=(*GPIO_IO & 0x00ffffff) | (val<<24);
return 1;
}
static struct file_operations adm5120_led_fops = {
.owner = THIS_MODULE,
.write = adm5120_led_write,
};
static struct miscdevice adm5120_led_device = {
LED_MINOR,
"led",
&adm5120_led_fops,
};
static int __init adm5120_led_init(void)
{
printk(KERN_INFO "ADM5120 LED & GPIO driver\n");
if (misc_register(&adm5120_led_device)) {
printk(KERN_WARNING "Couldn't register device %d\n", LED_MINOR);
return -EBUSY;
}
return 0;
}
static void __exit adm5120_led_exit(void)
{
misc_deregister(&adm5120_led_device);
}
module_init(adm5120_led_init);
module_exit(adm5120_led_exit);
MODULE_DESCRIPTION("ADM5120 LED and GPIO driver");
MODULE_AUTHOR("Jeroen Vreeken");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,196 @@
#include <linux/init.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bootinfo.h>
#ifdef CONFIG_MIPS_ADM5120
#include <asm/mach-adm5120/adm5120_defs.h>
#endif
#define IDT434_REG_BASE ((volatile void *) KSEG1ADDR(0x18000000))
#define GPIOF 0x050000
#define GPIOC 0x050004
#define GPIOD 0x050008
#define GPIO_RDY (1 << 0x08)
#define GPIO_WPX (1 << 0x09)
#define GPIO_ALE (1 << 0x0a)
#define GPIO_CLE (1 << 0x0b)
#define DEV2BASE 0x010020
#define LO_WPX (1 << 0)
#define LO_ALE (1 << 1)
#define LO_CLE (1 << 2)
#define LO_CEX (1 << 3)
#define LO_FOFF (1 << 5)
#define LO_SPICS (1 << 6)
#define LO_ULED (1 << 7)
#define MEM32(x) *((volatile unsigned *) (x))
/* RouterBoard RB1xx specific definitions */
#define SMEM1(x) (*((volatile unsigned char *) (KSEG1ADDR(ADM5120_SRAM1_BASE) + x)))
#define NAND_RW_REG 0x0 //data register
#define NAND_SET_CEn 0x1 //CE# low
#define NAND_CLR_CEn 0x2 //CE# high
#define NAND_CLR_CLE 0x3 //CLE low
#define NAND_SET_CLE 0x4 //CLE high
#define NAND_CLR_ALE 0x5 //ALE low
#define NAND_SET_ALE 0x6 //ALE high
#define NAND_SET_SPn 0x7 //SP# low (use spare area)
#define NAND_CLR_SPn 0x8 //SP# high (do not use spare area)
#define NAND_SET_WPn 0x9 //WP# low
#define NAND_CLR_WPn 0xA //WP# high
#define NAND_STS_REG 0xB //Status register
static void __iomem *p_nand;
#ifdef CONFIG_MIKROTIK_RB500
extern void changeLatchU5(unsigned char orMask, unsigned char nandMask);
static int rb500_dev_ready(struct mtd_info *mtd)
{
return MEM32(IDT434_REG_BASE + GPIOD) & GPIO_RDY;
}
/*
* hardware specific access to control-lines
*
* ctrl:
* NAND_CLE: bit 2 -> bit 3
* NAND_ALE: bit 3 -> bit 2
*/
static void rbmips_hwcontrol500(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct nand_chip *chip = mtd->priv;
unsigned char orbits, nandbits;
if (ctrl & NAND_CTRL_CHANGE) {
orbits = (ctrl & NAND_CLE) << 1;
orbits |= (ctrl & NAND_ALE) >> 1;
nandbits = (~ctrl & NAND_CLE) << 1;
nandbits |= (~ctrl & NAND_ALE) >> 1;
changeLatchU5(orbits, nandbits);
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
}
#endif
#ifdef CONFIG_MIPS_ADM5120
static int rb100_dev_ready(struct mtd_info *mtd)
{
return SMEM1(NAND_STS_REG) & 0x80; /* found out by experiment */
}
static void rbmips_hwcontrol100(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *chip = mtd->priv;
if (ctrl & NAND_CTRL_CHANGE)
SMEM1(ctrl) = 0x01;
if (cmd != NAND_CMD_NONE)
writeb(cmd, chip->IO_ADDR_W);
}
#endif
static struct mtd_partition partition_info[] = {
{
name:"RouterBoard NAND Boot",
offset:0,
size:4 * 1024 * 1024},
{
name:"RouterBoard NAND Main",
offset:MTDPART_OFS_NXTBLK,
size:MTDPART_SIZ_FULL}
};
static struct mtd_info rmtd;
static struct nand_chip rnand;
static unsigned init_ok = 0;
unsigned get_rbnand_block_size(void)
{
if (init_ok)
return rmtd.writesize;
else
return 0;
}
EXPORT_SYMBOL(get_rbnand_block_size);
int __init rbmips_init(void)
{
memset(&rmtd, 0, sizeof(rmtd));
memset(&rnand, 0, sizeof(rnand));
#ifdef CONFIG_MIKROTIK_RB500
printk("RB500 nand\n");
changeLatchU5(LO_WPX | LO_FOFF | LO_CEX,
LO_ULED | LO_ALE | LO_CLE);
rnand.cmd_ctrl = rbmips_hwcontrol500;
rnand.dev_ready = rb500_dev_ready;
rnand.IO_ADDR_W = (unsigned char *)
KSEG1ADDR(MEM32(IDT434_REG_BASE + DEV2BASE));
rnand.IO_ADDR_R = rnand.IO_ADDR_W;
#endif
#ifdef CONFIG_MIPS_ADM5120
printk("RB100 nand\n");
/* enable NAND flash */
MEM32(0xB2000064) = 0x100;
/* boot done */
MEM32(0xB2000008) = 0x1;
SMEM1(NAND_SET_SPn) = 0x01;
SMEM1(NAND_CLR_WPn) = 0x01;
rnand.IO_ADDR_R = (unsigned char *)KSEG1ADDR(ADM5120_SRAM1_BASE);
rnand.IO_ADDR_W = rnand.IO_ADDR_R;
rnand.cmd_ctrl = rbmips_hwcontrol100;
rnand.dev_ready = rb100_dev_ready;
#endif
p_nand = (void __iomem *) ioremap((void *) 0x18a20000, 0x1000);
if (!p_nand) {
printk("RBnand Unable ioremap buffer");
return -ENXIO;
}
rnand.ecc.mode = NAND_ECC_SOFT;
rnand.chip_delay = 25;
rnand.options |= NAND_NO_AUTOINCR;
rmtd.priv = &rnand;
#ifdef CONFIG_MIKROTIK_RB500
int *b;
b = (int *) KSEG1ADDR(0x18010020);
printk("dev2base 0x%08x mask 0x%08x c 0x%08x tc 0x%08x\n", b[0],
b[1], b[2], b[3]);
#endif
if (nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1)
&& nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1)) {
printk("RBxxx nand device not found");
iounmap((void *) p_nand);
return -ENXIO;
}
add_mtd_partitions(&rmtd, partition_info, 2);
init_ok = 1;
return 0;
}
module_init(rbmips_init);

View file

@ -0,0 +1,507 @@
/*
* ADM5120 built in ethernet switch driver
*
* Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005
*
* Inspiration for this driver came from the original ADMtek 2.4
* driver, Copyright ADMtek Inc.
*/
#include <linux/autoconf.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <asm/mipsregs.h>
#include <asm/irq.h>
#include <asm/io.h>
#include "adm5120sw.h"
#include "adm5120_info.h"
MODULE_AUTHOR("Jeroen Vreeken (pe1rxq@amsat.org)");
MODULE_DESCRIPTION("ADM5120 ethernet switch driver");
MODULE_LICENSE("GPL");
/*
* The ADM5120 uses an internal matrix to determine which ports
* belong to which VLAN.
* The default generates a VLAN (and device) for each port
* (including MII port) and the CPU port is part of all of them.
*
* Another example, one big switch and everything mapped to eth0:
* 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00
*/
static unsigned char vlan_matrix[SW_DEVS] = {
0x41, 0x42, 0x44, 0x48, 0x50, 0x60
};
static int adm5120_nrdevs;
static struct net_device *adm5120_devs[SW_DEVS];
static struct adm5120_dma
adm5120_dma_txh_v[ADM5120_DMA_TXH] __attribute__((aligned(16))),
adm5120_dma_txl_v[ADM5120_DMA_TXL] __attribute__((aligned(16))),
adm5120_dma_rxh_v[ADM5120_DMA_RXH] __attribute__((aligned(16))),
adm5120_dma_rxl_v[ADM5120_DMA_RXL] __attribute__((aligned(16))),
*adm5120_dma_txh,
*adm5120_dma_txl,
*adm5120_dma_rxh,
*adm5120_dma_rxl;
static struct sk_buff
*adm5120_skb_rxh[ADM5120_DMA_RXH],
*adm5120_skb_rxl[ADM5120_DMA_RXL],
*adm5120_skb_txh[ADM5120_DMA_TXH],
*adm5120_skb_txl[ADM5120_DMA_TXL];
static int adm5120_rxhi = 0;
static int adm5120_rxli = 0;
/* We don't use high priority tx for now */
/*static int adm5120_txhi = 0;*/
static int adm5120_txli = 0;
static int adm5120_txhit = 0;
static int adm5120_txlit = 0;
static int adm5120_if_open = 0;
static inline void adm5120_set_reg(unsigned int reg, unsigned long val)
{
*(volatile unsigned long*)(SW_BASE+reg) = val;
}
static inline unsigned long adm5120_get_reg(unsigned int reg)
{
return *(volatile unsigned long*)(SW_BASE+reg);
}
static inline void adm5120_rxfixup(struct adm5120_dma *dma,
struct sk_buff **skbl, int num)
{
int i;
/* Resubmit the entire ring */
for (i=0; i<num; i++) {
dma[i].status = 0;
dma[i].cntl = 0;
dma[i].len = ADM5120_DMA_RXSIZE;
dma[i].data = ADM5120_DMA_ADDR(skbl[i]->data) |
ADM5120_DMA_OWN | (i==num-1 ? ADM5120_DMA_RINGEND : 0);
}
}
static inline void adm5120_rx(struct adm5120_dma *dma, struct sk_buff **skbl,
int *index, int num)
{
struct sk_buff *skb, *skbn;
struct adm5120_sw *priv;
struct net_device *dev;
int port, vlan, len;
while (!(dma[*index].data & ADM5120_DMA_OWN)) {
port = (dma[*index].status & ADM5120_DMA_PORTID);
port >>= ADM5120_DMA_PORTSHIFT;
for (vlan = 0; vlan < adm5120_nrdevs; vlan++) {
if ((1<<port) & vlan_matrix[vlan])
break;
}
if (vlan == adm5120_nrdevs)
vlan = 0;
dev = adm5120_devs[vlan];
skb = skbl[*index];
len = (dma[*index].status & ADM5120_DMA_LEN);
len >>= ADM5120_DMA_LENSHIFT;
len -= ETH_FCS;
priv = netdev_priv(dev);
if (len <= 0 || len > ADM5120_DMA_RXSIZE ||
dma[*index].status & ADM5120_DMA_FCSERR) {
priv->stats.rx_errors++;
skbn = NULL;
} else {
skbn = dev_alloc_skb(ADM5120_DMA_RXSIZE+16);
if (skbn) {
skb_put(skb, len);
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_UNNECESSARY;
dev->last_rx = jiffies;
priv->stats.rx_packets++;
priv->stats.rx_bytes+=len;
skb_reserve(skbn, 2);
skbl[*index] = skbn;
} else {
printk(KERN_INFO "%s recycling!\n", dev->name);
}
}
dma[*index].status = 0;
dma[*index].cntl = 0;
dma[*index].len = ADM5120_DMA_RXSIZE;
dma[*index].data = ADM5120_DMA_ADDR(skbl[*index]->data) |
ADM5120_DMA_OWN |
(num-1==*index ? ADM5120_DMA_RINGEND : 0);
if (num == ++*index)
*index = 0;
if (skbn)
netif_rx(skb);
}
}
static inline void adm5120_tx(struct adm5120_dma *dma, struct sk_buff **skbl,
int *index, int num)
{
while((dma[*index].data & ADM5120_DMA_OWN) == 0 && skbl[*index]) {
dev_kfree_skb_irq(skbl[*index]);
skbl[*index] = NULL;
if (++*index == num)
*index = 0;
}
}
static irqreturn_t adm5120_sw_irq(int irq, void *dev_id)
{
unsigned long intreg;
adm5120_set_reg(ADM5120_INT_MASK,
adm5120_get_reg(ADM5120_INT_MASK) | ADM5120_INTHANDLE);
intreg = adm5120_get_reg(ADM5120_INT_ST);
adm5120_set_reg(ADM5120_INT_ST, intreg);
if (intreg & ADM5120_INT_RXH)
adm5120_rx(adm5120_dma_rxh, adm5120_skb_rxh, &adm5120_rxhi,
ADM5120_DMA_RXH);
if (intreg & ADM5120_INT_HFULL)
adm5120_rxfixup(adm5120_dma_rxh, adm5120_skb_rxh,
ADM5120_DMA_RXH);
if (intreg & ADM5120_INT_RXL)
adm5120_rx(adm5120_dma_rxl, adm5120_skb_rxl, &adm5120_rxli,
ADM5120_DMA_RXL);
if (intreg & ADM5120_INT_LFULL)
adm5120_rxfixup(adm5120_dma_rxl, adm5120_skb_rxl,
ADM5120_DMA_RXL);
if (intreg & ADM5120_INT_TXH)
adm5120_tx(adm5120_dma_txh, adm5120_skb_txh, &adm5120_txhit,
ADM5120_DMA_TXH);
if (intreg & ADM5120_INT_TXL)
adm5120_tx(adm5120_dma_txl, adm5120_skb_txl, &adm5120_txlit,
ADM5120_DMA_TXL);
adm5120_set_reg(ADM5120_INT_MASK,
adm5120_get_reg(ADM5120_INT_MASK) & ~ADM5120_INTHANDLE);
return IRQ_HANDLED;
}
static void adm5120_set_vlan(char *matrix)
{
unsigned long val;
val = matrix[0] + (matrix[1]<<8) + (matrix[2]<<16) + (matrix[3]<<24);
adm5120_set_reg(ADM5120_VLAN_GI, val);
val = matrix[4] + (matrix[5]<<8);
adm5120_set_reg(ADM5120_VLAN_GII, val);
}
static int adm5120_sw_open(struct net_device *dev)
{
if (!adm5120_if_open++)
adm5120_set_reg(ADM5120_INT_MASK,
adm5120_get_reg(ADM5120_INT_MASK) & ~ADM5120_INTHANDLE);
netif_start_queue(dev);
return 0;
}
static int adm5120_sw_stop(struct net_device *dev)
{
netif_stop_queue(dev);
if (!--adm5120_if_open)
adm5120_set_reg(ADM5120_INT_MASK,
adm5120_get_reg(ADM5120_INT_MASK) | ADM5120_INTMASKALL);
return 0;
}
static int adm5120_sw_tx(struct sk_buff *skb, struct net_device *dev)
{
struct adm5120_dma *dma = adm5120_dma_txl;
struct sk_buff **skbl = adm5120_skb_txl;
struct adm5120_sw *priv = netdev_priv(dev);
int *index = &adm5120_txli;
int num = ADM5120_DMA_TXL;
int trigger = ADM5120_SEND_TRIG_L;
dev->trans_start = jiffies;
if (dma[*index].data & ADM5120_DMA_OWN) {
dev_kfree_skb(skb);
priv->stats.tx_dropped++;
return 0;
}
dma[*index].data = ADM5120_DMA_ADDR(skb->data) | ADM5120_DMA_OWN;
if (*index == num-1)
dma[*index].data |= ADM5120_DMA_RINGEND;
dma[*index].status =
((skb->len<ETH_ZLEN?ETH_ZLEN:skb->len) << ADM5120_DMA_LENSHIFT) |
(0x1 << priv->port);
dma[*index].len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
skbl[*index]=skb;
if (++*index == num)
*index = 0;
adm5120_set_reg(ADM5120_SEND_TRIG, trigger);
return 0;
}
static void adm5120_tx_timeout(struct net_device *dev)
{
netif_wake_queue(dev);
}
static struct net_device_stats *adm5120_sw_stats(struct net_device *dev)
{
return &((struct adm5120_sw *)netdev_priv(dev))->stats;
}
static void adm5120_set_multicast_list(struct net_device *dev)
{
struct adm5120_sw *priv = netdev_priv(dev);
int portmask;
portmask = vlan_matrix[priv->port] & 0x3f;
if (dev->flags & IFF_PROMISC)
adm5120_set_reg(ADM5120_CPUP_CONF,
adm5120_get_reg(ADM5120_CPUP_CONF) &
~((portmask << ADM5120_DISUNSHIFT) & ADM5120_DISUNALL));
else
adm5120_set_reg(ADM5120_CPUP_CONF,
adm5120_get_reg(ADM5120_CPUP_CONF) |
(portmask << ADM5120_DISUNSHIFT));
if (dev->flags & IFF_PROMISC || dev->flags & IFF_ALLMULTI ||
dev->mc_count)
adm5120_set_reg(ADM5120_CPUP_CONF,
adm5120_get_reg(ADM5120_CPUP_CONF) &
~((portmask << ADM5120_DISMCSHIFT) & ADM5120_DISMCALL));
else
adm5120_set_reg(ADM5120_CPUP_CONF,
adm5120_get_reg(ADM5120_CPUP_CONF) |
(portmask << ADM5120_DISMCSHIFT));
}
static void adm5120_write_mac(struct net_device *dev)
{
struct adm5120_sw *priv = netdev_priv(dev);
unsigned char *mac = dev->dev_addr;
adm5120_set_reg(ADM5120_MAC_WT1,
mac[2] | (mac[3]<<8) | (mac[4]<<16) | (mac[5]<<24));
adm5120_set_reg(ADM5120_MAC_WT0, (priv->port<<3) |
(mac[0]<<16) | (mac[1]<<24) | ADM5120_MAC_WRITE | ADM5120_VLAN_EN);
while (!(adm5120_get_reg(ADM5120_MAC_WT0) & ADM5120_MAC_WRITE_DONE));
}
static int adm5120_sw_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
adm5120_write_mac(dev);
return 0;
}
static int adm5120_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
int err;
struct adm5120_sw_info info;
struct adm5120_sw *priv = netdev_priv(dev);
switch(cmd) {
case SIOCGADMINFO:
info.magic = 0x5120;
info.ports = adm5120_nrdevs;
info.vlan = priv->port;
err = copy_to_user(rq->ifr_data, &info, sizeof(info));
if (err)
return -EFAULT;
break;
case SIOCSMATRIX:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
err = copy_from_user(vlan_matrix, rq->ifr_data,
sizeof(vlan_matrix));
if (err)
return -EFAULT;
adm5120_set_vlan(vlan_matrix);
break;
case SIOCGMATRIX:
err = copy_to_user(rq->ifr_data, vlan_matrix,
sizeof(vlan_matrix));
if (err)
return -EFAULT;
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static void adm5120_dma_tx_init(struct adm5120_dma *dma, struct sk_buff **skb,
int num)
{
memset(dma, 0, sizeof(struct adm5120_dma)*num);
dma[num-1].data |= ADM5120_DMA_RINGEND;
memset(skb, 0, sizeof(struct skb*)*num);
}
static void adm5120_dma_rx_init(struct adm5120_dma *dma, struct sk_buff **skb,
int num)
{
int i;
memset(dma, 0, sizeof(struct adm5120_dma)*num);
for (i=0; i<num; i++) {
skb[i] = dev_alloc_skb(ADM5120_DMA_RXSIZE+16);
if (!skb[i]) {
i=num;
break;
}
skb_reserve(skb[i], 2);
dma[i].data = ADM5120_DMA_ADDR(skb[i]->data) | ADM5120_DMA_OWN;
dma[i].cntl = 0;
dma[i].len = ADM5120_DMA_RXSIZE;
dma[i].status = 0;
}
dma[i-1].data |= ADM5120_DMA_RINGEND;
}
static int __init adm5120_sw_init(void)
{
int i, err;
struct net_device *dev;
err = request_irq(SW_IRQ, adm5120_sw_irq, 0, "ethernet switch", NULL);
if (err)
goto out;
/* MII port? */
if (adm5120_get_reg(ADM5120_CODE) & ADM5120_CODE_PQFP)
adm5120_nrdevs = 5;
/* CFE based devices only have two enet ports */
else if (adm5120_info.boot_loader == BOOT_LOADER_CFE)
adm5120_nrdevs = 2;
else
adm5120_nrdevs = 6;
adm5120_set_reg(ADM5120_CPUP_CONF,
ADM5120_DISCCPUPORT | ADM5120_CRC_PADDING |
ADM5120_DISUNALL | ADM5120_DISMCALL);
adm5120_set_reg(ADM5120_PORT_CONF0, ADM5120_ENMC | ADM5120_ENBP);
adm5120_set_reg(ADM5120_PHY_CNTL2, adm5120_get_reg(ADM5120_PHY_CNTL2) |
ADM5120_AUTONEG | ADM5120_NORMAL | ADM5120_AUTOMDIX);
adm5120_set_reg(ADM5120_PHY_CNTL3, adm5120_get_reg(ADM5120_PHY_CNTL3) |
ADM5120_PHY_NTH);
adm5120_set_reg(ADM5120_INT_MASK, ADM5120_INTMASKALL);
adm5120_set_reg(ADM5120_INT_ST, ADM5120_INTMASKALL);
adm5120_dma_txh = (void *)KSEG1ADDR((u32)adm5120_dma_txh_v);
adm5120_dma_txl = (void *)KSEG1ADDR((u32)adm5120_dma_txl_v);
adm5120_dma_rxh = (void *)KSEG1ADDR((u32)adm5120_dma_rxh_v);
adm5120_dma_rxl = (void *)KSEG1ADDR((u32)adm5120_dma_rxl_v);
adm5120_dma_tx_init(adm5120_dma_txh, adm5120_skb_txh, ADM5120_DMA_TXH);
adm5120_dma_tx_init(adm5120_dma_txl, adm5120_skb_txl, ADM5120_DMA_TXL);
adm5120_dma_rx_init(adm5120_dma_rxh, adm5120_skb_rxh, ADM5120_DMA_RXH);
adm5120_dma_rx_init(adm5120_dma_rxl, adm5120_skb_rxl, ADM5120_DMA_RXL);
adm5120_set_reg(ADM5120_SEND_HBADDR, KSEG1ADDR(adm5120_dma_txh));
adm5120_set_reg(ADM5120_SEND_LBADDR, KSEG1ADDR(adm5120_dma_txl));
adm5120_set_reg(ADM5120_RECEIVE_HBADDR, KSEG1ADDR(adm5120_dma_rxh));
adm5120_set_reg(ADM5120_RECEIVE_LBADDR, KSEG1ADDR(adm5120_dma_rxl));
adm5120_set_vlan(vlan_matrix);
for (i=0; i<adm5120_nrdevs; i++) {
adm5120_devs[i] = alloc_etherdev(sizeof(struct adm5120_sw));
if (!adm5120_devs[i]) {
err = -ENOMEM;
goto out_int;
}
dev = adm5120_devs[i];
SET_MODULE_OWNER(dev);
memset(netdev_priv(dev), 0, sizeof(struct adm5120_sw));
((struct adm5120_sw*)netdev_priv(dev))->port = i;
dev->base_addr = SW_BASE;
dev->irq = SW_IRQ;
dev->open = adm5120_sw_open;
dev->hard_start_xmit = adm5120_sw_tx;
dev->stop = adm5120_sw_stop;
dev->get_stats = adm5120_sw_stats;
dev->set_multicast_list = adm5120_set_multicast_list;
dev->do_ioctl = adm5120_do_ioctl;
dev->tx_timeout = adm5120_tx_timeout;
dev->watchdog_timeo = ETH_TX_TIMEOUT;
dev->set_mac_address = adm5120_sw_set_mac_address;
/* HACK alert!!! In the original admtek driver it is asumed
that you can read the MAC addressess from flash, but edimax
decided to leave that space intentionally blank...
*/
memcpy(dev->dev_addr, "\x00\x50\xfc\x11\x22\x01", 6);
dev->dev_addr[5] += i;
adm5120_write_mac(dev);
if ((err = register_netdev(dev))) {
free_netdev(dev);
goto out_int;
}
printk(KERN_INFO "%s: ADM5120 switch port%d\n", dev->name, i);
}
adm5120_set_reg(ADM5120_CPUP_CONF,
ADM5120_CRC_PADDING | ADM5120_DISUNALL | ADM5120_DISMCALL);
return 0;
out_int:
/* Undo everything that did succeed */
for (; i; i--) {
unregister_netdev(adm5120_devs[i-1]);
free_netdev(adm5120_devs[i-1]);
}
free_irq(SW_IRQ, NULL);
out:
printk(KERN_ERR "ADM5120 Ethernet switch init failed\n");
return err;
}
static void __exit adm5120_sw_exit(void)
{
int i;
for (i = 0; i < adm5120_nrdevs; i++) {
unregister_netdev(adm5120_devs[i]);
free_netdev(adm5120_devs[i-1]);
}
free_irq(SW_IRQ, NULL);
for (i = 0; i < ADM5120_DMA_RXH; i++) {
if (!adm5120_skb_rxh[i])
break;
kfree_skb(adm5120_skb_rxh[i]);
}
for (i = 0; i < ADM5120_DMA_RXL; i++) {
if (!adm5120_skb_rxl[i])
break;
kfree_skb(adm5120_skb_rxl[i]);
}
}
module_init(adm5120_sw_init);
module_exit(adm5120_sw_exit);

View file

@ -0,0 +1,106 @@
/*
* Defines for ADM5120 built in ethernet switch driver
*
* Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005
*
* Values come from ADM5120 datasheet and original ADMtek 2.4 driver,
* Copyright ADMtek Inc.
*/
#ifndef _INCLUDE_ADM5120SW_H_
#define _INCLUDE_ADM5120SW_H_
#define SW_BASE KSEG1ADDR(0x12000000)
#define SW_DEVS 6
#define SW_IRQ 9
#define ETH_TX_TIMEOUT HZ/4
#define ETH_FCS 4;
#define ADM5120_CODE 0x00 /* CPU description */
#define ADM5120_CODE_PQFP 0x20000000 /* package type */
#define ADM5120_CPUP_CONF 0x24 /* CPU port config */
#define ADM5120_DISCCPUPORT 0x00000001 /* disable cpu port */
#define ADM5120_CRC_PADDING 0x00000002 /* software crc */
#define ADM5120_DISUNSHIFT 9
#define ADM5120_DISUNALL 0x00007e00 /* disable unknown from all */
#define ADM5120_DISMCSHIFT 16
#define ADM5120_DISMCALL 0x003f0000 /* disable multicast from all */
#define ADM5120_PORT_CONF0 0x28
#define ADM5120_ENMC 0x00003f00 /* Enable MC routing (ex cpu) */
#define ADM5120_ENBP 0x003f0000 /* Enable Back Pressure */
#define ADM5120_VLAN_GI 0x40 /* VLAN settings */
#define ADM5120_VLAN_GII 0x44
#define ADM5120_SEND_TRIG 0x48
#define ADM5120_SEND_TRIG_L 0x00000001
#define ADM5120_SEND_TRIG_H 0x00000002
#define ADM5120_MAC_WT0 0x58
#define ADM5120_MAC_WRITE 0x00000001
#define ADM5120_MAC_WRITE_DONE 0x00000002
#define ADM5120_VLAN_EN 0x00000040
#define ADM5120_MAC_WT1 0x5c
#define ADM5120_PHY_CNTL2 0x7c
#define ADM5120_AUTONEG 0x0000001f /* Auto negotiate */
#define ADM5120_NORMAL 0x01f00000 /* PHY normal mode */
#define ADM5120_AUTOMDIX 0x3e000000 /* Auto MDIX */
#define ADM5120_PHY_CNTL3 0x80
#define ADM5120_PHY_NTH 0x00000400
#define ADM5120_INT_ST 0xb0
#define ADM5120_INT_RXH 0x0000004
#define ADM5120_INT_RXL 0x0000008
#define ADM5120_INT_HFULL 0x0000010
#define ADM5120_INT_LFULL 0x0000020
#define ADM5120_INT_TXH 0x0000001
#define ADM5120_INT_TXL 0x0000002
#define ADM5120_INT_MASK 0xb4
#define ADM5120_INTMASKALL 0x1FDEFFF /* All interrupts */
#define ADM5120_INTHANDLE (ADM5120_INT_RXH | ADM5120_INT_RXL | \
ADM5120_INT_HFULL | ADM5120_INT_LFULL | \
ADM5120_INT_TXH | ADM5120_INT_TXL)
#define ADM5120_SEND_HBADDR 0xd0
#define ADM5120_SEND_LBADDR 0xd4
#define ADM5120_RECEIVE_HBADDR 0xd8
#define ADM5120_RECEIVE_LBADDR 0xdc
struct adm5120_dma {
u32 data;
u32 cntl;
u32 len;
u32 status;
} __attribute__ ((packed));
#define ADM5120_DMA_MASK 0x01ffffff
#define ADM5120_DMA_OWN 0x80000000 /* buffer owner */
#define ADM5120_DMA_RINGEND 0x10000000 /* Last in DMA ring */
#define ADM5120_DMA_ADDR(ptr) ((u32)(ptr) & ADM5120_DMA_MASK)
#define ADM5120_DMA_PORTID 0x00007000
#define ADM5120_DMA_PORTSHIFT 12
#define ADM5120_DMA_LEN 0x07ff0000
#define ADM5120_DMA_LENSHIFT 16
#define ADM5120_DMA_FCSERR 0x00000008
#define ADM5120_DMA_TXH 16
#define ADM5120_DMA_TXL 64
#define ADM5120_DMA_RXH 16
#define ADM5120_DMA_RXL 8
#define ADM5120_DMA_RXSIZE 1550
#define ADM5120_DMA_EXTRA 20
struct adm5120_sw {
int port;
struct net_device_stats stats;
};
#define SIOCSMATRIX SIOCDEVPRIVATE
#define SIOCGMATRIX SIOCDEVPRIVATE+1
#define SIOCGADMINFO SIOCDEVPRIVATE+2
struct adm5120_sw_info {
u16 magic;
u16 ports;
u16 vlan;
};
#endif /* _INCLUDE_ADM5120SW_H_ */

View file

@ -0,0 +1,524 @@
/*
* Serial driver for ADM5120 SoC
*
* Derived from drivers/serial/uart00.c
* Copyright 2001 Altera Corporation
*
* Some pieces are derived from the ADMtek 2.4 serial driver.
* Copyright (C) ADMtek Incorporated, 2003
* daniell@admtek.com.tw
* Which again was derived from drivers/char/serial.c
* Copyright (C) Linus Torvalds et al.
*
* Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005
*/
#include <linux/autoconf.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/console.h>
#define ADM5120_UART_BASE0 0x12600000
#define ADM5120_UART_BASE1 0x12800000
#define ADM5120_UART_SIZE 0x20
#define ADM5120_UART_IRQ0 1
#define ADM5120_UART_IRQ1 2
#define ADM5120_UART_REG(base, reg) \
(*(volatile u32 *)KSEG1ADDR((base)+(reg)))
#define ADM5120_UARTCLK_FREQ 62500000
#define ADM5120_UART_BAUDDIV(rate) ((unsigned long)(ADM5120_UARTCLK_FREQ/(16*(rate)) - 1))
#define ADM5120_UART_BAUD115200 ADM5120_UART_BAUDDIV(115200)
#define ADM5120_UART_DATA 0x00
#define ADM5120_UART_RS 0x04
#define ADM5120_UART_LCR_H 0x08
#define ADM5120_UART_LCR_M 0x0c
#define ADM5120_UART_LCR_L 0x10
#define ADM5120_UART_CR 0x14
#define ADM5120_UART_FR 0x18
#define ADM5120_UART_IR 0x1c
#define ADM5120_UART_FE 0x01
#define ADM5120_UART_PE 0x02
#define ADM5120_UART_BE 0x04
#define ADM5120_UART_OE 0x08
#define ADM5120_UART_ERR 0x0f
#define ADM5120_UART_FIFO_EN 0x10
#define ADM5120_UART_EN 0x01
#define ADM5120_UART_TIE 0x20
#define ADM5120_UART_RIE 0x50
#define ADM5120_UART_IE 0x78
#define ADM5120_UART_CTS 0x01
#define ADM5120_UART_DSR 0x02
#define ADM5120_UART_DCD 0x04
#define ADM5120_UART_TXFF 0x20
#define ADM5120_UART_TXFE 0x80
#define ADM5120_UART_RXFE 0x10
#define ADM5120_UART_BRK 0x01
#define ADM5120_UART_PEN 0x02
#define ADM5120_UART_EPS 0x04
#define ADM5120_UART_STP2 0x08
#define ADM5120_UART_W5 0x00
#define ADM5120_UART_W6 0x20
#define ADM5120_UART_W7 0x40
#define ADM5120_UART_W8 0x60
#define ADM5120_UART_MIS 0x01
#define ADM5120_UART_RIS 0x02
#define ADM5120_UART_TIS 0x04
#define ADM5120_UART_RTIS 0x08
static void adm5120ser_stop_tx(struct uart_port *port)
{
ADM5120_UART_REG(port->iobase, ADM5120_UART_CR) &= ~ADM5120_UART_TIE;
}
static void adm5120ser_irq_rx(struct uart_port *port)
{
struct tty_struct *tty = port->info->tty;
unsigned int status, ch, rds, flg, ignored = 0;
status = ADM5120_UART_REG(port->iobase, ADM5120_UART_FR);
while (!(status & ADM5120_UART_RXFE)) {
/*
* We need to read rds before reading the
* character from the fifo
*/
rds = ADM5120_UART_REG(port->iobase, ADM5120_UART_RS);
ch = ADM5120_UART_REG(port->iobase, ADM5120_UART_DATA);
port->icount.rx++;
if (tty->low_latency)
tty_flip_buffer_push(tty);
flg = TTY_NORMAL;
/*
* Note that the error handling code is
* out of the main execution path
*/
if (rds & ADM5120_UART_ERR)
goto handle_error;
if (uart_handle_sysrq_char(port, ch))
goto ignore_char;
error_return:
tty_insert_flip_char(tty, ch, flg);
ignore_char:
status = ADM5120_UART_REG(port->iobase, ADM5120_UART_FR);
}
out:
tty_flip_buffer_push(tty);
return;
handle_error:
ADM5120_UART_REG(port->iobase, ADM5120_UART_RS) = 0xff;
if (rds & ADM5120_UART_BE) {
port->icount.brk++;
if (uart_handle_break(port))
goto ignore_char;
} else if (rds & ADM5120_UART_PE)
port->icount.parity++;
else if (rds & ADM5120_UART_FE)
port->icount.frame++;
if (rds & ADM5120_UART_OE)
port->icount.overrun++;
if (rds & port->ignore_status_mask) {
if (++ignored > 100)
goto out;
goto ignore_char;
}
rds &= port->read_status_mask;
if (rds & ADM5120_UART_BE)
flg = TTY_BREAK;
else if (rds & ADM5120_UART_PE)
flg = TTY_PARITY;
else if (rds & ADM5120_UART_FE)
flg = TTY_FRAME;
if (rds & ADM5120_UART_OE) {
/*
* CHECK: does overrun affect the current character?
* ASSUMPTION: it does not.
*/
tty_insert_flip_char(tty, ch, flg);
ch = 0;
flg = TTY_OVERRUN;
}
#ifdef CONFIG_MAGIC_SYSRQ
port->sysrq = 0;
#endif
goto error_return;
}
static void adm5120ser_irq_tx(struct uart_port *port)
{
struct circ_buf *xmit = &port->info->xmit;
int count;
if (port->x_char) {
ADM5120_UART_REG(port->iobase, ADM5120_UART_DATA) =
port->x_char;
port->icount.tx++;
port->x_char = 0;
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
adm5120ser_stop_tx(port);
return;
}
count = port->fifosize >> 1;
do {
ADM5120_UART_REG(port->iobase, ADM5120_UART_DATA) =
xmit->buf[xmit->tail];
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (uart_circ_empty(xmit))
adm5120ser_stop_tx(port);
}
static void adm5120ser_irq_modem(struct uart_port *port)
{
unsigned int status;
status = ADM5120_UART_REG(port->iobase, ADM5120_UART_FR);
if (status & ADM5120_UART_DCD)
uart_handle_dcd_change(port, status & ADM5120_UART_DCD);
if (status & ADM5120_UART_DSR)
port->icount.dsr++;
if (status & ADM5120_UART_CTS)
uart_handle_cts_change(port, status & ADM5120_UART_CTS);
wake_up_interruptible(&port->info->delta_msr_wait);
}
static irqreturn_t adm5120ser_irq(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
unsigned long ir = ADM5120_UART_REG(port->iobase, ADM5120_UART_IR);
if (ir & (ADM5120_UART_RIS | ADM5120_UART_RTIS))
adm5120ser_irq_rx(port);
if (ir & ADM5120_UART_TIS)
adm5120ser_irq_tx(port);
if (ir & ADM5120_UART_MIS) {
adm5120ser_irq_modem(port);
ADM5120_UART_REG(port->iobase, ADM5120_UART_IR) = 0xff;
}
return IRQ_HANDLED;
}
static unsigned int adm5120ser_tx_empty(struct uart_port *port)
{
unsigned int fr = ADM5120_UART_REG(port->iobase, ADM5120_UART_FR);
return (fr & ADM5120_UART_TXFE) ? TIOCSER_TEMT : 0;
}
static void adm5120ser_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}
static unsigned int adm5120ser_get_mctrl(struct uart_port *port)
{
unsigned int result = 0;
unsigned int fr = ADM5120_UART_REG(port->iobase, ADM5120_UART_FR);
if (fr & ADM5120_UART_CTS)
result |= TIOCM_CTS;
if (fr & ADM5120_UART_DSR)
result |= TIOCM_DSR;
if (fr & ADM5120_UART_DCD)
result |= TIOCM_CAR;
return result;
}
static void adm5120ser_start_tx(struct uart_port *port)
{
ADM5120_UART_REG(port->iobase, ADM5120_UART_CR) |= ADM5120_UART_TIE;
}
static void adm5120ser_stop_rx(struct uart_port *port)
{
ADM5120_UART_REG(port->iobase, ADM5120_UART_CR) &= ~ADM5120_UART_RIE;
}
static void adm5120ser_enable_ms(struct uart_port *port)
{
}
static void adm5120ser_break_ctl(struct uart_port *port, int break_state)
{
unsigned long flags;
unsigned long lcrh;
spin_lock_irqsave(&port->lock, flags);
lcrh = ADM5120_UART_REG(port->iobase, ADM5120_UART_LCR_H);
if (break_state == -1)
lcrh |= ADM5120_UART_BRK;
else
lcrh &= ~ADM5120_UART_BRK;
ADM5120_UART_REG(port->iobase, ADM5120_UART_LCR_H) = lcrh;
spin_unlock_irqrestore(&port->lock, flags);
}
static int adm5120ser_startup(struct uart_port *port)
{
int ret;
ret = request_irq(port->irq, adm5120ser_irq, 0, "ADM5120 UART", port);
if (ret) {
printk(KERN_ERR "Couldn't get irq %d\n", port->irq);
return ret;
}
ADM5120_UART_REG(port->iobase, ADM5120_UART_LCR_H) |=
ADM5120_UART_FIFO_EN;
ADM5120_UART_REG(port->iobase, ADM5120_UART_CR) |=
ADM5120_UART_EN | ADM5120_UART_IE;
return 0;
}
static void adm5120ser_shutdown(struct uart_port *port)
{
ADM5120_UART_REG(port->iobase, ADM5120_UART_CR) &= ~ADM5120_UART_IE;
free_irq(port->irq, port);
}
static void adm5120ser_set_termios(struct uart_port *port,
struct termios *termios, struct termios *old)
{
unsigned int baud, quot, lcrh;
unsigned long flags;
termios->c_cflag |= CREAD;
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
lcrh = ADM5120_UART_FIFO_EN;
switch (termios->c_cflag & CSIZE) {
case CS5:
lcrh |= ADM5120_UART_W5;
break;
case CS6:
lcrh |= ADM5120_UART_W6;
break;
case CS7:
lcrh |= ADM5120_UART_W7;
break;
default:
lcrh |= ADM5120_UART_W8;
break;
}
if (termios->c_cflag & CSTOPB)
lcrh |= ADM5120_UART_STP2;
if (termios->c_cflag & PARENB) {
lcrh |= ADM5120_UART_PEN;
if (!(termios->c_cflag & PARODD))
lcrh |= ADM5120_UART_EPS;
}
spin_lock_irqsave(port->lock, flags);
ADM5120_UART_REG(port->iobase, ADM5120_UART_LCR_H) = lcrh;
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
port->read_status_mask = ADM5120_UART_OE;
if (termios->c_iflag & INPCK)
port->read_status_mask |= ADM5120_UART_FE | ADM5120_UART_PE;
if (termios->c_iflag & (BRKINT | PARMRK))
port->read_status_mask |= ADM5120_UART_BE;
/*
* Characters to ignore
*/
port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= ADM5120_UART_FE | ADM5120_UART_PE;
if (termios->c_iflag & IGNBRK) {
port->ignore_status_mask |= ADM5120_UART_BE;
/*
* If we're ignoring parity and break indicators,
* ignore overruns to (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= ADM5120_UART_OE;
}
quot = ADM5120_UART_BAUD115200;
ADM5120_UART_REG(port->iobase, ADM5120_UART_LCR_L) = quot & 0xff;
ADM5120_UART_REG(port->iobase, ADM5120_UART_LCR_M) = quot >> 8;
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *adm5120ser_type(struct uart_port *port)
{
return port->type == PORT_ADM5120 ? "ADM5120" : NULL;
}
static void adm5120ser_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE)
port->type = PORT_ADM5120;
}
static void adm5120ser_release_port(struct uart_port *port)
{
release_mem_region(port->iobase, ADM5120_UART_SIZE);
}
static int adm5120ser_request_port(struct uart_port *port)
{
return request_mem_region(port->iobase, ADM5120_UART_SIZE,
"adm5120-uart") != NULL ? 0 : -EBUSY;
}
static struct uart_ops adm5120ser_ops = {
.tx_empty = adm5120ser_tx_empty,
.set_mctrl = adm5120ser_set_mctrl,
.get_mctrl = adm5120ser_get_mctrl,
.stop_tx = adm5120ser_stop_tx,
.start_tx = adm5120ser_start_tx,
.stop_rx = adm5120ser_stop_rx,
.enable_ms = adm5120ser_enable_ms,
.break_ctl = adm5120ser_break_ctl,
.startup = adm5120ser_startup,
.shutdown = adm5120ser_shutdown,
.set_termios = adm5120ser_set_termios,
.type = adm5120ser_type,
.config_port = adm5120ser_config_port,
.release_port = adm5120ser_release_port,
.request_port = adm5120ser_request_port,
};
static void adm5120console_put(const char c)
{
while ((ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_FR) &
ADM5120_UART_TXFF) != 0);
ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_DATA) = c;
}
static void adm5120console_write(struct console *con, const char *s,
unsigned int count)
{
while (count--) {
if (*s == '\n')
adm5120console_put('\r');
adm5120console_put(*s);
s++;
}
}
static int __init adm5120console_setup(struct console *con, char *options)
{
/* Set to 115200 baud, 8N1 and enable FIFO */
ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_LCR_L) =
ADM5120_UART_BAUD115200 & 0xff;
ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_LCR_M) =
ADM5120_UART_BAUD115200 >> 8;
ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_LCR_H) =
ADM5120_UART_W8 | ADM5120_UART_FIFO_EN;
/* Enable port */
ADM5120_UART_REG(ADM5120_UART_BASE0, ADM5120_UART_CR) =
ADM5120_UART_EN;
return 0;
}
static struct uart_driver adm5120ser_reg;
static struct console adm5120_serconsole = {
.name = "ttyS",
.write = adm5120console_write,
.device = uart_console_device,
.setup = adm5120console_setup,
.flags = CON_PRINTBUFFER,
.cflag = B115200 | CS8 | CREAD,
.index = 0,
.data = &adm5120ser_reg,
};
static int __init adm5120console_init(void)
{
register_console(&adm5120_serconsole);
return 0;
}
console_initcall(adm5120console_init);
static struct uart_port adm5120ser_ports[] = {
{
.iobase = ADM5120_UART_BASE0,
.irq = ADM5120_UART_IRQ0,
.uartclk = ADM5120_UARTCLK_FREQ,
.fifosize = 16,
.ops = &adm5120ser_ops,
.line = 0,
.flags = ASYNC_BOOT_AUTOCONF,
},
#if (CONFIG_ADM5120_NR_UARTS > 1)
{
.iobase = ADM5120_UART_BASE1,
.irq = ADM5120_UART_IRQ1,
.uartclk = ADM5120_UARTCLK_FREQ,
.fifosize = 16,
.ops = &adm5120ser_ops,
.line = 1,
.flags = ASYNC_BOOT_AUTOCONF,
},
#endif
};
static struct uart_driver adm5120ser_reg = {
.owner = THIS_MODULE,
.driver_name = "ttyS",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
.nr = CONFIG_ADM5120_NR_UARTS,
.cons = &adm5120_serconsole,
};
static int __init adm5120ser_init(void)
{
int ret, i;
ret = uart_register_driver(&adm5120ser_reg);
if (!ret) {
for (i = 0; i < CONFIG_ADM5120_NR_UARTS; i++)
uart_add_one_port(&adm5120ser_reg, &adm5120ser_ports[i]);
}
return ret;
}
__initcall(adm5120ser_init);

View file

@ -0,0 +1,790 @@
/*
* HCD driver for ADM5120 SoC
*
* Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org)
*
* Based on the ADMtek 2.4 driver
* (C) Copyright 2003 Junius Chen <juniusc@admtek.com.tw>
* Which again was based on the ohci and uhci drivers.
*/
#include <linux/autoconf.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/usb.h>
#include <linux/platform_device.h>
#include "../core/hcd.h"
MODULE_DESCRIPTION("ADM5120 USB Host Controller Driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jeroen Vreeken (pe1rxq@amsat.org)");
#define ADMHCD_REG_CONTROL 0x00
#define ADMHCD_REG_INTSTATUS 0x04
#define ADMHCD_REG_INTENABLE 0x08
#define ADMHCD_REG_HOSTCONTROL 0x10
#define ADMHCD_REG_FMINTERVAL 0x18
#define ADMHCD_REG_FMNUMBER 0x1c
#define ADMHCD_REG_LSTHRESH 0x70
#define ADMHCD_REG_RHDESCR 0x74
#define ADMHCD_REG_PORTSTATUS0 0x78
#define ADMHCD_REG_PORTSTATUS1 0x7c
#define ADMHCD_REG_HOSTHEAD 0x80
#define ADMHCD_NUMPORTS 2
#define ADMHCD_HOST_EN 0x00000001 /* Host enable */
#define ADMHCD_SW_INTREQ 0x00000002 /* request software int */
#define ADMHCD_SW_RESET 0x00000008 /* Reset */
#define ADMHCD_INT_TD 0x00100000 /* TD completed */
#define ADMHCD_INT_SW 0x20000000 /* software interrupt */
#define ADMHCD_INT_FATAL 0x40000000 /* Fatal interrupt */
#define ADMHCD_INT_ACT 0x80000000 /* Interrupt active */
#define ADMHCD_STATE_RST 0x00000000 /* bus state reset */
#define ADMHCD_STATE_RES 0x00000001 /* bus state resume */
#define ADMHCD_STATE_OP 0x00000002 /* bus state operational */
#define ADMHCD_STATE_SUS 0x00000003 /* bus state suspended */
#define ADMHCD_DMA_EN 0x00000004 /* enable dma engine */
#define ADMHCD_NPS 0x00000020 /* No Power Switch */
#define ADMHCD_LPSC 0x04000000 /* Local power switch change */
#define ADMHCD_CCS 0x00000001 /* current connect status */
#define ADMHCD_PES 0x00000002 /* port enable status */
#define ADMHCD_PSS 0x00000004 /* port suspend status */
#define ADMHCD_POCI 0x00000008 /* port overcurrent indicator */
#define ADMHCD_PRS 0x00000010 /* port reset status */
#define ADMHCD_PPS 0x00000100 /* port power status */
#define ADMHCD_LSDA 0x00000200 /* low speed device attached */
#define ADMHCD_CSC 0x00010000 /* connect status change */
#define ADMHCD_PESC 0x00020000 /* enable status change */
#define ADMHCD_PSSC 0x00040000 /* suspend status change */
#define ADMHCD_OCIC 0x00080000 /* overcurrent change*/
#define ADMHCD_PRSC 0x00100000 /* reset status change */
struct admhcd_ed {
/* Don't change first four, they used for DMA */
u32 control;
struct admhcd_td *tail;
struct admhcd_td *head;
struct admhcd_ed *next;
/* the rest is for the driver only: */
struct admhcd_td *cur;
struct usb_host_endpoint *ep;
struct urb *urb;
struct admhcd_ed *real;
} __attribute__ ((packed));
#define ADMHCD_ED_EPSHIFT 7 /* Shift for endpoint number */
#define ADMHCD_ED_INT 0x00000800 /* Is this an int endpoint */
#define ADMHCD_ED_SPEED 0x00002000 /* Is it a high speed dev? */
#define ADMHCD_ED_SKIP 0x00004000 /* Skip this ED */
#define ADMHCD_ED_FORMAT 0x00008000 /* Is this an isoc endpoint */
#define ADMHCD_ED_MAXSHIFT 16 /* Shift for max packet size */
struct admhcd_td {
/* Don't change first four, they are used for DMA */
u32 control;
u32 buffer;
u32 buflen;
struct admhcd_td *next;
/* the rest is for the driver only: */
struct urb *urb;
struct admhcd_td *real;
} __attribute__ ((packed));
#define ADMHCD_TD_OWN 0x80000000
#define ADMHCD_TD_TOGGLE 0x00000000
#define ADMHCD_TD_DATA0 0x01000000
#define ADMHCD_TD_DATA1 0x01800000
#define ADMHCD_TD_OUT 0x00200000
#define ADMHCD_TD_IN 0x00400000
#define ADMHCD_TD_SETUP 0x00000000
#define ADMHCD_TD_ISO 0x00010000
#define ADMHCD_TD_R 0x00040000
#define ADMHCD_TD_INTEN 0x00010000
static int admhcd_td_err[16] = {
0, /* No */
-EREMOTEIO, /* CRC */
-EREMOTEIO, /* bit stuff */
-EREMOTEIO, /* data toggle */
-EPIPE, /* stall */
-ETIMEDOUT, /* timeout */
-EPROTO, /* pid err */
-EPROTO, /* unexpected pid */
-EREMOTEIO, /* data overrun */
-EREMOTEIO, /* data underrun */
-ETIMEDOUT, /* 1010 */
-ETIMEDOUT, /* 1011 */
-EREMOTEIO, /* buffer overrun */
-EREMOTEIO, /* buffer underrun */
-ETIMEDOUT, /* 1110 */
-ETIMEDOUT, /* 1111 */
};
#define ADMHCD_TD_ERRMASK 0x38000000
#define ADMHCD_TD_ERRSHIFT 27
#define TD(td) ((struct admhcd_td *)(((u32)(td)) & ~0xf))
#define ED(ed) ((struct admhcd_ed *)(((u32)(ed)) & ~0xf))
struct admhcd {
u32 base;
u32 dma_en;
spinlock_t lock;
unsigned long flags;
};
#define hcd_to_admhcd(hcd) ((struct admhcd *)(hcd)->hcd_priv)
static char hcd_name[] = "adm5120-hcd";
static u32 admhcd_reg_get(struct admhcd *ahcd, int reg)
{
return *(volatile u32 *)KSEG1ADDR(ahcd->base+reg);
}
static void admhcd_reg_set(struct admhcd *ahcd, int reg, u32 val)
{
*(volatile u32 *)KSEG1ADDR(ahcd->base+reg) = val;
}
static void admhcd_lock(struct admhcd *ahcd)
{
spin_lock_irqsave(&ahcd->lock, ahcd->flags);
ahcd->dma_en = admhcd_reg_get(ahcd, ADMHCD_REG_HOSTCONTROL) &
ADMHCD_DMA_EN;
admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP);
}
static void admhcd_unlock(struct admhcd *ahcd)
{
admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL,
ADMHCD_STATE_OP | ahcd->dma_en);
spin_unlock_irqrestore(&ahcd->lock, ahcd->flags);
}
static struct admhcd_td *admhcd_td_alloc(struct admhcd_ed *ed, struct urb *urb)
{
struct admhcd_td *tdn, *td;
tdn = kmalloc(sizeof(struct admhcd_td), GFP_ATOMIC);
if (!tdn)
return NULL;
tdn->real = tdn;
tdn = (struct admhcd_td *)KSEG1ADDR(tdn);
memset(tdn, 0, sizeof(struct admhcd_td));
if (ed->cur == NULL) {
ed->cur = tdn;
ed->head = tdn;
ed->tail = tdn;
td = tdn;
} else {
/* Supply back the old tail and link in new td as tail */
td = TD(ed->tail);
TD(ed->tail)->next = tdn;
ed->tail = tdn;
}
td->urb = urb;
return td;
}
static void admhcd_td_free(struct admhcd_ed *ed, struct urb *urb)
{
struct admhcd_td *td, **tdp;
if (urb == NULL)
ed->control |= ADMHCD_ED_SKIP;
tdp = &ed->cur;
td = ed->cur;
do {
if (td->urb == urb)
break;
tdp = &td->next;
td = TD(td->next);
} while (td);
while (td && td->urb == urb) {
*tdp = TD(td->next);
kfree(td->real);
td = *tdp;
}
}
/* Find an endpoint's descriptor, if needed allocate a new one and link it
in the DMA chain
*/
static struct admhcd_ed *admhcd_get_ed(struct admhcd *ahcd,
struct usb_host_endpoint *ep, struct urb *urb)
{
struct admhcd_ed *hosthead;
struct admhcd_ed *found = NULL, *ed = NULL;
unsigned int pipe = urb->pipe;
admhcd_lock(ahcd);
hosthead = (struct admhcd_ed *)admhcd_reg_get(ahcd, ADMHCD_REG_HOSTHEAD);
if (hosthead) {
for (ed = hosthead;; ed = ED(ed->next)) {
if (ed->ep == ep) {
found = ed;
break;
}
if (ED(ed->next) == hosthead)
break;
}
}
if (!found) {
found = kmalloc(sizeof(struct admhcd_ed), GFP_ATOMIC);
if (!found)
goto out;
memset(found, 0, sizeof(struct admhcd_ed));
found->real = found;
found->ep = ep;
found = (struct admhcd_ed *)KSEG1ADDR(found);
found->control = usb_pipedevice(pipe) |
(usb_pipeendpoint(pipe) << ADMHCD_ED_EPSHIFT) |
(usb_pipeint(pipe) ? ADMHCD_ED_INT : 0) |
(urb->dev->speed == USB_SPEED_FULL ? ADMHCD_ED_SPEED : 0) |
(usb_pipeisoc(pipe) ? ADMHCD_ED_FORMAT : 0) |
(usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe)) << ADMHCD_ED_MAXSHIFT);
/* Alloc first dummy td */
admhcd_td_alloc(found, NULL);
if (hosthead) {
found->next = hosthead;
ed->next = found;
} else {
found->next = found;
admhcd_reg_set(ahcd, ADMHCD_REG_HOSTHEAD, (u32)found);
}
}
out:
admhcd_unlock(ahcd);
return found;
}
static struct admhcd_td *admhcd_td_fill(u32 control, struct admhcd_td *td,
dma_addr_t data, int len)
{
td->buffer = data;
td->buflen = len;
td->control = control;
return TD(td->next);
}
static void admhcd_ed_start(struct admhcd *ahcd, struct admhcd_ed *ed)
{
struct admhcd_td *td = ed->cur;
if (ed->urb)
return;
if (td->urb) {
ed->urb = td->urb;
while (1) {
td->control |= ADMHCD_TD_OWN;
if (TD(td->next)->urb != td->urb) {
td->buflen |= ADMHCD_TD_INTEN;
break;
}
td = TD(td->next);
}
}
ed->head = TD(ed->head);
ahcd->dma_en |= ADMHCD_DMA_EN;
}
static irqreturn_t adm5120hcd_irq(int irq, void *ptr, struct pt_regs *regs)
{
struct usb_hcd *hcd = (struct usb_hcd *)ptr;
struct admhcd *ahcd = hcd_to_admhcd(hcd);
u32 intstatus;
intstatus = admhcd_reg_get(ahcd, ADMHCD_REG_INTSTATUS);
if (intstatus & ADMHCD_INT_FATAL) {
admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS, ADMHCD_INT_FATAL);
//
}
if (intstatus & ADMHCD_INT_SW) {
admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS, ADMHCD_INT_SW);
//
}
if (intstatus & ADMHCD_INT_TD) {
struct admhcd_ed *ed, *head;
admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS, ADMHCD_INT_TD);
head = (struct admhcd_ed *)admhcd_reg_get(ahcd, ADMHCD_REG_HOSTHEAD);
ed = head;
if (ed) do {
/* Is it a finished TD? */
if (ed->urb && !(ed->cur->control & ADMHCD_TD_OWN)) {
struct admhcd_td *td;
int error;
td = ed->cur;
error = (td->control & ADMHCD_TD_ERRMASK) >>
ADMHCD_TD_ERRSHIFT;
ed->urb->status = admhcd_td_err[error];
admhcd_td_free(ed, ed->urb);
// Calculate real length!!!
ed->urb->actual_length = ed->urb->transfer_buffer_length;
ed->urb->hcpriv = NULL;
usb_hcd_giveback_urb(hcd, ed->urb);
ed->urb = NULL;
}
admhcd_ed_start(ahcd, ed);
ed = ED(ed->next);
} while (ed != head);
}
return IRQ_HANDLED;
}
static int admhcd_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep,
struct urb *urb, int mem_flags)
{
struct admhcd *ahcd = hcd_to_admhcd(hcd);
struct admhcd_ed *ed;
struct admhcd_td *td;
int size = 0, i, zero = 0, ret = 0;
unsigned int pipe = urb->pipe, toggle = 0;
dma_addr_t data = (dma_addr_t)urb->transfer_buffer;
int data_len = urb->transfer_buffer_length;
ed = admhcd_get_ed(ahcd, ep, urb);
if (!ed)
return -ENOMEM;
switch(usb_pipetype(pipe)) {
case PIPE_CONTROL:
size = 2;
case PIPE_INTERRUPT:
case PIPE_BULK:
default:
size += urb->transfer_buffer_length / 4096;
if (urb->transfer_buffer_length % 4096)
size++;
if (size == 0)
size++;
else if (urb->transfer_flags & URB_ZERO_PACKET &&
!(urb->transfer_buffer_length %
usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe)))) {
size++;
zero = 1;
}
break;
case PIPE_ISOCHRONOUS:
size = urb->number_of_packets;
break;
}
admhcd_lock(ahcd);
/* Remember the first td */
td = admhcd_td_alloc(ed, urb);
if (!td) {
ret = -ENOMEM;
goto out;
}
/* Allocate additionall tds first */
for (i = 1; i < size; i++) {
if (admhcd_td_alloc(ed, urb) == NULL) {
admhcd_td_free(ed, urb);
ret = -ENOMEM;
goto out;
}
}
if (usb_gettoggle(urb->dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
toggle = ADMHCD_TD_TOGGLE;
else {
toggle = ADMHCD_TD_DATA0;
usb_settoggle(urb->dev, usb_pipeendpoint(pipe),
usb_pipeout(pipe), 1);
}
switch(usb_pipetype(pipe)) {
case PIPE_CONTROL:
td = admhcd_td_fill(ADMHCD_TD_SETUP | ADMHCD_TD_DATA0,
td, (dma_addr_t)urb->setup_packet, 8);
while (data_len > 0) {
td = admhcd_td_fill(ADMHCD_TD_DATA1
| ADMHCD_TD_R |
(usb_pipeout(pipe) ?
ADMHCD_TD_OUT : ADMHCD_TD_IN), td,
data, data_len % 4097);
data_len -= 4096;
}
admhcd_td_fill(ADMHCD_TD_DATA1 | (usb_pipeout(pipe) ?
ADMHCD_TD_IN : ADMHCD_TD_OUT), td,
data, 0);
break;
case PIPE_INTERRUPT:
case PIPE_BULK:
//info ok for interrupt?
i = 0;
while(data_len > 4096) {
td = admhcd_td_fill((usb_pipeout(pipe) ?
ADMHCD_TD_OUT :
ADMHCD_TD_IN | ADMHCD_TD_R) |
(i ? ADMHCD_TD_TOGGLE : toggle), td,
data, 4096);
data += 4096;
data_len -= 4096;
i++;
}
td = admhcd_td_fill((usb_pipeout(pipe) ?
ADMHCD_TD_OUT : ADMHCD_TD_IN) |
(i ? ADMHCD_TD_TOGGLE : toggle), td, data, data_len);
i++;
if (zero)
admhcd_td_fill((usb_pipeout(pipe) ?
ADMHCD_TD_OUT : ADMHCD_TD_IN) |
(i ? ADMHCD_TD_TOGGLE : toggle), td, 0, 0);
break;
case PIPE_ISOCHRONOUS:
for (i = 0; i < urb->number_of_packets; i++) {
td = admhcd_td_fill(ADMHCD_TD_ISO |
((urb->start_frame + i) & 0xffff), td,
data + urb->iso_frame_desc[i].offset,
urb->iso_frame_desc[i].length);
}
break;
}
urb->hcpriv = ed;
admhcd_ed_start(ahcd, ed);
out:
admhcd_unlock(ahcd);
return ret;
}
static int admhcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
{
struct admhcd *ahcd = hcd_to_admhcd(hcd);
struct admhcd_ed *ed;
admhcd_lock(ahcd);
ed = urb->hcpriv;
if (ed && ed->urb != urb)
admhcd_td_free(ed, urb);
admhcd_unlock(ahcd);
return 0;
}
static void admhcd_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
{
struct admhcd *ahcd = hcd_to_admhcd(hcd);
struct admhcd_ed *ed, *edt, *head;
admhcd_lock(ahcd);
head = (struct admhcd_ed *)admhcd_reg_get(ahcd, ADMHCD_REG_HOSTHEAD);
if (!head)
goto out;
for (ed = head; ED(ed->next) != head; ed = ED(ed->next))
if (ed->ep == ep)
break;
if (ed->ep != ep)
goto out;
while (ed->cur)
admhcd_td_free(ed, ed->cur->urb);
if (head == ed) {
if (ED(ed->next) == ed) {
admhcd_reg_set(ahcd, ADMHCD_REG_HOSTHEAD, 0);
ahcd->dma_en = 0;
goto out_free;
}
head = ED(ed->next);
for (edt = head; ED(edt->next) != head; edt = ED(edt->next));
edt->next = ED(ed->next);
admhcd_reg_set(ahcd, ADMHCD_REG_HOSTHEAD, (u32)ed->next);
goto out_free;
}
for (edt = head; edt->next != ed; edt = edt->next);
edt->next = ed->next;
out_free:
kfree(ed->real);
out:
admhcd_unlock(ahcd);
}
static int admhcd_get_frame_number(struct usb_hcd *hcd)
{
struct admhcd *ahcd = hcd_to_admhcd(hcd);
return admhcd_reg_get(ahcd, ADMHCD_REG_FMNUMBER) & 0x0000ffff;
}
static int admhcd_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct admhcd *ahcd = hcd_to_admhcd(hcd);
int port;
*buf = 0;
for (port = 0; port < ADMHCD_NUMPORTS; port++) {
if (admhcd_reg_get(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4) &
(ADMHCD_CSC | ADMHCD_PESC | ADMHCD_PSSC | ADMHCD_OCIC |
ADMHCD_PRSC))
*buf |= (1 << (port + 1));
}
return !!*buf;
}
static __u8 root_hub_hub_des[] = {
0x09, /* __u8 bLength; */
0x29, /* __u8 bDescriptorType; Hub-descriptor */
0x02, /* __u8 bNbrPorts; */
0x0a, 0x00, /* __u16 wHubCharacteristics; */
0x01, /* __u8 bPwrOn2pwrGood; 2ms */
0x00, /* __u8 bHubContrCurrent; 0mA */
0x00, /* __u8 DeviceRemovable; */
0xff, /* __u8 PortPwrCtrlMask; */
};
static int admhcd_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
struct admhcd *ahcd = hcd_to_admhcd(hcd);
int retval = 0, len;
unsigned int port = wIndex -1;
switch (typeReq) {
case GetHubStatus:
*(__le32 *)buf = cpu_to_le32(0);
break;
case GetPortStatus:
if (port >= ADMHCD_NUMPORTS)
goto err;
*(__le32 *)buf = cpu_to_le32(
admhcd_reg_get(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4));
break;
case SetHubFeature: /* We don't implement these */
case ClearHubFeature:
switch (wValue) {
case C_HUB_OVER_CURRENT:
case C_HUB_LOCAL_POWER:
break;
default:
goto err;
}
case SetPortFeature:
if (port >= ADMHCD_NUMPORTS)
goto err;
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
ADMHCD_PSS);
break;
case USB_PORT_FEAT_RESET:
if (admhcd_reg_get(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4)
& ADMHCD_CCS) {
admhcd_reg_set(ahcd,
ADMHCD_REG_PORTSTATUS0 + port*4,
ADMHCD_PRS | ADMHCD_CSC);
mdelay(50);
admhcd_reg_set(ahcd,
ADMHCD_REG_PORTSTATUS0 + port*4,
ADMHCD_PES | ADMHCD_CSC);
}
break;
case USB_PORT_FEAT_POWER:
admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
ADMHCD_PPS);
break;
default:
goto err;
}
break;
case ClearPortFeature:
if (port >= ADMHCD_NUMPORTS)
goto err;
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
ADMHCD_CCS);
break;
case USB_PORT_FEAT_C_ENABLE:
admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
ADMHCD_PESC);
break;
case USB_PORT_FEAT_SUSPEND:
admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
ADMHCD_POCI);
break;
case USB_PORT_FEAT_C_SUSPEND:
admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
ADMHCD_PSSC);
case USB_PORT_FEAT_POWER:
admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
ADMHCD_LSDA);
break;
case USB_PORT_FEAT_C_CONNECTION:
admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
ADMHCD_CSC);
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
ADMHCD_OCIC);
break;
case USB_PORT_FEAT_C_RESET:
admhcd_reg_set(ahcd, ADMHCD_REG_PORTSTATUS0 + port*4,
ADMHCD_PRSC);
break;
default:
goto err;
}
break;
case GetHubDescriptor:
len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength);
memcpy(buf, root_hub_hub_des, len);
break;
default:
err:
retval = -EPIPE;
}
return retval;
}
static struct hc_driver adm5120_hc_driver = {
.description = hcd_name,
.product_desc = "ADM5120 HCD",
.hcd_priv_size = sizeof(struct admhcd),
.flags = HCD_USB11,
.urb_enqueue = admhcd_urb_enqueue,
.urb_dequeue = admhcd_urb_dequeue,
.endpoint_disable = admhcd_endpoint_disable,
.get_frame_number = admhcd_get_frame_number,
.hub_status_data = admhcd_hub_status_data,
.hub_control = admhcd_hub_control,
};
static int __init adm5120hcd_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct admhcd *ahcd;
struct usb_device *udev;
int err = 0;
if (!request_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start, hcd_name)) {
pr_debug("couldn't request mem\n");
err = -EBUSY;
goto out;
}
//hcd = usb_create_hcd(&adm5120_hc_driver, pdev, pdev->bus_id);
if (!hcd)
goto out_mem;
ahcd = hcd_to_admhcd(hcd);
dev_set_drvdata(pdev, ahcd);
hcd->self.controller = pdev;
//hcd->self.bus_name = pdev->bus_id;
hcd->irq = pdev->resource[1].start;
hcd->regs = (void *)pdev->resource[0].start;
hcd->product_desc = hcd_name;
ahcd->base = pdev->resource[0].start;
if (request_irq(pdev->resource[1].start, adm5120hcd_irq, 0, hcd_name,
hcd)) {
pr_debug("couldn't request irq\n");
err = -EBUSY;
goto out_hcd;
}
//err = usb_register_bus(&hcd->self);
//if (err < 0)
// goto out_irq;
spin_lock_init(&ahcd->lock);
admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0);
mdelay(10);
admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_SW_RESET);
while (admhcd_reg_get(ahcd, ADMHCD_REG_CONTROL) & ADMHCD_SW_RESET)
mdelay(1);
admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_HOST_EN);
admhcd_reg_set(ahcd, ADMHCD_REG_HOSTHEAD, 0x00000000);
admhcd_reg_set(ahcd, ADMHCD_REG_FMINTERVAL, 0x20002edf);
admhcd_reg_set(ahcd, ADMHCD_REG_LSTHRESH, 0x628);
admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE,
ADMHCD_INT_ACT | ADMHCD_INT_FATAL | ADMHCD_INT_SW | ADMHCD_INT_TD);
admhcd_reg_set(ahcd, ADMHCD_REG_INTSTATUS,
ADMHCD_INT_ACT | ADMHCD_INT_FATAL | ADMHCD_INT_SW | ADMHCD_INT_TD);
admhcd_reg_set(ahcd, ADMHCD_REG_RHDESCR, ADMHCD_NPS | ADMHCD_LPSC);
admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP);
udev = usb_alloc_dev(NULL, &hcd->self, 0);
if (!udev) {
err = -ENOMEM;
goto out_bus;
}
udev->speed = USB_SPEED_FULL;
hcd->state = HC_STATE_RUNNING;
//err = hcd_register_root(udev, hcd);
//if (err != 0) {
// usb_put_dev(udev);
// goto out_dev;
//}
return 0;
out_dev:
usb_put_dev(udev);
out_bus:
//usb_deregister_bus(&hcd->self);
out_irq:
free_irq(pdev->resource[1].start, hcd);
out_hcd:
usb_put_hcd(hcd);
out_mem:
release_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start);
out:
return err;
}
static int __init_or_module adm5120hcd_remove(struct platform_device *pdev)
{
device_init_wakeup(&pdev->dev, 0);
}
static struct platform_driver adm5120hcd_driver = {
.probe = adm5120hcd_probe,
.remove = adm5120hcd_remove,
.driver = {
.name = "adm5120-hcd",
.owner = THIS_MODULE,
},
};
static int __init adm5120hcd_init(void)
{
if (usb_disabled())
return -ENODEV;
return platform_driver_register(&adm5120hcd_driver);
}
static void __exit adm5120hcd_exit(void)
{
platform_driver_unregister(&adm5120hcd_driver);
}
module_init(adm5120hcd_init);
module_exit(adm5120hcd_exit);

View file

@ -0,0 +1,60 @@
/*
* $Id$
*
* ADM5120 SoC definitions
*
* This file defines some constants specific to the ADM5120 SoC
*
* Copyright (C) 2007 OpenWrt.org
* Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu>
*
* 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 Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _ADM5120_DEFS_H
#define _ADM5120_DEFS_H
#define ADM5120_SDRAM0_BASE 0x00000000
#define ADM5120_SDRAM1_BASE 0x01000000
#define ADM5120_SRAM1_BASE 0x10000000
#define ADM5120_MPMC_BASE 0x11000000
#define ADM5120_USBC_BASE 0x11200000
#define ADM5120_PCIMEM_BASE 0x11400000
#define ADM5120_PCIIO_BASE 0x11500000
#define ADM5120_PCICFG_ADDR 0x115FFFF0
#define ADM5120_PCICFG_DATA 0x115FFFF8
#define ADM5120_SWITCH_BASE 0x12000000
#define ADM5120_INTC_BASE 0x12200000
#define ADM5120_UART0_BASE 0x12600000
#define ADM5120_UART1_BASE 0x12800000
#define ADM5120_SRAM0_BASE 0x1FC00000
#define ADM5120_MPMC_SIZE 0x1000
#define ADM5120_USBC_SIZE 0x84
#define ADM5120_PCIMEM_SIZE (ADM5120_PCIIO_BASE - ADM5120_PCIMEM_BASE)
#define ADM5120_PCIIO_SIZE (ADM5120_PCICFG_ADDR - ADM5120_PCIIO_BASE)
#define ADM5120_PCICFG_SIZE 0x10
#define ADM5120_SWITCH_SIZE 0x114
#define ADM5120_INTC_SIZE 0x28
#define ADM5120_UART_SIZE 0x20
#define ADM5120_CLK_175 175000000
#define ADM5120_CLK_200 200000000
#define ADM5120_CLK_225 225000000
#define ADM5120_CLK_250 250000000
#define ADM5120_UART_CLOCK 62500000
#endif /* _ADM5120_DEFS_H */

View file

@ -0,0 +1,70 @@
/*
* $Id$
*
* Copyright (C) 2007 OpenWrt.org
* Copyright (C) Gabor Juhos <juhosg@freemail.hu>
*
* 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.
*/
#ifndef _ADM5120_INFO_H
#define _ADM5120_INFO_H
#include <linux/types.h>
struct adm5120_info {
unsigned int product_code;
unsigned int revision;
unsigned int cpu_package;
unsigned int nand_boot;
unsigned long cpu_speed;
unsigned int boot_loader;
unsigned int board_type;
unsigned int num_iface;
};
#define CPU_SPEED_175 175000000
#define CPU_SPEED_200 200000000
#define CPU_SPEED_225 225000000
#define CPU_SPEED_250 250000000
#define CPU_PACKAGE_PQFP 0
#define CPU_PACKAGE_BGA 1
#define BOOT_LOADER_UNKNOWN 0
#define BOOT_LOADER_CFE 1
#define BOOT_LOADER_UBOOT 2
#define BOOT_LOADER_MYLOADER 3
#define BOOT_LOADER_ROUTERBOOT 4
#define BOOT_LOADER_LAST 4
#define BOARD_TYPE_UNKNOWN 0
#define BOARD_TYPE_WP54G_WRT 1
#define BOARD_TYPE_WP54G 2
#define BOARD_TYPE_WP54AG 3
#define BOARD_TYPE_WPP54G 4
#define BOARD_TYPE_WPP54AG 5
#define BOARD_TYPE_NP28G 6
#define BOARD_TYPE_NP28GHS 7
#define BOARD_TYPE_NP27G 8
#define BOARD_TYPE_WP54Gv1C 9
#define BOARD_TYPE_RB_111 10
#define BOARD_TYPE_RB_112 11
#define BOARD_TYPE_RB_133 12
#define BOARD_TYPE_RB_133C 13
#define BOARD_TYPE_RB_150 14
#define BOARD_TYPE_RB_153 15
#define BOART_TYPE_LAST 15
extern struct adm5120_info adm5120_info;
extern void adm5120_info_init(void);
static inline int adm5120_has_pci(void)
{
return (adm5120_info.cpu_package == CPU_PACKAGE_BGA);
}
#endif /* _ADM5120_INFO_H */

View file

@ -0,0 +1,89 @@
/*
* ADM5120 ethernet switch definitions
*
* This header file defines the hardware registers of the ADM5120 SoC
* built-in Ethernet switch.
*
* Copyright (C) 2007 OpenWrt.org
* Copyright (C) 2007 Gabor Juhos <juhosg@freemail.hu>
*
* 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 Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _ADM5120_SWITCH_H
#define _ADM5120_SWITCH_H
#define BITMASK(len) ((1 << (len))-1)
#define ONEBIT(at) (1 << (at))
/* Switch register offsets */
#define SWITCH_REG_CODE 0x0000
#define SWITCH_REG_SOFT_RESET 0x0004
#define SWITCH_REG_MEMCTRL 0x001C
#define SWITCH_REG_CPUP_CONF 0x0024
#define SWITCH_REG_PORT_CONF0 0x0028
#define SWITCH_REG_PORT_CONF1 0x002C
#define SWITCH_REG_PORT_CONF2 0x0030
#define SWITCH_REG_VLAN_G1 0x0040
#define SWITCH_REG_VLAN_G2 0x0044
#define SWITCH_REG_SEND_TRIG 0x0048
#define SWITCH_REG_MAC_WT0 0x0058
#define SWITCH_REG_MAC_WT1 0x005C
#define SWITCH_REG_PHY_CNTL0 0x0068
#define SWITCH_REG_PHY_CNTL1 0x006C
#define SWITCH_REG_PHY_CNTL2 0x007C
#define SWITCH_REG_PHY_CNTL3 0x0080
#define SWITCH_REG_PRI_CNTL 0x0084
#define SWITCH_REG_INT_STATUS 0x00B0
#define SWITCH_REG_INT_MASK 0x00B4
#define SWITCH_REG_GPIO_CONF0 0x00B8
#define SWITCH_REG_GPIO_CONF2 0x00BC
#define SWITCH_REG_WDOG0 0x00C0
#define SWITCH_REG_WDOG1 0x00C4
#define SWITCH_REG_PHY_CNTL4 0x00A0
#define SWITCH_REG_SEND_HBADDR 0x00D0
#define SWITCH_REG_SEND_LBADDR 0x00D4
#define SWITCH_REG_RECV_HBADDR 0x00D8
#define SWITCH_REG_RECV_LBADDR 0x00DC
#define SWITCH_REG_TIMER_INT 0x00F0
#define SWITCH_REG_TIMER 0x00F4
#define SWITCH_REG_PORT0_LED 0x0100
#define SWITCH_REG_PORT1_LED 0x0104
#define SWITCH_REG_PORT2_LED 0x0108
#define SWITCH_REG_PORT3_LED 0x010C
#define SWITCH_REG_PORT4_LED 0x0110
/* CODE register bits */
#define CODE_PC_MASK BITMASK(16) /* Product Code */
#define CODE_REV_SHIFT 16
#define CODE_REV_MASK BITMASK(4) /* Product Revision */
#define CODE_CLKS_SHIFT 20
#define CODE_CLKS_MASK BITMASK(2) /* Clock Speed */
#define CODE_CLKS_175 0 /* 175 MHz */
#define CODE_CLKS_200 1 /* 200 MHz */
#define CODE_CLKS_225 2 /* 225 MHz */
#define CODE_CLKS_250 3 /* 250 MHz */
#define CODE_NAB ONEBIT(24) /* NAND boot */
#define CODE_PK_MASK BITMASK(1) /* Package type */
#define CODE_PK_SHIFT 29
#define CODE_PK_BGA 0 /* BGA package */
#define CODE_PK_PQFP 1 /* PQFP package */
#endif /* _ADM5120_SWITCH_H */

View file

@ -0,0 +1,167 @@
/*
* Copyright (C) 2006,2007 Gabor Juhos
*
* 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.
*
*/
#ifndef _MYLOADER_H_
#define _MYLOADER_H_
/*
* Firmware file format:
*
* <header>
* [<block descriptor 0>]
* ...
* [<block descriptor n>]
* <null block descriptor>
* [<block data 0>]
* ...
* [<block data n>]
*
*
*/
/* Myloader specific magic numbers */
#define MYLO_MAGIC_FIRMWARE 0x4C594D00
#define MYLO_MAGIC_20021103 0x20021103
#define MYLO_MAGIC_20021107 0x20021107
#define MYLO_MAGIC_SYS_PARAMS MYLO_MAGIC_20021107
#define MYLO_MAGIC_PARTITIONS MYLO_MAGIC_20021103
#define MYLO_MAGIC_BOARD_PARAMS MYLO_MAGIC_20021103
/*
* Addresses of the data structures provided by MyLoader
*/
#define MYLO_MIPS_SYS_PARAMS 0x80000800 /* System Parameters */
#define MYLO_MIPS_BOARD_PARAMS 0x80000A00 /* Board Parameters */
#define MYLO_MIPS_PARTITIONS 0x80000C00 /* Partition Table */
#define MYLO_MIPS_BOOT_PARAMS 0x80000E00 /* Boot Parameters */
/* Vendor ID's (seems to be same as the PCI vendor ID's) */
#define VENID_COMPEX 0x11F6
/* Devices based on the ADM5120 */
#define DEVID_COMPEX_NP27G 0x0078
#define DEVID_COMPEX_NP28G 0x044C
#define DEVID_COMPEX_NP28GHS 0x044E
#define DEVID_COMPEX_WP54Gv1C 0x0514
#define DEVID_COMPEX_WP54G 0x0515
#define DEVID_COMPEX_WP54AG 0x0546
#define DEVID_COMPEX_WPP54AG 0x0550
#define DEVID_COMPEX_WPP54G 0x0555
/* Devices based on the IXP422 */
#define DEVID_COMPEX_WP18 0x047E
#define DEVID_COMPEX_NP18A 0x0489
/* Other devices */
#define DEVID_COMPEX_NP26G8M 0x03E8
#define DEVID_COMPEX_NP26G16M 0x03E9
struct mylo_fw_header {
uint32_t magic; /* must be MYLO_MAGIC_FIRMWARE */
uint32_t crc; /* CRC of the whole firmware */
uint32_t res0; /* unknown/unused */
uint32_t res1; /* unknown/unused */
uint16_t vid; /* vendor ID */
uint16_t did; /* device ID */
uint16_t svid; /* sub vendor ID */
uint16_t sdid; /* sub device ID */
uint32_t rev; /* device revision */
uint32_t fwhi; /* FIXME: firmware version high? */
uint32_t fwlo; /* FIXME: firmware version low? */
uint32_t flags; /* firmware flags */
};
#define FW_FLAG_BOARD_PARAMS_WP 0x01 /* board parameters are write protected */
#define FW_FLAG_BOOT_SECTOR_WE 0x02 /* enable of write boot sectors (below 64K) */
struct mylo_fw_blockdesc {
uint32_t type; /* block type */
uint32_t addr; /* relative address to flash start */
uint32_t dlen; /* size of block data in bytes */
uint32_t blen; /* total size of block in bytes */
};
#define FW_DESC_TYPE_UNUSED 0
#define FW_DESC_TYPE_USED 1
struct mylo_partition {
uint16_t flags; /* partition flags */
uint16_t type; /* type of the partition */
uint32_t addr; /* relative address of the partition from the
flash start */
uint32_t size; /* size of the partition in bytes */
uint32_t param; /* if this is the active partition, the
MyLoader load code to this address */
};
#define PARTITION_FLAG_ACTIVE 0x8000 /* this is the active partition,
* MyLoader loads firmware from here */
#define PARTITION_FLAG_ISRAM 0x2000 /* FIXME: this is a RAM partition? */
#define PARTIIION_FLAG_RAMLOAD 0x1000 /* FIXME: load this partition into the RAM? */
#define PARTITION_FLAG_PRELOAD 0x0800 /* the partition data preloaded to RAM
* before decompression */
#define PARTITION_FLAG_HAVEHDR 0x0002 /* the partition data have a header */
#define PARTITION_TYPE_FREE 0
#define PARTITION_TYPE_USED 1
#define MYLO_MAX_PARTITIONS 8 /* maximum number of partitions in the
partition table */
struct mylo_partition_table {
uint32_t magic; /* must be MYLO_MAGIC_PARTITIONS */
uint32_t res0; /* unknown/unused */
uint32_t res1; /* unknown/unused */
uint32_t res2; /* unknown/unused */
struct mylo_partition partitions[MYLO_MAX_PARTITIONS];
};
struct mylo_partition_header {
uint32_t len; /* length of the partition data */
uint32_t crc; /* CRC value of the partition data */
};
struct mylo_system_params {
uint32_t magic; /* must be MYLO_MAGIC_SYS_PARAMS */
uint32_t res0;
uint32_t res1;
uint32_t mylo_ver;
uint16_t vid; /* Vendor ID */
uint16_t did; /* Device ID */
uint16_t svid; /* Sub Vendor ID */
uint16_t sdid; /* Sub Device ID */
uint32_t rev; /* device revision */
uint32_t fwhi;
uint32_t fwlo;
uint32_t tftp_addr;
uint32_t prog_start;
uint32_t flash_size; /* Size of boot FLASH in bytes */
uint32_t dram_size; /* Size of onboard RAM in bytes */
};
struct mylo_eth_addr {
uint8_t mac[6];
uint8_t csum[2];
};
#define MYLO_ETHADDR_COUNT 8 /* maximum number of ethernet address
in the board parameters */
struct mylo_board_params {
uint32_t magic; /* must be MYLO_MAGIC_BOARD_PARAMS */
uint32_t res0;
uint32_t res1;
uint32_t res2;
struct mylo_eth_addr addr[MYLO_ETHADDR_COUNT];
};
#endif /* _MYLOADER_H_*/

View file

@ -0,0 +1,57 @@
#
# Copyright (C) 2006 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
include $(INCLUDE_DIR)/kernel.mk
LOADADDR = 0x81000000 # RAM start + 16M
KERNEL_ENTRY = 0x80101000
RAMSIZE = 0x00100000 # 1MB
IMAGE_COPY = 1
LOADER_MAKEOPTS= \
KDIR=$(KDIR) \
LOADADDR=$(LOADADDR) \
KERNEL_ENTRY=$(KERNEL_ENTRY) \
RAMSIZE=$(RAMSIZE) \
IMAGE_COPY=$(IMAGE_COPY)
#define Build/Compile
# $(CC) -o $(STAGING_DIR)/bin/patch-cmdline $(PLATFORM_DIR)/src/patch-cmdline.c
#endef
define Build/Clean
$(MAKE) -C $(GENERIC_PLATFORM_DIR)/image/lzma-loader $(LOADER_MAKEOPTS) clean
endef
define Image/Prepare
cat $(KDIR)/vmlinux | $(STAGING_DIR)/bin/lzma e -si -so -eos -lc1 -lp2 -pb2 > $(KDIR)/vmlinux.lzma
$(MAKE) -C $(GENERIC_PLATFORM_DIR)/image/lzma-loader $(LOADER_MAKEOPTS) clean compile
endef
define Image/BuildKernel
$(CP) $(KDIR)/loader.elf $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-vmlinux
endef
define Image/cmdline/jffs2-64k
block2mtd.block2mtd=/dev/cfa2,65536 root=/dev/mtdblock0 rootfstype=jffs2 init=/etc/preinit
endef
define Image/cmdline/jffs2-128k
block2mtd.block2mtd=/dev/cfa2,131072 root=/dev/mtdblock0 rootfstype=jffs2 init=/etc/preinit
endef
define Image/cmdline/ext2
root=/dev/cfa2 rootfstype=ext2 init=/etc/preinit
endef
define Image/Build
#$(STAGING_DIR)/bin/patch-cmdline $(KDIR)/vmlinux.elf '$(strip $(call Image/cmdline/$(1))) '
./gen_image.sh $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).bin 4 $(KDIR)/vmlinux.elf $(CONFIG_TARGET_ROOTFS_FSPART) $(KDIR)/root.$(1)
endef
$(eval $(call BuildImage))

View file

@ -0,0 +1,17 @@
#!/usr/bin/env bash
OUTPUT="$1"
KERNELSIZE="$2"
KERNELIMAGE="$3"
ROOTFSSIZE="$4"
ROOTFSIMAGE="$5"
rm -f "$OUTPUT"
# create partition table
set `ptgen -o "$OUTPUT" -h 16 -s 32 -t 0x27 -p ${KERNELSIZE}m -t 0x83 -p ${ROOTFSSIZE}m`
KERNELOFFSET="$(($1 / 512))"
ROOTFSOFFSET="$(($2 / 512))"
dd if="$KERNELIMAGE" of="$OUTPUT" bs=512 conv=notrunc seek="$KERNELOFFSET"
dd if="$ROOTFSIMAGE" of="$OUTPUT" bs=512 conv=notrunc seek="$ROOTFSOFFSET"

View file

@ -0,0 +1,34 @@
#
# Copyright (C) 2006 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# $Id: Makefile 4439 2006-08-04 17:14:36Z nbd $
include $(TOPDIR)/rules.mk
PKG_NAME := lzma-loader
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
$(PKG_BUILD_DIR)/.prepared:
mkdir $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
touch $@
$(PKG_BUILD_DIR)/loader.gz: $(PKG_BUILD_DIR)/.prepared
$(MAKE) -C $(PKG_BUILD_DIR) CC="$(TARGET_CC)" \
LD="$(TARGET_CROSS)ld" CROSS_COMPILE="$(TARGET_CROSS)"
download:
prepare: $(PKG_BUILD_DIR)/.prepared
compile: $(PKG_BUILD_DIR)/loader.gz
install:
ifneq ($(TARGET),)
install: compile
$(CP) $(PKG_BUILD_DIR)/loader.gz $(PKG_BUILD_DIR)/loader.elf $(TARGET)/
endif
clean:
rm -rf $(PKG_BUILD_DIR)

View file

@ -0,0 +1,663 @@
/*
LzmaDecode.c
LZMA Decoder
LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
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
typedef struct _CRangeDecoder
{
Byte *Buffer;
Byte *BufferLim;
UInt32 Range;
UInt32 Code;
#ifdef _LZMA_IN_CB
ILzmaInCallback *InCallback;
int Result;
#endif
int ExtraBytes;
} CRangeDecoder;
Byte RangeDecoderReadByte(CRangeDecoder *rd)
{
if (rd->Buffer == rd->BufferLim)
{
#ifdef _LZMA_IN_CB
UInt32 size;
rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size);
rd->BufferLim = rd->Buffer + size;
if (size == 0)
#endif
{
rd->ExtraBytes = 1;
return 0xFF;
}
}
return (*rd->Buffer++);
}
/* #define ReadByte (*rd->Buffer++) */
#define ReadByte (RangeDecoderReadByte(rd))
void RangeDecoderInit(CRangeDecoder *rd,
#ifdef _LZMA_IN_CB
ILzmaInCallback *inCallback
#else
Byte *stream, UInt32 bufferSize
#endif
)
{
int i;
#ifdef _LZMA_IN_CB
rd->InCallback = inCallback;
rd->Buffer = rd->BufferLim = 0;
#else
rd->Buffer = stream;
rd->BufferLim = stream + bufferSize;
#endif
rd->ExtraBytes = 0;
rd->Code = 0;
rd->Range = (0xFFFFFFFF);
for(i = 0; i < 5; i++)
rd->Code = (rd->Code << 8) | ReadByte;
}
#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code;
#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits)
{
RC_INIT_VAR
UInt32 result = 0;
int i;
for (i = numTotalBits; i > 0; i--)
{
/* UInt32 t; */
range >>= 1;
result <<= 1;
if (code >= range)
{
code -= range;
result |= 1;
}
/*
t = (code - range) >> 31;
t &= 1;
code -= range & (t - 1);
result = (result + result) | (1 - t);
*/
RC_NORMALIZE
}
RC_FLUSH_VAR
return result;
}
int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd)
{
UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob;
if (rd->Code < bound)
{
rd->Range = bound;
*prob += (kBitModelTotal - *prob) >> kNumMoveBits;
if (rd->Range < kTopValue)
{
rd->Code = (rd->Code << 8) | ReadByte;
rd->Range <<= 8;
}
return 0;
}
else
{
rd->Range -= bound;
rd->Code -= bound;
*prob -= (*prob) >> kNumMoveBits;
if (rd->Range < kTopValue)
{
rd->Code = (rd->Code << 8) | ReadByte;
rd->Range <<= 8;
}
return 1;
}
}
#define RC_GET_BIT2(prob, mi, A0, A1) \
UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
if (code < bound) \
{ A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
else \
{ A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
RC_NORMALIZE
#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;)
int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
{
int mi = 1;
int i;
#ifdef _LZMA_LOC_OPT
RC_INIT_VAR
#endif
for(i = numLevels; i > 0; i--)
{
#ifdef _LZMA_LOC_OPT
CProb *prob = probs + mi;
RC_GET_BIT(prob, mi)
#else
mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd);
#endif
}
#ifdef _LZMA_LOC_OPT
RC_FLUSH_VAR
#endif
return mi - (1 << numLevels);
}
int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
{
int mi = 1;
int i;
int symbol = 0;
#ifdef _LZMA_LOC_OPT
RC_INIT_VAR
#endif
for(i = 0; i < numLevels; i++)
{
#ifdef _LZMA_LOC_OPT
CProb *prob = probs + mi;
RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i))
#else
int bit = RangeDecoderBitDecode(probs + mi, rd);
mi = mi + mi + bit;
symbol |= (bit << i);
#endif
}
#ifdef _LZMA_LOC_OPT
RC_FLUSH_VAR
#endif
return symbol;
}
Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd)
{
int symbol = 1;
#ifdef _LZMA_LOC_OPT
RC_INIT_VAR
#endif
do
{
#ifdef _LZMA_LOC_OPT
CProb *prob = probs + symbol;
RC_GET_BIT(prob, symbol)
#else
symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
#endif
}
while (symbol < 0x100);
#ifdef _LZMA_LOC_OPT
RC_FLUSH_VAR
#endif
return symbol;
}
Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
{
int symbol = 1;
#ifdef _LZMA_LOC_OPT
RC_INIT_VAR
#endif
do
{
int bit;
int matchBit = (matchByte >> 7) & 1;
matchByte <<= 1;
#ifdef _LZMA_LOC_OPT
{
CProb *prob = probs + ((1 + matchBit) << 8) + symbol;
RC_GET_BIT2(prob, symbol, bit = 0, bit = 1)
}
#else
bit = RangeDecoderBitDecode(probs + ((1 + matchBit) << 8) + symbol, rd);
symbol = (symbol << 1) | bit;
#endif
if (matchBit != bit)
{
while (symbol < 0x100)
{
#ifdef _LZMA_LOC_OPT
CProb *prob = probs + symbol;
RC_GET_BIT(prob, symbol)
#else
symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
#endif
}
break;
}
}
while (symbol < 0x100);
#ifdef _LZMA_LOC_OPT
RC_FLUSH_VAR
#endif
return symbol;
}
#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)
int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
{
if(RangeDecoderBitDecode(p + LenChoice, rd) == 0)
return RangeDecoderBitTreeDecode(p + LenLow +
(posState << kLenNumLowBits), kLenNumLowBits, rd);
if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0)
return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid +
(posState << kLenNumMidBits), kLenNumMidBits, rd);
return kLenNumLowSymbols + kLenNumMidSymbols +
RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd);
}
#define kNumStates 12
#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
#ifdef _LZMA_OUT_READ
typedef struct _LzmaVarState
{
CRangeDecoder RangeDecoder;
Byte *Dictionary;
UInt32 DictionarySize;
UInt32 DictionaryPos;
UInt32 GlobalPos;
UInt32 Reps[4];
int lc;
int lp;
int pb;
int State;
int PreviousIsMatch;
int RemainLen;
} LzmaVarState;
int LzmaDecoderInit(
unsigned char *buffer, UInt32 bufferSize,
int lc, int lp, int pb,
unsigned char *dictionary, UInt32 dictionarySize,
#ifdef _LZMA_IN_CB
ILzmaInCallback *inCallback
#else
unsigned char *inStream, UInt32 inSize
#endif
)
{
LzmaVarState *vs = (LzmaVarState *)buffer;
CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
UInt32 i;
if (bufferSize < numProbs * sizeof(CProb) + sizeof(LzmaVarState))
return LZMA_RESULT_NOT_ENOUGH_MEM;
vs->Dictionary = dictionary;
vs->DictionarySize = dictionarySize;
vs->DictionaryPos = 0;
vs->GlobalPos = 0;
vs->Reps[0] = vs->Reps[1] = vs->Reps[2] = vs->Reps[3] = 1;
vs->lc = lc;
vs->lp = lp;
vs->pb = pb;
vs->State = 0;
vs->PreviousIsMatch = 0;
vs->RemainLen = 0;
dictionary[dictionarySize - 1] = 0;
for (i = 0; i < numProbs; i++)
p[i] = kBitModelTotal >> 1;
RangeDecoderInit(&vs->RangeDecoder,
#ifdef _LZMA_IN_CB
inCallback
#else
inStream, inSize
#endif
);
return LZMA_RESULT_OK;
}
int LzmaDecode(unsigned char *buffer,
unsigned char *outStream, UInt32 outSize,
UInt32 *outSizeProcessed)
{
LzmaVarState *vs = (LzmaVarState *)buffer;
CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
CRangeDecoder rd = vs->RangeDecoder;
int state = vs->State;
int previousIsMatch = vs->PreviousIsMatch;
Byte previousByte;
UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
UInt32 nowPos = 0;
UInt32 posStateMask = (1 << (vs->pb)) - 1;
UInt32 literalPosMask = (1 << (vs->lp)) - 1;
int lc = vs->lc;
int len = vs->RemainLen;
UInt32 globalPos = vs->GlobalPos;
Byte *dictionary = vs->Dictionary;
UInt32 dictionarySize = vs->DictionarySize;
UInt32 dictionaryPos = vs->DictionaryPos;
if (len == -1)
{
*outSizeProcessed = 0;
return LZMA_RESULT_OK;
}
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
int LzmaDecode(
Byte *buffer, UInt32 bufferSize,
int lc, int lp, int pb,
#ifdef _LZMA_IN_CB
ILzmaInCallback *inCallback,
#else
unsigned char *inStream, UInt32 inSize,
#endif
unsigned char *outStream, UInt32 outSize,
UInt32 *outSizeProcessed)
{
UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
CProb *p = (CProb *)buffer;
CRangeDecoder rd;
UInt32 i;
int state = 0;
int previousIsMatch = 0;
Byte previousByte = 0;
UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
UInt32 nowPos = 0;
UInt32 posStateMask = (1 << pb) - 1;
UInt32 literalPosMask = (1 << lp) - 1;
int len = 0;
if (bufferSize < numProbs * sizeof(CProb))
return LZMA_RESULT_NOT_ENOUGH_MEM;
for (i = 0; i < numProbs; i++)
p[i] = kBitModelTotal >> 1;
RangeDecoderInit(&rd,
#ifdef _LZMA_IN_CB
inCallback
#else
inStream, inSize
#endif
);
#endif
*outSizeProcessed = 0;
while(nowPos < outSize)
{
int posState = (int)(
(nowPos
#ifdef _LZMA_OUT_READ
+ globalPos
#endif
)
& posStateMask);
#ifdef _LZMA_IN_CB
if (rd.Result != LZMA_RESULT_OK)
return rd.Result;
#endif
if (rd.ExtraBytes != 0)
return LZMA_RESULT_DATA_ERROR;
if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
{
CProb *probs = p + Literal + (LZMA_LIT_SIZE *
(((
(nowPos
#ifdef _LZMA_OUT_READ
+ globalPos
#endif
)
& literalPosMask) << lc) + (previousByte >> (8 - lc))));
if (state < 4) state = 0;
else if (state < 10) state -= 3;
else state -= 6;
if (previousIsMatch)
{
Byte matchByte;
#ifdef _LZMA_OUT_READ
UInt32 pos = dictionaryPos - rep0;
if (pos >= dictionarySize)
pos += dictionarySize;
matchByte = dictionary[pos];
#else
matchByte = outStream[nowPos - rep0];
#endif
previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte);
previousIsMatch = 0;
}
else
previousByte = LzmaLiteralDecode(probs, &rd);
outStream[nowPos++] = previousByte;
#ifdef _LZMA_OUT_READ
dictionary[dictionaryPos] = previousByte;
if (++dictionaryPos == dictionarySize)
dictionaryPos = 0;
#endif
}
else
{
previousIsMatch = 1;
if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1)
{
if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0)
{
if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0)
{
#ifdef _LZMA_OUT_READ
UInt32 pos;
#endif
if (
(nowPos
#ifdef _LZMA_OUT_READ
+ globalPos
#endif
)
== 0)
return LZMA_RESULT_DATA_ERROR;
state = state < 7 ? 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;
continue;
}
}
else
{
UInt32 distance;
if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0)
distance = rep1;
else
{
if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0)
distance = rep2;
else
{
distance = rep3;
rep3 = rep2;
}
rep2 = rep1;
}
rep1 = rep0;
rep0 = distance;
}
len = LzmaLenDecode(p + RepLenCoder, &rd, posState);
state = state < 7 ? 8 : 11;
}
else
{
int posSlot;
rep3 = rep2;
rep2 = rep1;
rep1 = rep0;
state = state < 7 ? 7 : 10;
len = LzmaLenDecode(p + LenCoder, &rd, posState);
posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
kNumPosSlotBits), kNumPosSlotBits, &rd);
if (posSlot >= kStartPosModelIndex)
{
int numDirectBits = ((posSlot >> 1) - 1);
rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
if (posSlot < kEndPosModelIndex)
{
rep0 += RangeDecoderReverseBitTreeDecode(
p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd);
}
else
{
rep0 += RangeDecoderDecodeDirectBits(&rd,
numDirectBits - kNumAlignBits) << kNumAlignBits;
rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd);
}
}
else
rep0 = posSlot;
rep0++;
}
if (rep0 == (UInt32)(0))
{
/* it's for stream version */
len = -1;
break;
}
if (rep0 > nowPos
#ifdef _LZMA_OUT_READ
+ globalPos
#endif
)
{
return LZMA_RESULT_DATA_ERROR;
}
len += kMatchMinLen;
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
outStream[nowPos++] = previousByte;
len--;
}
while(len > 0 && nowPos < outSize);
}
}
#ifdef _LZMA_OUT_READ
vs->RangeDecoder = rd;
vs->DictionaryPos = dictionaryPos;
vs->GlobalPos = globalPos + nowPos;
vs->Reps[0] = rep0;
vs->Reps[1] = rep1;
vs->Reps[2] = rep2;
vs->Reps[3] = rep3;
vs->State = state;
vs->PreviousIsMatch = previousIsMatch;
vs->RemainLen = len;
#endif
*outSizeProcessed = nowPos;
return LZMA_RESULT_OK;
}

View file

@ -0,0 +1,100 @@
/*
LzmaDecode.h
LZMA Decoder interface
LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
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 */
#ifndef UInt32
#ifdef _LZMA_UINT32_IS_ULONG
#define UInt32 unsigned long
#else
#define UInt32 unsigned int
#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
#define LZMA_RESULT_NOT_ENOUGH_MEM 2
#ifdef _LZMA_IN_CB
typedef struct _ILzmaInCallback
{
int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize);
} ILzmaInCallback;
#endif
#define LZMA_BASE_SIZE 1846
#define LZMA_LIT_SIZE 768
/*
bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb)
bufferSize += 100 in case of _LZMA_OUT_READ
by default CProb is unsigned short,
but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int)
*/
#ifdef _LZMA_OUT_READ
int LzmaDecoderInit(
unsigned char *buffer, UInt32 bufferSize,
int lc, int lp, int pb,
unsigned char *dictionary, UInt32 dictionarySize,
#ifdef _LZMA_IN_CB
ILzmaInCallback *inCallback
#else
unsigned char *inStream, UInt32 inSize
#endif
);
#endif
int LzmaDecode(
unsigned char *buffer,
#ifndef _LZMA_OUT_READ
UInt32 bufferSize,
int lc, int lp, int pb,
#ifdef _LZMA_IN_CB
ILzmaInCallback *inCallback,
#else
unsigned char *inStream, UInt32 inSize,
#endif
#endif
unsigned char *outStream, UInt32 outSize,
UInt32 *outSizeProcessed);
#endif

View file

@ -0,0 +1,77 @@
#
# Makefile for Broadcom BCM947XX boards
#
# Copyright 2001-2003, Broadcom Corporation
# All Rights Reserved.
#
# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
#
# Copyright 2004 Manuel Novoa III <mjn3@codepoet.org>
# Modified to support bzip'd kernels.
# Of course, it would be better to integrate bunzip capability into CFE.
#
# Copyright 2005 Oleg I. Vdovikin <oleg@cs.msu.su>
# Cleaned up, modified for lzma support, removed from kernel
#
TEXT_START := 0x80001000
BZ_TEXT_START := 0x80300000
OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S
CFLAGS = -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -Os \
-fno-strict-aliasing -fno-common -fomit-frame-pointer -G 0 -mno-abicalls -fno-pic \
-ffunction-sections -pipe -mlong-calls -fno-common \
-mabi=32 -march=mips32 -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap
CFLAGS += -DLOADADDR=$(TEXT_START) -D_LZMA_IN_CB
ASFLAGS = $(CFLAGS) -D__ASSEMBLY__ -DBZ_TEXT_START=$(BZ_TEXT_START)
SEDFLAGS := s/BZ_TEXT_START/$(BZ_TEXT_START)/;s/TEXT_START/$(TEXT_START)/
OBJECTS := head.o data.o
all: loader.gz loader.elf
# Don't build dependencies, this may die if $(CC) isn't gcc
dep:
install:
loader.gz: loader
gzip -nc9 $< > $@
loader.elf: loader.o
cp $< $@
loader: loader.o
$(OBJCOPY) $< $@
loader.o: loader.lds $(OBJECTS)
$(LD) -static --gc-sections -no-warn-mismatch -T loader.lds -o $@ $(OBJECTS)
loader.lds: loader.lds.in Makefile
@sed "$(SEDFLAGS)" < $< > $@
data.o: data.lds decompress.image
$(LD) -no-warn-mismatch -T data.lds -r -o $@ -b binary decompress.image -b elf32-tradlittlemips
data.lds:
@echo "SECTIONS { .data : { code_start = .; *(.data) code_stop = .; }}" > $@
decompress.image: decompress
$(OBJCOPY) $< $@
decompress: decompress.lds decompress.o LzmaDecode.o
$(LD) -static --gc-sections -no-warn-mismatch -T decompress.lds -o $@ decompress.o LzmaDecode.o
decompress.lds: decompress.lds.in Makefile
@sed "$(SEDFLAGS)" < $< > $@
mrproper: clean
clean:
rm -f loader.gz loader decompress *.lds *.o *.image

View file

@ -0,0 +1,55 @@
/*
* 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
*
*/
The code is intended to decompress kernel, being compressed using lzma utility
build using 7zip LZMA SDK. This utility is located in the LZMA_Alone directory
decompressor code expects that your .trx file consist of three partitions:
1) decompressor itself (this is gziped code which pmon/cfe will extract and run
on boot-up instead of real kernel)
2) LZMA compressed kernel (both streamed and regular modes are supported now)
3) Root filesystem
Please be sure to apply the following patch for use this new trx layout (it will
allow using both new and old trx files for root filesystem lookup code)
--- linuz/arch/mips/brcm-boards/bcm947xx/setup.c 2005-01-23 19:24:27.503322896 +0300
+++ linux/arch/mips/brcm-boards/bcm947xx/setup.c 2005-01-23 19:29:05.237100944 +0300
@@ -221,7 +221,9 @@
/* Try looking at TRX header for rootfs offset */
if (le32_to_cpu(trx->magic) == TRX_MAGIC) {
bcm947xx_parts[1].offset = off;
- if (le32_to_cpu(trx->offsets[1]) > off)
+ if (le32_to_cpu(trx->offsets[2]) > off)
+ off = le32_to_cpu(trx->offsets[2]);
+ else if (le32_to_cpu(trx->offsets[1]) > off)
off = le32_to_cpu(trx->offsets[1]);
continue;
}
Revision history:
0.02 Initial release
0.03 Added Mineharu Takahara <mtakahar@yahoo.com> patch to pass actual
output size to decoder (stream mode compressed input is not
a requirement anymore)
0.04 Reordered functions using lds script

View file

@ -0,0 +1,239 @@
/*
* 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
*
* 24-Mar-2007 Gabor Juhos
* pass original values of the a0,a1,a2,a3 registers to the kernel
*
*/
#include "LzmaDecode.h"
#define BCM4710_FLASH 0x1fc00000 /* Flash */
#define KSEG0 0x80000000
#define KSEG1 0xa0000000
#define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
#define Index_Invalidate_I 0x00
#define Index_Writeback_Inv_D 0x01
#define cache_unroll(base,op) \
__asm__ __volatile__( \
".set noreorder;\n" \
".set mips3;\n" \
"cache %1, (%0);\n" \
".set mips0;\n" \
".set reorder\n" \
: \
: "r" (base), \
"i" (op));
static __inline__ void blast_icache(unsigned long size, unsigned long lsize)
{
unsigned long start = KSEG0;
unsigned long end = (start + size);
while(start < end) {
cache_unroll(start,Index_Invalidate_I);
start += lsize;
}
}
static __inline__ void blast_dcache(unsigned long size, unsigned long lsize)
{
unsigned long start = KSEG0;
unsigned long end = (start + size);
while(start < end) {
cache_unroll(start,Index_Writeback_Inv_D);
start += lsize;
}
}
#define TRX_MAGIC 0x30524448 /* "HDR0" */
struct trx_header {
unsigned int magic; /* "HDR0" */
unsigned int len; /* Length of file including header */
unsigned int crc32; /* 32-bit CRC from flag_version to end of file */
unsigned int flag_version; /* 0:15 flags, 16:31 version */
unsigned int offsets[3]; /* Offsets of partitions from start of header */
};
/* beyound the image end, size not known in advance */
extern unsigned char workspace[];
unsigned int offset;
unsigned char *data;
typedef void (*kernel_entry)(unsigned long reg_a0, unsigned long reg_a1,
unsigned long reg_a2, unsigned long reg_a3);
/* flash access should be aligned, so wrapper is used */
/* read byte from the flash, all accesses are 32-bit aligned */
static int read_byte(void *object, unsigned char **buffer, UInt32 *bufferSize)
{
static unsigned int val;
if (((unsigned int)offset % 4) == 0) {
val = *(unsigned int *)data;
data += 4;
}
*bufferSize = 1;
*buffer = ((unsigned char *)&val) + (offset++ & 3);
return LZMA_RESULT_OK;
}
static __inline__ unsigned char get_byte(void)
{
unsigned char *buffer;
UInt32 fake;
return read_byte(0, &buffer, &fake), *buffer;
}
/* should be the first function */
void entry(unsigned long reg_a0, unsigned long reg_a1,
unsigned long reg_a2, unsigned long reg_a3,
unsigned long icache_size, unsigned long icache_lsize,
unsigned long dcache_size, unsigned long dcache_lsize)
{
unsigned int i; /* temp value */
unsigned int lc; /* literal context bits */
unsigned int lp; /* literal pos state bits */
unsigned int pb; /* pos state bits */
unsigned int osize; /* uncompressed size */
ILzmaInCallback callback;
callback.Read = read_byte;
uart_write_str("decompress kernel ... ");
/* look for trx header, 32-bit data access */
for (data = ((unsigned char *) KSEG1ADDR(BCM4710_FLASH));
((struct trx_header *)data)->magic != TRX_MAGIC; data += 65536);
/* compressed kernel is in the partition 0 or 1 */
if (((struct trx_header *)data)->offsets[1] > 65536)
data += ((struct trx_header *)data)->offsets[0];
else
data += ((struct trx_header *)data)->offsets[1];
offset = 0;
/* lzma args */
i = get_byte();
lc = i % 9, i = i / 9;
lp = i % 5, pb = i / 5;
/* skip rest of the LZMA coder property */
for (i = 0; i < 4; i++)
get_byte();
/* 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) */
for (i = 0; i < 4; i++)
get_byte();
/* decompress kernel */
if (LzmaDecode(workspace, ~0, lc, lp, pb, &callback,
(unsigned char*)LOADADDR, osize, &i) == LZMA_RESULT_OK)
{
blast_dcache(dcache_size, dcache_lsize);
blast_icache(icache_size, icache_lsize);
/* Jump to load address */
uart_write_str("ok\r\n");
((kernel_entry) LOADADDR)(reg_a0, reg_a1, reg_a2, reg_a3);
}
uart_write_str("failed\r\n");
while (1 );
}
/* *********************************************************************
*
* ADM5120 UART driver File: dev_adm_uart.c
*
* This is a console device driver for an ADM5120 UART
*
*********************************************************************
*
* Copyright 2006
* Compex Systems. All rights reserved.
*
********************************************************************* */
#define READCSR(r) *(volatile UInt32 *)(0xB2600000+(r))
#define WRITECSR(r,v) *(volatile UInt32 *)(0xB2600000+(r)) = v
#define UART_DR_REG 0x00
#define UART_FR_REG 0x18
#define UART_TX_FIFO_FULL 0x20
int uart_write(int val)
{
WRITECSR(UART_DR_REG, val);
while ( (READCSR(UART_FR_REG) & UART_TX_FIFO_FULL) );
return 0;
}
int uart_write_str(char * str)
{
while ( *str != 0 ) {
uart_write ( *str++ );
}
return 0;
}
int uart_write_hex(int val)
{
int i;
int tmp;
uart_write_str("0x");
for ( i=0 ; i<8 ; i++ ) {
tmp = (val >> ((7-i) * 4 )) & 0xf;
tmp = tmp < 10 ? (tmp + '0') : (tmp + 'A' - 10);
uart_write(tmp);
}
uart_write_str("\r\n");
return 0;
}

View file

@ -0,0 +1,20 @@
OUTPUT_ARCH(mips)
ENTRY(entry)
SECTIONS {
. = BZ_TEXT_START;
.text : {
*(.text.entry)
*(.text)
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
workspace = .;
}

View file

@ -0,0 +1,166 @@
/* Copyright 2007 Gabor Juhos */
/* keep original values of the a0,a1,a2,a3 registers */
/* cache manipulation adapted from Broadcom code */
/* Copyright 2005 Oleg I. Vdovikin (oleg@cs.msu.su) */
/* cache manipulation adapted from Broadcom code */
/* idea taken from original bunzip2 decompressor code */
/* Copyright 2004 Manuel Novoa III (mjn3@codepoet.org) */
/* Licensed under the linux kernel's version of the GPL.*/
#include <asm/asm.h>
#include <asm/regdef.h>
#define KSEG0 0x80000000
#define C0_CONFIG $16
#define C0_TAGLO $28
#define C0_TAGHI $29
#define CONF1_DA_SHIFT 7 /* D$ associativity */
#define CONF1_DA_MASK 0x00000380
#define CONF1_DA_BASE 1
#define CONF1_DL_SHIFT 10 /* D$ line size */
#define CONF1_DL_MASK 0x00001c00
#define CONF1_DL_BASE 2
#define CONF1_DS_SHIFT 13 /* D$ sets/way */
#define CONF1_DS_MASK 0x0000e000
#define CONF1_DS_BASE 64
#define CONF1_IA_SHIFT 16 /* I$ associativity */
#define CONF1_IA_MASK 0x00070000
#define CONF1_IA_BASE 1
#define CONF1_IL_SHIFT 19 /* I$ line size */
#define CONF1_IL_MASK 0x00380000
#define CONF1_IL_BASE 2
#define CONF1_IS_SHIFT 22 /* Instruction cache sets/way */
#define CONF1_IS_MASK 0x01c00000
#define CONF1_IS_BASE 64
#define Index_Invalidate_I 0x00
#define Index_Writeback_Inv_D 0x01
.text
LEAF(startup)
.set noreorder
/* Copy decompressor code to the right place */
li t0, BZ_TEXT_START
la t1, code_start
la t2, code_stop
$L1:
lw t3, 0(t1)
sw t3, 0(t0)
add t1, 4
blt t1, t2, $L1
add t0, 4
/* At this point we need to invalidate dcache and */
/* icache before jumping to new code */
1: /* Get cache sizes */
.set mips32
mfc0 s0,C0_CONFIG,1
.set mips0
li s1,CONF1_DL_MASK
and s1,s0
beq s1,zero,nodc
nop
srl s1,CONF1_DL_SHIFT
li t0,CONF1_DL_BASE
sll s1,t0,s1 /* s1 has D$ cache line size */
li s2,CONF1_DA_MASK
and s2,s0
srl s2,CONF1_DA_SHIFT
addiu s2,CONF1_DA_BASE /* s2 now has D$ associativity */
li t0,CONF1_DS_MASK
and t0,s0
srl t0,CONF1_DS_SHIFT
li s3,CONF1_DS_BASE
sll s3,s3,t0 /* s3 has D$ sets per way */
multu s2,s3 /* sets/way * associativity */
mflo t0 /* total cache lines */
multu s1,t0 /* D$ linesize * lines */
mflo s2 /* s2 is now D$ size in bytes */
/* Initilize the D$: */
mtc0 zero,C0_TAGLO
mtc0 zero,C0_TAGHI
li t0,KSEG0 /* Just an address for the first $ line */
addu t1,t0,s2 /* + size of cache == end */
.set mips3
1: cache Index_Writeback_Inv_D,0(t0)
.set mips0
bne t0,t1,1b
addu t0,s1
nodc:
/* Now we get to do it all again for the I$ */
move s3,zero /* just in case there is no icache */
move s4,zero
li t0,CONF1_IL_MASK
and t0,s0
beq t0,zero,noic
nop
srl t0,CONF1_IL_SHIFT
li s3,CONF1_IL_BASE
sll s3,t0 /* s3 has I$ cache line size */
li t0,CONF1_IA_MASK
and t0,s0
srl t0,CONF1_IA_SHIFT
addiu s4,t0,CONF1_IA_BASE /* s4 now has I$ associativity */
li t0,CONF1_IS_MASK
and t0,s0
srl t0,CONF1_IS_SHIFT
li s5,CONF1_IS_BASE
sll s5,t0 /* s5 has I$ sets per way */
multu s4,s5 /* sets/way * associativity */
mflo t0 /* s4 is now total cache lines */
multu s3,t0 /* I$ linesize * lines */
mflo s4 /* s4 is cache size in bytes */
/* Initilize the I$: */
mtc0 zero,C0_TAGLO
mtc0 zero,C0_TAGHI
li t0,KSEG0 /* Just an address for the first $ line */
addu t1,t0,s4 /* + size of cache == end */
.set mips3
1: cache Index_Invalidate_I,0(t0)
.set mips0
bne t0,t1,1b
addu t0,s3
noic:
li t0, BZ_TEXT_START
addiu sp, -32 /* reserve stack for parameters */
#if 0
sw a0, 0(sp)
sw a1, 4(sp)
sw a2, 8(sp)
sw a3, 12(sp)
#endif
sw s3, 16(sp) /* icache line size */
sw s4, 20(sp) /* icache size */
sw s1, 24(sp) /* dcache line size */
jr t0
sw s2, 28(sp) /* dcache size */
.set reorder
END(startup)

View file

@ -0,0 +1,17 @@
OUTPUT_ARCH(mips)
ENTRY(startup)
SECTIONS {
. = TEXT_START;
.text : {
*(.text)
*(.rodata)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}

View file

@ -0,0 +1,64 @@
diff -urN linux-2.6.19.2/arch/mips/Kconfig linux-2.6.19.2.new/arch/mips/Kconfig
--- linux-2.6.19.2/arch/mips/Kconfig 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2.new/arch/mips/Kconfig 2007-01-23 14:49:38.000000000 +0100
@@ -12,6 +12,18 @@
prompt "System type"
default SGI_IP22
+config MIPS_ADM5120
+ bool "Support for ADM5120 SoC"
+ select SYS_HAS_CPU_MIPS32_R1
+ select DMA_NONCOHERENT
+ select HW_HAS_PCI
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SYS_SUPPORTS_32BIT_KERNEL
+
+config PCI_ADM5120
+ bool "Add PCI control support for ADM5120"
+ depends on MIPS_ADM5120 && PCI
+
config MIPS_MTX1
bool "4G Systems MTX-1 board"
select DMA_NONCOHERENT
diff -urN linux-2.6.19.2/arch/mips/Makefile linux-2.6.19.2.new/arch/mips/Makefile
--- linux-2.6.19.2/arch/mips/Makefile 2007-01-23 14:02:57.000000000 +0100
+++ linux-2.6.19.2.new/arch/mips/Makefile 2007-01-23 14:49:39.000000000 +0100
@@ -165,6 +165,14 @@
load-$(CONFIG_MACH_JAZZ) += 0xffffffff80080000
#
+# ADMtek 5120
+#
+
+core-$(CONFIG_MIPS_ADM5120) += arch/mips/adm5120/
+cflags-$(CONFIG_MIPS_ADM5120) += -Iinclude/asm-mips/mach-adm5120
+load-$(CONFIG_MIPS_ADM5120) += 0xffffffff80101000
+
+#
# Common Alchemy Au1x00 stuff
#
core-$(CONFIG_SOC_AU1X00) += arch/mips/au1000/common/
diff -urN linux-2.6.19.2/arch/mips/pci/Makefile linux-2.6.19.2.new/arch/mips/pci/Makefile
--- linux-2.6.19.2/arch/mips/pci/Makefile 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2.new/arch/mips/pci/Makefile 2007-01-23 14:49:40.000000000 +0100
@@ -53,3 +53,4 @@
obj-$(CONFIG_VICTOR_MPC30X) += fixup-mpc30x.o
obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o
obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o
+obj-$(CONFIG_PCI_ADM5120) += ops-adm5120.o pci-adm5120.o
diff -urN linux-2.6.19.2/include/asm-mips/bootinfo.h linux-2.6.19.2.new/include/asm-mips/bootinfo.h
--- linux-2.6.19.2/include/asm-mips/bootinfo.h 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2.new/include/asm-mips/bootinfo.h 2007-01-23 14:49:40.000000000 +0100
@@ -212,6 +212,12 @@
#define MACH_GROUP_NEC_EMMA2RH 25 /* NEC EMMA2RH (was 23) */
#define MACH_NEC_MARKEINS 0 /* NEC EMMA2RH Mark-eins */
+/*
+ * Valid machtype for group ADMtek
+ */
+#define MACH_GROUP_ADM_GW 23
+#define MACH_ADM_GW_5120 0
+
#define CL_SIZE COMMAND_LINE_SIZE
const char *get_system_type(void);

View file

@ -0,0 +1,25 @@
diff -urN linux-2.6.19.2/drivers/mtd/maps/Kconfig linux-2.6.19.2-adm5120/drivers/mtd/maps/Kconfig
--- linux-2.6.19.2/drivers/mtd/maps/Kconfig 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/mtd/maps/Kconfig 2007-01-23 01:13:39.000000000 +0100
@@ -622,5 +622,10 @@
This selection automatically selects the map_ram driver.
+config MTD_ADM5120
+ tristate "Map driver for ADMtek ADM5120 boards"
+ depends on MIPS_ADM5120
+ select MTD_CFI_AMDSTD
+
endmenu
diff -urN linux-2.6.19.2/drivers/mtd/maps/Makefile linux-2.6.19.2-adm5120/drivers/mtd/maps/Makefile
--- linux-2.6.19.2/drivers/mtd/maps/Makefile 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/mtd/maps/Makefile 2007-01-23 01:20:52.000000000 +0100
@@ -43,6 +43,7 @@
obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
obj-$(CONFIG_MTD_PCI) += pci.o
obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o
+obj-$(CONFIG_MTD_ADM5120) += adm5120_mtd.o
obj-$(CONFIG_MTD_LASAT) += lasat.o
obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
obj-$(CONFIG_MTD_EDB7312) += edb7312.o

View file

@ -0,0 +1,25 @@
diff -urN linux-2.6.19.2/drivers/net/Kconfig linux-2.6.19.2-adm5120/drivers/net/Kconfig
--- linux-2.6.19.2/drivers/net/Kconfig 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/net/Kconfig 2007-01-23 01:13:39.000000000 +0100
@@ -450,6 +450,10 @@
If you have an Alchemy Semi AU1X00 based system
say Y. Otherwise, say N.
+config MIPS_ADM5120_ENET
+ tristate "MIPS ADM5120 Ethernet switch support"
+ depends on NET_ETHERNET && MIPS_ADM5120
+
config NET_SB1250_MAC
tristate "SB1250 Ethernet support"
depends on NET_ETHERNET && SIBYTE_SB1xxx_SOC
diff -urN linux-2.6.19.2/drivers/net/Makefile linux-2.6.19.2-adm5120/drivers/net/Makefile
--- linux-2.6.19.2/drivers/net/Makefile 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/net/Makefile 2007-01-23 01:13:39.000000000 +0100
@@ -164,6 +164,7 @@
# This is also a 82596 and should probably be merged
obj-$(CONFIG_LP486E) += lp486e.o
+obj-$(CONFIG_MIPS_ADM5120_ENET) += adm5120sw.o
obj-$(CONFIG_ETH16I) += eth16i.o
obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o
obj-$(CONFIG_HPLANCE) += hplance.o 7990.o

View file

@ -0,0 +1,50 @@
diff -urN linux-2.6.19.2/drivers/serial/Kconfig linux-2.6.19.2-adm5120/drivers/serial/Kconfig
--- linux-2.6.19.2/drivers/serial/Kconfig 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/serial/Kconfig 2007-01-23 01:13:39.000000000 +0100
@@ -246,6 +246,22 @@
comment "Non-8250 serial port support"
+config SERIAL_ADM5120
+ bool "ADM5120 serial port support"
+ depends on MIPS_ADM5120
+ select SERIAL_CORE
+ select SERIAL_CORE_CONSOLE
+ help
+ Driver for the on chip UARTs on the ADM5120 SoC
+
+config ADM5120_NR_UARTS
+ int "Maximum number of ADM5120 serial ports"
+ depends on SERIAL_ADM5120
+ default "2"
+ ---help---
+ Set this to the number of serial ports you want the driver to
+ support.
+
config SERIAL_AMBA_PL010
tristate "ARM AMBA PL010 serial port support"
depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE)
diff -urN linux-2.6.19.2/drivers/serial/Makefile linux-2.6.19.2-adm5120/drivers/serial/Makefile
--- linux-2.6.19.2/drivers/serial/Makefile 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/serial/Makefile 2007-01-23 01:21:45.000000000 +0100
@@ -20,6 +20,7 @@
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
obj-$(CONFIG_SERIAL_8250_AU1X00) += 8250_au1x00.o
+obj-$(CONFIG_SERIAL_ADM5120) += adm5120_uart.o
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
diff -urN linux-2.6.19.2/include/linux/serial_core.h linux-2.6.19.2-adm5120/include/linux/serial_core.h
--- linux-2.6.19.2/include/linux/serial_core.h 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/include/linux/serial_core.h 2007-01-23 01:13:39.000000000 +0100
@@ -133,6 +133,9 @@
#define PORT_S3C2412 73
+/* ADMtek ADM5120 SoC */
+#define PORT_ADM5120 68
+
#ifdef __KERNEL__
#include <linux/compiler.h>

View file

@ -0,0 +1,53 @@
diff -urN linux-2.6.19.2/drivers/usb/core/hub.c linux-2.6.19.2-adm5120/drivers/usb/core/hub.c
--- linux-2.6.19.2/drivers/usb/core/hub.c 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/usb/core/hub.c 2007-01-23 01:13:39.000000000 +0100
@@ -2156,6 +2156,8 @@
USB_DT_DEVICE << 8, 0,
buf, GET_DESCRIPTOR_BUFSIZE,
(i ? USB_CTRL_GET_TIMEOUT : 1000));
+printk(KERN_CRIT "usb_control_msg: %d %d %d (%d)\n", r, buf->bMaxPacketSize0,
+buf->bDescriptorType, USB_DT_DEVICE);
switch (buf->bMaxPacketSize0) {
case 8: case 16: case 32: case 64: case 255:
if (buf->bDescriptorType ==
diff -urN linux-2.6.19.2/drivers/usb/host/Kconfig linux-2.6.19.2-adm5120/drivers/usb/host/Kconfig
--- linux-2.6.19.2/drivers/usb/host/Kconfig 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/usb/host/Kconfig 2007-01-23 01:13:39.000000000 +0100
@@ -192,3 +192,6 @@
To compile this driver as a module, choose M here: the
module will be called "sl811_cs".
+config USB_ADM5120_HCD
+ tristate "ADM5120 HCD support"
+ depends on USB && MIPS_ADM5120
diff -urN linux-2.6.19.2/drivers/usb/host/Makefile linux-2.6.19.2-adm5120/drivers/usb/host/Makefile
--- linux-2.6.19.2/drivers/usb/host/Makefile 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/usb/host/Makefile 2007-01-23 01:13:39.000000000 +0100
@@ -16,3 +16,4 @@
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o
+obj-$(CONFIG_USB_ADM5120_HCD) += adm5120-hcd.o
diff -urN linux-2.6.19.2/drivers/usb/Kconfig linux-2.6.19.2-adm5120/drivers/usb/Kconfig
--- linux-2.6.19.2/drivers/usb/Kconfig 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/usb/Kconfig 2007-01-23 01:13:39.000000000 +0100
@@ -91,8 +91,6 @@
source "drivers/usb/net/Kconfig"
-source "drivers/usb/mon/Kconfig"
-
comment "USB port drivers"
depends on USB
diff -urN linux-2.6.19.2/drivers/usb/Makefile linux-2.6.19.2-adm5120/drivers/usb/Makefile
--- linux-2.6.19.2/drivers/usb/Makefile 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/usb/Makefile 2007-01-23 01:22:18.000000000 +0100
@@ -17,6 +17,7 @@
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_ETRAX_USB_HOST) += host/
obj-$(CONFIG_USB_OHCI_AT91) += host/
+obj-$(CONFIG_USB_ADM5120_HCD) += host/
obj-$(CONFIG_USB_ACM) += class/
obj-$(CONFIG_USB_PRINTER) += class/

View file

@ -0,0 +1,25 @@
diff -urN linux-2.6.19.2/drivers/char/Kconfig linux-2.6.19.2-adm5120/drivers/char/Kconfig
--- linux-2.6.19.2/drivers/char/Kconfig 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/char/Kconfig 2007-01-23 01:13:39.000000000 +0100
@@ -1034,7 +1034,9 @@
The mmtimer device allows direct userspace access to the
Altix system timer.
-source "drivers/char/tpm/Kconfig"
+config ADM5120_GPIO
+ tristate "ADM5120 GPIO"
+ depends on MIPS_ADM5120
config TELCLOCK
tristate "Telecom clock driver for MPBL0010 ATCA SBC"
diff -urN linux-2.6.19.2/drivers/char/Makefile linux-2.6.19.2-adm5120/drivers/char/Makefile
--- linux-2.6.19.2/drivers/char/Makefile 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2-adm5120/drivers/char/Makefile 2007-01-23 01:20:01.000000000 +0100
@@ -90,6 +90,7 @@
obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_TANBAC_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o
+obj-$(CONFIG_ADM5120_GPIO) += adm5120_gpio.o
obj-$(CONFIG_WATCHDOG) += watchdog/
obj-$(CONFIG_MWAVE) += mwave/

View file

@ -0,0 +1,37 @@
diff -Nur linux-2.6.19.2/drivers/mtd/Kconfig.old linux-2.6.19.2/drivers/mtd/Kconfig
--- linux-2.6.19.2/drivers/mtd/Kconfig.old 2007-03-25 08:13:02.000000000 +0200
+++ linux-2.6.19.2/drivers/mtd/Kconfig 2007-03-26 13:37:47.000000000 +0200
@@ -157,6 +157,22 @@
for your particular device. It won't happen automatically. The
'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
+config MTD_MYLOADER_PARTS
+ tristate "MyLoader partition parsing"
+ depends on MIPS_ADM5120 && MTD_PARTITIONS
+ ---help---
+ MyLoader is a bootloader which allows the user to define partitions
+ in flash devices, by putting a table in the second erase block
+ on the device, similar to a partition table. This table gives the
+ offsets and lengths of the user defined partitions.
+
+ If you need code which can detect and parse these tables, and
+ register MTD 'partitions' corresponding to each image detected,
+ enable this option.
+
+ You will still need the parsing functions to be called by the driver
+ for your particular device. It won't happen automatically.
+
comment "User Modules And Translation Layers"
depends on MTD
diff -Nur linux-2.6.19.2/drivers/mtd/Makefile.old linux-2.6.19.2/drivers/mtd/Makefile
--- linux-2.6.19.2/drivers/mtd/Makefile.old 2007-01-10 20:10:37.000000000 +0100
+++ linux-2.6.19.2/drivers/mtd/Makefile 2007-03-26 13:28:23.000000000 +0200
@@ -12,6 +12,7 @@
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
+obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_CHAR) += mtdchar.o

View file

@ -0,0 +1,31 @@
--- linux-2.6.19.2/drivers/mtd/chips/Kconfig.old 2007-01-11 03:10:36.000000000 +0800
+++ linux-2.6.19.2/drivers/mtd/chips/Kconfig 2007-03-29 14:43:32.000000000 +0800
@@ -199,6 +199,14 @@
provides support for one of those command sets, used on chips
including the AMD Am29LV320.
+config MTD_CFI_AMDSTD_FORCE_BOTTOM_BOOT
+ bool "Force bottom boot for Macronix flash chips"
+ depends on MTD_CFI_AMDSTD
+ help
+ Some Macronix flash chips have wrong CFI info, and the driver may
+ detect the type incorrectly. Select this if the chip part number
+ ends with BTC.
+
config MTD_CFI_STAA
tristate "Support for ST (Advanced Architecture) flash chips"
depends on MTD_GEN_PROBE
--- linux-2.6.19.2/drivers/mtd/chips/cfi_cmdset_0002.c.old 2007-03-22 16:14:56.000000000 +0800
+++ linux-2.6.19.2/drivers/mtd/chips/cfi_cmdset_0002.c 2007-03-29 14:07:28.000000000 +0800
@@ -320,6 +320,11 @@
cfi_tell_features(extp);
#endif
+#ifdef CONFIG_MTD_CFI_AMDSTD_FORCE_BOTTOM_BOOT
+ extp->TopBottom = 2;
+ bootloc = extp->TopBottom;
+#endif
+
bootloc = extp->TopBottom;
if ((bootloc != 2) && (bootloc != 3)) {
printk(KERN_WARNING "%s: CFI does not contain boot "

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,27 @@
diff -urN linux.old/drivers/mtd/nand/Kconfig linux.dev/drivers/mtd/nand/Kconfig
--- linux.old/drivers/mtd/nand/Kconfig 2006-11-29 22:57:37.000000000 +0100
+++ linux.dev/drivers/mtd/nand/Kconfig 2006-12-14 04:38:51.000000000 +0100
@@ -75,6 +75,12 @@
help
Support for NAND flash on Technologic Systems TS-7250 platform.
+config MTD_NAND_RB500
+ tristate "NAND Flash device on RB500 board"
+ depends on MTD_NAND
+ help
+ Support for NAND flash on RB500 platform.
+
config MTD_NAND_IDS
tristate
diff -urN linux.old/drivers/mtd/nand/Makefile linux.dev/drivers/mtd/nand/Makefile
--- linux.old/drivers/mtd/nand/Makefile 2006-11-29 22:57:37.000000000 +0100
+++ linux.dev/drivers/mtd/nand/Makefile 2006-12-14 04:38:51.000000000 +0100
@@ -9,6 +9,7 @@
obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
+obj-$(CONFIG_MTD_NAND_RB500) += rbmipsnand.o
obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o

View file

@ -0,0 +1,17 @@
#
# Copyright (C) 2006 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
define Profile/Atheros
NAME:=Atheros WiFi (default)
PACKAGES:=kmod-madwifi
endef
define Profile/Atheros/Description
Package set compatible with hardware using Atheros WiFi cards
endef
$(eval $(call Profile,Atheros))

View file

@ -0,0 +1,17 @@
#
# Copyright (C) 2006 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
define Profile/Texas
NAME:=Texas Instruments WiFi
PACKAGES:=kmod-acx
endef
define Profile/Texas/Description
Package set compatible with hardware using Texas Instruments WiFi cards
endef
$(eval $(call Profile,Texas))

View file

@ -0,0 +1,17 @@
#
# Copyright (C) 2006 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
define Profile/None
NAME:=No WiFi
PACKAGES:=
endef
define Profile/None/Description
Package set without WiFi support
endef
$(eval $(call Profile,None))