Hi,
I finally succeeded in getting 2.6.10 working on my adm5120 router. Attached is a patch against 2.6.10 with the needed changes.
First a list of what it does NOT do: -ethernet -usb -pci (my board doesn't have pci) -anything usefull :)
What it does do:
-Boot
-Serial support (with improved timing compared to the official 2.4.18 kernels)
-Simplified init code (the 2.4.18 code was way to complex)
I also found the most probable reason people had problems porting the released sources to other kernels: the bootloader jumps to a fixed address that just happens to be the kernel_entry in 2.4.18
I 'solved' it by adding a jump on this address to the real kernel_entry (which is at the other end of the kernel in 2.6)
I also had some great fun figuring out how the hell initramfs is supposed to work.... To finally find out after two days I had one slash to little in the configured path..... I also found that standard 2.6.10 doesn't support symlinks and my initramfs ended up being 14Mb.
Next I plan to port the ethernet driver and usb. I don't think I will port the led driver as is, its much easier to just offer a character device with access to the GPIO port than the 'LED BLINK' stuff used in the ADMtek led driver.
Jeroen
diff -ruN linux-2.6.10/Makefile linux-2.6.10-adm.1/Makefile --- linux-2.6.10/Makefile 2004-12-24 22:35:01.000000000 +0100 +++ linux-2.6.10-adm.1/Makefile 2005-01-27 21:07:04.000000000 +0100 @@ -4,6 +4,8 @@ EXTRAVERSION = NAME=Woozy Numbat +ARCH=mips + # *DOCUMENTATION* # To see a list of typical targets execute "make help" # More info can be located in ./README @@ -722,6 +724,10 @@ vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE $(call if_changed_rule,vmlinux__) +vmlinuz: vmlinux + $(OBJCOPY) -O binary vmlinux vmlinux.bin + gzip vmlinux.bin -c >vmlinuz + # The actual objects are generated when descending, # make sure no implicit rule kicks in $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ; diff -ruN linux-2.6.10/arch/mips/Kconfig linux-2.6.10-adm.1/arch/mips/Kconfig --- linux-2.6.10/arch/mips/Kconfig 2004-12-24 22:34:45.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/Kconfig 2005-01-27 21:06:17.000000000 +0100 @@ -46,6 +46,10 @@ the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at <http://www.linux-mips.org/>. +config MIPS_AM5120 + bool "Support for ADM5120 board" + select DMA_NONCOHERENT + config MIPS_MAGNUM_4000 bool "Support for MIPS Magnum 4000" depends on MACH_JAZZ diff -ruN linux-2.6.10/arch/mips/Makefile linux-2.6.10-adm.1/arch/mips/Makefile --- linux-2.6.10/arch/mips/Makefile 2004-12-24 22:33:49.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/Makefile 2005-01-27 21:06:16.000000000 +0100 @@ -49,7 +49,7 @@ endif ifdef CONFIG_CROSSCOMPILE -CROSS_COMPILE := $(tool-prefix) +CROSS_COMPILE := /export/tools/bin/$(tool-prefix) endif ifdef CONFIG_BUILD_ELF64 @@ -232,6 +232,13 @@ load-$(CONFIG_MACH_JAZZ) += 0xffffffff80080000 # +# ADMtek 5120 +# + +core-$(CONFIG_MIPS_AM5120) += arch/mips/am5120/ +load-$(CONFIG_MIPS_AM5120) += 0xffffffff80002000 + +# # Common Alchemy Au1x00 stuff # core-$(CONFIG_SOC_AU1X00) += arch/mips/au1000/common/ diff -ruN linux-2.6.10/arch/mips/am5120/5120_rtc.c linux-2.6.10-adm.1/arch/mips/am5120/5120_rtc.c --- linux-2.6.10/arch/mips/am5120/5120_rtc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/am5120/5120_rtc.c 2005-01-27 21:06:17.000000000 +0100 @@ -0,0 +1,73 @@ +/***************************************************************************** +; +; (C) Unpublished Work of ADMtek Incorporated. All Rights Reserved. +; +; THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL, +; PROPRIETARY AND TRADESECRET INFORMATION OF ADMTEK INCORPORATED. +; ACCESS TO THIS WORK IS RESTRICTED TO (I) ADMTEK EMPLOYEES WHO HAVE A +; NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR ASSIGNMENTS +; AND (II) ENTITIES OTHER THAN ADMTEK WHO HAVE ENTERED INTO APPROPRIATE +; LICENSE AGREEMENTS. NO PART OF THIS WORK MAY BE USED, PRACTICED, +; PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, +; ABBRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, +; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ADMTEK. +; ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD +; SUBJECT THE PERPERTRATOR TO CRIMINAL AND CIVIL LIABILITY. +; +;------------------------------------------------------------------------------ +; +; Project : ADM5120 +; Creator : daniell@xxxxxxxxxxxxx +; File : arch/mips/am5120/5120_rtc.c +; Date : 2003.3.4 +; Abstract: +; +;Modification History: +; +;*****************************************************************************/ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/serial.h> +#include <linux/types.h> +#include <linux/string.h> + +#include <asm/reboot.h> +#include <asm/io.h> +#include <asm/time.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/system.h> + +#include <linux/mc146818rtc.h> +#include <asm/am5120/adm5120.h> +#include <asm-arm/rtc.h> + +struct rtc_ops *rtc_ops=NULL; +/* +static unsigned char am5120_rtc_read_data(unsigned long addr) +{ + //outb(addr, MALTA_RTC_ADR_REG); + //return inb(MALTA_RTC_DAT_REG); + return 0; +} + +static void am5120_rtc_write_data(unsigned char data, unsigned long addr) +{ + //outb(addr, MALTA_RTC_ADR_REG); + //outb(data, MALTA_RTC_DAT_REG); +} + +static int am5120_rtc_bcd_mode(void) +{ + return 0; +} + +struct rtc_ops am5120_rtc_ops = { + &am5120_rtc_read_data, + &am5120_rtc_write_data, + &am5120_rtc_bcd_mode +}; +*/ diff -ruN linux-2.6.10/arch/mips/am5120/Makefile linux-2.6.10-adm.1/arch/mips/am5120/Makefile --- linux-2.6.10/arch/mips/am5120/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/am5120/Makefile 2005-01-27 21:06:17.000000000 +0100 @@ -0,0 +1,3 @@ + +obj-y := setup.o prom.o irq.o serial.o memory.o mipsIRQ.o time.o pci.o +# 5120_rtc.o led.o diff -ruN linux-2.6.10/arch/mips/am5120/irq.c linux-2.6.10-adm.1/arch/mips/am5120/irq.c --- linux-2.6.10/arch/mips/am5120/irq.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/am5120/irq.c 2005-01-27 21:06:17.000000000 +0100 @@ -0,0 +1,181 @@ +/***************************************************************************** +; +; (C) Unpublished Work of ADMtek Incorporated. All Rights Reserved. +; +; THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL, +; PROPRIETARY AND TRADESECRET INFORMATION OF ADMTEK INCORPORATED. +; ACCESS TO THIS WORK IS RESTRICTED TO (I) ADMTEK EMPLOYEES WHO HAVE A +; NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR ASSIGNMENTS +; AND (II) ENTITIES OTHER THAN ADMTEK WHO HAVE ENTERED INTO APPROPRIATE +; LICENSE AGREEMENTS. NO PART OF THIS WORK MAY BE USED, PRACTICED, +; PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, +; ABBRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, +; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ADMTEK. +; ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD +; SUBJECT THE PERPERTRATOR TO CRIMINAL AND CIVIL LIABILITY. +; +;------------------------------------------------------------------------------ +; +; Project : ADM5120 +; Creator : daniell@xxxxxxxxxxxxx +; File : arch/mips/am5120/irq.c +; Date : 2003.3.4 +; Abstract: +; +;Modification History: +; +; Jeroen Vreeken (pe1rxq@xxxxxxxxx) +; Simplified and merged with 5120_int.c +; +; Includes code by: +; Carsten Langgaard, carstenl@xxxxxxxx +; Copyright (C) 2000, 2001 MIPS Technologies, Inc. +; Copyright (C) 2001 Ralf Baechle +; +;*****************************************************************************/ + +#include <linux/config.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/mipsregs.h> +#include <asm/gdb-stub.h> + +#include <asm/am5120/adm5120.h> + +extern void breakpoint(void); +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); + +static spinlock_t mips_irq_lock = SPIN_LOCK_UNLOCKED; + +void am5120_hw0_irqdispatch(struct pt_regs *regs) +{ + unsigned long flags; + unsigned long intsrc; + int i; + + /* We don't have multiple cpus, is this locking really needed??? + - Jeroen + */ + spin_lock_irqsave(&mips_irq_lock, flags); + + intsrc = ADM5120_INTC_REG(IRQ_STATUS_REG) & IRQ_MASK; + + for (i = 0; intsrc; intsrc >>= 1, i++) + if (intsrc & 0x1) + do_IRQ(i, regs); + + spin_unlock_irqrestore(&mips_irq_lock, flags); +} + + +void enable_am5120_irq(unsigned int irq) +{ + int s; + + /* Disable all interrupts (FIQ/IRQ) */ + s = mips_int_lock(); + + if ((irq < 0) || (irq > INT_LVL_MAX)) + goto err_exit; + + ADM5120_INTC_REG(IRQ_ENABLE_REG) = (1<<irq); + +err_exit: + + /* Restore the interrupts states */ + mips_int_unlock(s); +} + + +void disable_am5120_irq(unsigned int irq) +{ + int s; + + /* Disable all interrupts (FIQ/IRQ) */ + s = mips_int_lock(); + + if ((irq < 0) || (irq > INT_LVL_MAX)) + goto err_exit; + + ADM5120_INTC_REG(IRQ_DISABLE_REG) = (1<<irq); + +err_exit: + /* Restore the interrupts states */ + mips_int_unlock(s); +} + +unsigned int startup_am5120_irq(unsigned int irq) +{ + enable_am5120_irq(irq); + return 0; +} + +void shutdown_am5120_irq(unsigned int irq) +{ + disable_am5120_irq(irq); +} + +static inline void ack_am5120_irq(unsigned int irq_nr) +{ + ADM5120_INTC_REG(IRQ_DISABLE_REG) = (1 << irq_nr); +} + + +static void end_am5120_irq(unsigned int irq_nr) +{ + ADM5120_INTC_REG(IRQ_ENABLE_REG) = (1 << irq_nr); +} + + +void set_affinity_am5120_irq(unsigned int irq, cpumask_t mask) +{ + return; +} + + +static hw_irq_controller am5120_irq_type = { + "ADM5120 INTC", + startup_am5120_irq, + shutdown_am5120_irq, + enable_am5120_irq, + disable_am5120_irq, + ack_am5120_irq, + end_am5120_irq, + set_affinity_am5120_irq +}; + + +void __init arch_init_irq(void) +{ + int i; + set_except_vector(0, mipsIRQ); + + for (i=0; i<=INT_LVL_MAX; i++) { + irq_desc[i].status=IRQ_DISABLED; + irq_desc[i].action=0; + irq_desc[i].depth=1; + irq_desc[i].handler=&am5120_irq_type; + } + +#ifdef CONFIG_REMOTE_DEBUG + printk("Setting debug traps - please connect the remote debugger.\n"); + + set_debug_traps(); + + breakpoint(); +#endif +} + diff -ruN linux-2.6.10/arch/mips/am5120/led.c linux-2.6.10-adm.1/arch/mips/am5120/led.c --- linux-2.6.10/arch/mips/am5120/led.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/am5120/led.c 2005-01-27 21:06:17.000000000 +0100 @@ -0,0 +1,493 @@ +/* + * LED interface for WP3200 + * + * Copyright (C) 2002, by Allen Hung + * + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/fcntl.h> +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/proc_fs.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/system.h> +#include "led.h" + +#define BUF_LEN 30 + +struct LED_DATA { + char sts_buf[BUF_LEN+1]; + unsigned long sts; +}; + +struct LED_DATA led_data[LED_DEV_NUM]; +// sam 01-30-2004 for watchdog +static struct timer_list watchdog; +// end sam + +static struct timer_list blink_timer[LED_DEV_NUM]; +static char cmd_buf[BUF_LEN+1]; + +//------------------------------------------------------------ +static long atoh(char *p) +{ + long v = 0, c; + while ( (c = *p++) ) { + if ( c >= '0' && c <= '9' ) v = (v << 4) + c - '0'; + else if ( c >= 'a' && c <= 'f' ) v = (v << 4) + c - 'a' + 0xA; + else if ( c >= 'A' && c <= 'F' ) v = (v << 4) + c - 'A' + 0xA; + else break; + } + return v; +} + + +#define GPIO_VAL (*(unsigned long *)0xb20000b8) +#define GPIO_SEL (*(unsigned long *)0xb20000bc) +#define GPIO_SEL_I_O (*(unsigned long *)0xb20000b8) +#define GPIO_O_EN (*(unsigned long *)0xb20000b8) +#define INIT_WATCHDOG_REGISTER 0x20 + +// sam 1-30-2004 LED status +// bit map as following +// BIT 4:0 Link status -->PHY Link ->1 = up, 0 = down +#define LINK_STATUS (*(unsigned long *)0xb2000014) +#define WATCHDOG_VAL (*(unsigned long *)0xb20000c0) +#define WATCHDOG_PERIOD 2000 // unit ms +#define EXPIRE_TIME 300 // unit 10 ms +#define CLEAR_TIMEER 0xffffa000l // bit 14:0 -> count up timer, write 0 to clear +#define ENABLE_WATCHDOG 0x80000000l // bit 31 -> 1 enable , 0 disable watchdog +#define WATCHDOG_SET_TMR_SHIFT 16 // bit 16:30 -> watchdog timer set +// end sam +//------------------------------------------------------------ +static void turn_led(int id, int on) +{ + unsigned long led_bit = 1 << (id); + unsigned long led_bit_val; + + led_bit_val = led_bit << 24; + + switch ( on ) { + case 0: GPIO_VAL |= led_bit_val; break; // LED OFF + case 1: GPIO_VAL &= ~led_bit_val; break; // LED ON + case 2: GPIO_VAL ^= led_bit_val; break; // LED inverse + } +} + +static void blink_wrapper(u_long id) +{ + u_long sts = led_data[id].sts; + if ( (sts & LED_BLINK_CMD) == LED_BLINK_CMD ) { + int period = sts & LED_BLINK_PERIOD; + blink_timer[id].expires = jiffies + (period * HZ / 1000); + turn_led(id, 2); + add_timer(&blink_timer[id]); + } + else if ( sts == LED_ON || sts == LED_OFF ) + turn_led(id, sts==LED_ON ? 1 : 0); +} +//------------------------------------------------------------ +static void get_token_str(char *str, char token[][21], int token_num) +{ + int t, i; + for ( t = 0 ; t < token_num ; t++ ) { + memset(token[t], 0, 21); + while ( *str == ' ' ) str++; + for ( i = 0 ; str[i] ; i++ ) { + if ( str[i] == '\t' || str[i] == ' ' || str[i] == '\n' ) break; + if ( i < 20 ) token[t][i] = str[i]; + } + str += i; + } +} + +//------------------------------------------------------------ +static void set_led_status_by_str(int id) +{ + char token[3][21], *p; + + get_token_str(led_data[id].sts_buf, token, 3); + if ( strcmp(token[0], "LED") ) + goto set_led_off; + if ( !strcmp(token[1], "ON") ) { + turn_led(id, 1); + led_data[id].sts = LED_ON; + } + else if ( !strcmp(token[1], "OFF") ) { + goto set_led_off; + } + else if ( !strcmp(token[1], "BLINK") ) { + int period = 0; + p = token[2]; + if ( !strcmp(p, "FAST") ) + period = LED_BLINK_FAST & LED_BLINK_PERIOD; + else if ( !strcmp(p, "SLOW") ) + period = LED_BLINK_SLOW & LED_BLINK_PERIOD; + else if ( !strcmp(p, "EXTRA_SLOW") ) + period = LED_BLINK_EXTRA_SLOW & LED_BLINK_PERIOD; + else if ( !strcmp(p, "OFF") ) + goto set_led_off; + else if ( *p >= '0' && *p <= '9' ) { + while ( *p >= '0' && *p <= '9' ) + period = period * 10 + (*p++) - '0'; + if ( period > 10000 ) period = 10000; + } + else + period = LED_BLINK & LED_BLINK_PERIOD; + if ( period == 0 ) + goto set_led_off; + sprintf(led_data[id].sts_buf, "LED BLINK %d\n", period); + led_data[id].sts = LED_BLINK_CMD + period; + turn_led(id, 2); + // Set timer for next blink + del_timer(&blink_timer[id]); + blink_timer[id].function = blink_wrapper; + blink_timer[id].data = id; + init_timer(&blink_timer[id]); + blink_timer[id].expires = jiffies + (period * HZ / 1000); + add_timer(&blink_timer[id]); + } + else + goto set_led_off; + return; + set_led_off: + strcpy(led_data[id].sts_buf, "LED OFF\n"); + led_data[id].sts = LED_OFF; + turn_led(id, 0); +} + +//---------------------------------------------------------------------- +static int led_read_proc(char *buf, char **start, off_t fpos, int length, int *eof, void *data) +{ + int len, dev; + for ( len = dev = 0 ; dev < LED_DEV_NUM ; dev++ ) { + len += sprintf(buf+len, "%d: %s", dev, led_data[dev].sts_buf); + } + len = strlen(buf) - fpos; + if ( len <= 0 ) { + *start = buf; + *eof = 1; + return 0; + } + *start = buf + fpos; + if ( len <= length ) *eof = 1; + return len < length ? len : length; +} + +//---------------------------------------------------------------------- +static int led_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int id = (int)file->private_data; + + switch ( cmd ) { + case LED_ON: + strcpy(led_data[id].sts_buf, "LED ON\n"); + set_led_status_by_str(id); + break; + case LED_OFF: + strcpy(led_data[id].sts_buf, "LED OFF\n"); + set_led_status_by_str(id); + break; + default: + if ( (cmd & LED_BLINK_CMD) != LED_BLINK_CMD ) + break; + case LED_BLINK: + case LED_BLINK_FAST: + case LED_BLINK_SLOW: + case LED_BLINK_EXTRA_SLOW: + sprintf(led_data[id].sts_buf, "LED BLINK %d\n", (int)(cmd & LED_BLINK_PERIOD)); + set_led_status_by_str(id); + break; + } + return 0; +} + +static int led_open(struct inode *inode, struct file *file) +{ + int led_id = MINOR(inode->i_rdev); + unsigned long led_bit = 1 << (led_id); + if ( led_id >= LED_DEV_NUM ) + return -ENODEV; + + GPIO_SEL_I_O &= ~led_bit; // 0 to GPIO + GPIO_O_EN |= (led_bit << 16); // 0 to Output + + file->private_data = (void*)led_id; + return 0; +} + +static long led_read(struct file *file, char *buf, size_t count, loff_t *fpos) +{ + int rem, len; + int id = (int)file->private_data; + char *p = led_data[id].sts_buf; + len = strlen(p); + rem = len - *fpos; + if ( rem <= 0 ) { + *fpos = len; + return 0; + } + if ( rem > count ) rem = count; + memcpy(buf, p+(*fpos), rem); + *fpos += rem; + return rem; +} + +static long led_write(struct file *file, char *buf, size_t count, loff_t *fpos) +{ + int len; + int id = (int)file->private_data; + char *p = id == REG_MINOR ? cmd_buf : led_data[id].sts_buf; + memset(p, 0, BUF_LEN); + p += *fpos; + len = 0; + while ( count > 0 ) { + if ( *fpos < BUF_LEN ) { + int c = *buf++; + p[len] = c>='a' && c<='z' ? c-'a'+'A' : c; + } + (*fpos)++; + len++; + count--; + } + return len; +} + +static int led_flush(struct file *file) +{ + int id = (int)file->private_data; + if ( file->f_mode & FMODE_WRITE ) + set_led_status_by_str(id); + return 0; +} + +static struct file_operations led_fops = { + read: led_read, + write: led_write, + flush: led_flush, + ioctl: led_ioctl, + open: led_open, +}; + +//---------------------------------------------- +static unsigned long *reg_addr; +static int dump_len; + +static int dump_content(char *buf) +{ + int i, j, len; + unsigned long *p = reg_addr; + j = dump_len/4 + ((dump_len&3) ? 1 : 0); + len = sprintf(buf, "Reg Addr = %08lX, Value = \n", (unsigned long)p); + for ( i = 0 ; i < j ; i++, p++ ) + len += sprintf(buf+len,"%08lX%c", *p, (i&7)==7||i==j-1?'\n':' '); + return len; +} + +static long gpio_read(struct file *file, char *buf, size_t count, loff_t *fpos) +{ + int rem, len; + int id = (int)file->private_data; + char temp[80*10]; + if ( id < GPIO_DEV_NUM ) { + int gpio_bit = 1 << id; + len = sprintf(temp, "%d\n", ((GPIO_VAL >> 8)&gpio_bit) ? 1 : 0); + } + else // REG device + len = dump_content(temp); + rem = len - *fpos; + if ( rem <= 0 ) { + *fpos = len; + return 0; + } + if ( rem > count ) rem = count; + memcpy(buf, temp+(*fpos), rem); + *fpos += rem; + return rem; +} + +static int gpio_flush(struct file *file) +{ + long v, addr; + int id = (int)file->private_data; + + if ( id == REG_MINOR && (file->f_mode & FMODE_WRITE) ) { + char token[3][21], *p; + get_token_str(cmd_buf, token, 3); + // get reg address + p = token[0]; + if ( *p == 0 ) return 0; + addr = atoh(p); + //--------------------- + p = token[1]; + if ( *p == 'W' ) { + int width = 0; + if ( !strcmp(p, "W") || !strcmp(p, "WW") ) + width = 4; + else if ( !strcmp(p, "WH") ) + width = 2; + else if ( !strcmp(p, "WB") ) + width = 1; + else + return 0; + p = token[2]; + if ( *p == 0 ) return 0; + v = atoh(p); + switch ( width ) { + case 1: *((char *)addr) = (v & 0xFF); break; + case 2: *((short*)addr) = (v & 0xFFFF); break; + case 4: *((long *)addr) = v; break; + } + } + else { // get dump len + char temp[80*10]; + reg_addr = (unsigned long *)(addr & ~3); + dump_len = 4; + if ( *p ) { + dump_len = atoh(p); + dump_len = dump_len < 4 ? 4 : dump_len > 32*10 ? 32*10 : dump_len; + } + dump_content(temp); + printk( KERN_INFO "%s", temp); + } + cmd_buf[0] = 0; + } + return 0; +} + +static int gpio_open(struct inode *inode, struct file *file) +{ + int id = MINOR(inode->i_rdev); + if ( id >= GPIO_DEV_NUM && id != REG_MINOR ) + return -ENODEV; + if ( id < GPIO_DEV_NUM ) { + int gpio_bit = 1 << id; + + GPIO_SEL = 0; + GPIO_SEL |= gpio_bit; // bit=0 for GPIO + } + file->private_data = (void*)id; + return 0; +} + +static struct file_operations gpio_fops = { + read: gpio_read, + open: gpio_open, + flush: gpio_flush, + write: led_write, +}; + +//---------------------------------------------- +static void watchdog_wrapper(unsigned int period) +{ + // clear timer count + WATCHDOG_VAL &= CLEAR_TIMEER; + watchdog.expires = jiffies + (period * HZ / 1000); + add_timer(&watchdog); +} +//---------------------------------------------- +static int init_status; + +#define INIT_REGION 0x01 +#define INIT_LED_REGISTER 0x02 +#define INIT_LED_PROC_READ 0x04 +#define INIT_GPIO_REGISTER 0x08 + +static void led_exit(void) +{ + int id; + for ( id = 0 ; id < LED_DEV_NUM ; id++ ) { + del_timer(&blink_timer[id]); + turn_led(id, 0); + } + if ( init_status & INIT_LED_PROC_READ ) + remove_proc_entry("driver/led", NULL); + + if ( init_status & INIT_LED_REGISTER ) + unregister_chrdev(LED_MAJOR, "led"); + + if ( init_status & INIT_GPIO_REGISTER ) + unregister_chrdev(GPIO_MAJOR, "gpio"); + + if ( init_status & INIT_REGION ) + release_region(GPIO_IO_BASE, GPIO_IO_EXTENT); +} + +static int __init led_init(void) +{ + int result, id; + init_status = 0; + + //---- request region -------------------------- + /* + if ( check_region(GPIO_IO_BASE, GPIO_IO_EXTENT) ) { + printk(KERN_ERR "gpio: I/O port %lX is not free.\n", GPIO_IO_BASE); + return -EIO; + } + request_region(GPIO_IO_BASE, GPIO_IO_EXTENT, "gpio"); + init_status |= INIT_REGION; + */ + //----- register device (LED)------------------------- + result = register_chrdev(LED_MAJOR, "led", &led_fops); + if ( result < 0 ) { + printk(KERN_ERR "led: can't register char device\n" ); + led_exit(); + return result; + } + init_status |= INIT_LED_REGISTER; + //----- register device (GPIO)------------------------- + result = register_chrdev(GPIO_MAJOR, "gpio", &gpio_fops); + if ( result < 0 ) { + printk(KERN_ERR "gpio: can't register char device\n" ); + led_exit(); + return result; + } + init_status |= INIT_GPIO_REGISTER; + // sam 1-30-2004 LAN Status + // ----- register device (LAN_STATUS)------------------- +/* result = register_chrdev(LAN_STATUS_MAJOR, "lanSt", &lanSt_fops); + if ( result < 0 ) { + printk(KERN_ERR "lanSt: can't register char device\n" ); + led_exit(); + return result; + } + init_status |= INIT_LAN_STATUS_REGISTER; + */ + // -----------init watchdog timer------------------------- + //del_timer(&blink_timer[id]); + WATCHDOG_VAL = ENABLE_WATCHDOG | ( EXPIRE_TIME << WATCHDOG_SET_TMR_SHIFT); + watchdog.function = watchdog_wrapper; + watchdog.data = WATCHDOG_PERIOD; + init_timer(&watchdog); + watchdog.expires = jiffies + (WATCHDOG_PERIOD * HZ / 1000); + add_timer(&watchdog); + init_status |= INIT_WATCHDOG_REGISTER; + + // end sam + //------ read proc ------------------- + if ( !create_proc_read_entry("driver/led", 0, 0, led_read_proc, NULL) ) { + printk(KERN_ERR "led: can't create /proc/driver/led\n"); + led_exit(); + return -ENOMEM; + } + init_status |= INIT_LED_PROC_READ; + //------------------------------ + reg_addr = (unsigned long *)0xB4000000; + dump_len = 4; + for ( id = 0 ; id < LED_DEV_NUM ; id++ ) { + strcpy(led_data[id].sts_buf, "LED OFF\n" ); + set_led_status_by_str(id); + } + printk(KERN_INFO "LED & GPIO Driver " LED_VERSION "\n"); + return 0; +} + +module_init(led_init); +module_exit(led_exit); +EXPORT_NO_SYMBOLS; diff -ruN linux-2.6.10/arch/mips/am5120/led.h linux-2.6.10-adm.1/arch/mips/am5120/led.h --- linux-2.6.10/arch/mips/am5120/led.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/am5120/led.h 2005-01-27 21:06:17.000000000 +0100 @@ -0,0 +1,26 @@ +#ifndef _LED_H_INCLUDED +#define _LED_H_INCLUDED + +#include <linux/config.h> + +#define LED_VERSION "v1.0" +#define LED_MAJOR 166 +#define LED_DEV_NUM 8 +#define LED_GPIO_START 1 +#define GPIO_MAJOR 167 +#define GPIO_DEV_NUM 16 +#define REG_MINOR 128 +//#define GPIO_IO_BASE 0xB4002480 +#define GPIO_IO_BASE ((unsigned long)0xb20000b8) +#define GPIO_IO_EXTENT 0x40 + +#define LED_ON 0x010000 +#define LED_OFF 0x020000 +#define LED_BLINK_CMD 0x030000 +#define LED_BLINK_PERIOD 0x00FFFF +#define LED_BLINK (LED_BLINK_CMD|1000) +#define LED_BLINK_FAST (LED_BLINK_CMD|250) +#define LED_BLINK_SLOW (LED_BLINK_CMD|500) +#define LED_BLINK_EXTRA_SLOW (LED_BLINK_CMD|2000) + +#endif diff -ruN linux-2.6.10/arch/mips/am5120/memory.c linux-2.6.10-adm.1/arch/mips/am5120/memory.c --- linux-2.6.10/arch/mips/am5120/memory.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/am5120/memory.c 2005-01-27 21:06:17.000000000 +0100 @@ -0,0 +1,84 @@ +/***************************************************************************** +; +; (C) Unpublished Work of ADMtek Incorporated. All Rights Reserved. +; +; THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL, +; PROPRIETARY AND TRADESECRET INFORMATION OF ADMTEK INCORPORATED. +; ACCESS TO THIS WORK IS RESTRICTED TO (I) ADMTEK EMPLOYEES WHO HAVE A +; NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR ASSIGNMENTS +; AND (II) ENTITIES OTHER THAN ADMTEK WHO HAVE ENTERED INTO APPROPRIATE +; LICENSE AGREEMENTS. NO PART OF THIS WORK MAY BE USED, PRACTICED, +; PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, +; ABBRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, +; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ADMTEK. +; ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD +; SUBJECT THE PERPERTRATOR TO CRIMINAL AND CIVIL LIABILITY. +; +;------------------------------------------------------------------------------ +; +; Project : ADM5120 +; Creator : daniell@xxxxxxxxxxxxx +; File : arch/mips/am5120/memory.c +; Date : 2003.3.4 +; Abstract: +; +;Modification History: +; +; Jeroen Vreeken (pe1rxq@xxxxxxxxx) +; Simplified by ripping out fake env stuff. +; +;*****************************************************************************/ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/bootmem.h> + +#include <asm/bootinfo.h> +#include <asm/page.h> +#include <asm/am5120/prom.h> +#include <asm/am5120/adm5120.h> + + +/* References to section boundaries */ +extern char _end; + +#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) +#define ADM5120_MEMSIZE 0x1000000 /* 16 Mb */ + +void __init prom_meminit(void) +{ + unsigned long base=CPHYSADDR(PFN_ALIGN(&_end)); + unsigned long size=ADM5120_MEMSIZE; + + add_memory_region(base, size-base, BOOT_MEM_RAM); +} + + +void __init prom_free_prom_memory (void) +{ + int i; + unsigned long freed = 0; + unsigned long addr; + + for (i = 0; i < boot_mem_map.nr_map; i++) + { + if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) + continue; + + addr = boot_mem_map.map[i].addr; + while (addr < boot_mem_map.map[i].addr + + boot_mem_map.map[i].size) + { + ClearPageReserved(virt_to_page(__va(addr))); + set_page_count(virt_to_page(__va(addr)), 1); + free_page((unsigned long)__va(addr)); + addr += PAGE_SIZE; + freed += PAGE_SIZE; + } + } + + printk("Freeing prom memory: %ldkb freed\n", freed >> 10); +} + + diff -ruN linux-2.6.10/arch/mips/am5120/mipsIRQ.S linux-2.6.10-adm.1/arch/mips/am5120/mipsIRQ.S --- linux-2.6.10/arch/mips/am5120/mipsIRQ.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/am5120/mipsIRQ.S 2005-01-27 21:06:17.000000000 +0100 @@ -0,0 +1,135 @@ +/* + * Carsten Langgaard, carstenl@xxxxxxxx + * 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/config.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 am5120_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) + diff -ruN linux-2.6.10/arch/mips/am5120/pci.c linux-2.6.10-adm.1/arch/mips/am5120/pci.c --- linux-2.6.10/arch/mips/am5120/pci.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/am5120/pci.c 2005-01-27 21:06:17.000000000 +0100 @@ -0,0 +1,214 @@ +/***************************************************************************** +; +; (C) Unpublished Work of ADMtek Incorporated. All Rights Reserved. +; +; THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL, +; PROPRIETARY AND TRADESECRET INFORMATION OF ADMTEK INCORPORATED. +; ACCESS TO THIS WORK IS RESTRICTED TO (I) ADMTEK EMPLOYEES WHO HAVE A +; NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR ASSIGNMENTS +; AND (II) ENTITIES OTHER THAN ADMTEK WHO HAVE ENTERED INTO APPROPRIATE +; LICENSE AGREEMENTS. NO PART OF THIS WORK MAY BE USED, PRACTICED, +; PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, +; ABBRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, +; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ADMTEK. +; ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD +; SUBJECT THE PERPERTRATOR TO CRIMINAL AND CIVIL LIABILITY. +; +;------------------------------------------------------------------------------ +; +; Project : ADM5120 +; Creator : +; File : +; Abstract: +; +;Modification History: +; +; +;*****************************************************************************/ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <asm/byteorder.h> + +#ifdef CONFIG_PCI + +#include <asm/pci_channel.h> +#include <asm/am5120/adm5120.h> + + +volatile u32* pci_config_address_reg = (volatile u32*)KSEG1ADDR(0x115ffff0); +volatile u32* pci_config_data_reg = (volatile u32*)KSEG1ADDR(0x115ffff8); + +#define PCI_ENABLE 0x80000000 +#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 +#define PCI_DEF_LATENCY_TIMER 0x20 +#define PCI_DEF_CACHE_LATENCY ((PCI_DEF_LATENCY_TIMER << 8) | PCI_DEF_CACHE_LINE_SZ) + + + +#define cfgaddr(dev, where) (((dev->bus->number & 0xff) << 0x10) | \ + ((dev->devfn & 0xff) << 0x08) | \ + (where & 0xfc)) | PCI_ENABLE + + +/* + * We can't address 8 and 16 bit words directly. Instead we have to + * read/write a 32bit word and mask/modify the data we actually want. + */ +static int am5120_read_config_byte (struct pci_dev *dev, + int where, unsigned char *val) +{ + *pci_config_address_reg = cfgaddr(dev, where); + *val = ((*pci_config_data_reg) >> ((where&3)<<3)) & 0xff; +// printk("pci_read_byte 0x%x == 0x%x\n", where, *val); + return PCIBIOS_SUCCESSFUL; +} + +static int am5120_read_config_word (struct pci_dev *dev, + int where, unsigned short *val) +{ + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + *pci_config_address_reg = cfgaddr(dev, where); + *val = ((*pci_config_data_reg) >> ((where&3)<<3)) & 0xffff; +// printk("pci_read_word 0x%x == 0x%x\n", where, *val); + return PCIBIOS_SUCCESSFUL; +} + +int am5120_read_config_dword (struct pci_dev *dev, + int where, unsigned int *val) +{ + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + *pci_config_address_reg = cfgaddr(dev, where); + *val = (*pci_config_data_reg); +// printk("pci_read_dword 0x%x == 0x%x\n", where, *val); + return PCIBIOS_SUCCESSFUL; +} + +static int am5120_write_config_byte (struct pci_dev *dev, + int where, unsigned char val) +{ + *pci_config_address_reg = cfgaddr(dev, where); + *(volatile u8 *)(((int)pci_config_data_reg) + (where & 3)) = val; +// printk("pci_write_byte 0x%x = 0x%x\n", where, val); + return PCIBIOS_SUCCESSFUL; +} + +static int am5120_write_config_word (struct pci_dev *dev, + int where, unsigned short val) +{ + if (where & 1) + return PCIBIOS_BAD_REGISTER_NUMBER; + *pci_config_address_reg = cfgaddr(dev, where); + *(volatile u16 *)(((int)pci_config_data_reg) + (where & 2)) = (val); +// printk("pci_write_word 0x%x = 0x%x\n", where, val); + return PCIBIOS_SUCCESSFUL; +} + +static int am5120_write_config_dword (struct pci_dev *dev, + int where, unsigned int val) +{ + if (where & 3) + return PCIBIOS_BAD_REGISTER_NUMBER; + *pci_config_address_reg = cfgaddr(dev, where); + *pci_config_data_reg = (val); +// printk("pci_write_dword 0x%x = 0x%x\n", where, val); + return PCIBIOS_SUCCESSFUL; +} + + + +struct pci_ops am5120_pci_ops = { + am5120_read_config_byte, + am5120_read_config_word, + am5120_read_config_dword, + am5120_write_config_byte, + am5120_write_config_word, + am5120_write_config_dword +}; +struct resource pciioport_resource = { + "pci IO space", + 0x11500000, + 0x115ffff0-1, + IORESOURCE_IO +}; + +struct resource pciiomem_resource = { + "pci memory space", + 0x11400000, + 0x11500000-1, + IORESOURCE_MEM +}; + +static void am5120_pcibios_fixup(struct pci_dev *dev) +{ + printk("am5120 fix up\n"); + pci_write_config_word(dev, PCI_COMMAND, PCI_CMM_DEF); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, PCI_DEF_CACHE_LATENCY); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0); + +} + +struct pci_channel mips_pci_channels[] = { + { &am5120_pci_ops, &pciioport_resource, &pciiomem_resource,0,0xff}, + { NULL, NULL, NULL , NULL , NULL} +}; + + + +unsigned __init int pcibios_assign_all_busses(void) +{ + return 1; +} + +void __init pcibios_fixup(void) +{ + printk("pcibios_fixup\n"); +} + +void __init pcibios_fixup_irqs(void) +{ + struct pci_dev *dev; + int slot_num; + + printk("fixup IRQ\n"); + pci_for_each_dev(dev) { + slot_num = PCI_SLOT(dev->devfn); + switch(slot_num) { + case 2: + dev->irq = 6; + pci_write_config_word(dev, PCI_INTERRUPT_LINE, 6); + break; + case 3: + dev->irq = 7; + pci_write_config_word(dev, PCI_INTERRUPT_LINE, 7); + break; + case 4: + dev->irq = 8; + pci_write_config_word(dev, PCI_INTERRUPT_LINE, 8); + break; + default: break; + } + } +} + +void __init pcibios_fixup_resources(struct pci_dev *dev) +{ + printk("fixup resource\n"); + if (dev->devfn == 0) + { + printk("fixup host controller\n"); + am5120_pcibios_fixup(dev); + } +} + +#endif /* CONFIG_PCI */ diff -ruN linux-2.6.10/arch/mips/am5120/prom.c linux-2.6.10-adm.1/arch/mips/am5120/prom.c --- linux-2.6.10/arch/mips/am5120/prom.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/am5120/prom.c 2005-01-27 21:06:17.000000000 +0100 @@ -0,0 +1,70 @@ +/***************************************************************************** +; +; (C) Unpublished Work of ADMtek Incorporated. All Rights Reserved. +; +; THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL, +; PROPRIETARY AND TRADESECRET INFORMATION OF ADMTEK INCORPORATED. +; ACCESS TO THIS WORK IS RESTRICTED TO (I) ADMTEK EMPLOYEES WHO HAVE A +; NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR ASSIGNMENTS +; AND (II) ENTITIES OTHER THAN ADMTEK WHO HAVE ENTERED INTO APPROPRIATE +; LICENSE AGREEMENTS. NO PART OF THIS WORK MAY BE USED, PRACTICED, +; PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, +; ABBRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, +; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ADMTEK. +; ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD +; SUBJECT THE PERPERTRATOR TO CRIMINAL AND CIVIL LIABILITY. +; +;------------------------------------------------------------------------------ +; +; Project : ADM5120 +; Creator : daniell@xxxxxxxxxxxxx +; File : arch/mips/am5120/prom.c +; Date : 2003.3.4 +; Abstract: +; +;Modification History: +; +; Jeroen Vreeken (pe1rxq@xxxxxxxxx) +; Ripped out cmdline and env stuff left over from YAMON cut-and-paste. +; +;*****************************************************************************/ + +#include <linux/init.h> +#include <linux/config.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> + +extern void am5120_serial_console_init(void); +void setup_prom_printf(int); +void prom_printf(char *, ...); +void prom_meminit(void); + +/* + * 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; + + /* set IO port base to zero */ + + /* init print from uart0 */ + setup_prom_printf(0); + + prom_printf("\nLINUX started...\n"); + + /* init command line */ + strcpy(&(arcs_cmdline[0]), ""/*"root=/dev/ram0 console=ttyS0"*/); + + /* init memory map */ + prom_meminit(); +} + + diff -ruN linux-2.6.10/arch/mips/am5120/serial.c linux-2.6.10-adm.1/arch/mips/am5120/serial.c --- linux-2.6.10/arch/mips/am5120/serial.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/am5120/serial.c 2005-01-27 21:06:17.000000000 +0100 @@ -0,0 +1,1711 @@ +/***************************************************************************** +; +; (C) Unpublished Work of ADMtek Incorporated. All Rights Reserved. +; +; THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL, +; PROPRIETARY AND TRADESECRET INFORMATION OF ADMTEK INCORPORATED. +; ACCESS TO THIS WORK IS RESTRICTED TO (I) ADMTEK EMPLOYEES WHO HAVE A +; NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR ASSIGNMENTS +; AND (II) ENTITIES OTHER THAN ADMTEK WHO HAVE ENTERED INTO APPROPRIATE +; LICENSE AGREEMENTS. NO PART OF THIS WORK MAY BE USED, PRACTICED, +; PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, +; ABBRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, +; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ADMTEK. +; ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD +; SUBJECT THE PERPERTRATOR TO CRIMINAL AND CIVIL LIABILITY. +; +;------------------------------------------------------------------------------ +; +; Project : ADM5120 +; Creator : daniell@xxxxxxxxxxxxx +; File : arch/mips/am5120/printf.c +; Date : 2003.3.4 +; Abstract: +; +;Modification History: +; +;*****************************************************************************/ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/serial.h> +#include <linux/serialP.h> +#include <linux/serial_reg.h> +#include <linux/console.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/devpts_fs.h> + +#include <linux/major.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/delay.h> + +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/serial.h> +#include <asm/am5120/adm5120.h> + + +//#define SERIAL_DEBUG_OPEN 1 +//#define SERIAL_DEBUG_INTR 1 + +static struct tty_driver dev_tty_driver; + +/* + * IN_W + */ +static inline unsigned long IN_W(unsigned long _addr) +{ + return (*(volatile unsigned long *)(_addr)); +} + + +/* + * OUT_W + */ +static inline void OUT_W(unsigned long _addr, unsigned long _value) +{ + (*((volatile unsigned long *)(_addr))) = _value; +} + + +/* + * serial_in + */ +static unsigned int serial_in(struct async_struct *info, int offset) +{ + return IN_W(info->port + offset); +} + + +/* + * serial_out + */ +static void serial_out(struct async_struct *info, int offset, + int value) +{ + OUT_W(info->port + offset, value); +} + + +/* + * serial state + */ +static struct serial_state rs_table[] = +{ + {baud_base:UART_115200bps_DIVISOR, port:KSEG1ADDR(UART0_BASE), irq:1, flags:STD_COM_FLAGS, type:SERIAL_IO_MEM} +}; + + +/*------------------------------------------------------- + * prom_printf + * + *-----------------------------------------------------*/ +/* + * Hooks to fake "prom" console I/O before devices + * are fully initialized. + */ +static struct async_struct prom_port_info = {0}; + +void __init setup_prom_printf(int tty_no) +{ + struct serial_state *ser = &rs_table[tty_no]; + + prom_port_info.state = ser; + prom_port_info.magic = SERIAL_MAGIC; + prom_port_info.port = ser->port; + prom_port_info.flags = ser->flags; + + /* set baudrate to 115200 */ + serial_out(&prom_port_info, UART_LCR_L_REG, prom_port_info.state->baud_base); + serial_out(&prom_port_info, UART_LCR_M_REG, prom_port_info.state->baud_base >> 8); + + /* Set default line mode */ + serial_out(&prom_port_info, UART_LCR_H_REG, UART_WLEN_8BITS | UART_ENABLE_FIFO); + + /* Enable uart port */ + serial_out(&prom_port_info, UART_CR_REG, UART_PORT_EN); +} + + +/* + * putPromChar + */ +int putPromChar(char c) +{ + if (!prom_port_info.state) { /* need to init device first */ + return 0; + } + + while ((serial_in(&prom_port_info, UART_FR_REG) & + UART_TX_FIFO_FULL) != 0); + + serial_out(&prom_port_info, UART_DR_REG, c); + + return 1; +} + + +/* + * getPromChar + */ +char getPromChar(void) +{ + if (!prom_port_info.state) /* need to init device first */ + return 0; + + if ((serial_in(&prom_port_info, UART_FR_REG) & UART_RX_FIFO_EMPTY)) + return 0; + + return(serial_in(&prom_port_info, UART_DR_REG)); +} + + +static char buf[1024]; + +/* + * prom_printf + */ +void __init prom_printf(char *fmt, ...) +{ + va_list args; + int l; + char *p, *buf_end; + long flags; + + int putPromChar(char); + + /* Low level, brute force, not SMP safe... */ + save_and_cli(flags); + 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); + } + restore_flags(flags); +} + + +/*------------------------------------------------------- + * console driver + * + *-----------------------------------------------------*/ +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +static void serial_console_write(struct console *co, const char *s, + unsigned count) +{ + int i; + + for (i = 0; i < count; i++, s++) + { + if (*s == '\n') + putPromChar('\r'); + putPromChar(*s); + } +} + + +/* + * Receive character from the serial port + */ +static int serial_console_wait_key(struct console *co) +{ + return 0; +} + + +/* + * Get serial console device + */ +static struct tty_driver *serial_console_device(struct console *c, int *index) +{ + *index=c->index; + return &dev_tty_driver; +} + + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first rs_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +static int __init serial_console_setup(struct console *co, char *options) +{ + return 0; +} + + +/* + * Console data structure + */ +static struct console sercons = { + name: "ttyS", + write: serial_console_write, + device: serial_console_device, +// wait_key: serial_console_wait_key, + setup: serial_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +/* + * Register console. + */ +static int __init am5120_serial_console_init(void) +{ + register_console(&sercons); + return 0; +} +console_initcall(am5120_serial_console_init); + +/*------------------------------------------------------ + * Register tty driver + * + *----------------------------------------------------*/ + +static char *serial_version = "0.01"; +static char *serial_revdate = "2003-04-17"; + +#define LOCAL_VERSTRING "" + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) +#define WAKEUP_CHARS 256 +#define RS_ISR_PASS_LIMIT 256 + +static unsigned char *tmp_buf; +#ifdef DECLARE_MUTEX +static DECLARE_MUTEX(tmp_buf_sem); +#else +static struct semaphore tmp_buf_sem = MUTEX; +#endif + +static int serial_refcount; +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; +static unsigned char *tmp_buf = 0; +static struct async_struct *IRQ_ports[NR_IRQS] = {0}; + + + + +static void do_softint(void *private_) +{ + struct async_struct *info = (struct async_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif + } +} + + +static int get_async_struct(int line, struct async_struct **ret_info) +{ + struct async_struct *info; + struct serial_state *sstate; + + sstate = rs_table + line; + sstate->count++; + if (sstate->info) { + *ret_info = sstate->info; + return 0; + } + + info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); + if (!info) { + sstate->count--; + return -ENOMEM; + } + + memset(info, 0, sizeof(struct async_struct)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + info->magic = SERIAL_MAGIC; + info->port = sstate->port; + info->flags = sstate->flags; + info->io_type = sstate->io_type; + info->iomem_base = sstate->iomem_base; + info->iomem_reg_shift = sstate->iomem_reg_shift; + info->xmit_fifo_size = sstate->xmit_fifo_size; + info->line = line; + INIT_WORK(&info->work, do_softint, info); +// info->tqueue.routine = do_softint; +// info->tqueue.data = info; + info->state = sstate; + if (sstate->info) { + kfree(info); + *ret_info = sstate->info; + return 0; + } + *ret_info = sstate->info = info; + return 0; +} + + +static void transmit_chars(struct async_struct *info, int *intr_done) +{ + if (info->x_char) { + serial_out(info, UART_DR_REG, info->x_char); + info->state->icount.tx++; + info->x_char = 0; + if (intr_done) + *intr_done = 0; + return; + } + + if (info->xmit.head == info->xmit.tail + || info->tty->stopped + || info->tty->hw_stopped) { + info->IER &= ~UART_TX_INT_EN; + serial_out(info, UART_CR_REG, info->IER); + return; + } + + do { + while ((serial_in(info, UART_FR_REG) & UART_TX_FIFO_FULL) != 0) + ; + + serial_out(info, UART_DR_REG, info->xmit.buf[info->xmit.tail]); + info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1); + info->state->icount.tx++; + if (info->xmit.head == info->xmit.tail) + break; + } while (1); + + //if (CIRC_CNT(info->xmit.head, + // info->xmit.tail, + // SERIAL_XMIT_SIZE) < WAKEUP_CHARS) + //rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif + + if (intr_done) + *intr_done = 0; + + if (info->xmit.head == info->xmit.tail) { + info->IER &= ~UART_TX_INT_EN; + serial_out(info, UART_CR_REG, info->IER); + } +} + + + +static void receive_chars(struct async_struct *info, + struct pt_regs * regs) +{ + struct tty_struct *tty = info->tty; + unsigned char ch; + //int ignored = 0; + struct async_icount *icount; + unsigned int status; + unsigned int rsr_flag; + + icount = &info->state->icount; + + do { + ch = serial_in(info, UART_DR_REG); + + rsr_flag = serial_in(info, UART_RSR_REG); + serial_out(info, UART_RSR_REG, rsr_flag); + + if (rsr_flag & UART_RX_ERROR) + goto ignore_char; + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + + *tty->flip.char_buf_ptr = ch; + icount->rx++; + +#ifdef SERIAL_DEBUG_INTR + printk("DR%02x...", ch); +#endif + *tty->flip.flag_buf_ptr = 0; + + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + + status = serial_in(info, UART_FR_REG); + + } while (!(status & UART_RX_FIFO_EMPTY)); + +ignore_char: + + tty_flip_buffer_push(tty); +} + + +/* + * This is the serial driver's interrupt routine for a single port + */ +irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + int status; + int pass_counter = 0; + struct async_struct * info; + int handled=IRQ_NONE; + +#ifdef SERIAL_DEBUG_INTR + printk("rs_interrupt(%d)...", irq); +#endif + + info = IRQ_ports[irq]; + if (!info || !info->tty) + return handled; + + do { + status = serial_in(info, UART_IIR_REG); + + if (status & (UART_RX_INT | UART_RX_TIMEOUT_INT)) + { + //if ((serial_in(info, UART_FR_REG) & UART_RX_FIFO_EMPTY)) + // break; + handled=IRQ_HANDLED; + receive_chars(info, regs); + } + + if (status & UART_TX_INT) + { + handled=IRQ_HANDLED; + transmit_chars(info, 0); + } + + if (pass_counter++ > RS_ISR_PASS_LIMIT) { + break; + } + + } while (serial_in(info, UART_IIR_REG) & (UART_RX_INT | UART_RX_TIMEOUT_INT | UART_TX_INT)); + + info->last_active = jiffies; + return handled; +} + + +static int startup(struct async_struct * info) +{ + unsigned long flags; + int retval=0; + irqreturn_t (*handler)(int, void *, struct pt_regs *); + struct serial_state *state= info->state; + unsigned long page; + + if (info->flags & ASYNC_INITIALIZED) + return retval; + + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); + + cli(); + + if (!CONFIGURED_SERIAL_PORT(state) || !state->type) + { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + goto errout; + } + + if (info->xmit.buf) + free_page(page); + else + info->xmit.buf = (unsigned char *) page; + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttyS%d (irq %d)...", info->line, state->irq); +#endif + + /* + * Allocate the IRQ if necessary + */ + if ((!IRQ_ports[state->irq] || !IRQ_ports[state->irq]->next_port)) + { + if (IRQ_ports[state->irq]) + { + retval = -EBUSY; + goto errout; + } + else + handler = rs_interrupt; + + retval = request_irq(state->irq, handler, SA_SHIRQ, + "serial", &IRQ_ports[state->irq]); + if (retval) + { + if (capable(CAP_SYS_ADMIN)) + { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + } + goto errout; + } + } + + /* + * Insert serial port into IRQ chain. + */ + info->prev_port = 0; + info->next_port = IRQ_ports[state->irq]; + + if (info->next_port) + info->next_port->prev_port = info; + + IRQ_ports[state->irq] = info; + + /* + * Now, initialize the UART + */ + serial_out(info, UART_LCR_L_REG, info->state->baud_base); + serial_out(info, UART_LCR_M_REG, info->state->baud_base >> 8); + serial_out(info, UART_LCR_H_REG, (UART_WLEN_8BITS | UART_ENABLE_FIFO)); + + /* + * Finally, enable interrupts + */ + info->IER = UART_RX_INT_EN | UART_RX_TIMEOUT_INT_EN | UART_PORT_EN; + serial_out(info, UART_CR_REG, info->IER); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + + info->xmit.head = info->xmit.tail = 0; + + /* + * and set the speed of the serial port + */ + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + + return 0; + +errout: + restore_flags(flags); + return retval; +} + + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct async_struct *info; + int retval, line; + unsigned long page; + +// line = MINOR(tty->device) - tty->driver.minor_start; + line=0; + if ((line < 0) || (line >= NR_PORTS)) + { + return -ENODEV; + } + + retval = get_async_struct(line, &info); + if (retval) + { + return retval; + } + + tty->driver_data = info; + info->tty = tty; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->state->count); +#endif + + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + if (!tmp_buf) + { + page = get_zeroed_page(GFP_KERNEL); + if (!page) + { + return -ENOMEM; + } + + if (tmp_buf) + free_page(page); + else + tmp_buf = (unsigned char *) page; + } + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) + { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); + + return -EAGAIN; + } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) + { + return retval; + } + +#if 0 + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } +#endif + + if ((info->state->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) + { +// if (tty->driver.subtype == SERIAL_TYPE_NORMAL) +// *tty->termios = info->state->normal_termios; +// else +// *tty->termios = info->state->callout_termios; + } + +// info->session = current->session; +// info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d successful...", info->line); +#endif + + return 0; +} + + +/* + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state; + unsigned long flags; + + state = info->state; + + save_flags(flags); + cli(); + + //if (tty_hung_up_p(filp)) { + // DBG_CNT("before DEC-hung"); + // restore_flags(flags); + // return; + //} + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, state->count); +#endif + + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + //printk("rs_close: bad serial port count; tty->count is 1, " + // "state->count is %d\n", state->count); + state->count = 1; + } + + if (--state->count < 0) { + //printk("rs_close: bad serial port count for ttys%d: %d\n", + // info->line, state->count); + state->count = 0; + } + + restore_flags(flags); + return; + +#if 0 + info->flags |= ASYNC_CLOSING; + restore_flags(flags); + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->state->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->state->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + //info->IER &= ~UART_IER_RLSI; + //info->read_status_mask &= ~UART_LSR_DR; + //if (info->flags & ASYNC_INITIALIZED) { + // serial_out(info, UART_IER, info->IER); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + // rs_wait_until_sent(tty, info->timeout); + //} + //shutdown(info); + + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + //if (info->blocked_open) { + // if (info->close_delay) { + // set_current_state(TASK_INTERRUPTIBLE); + // schedule_timeout(info->close_delay); + // } + // wake_up_interruptible(&info->open_wait); + //} + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + + wake_up_interruptible(&info->close_wait); +#endif +} + + +static int rs_write(struct tty_struct * tty, const unsigned char *buf, + int count) +{ + int c, ret = 0; + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (!tty || !info->xmit.buf || !tmp_buf) + return 0; + + save_flags(flags); + if (0/*from_user*/) { + down(&tmp_buf_sem); + while (1) { + int c1; + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); + c1 = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + if (c1 < c) + c = c1; + memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + cli(); + while (1) { + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) { + break; + } + memcpy(info->xmit.buf + info->xmit.head, buf, c); + info->xmit.head = ((info->xmit.head + c) & + (SERIAL_XMIT_SIZE-1)); + buf += c; + count -= c; + ret += c; + } + restore_flags(flags); + } + if (info->xmit.head != info->xmit.tail + && !tty->stopped + && !tty->hw_stopped + && !(info->IER & UART_TX_INT)) { + info->IER |= UART_TX_INT_EN; + serial_out(info, UART_CR_REG, info->IER); + } + return ret; +} + + +static void rs_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (!tty || !info->xmit.buf) + return; + + save_flags(flags); + cli(); + + if (CIRC_SPACE(info->xmit.head, + info->xmit.tail, + SERIAL_XMIT_SIZE) == 0) { + restore_flags(flags); + return; + } + + info->xmit.buf[info->xmit.head] = ch; + info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); + restore_flags(flags); +} + + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (info->xmit.head == info->xmit.tail + || tty->stopped + || tty->hw_stopped + || !info->xmit.buf) + return; + + save_flags(flags); + cli(); + + info->IER |= UART_TX_INT_EN; + serial_out(info, UART_CR_REG, info->IER); + restore_flags(flags); +} + + +static int rs_write_room(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); +} + + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + save_flags(flags); + cli(); + + info->xmit.head = info->xmit.tail = 0; + restore_flags(flags); + wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + + +static int get_serial_info(struct async_struct * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + struct serial_state *state = info->state; + + if (!retinfo) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + tmp.type = state->type; + tmp.line = state->line; + tmp.port = state->port; + //if (HIGH_BITS_OFFSET) + // tmp.port_high = state->port >> HIGH_BITS_OFFSET; + //else + tmp.port_high = 0; + tmp.irq = state->irq; + tmp.flags = state->flags; + tmp.xmit_fifo_size = state->xmit_fifo_size; + tmp.baud_base = state->baud_base; + tmp.close_delay = state->close_delay; + tmp.closing_wait = state->closing_wait; + tmp.custom_divisor = state->custom_divisor; + tmp.hub6 = state->hub6; + tmp.io_type = state->io_type; + if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + return -EFAULT; + return 0; +} + + +#if 0 +static int set_serial_info(struct async_struct * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct serial_state old_state, *state; + unsigned int i,change_irq,change_port; + int retval = 0; + unsigned long new_port; + + if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) + return -EFAULT; + state = info->state; + old_state = *state; + + new_port = new_serial.port; + if (HIGH_BITS_OFFSET) + new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; + + change_irq = new_serial.irq != state->irq; + change_port = (new_port != ((int) state->port)) || + (new_serial.hub6 != state->hub6); + + if (!capable(CAP_SYS_ADMIN)) { + if (change_irq || change_port || + (new_serial.baud_base != state->baud_base) || + (new_serial.type != state->type) || + (new_serial.close_delay != state->close_delay) || + (new_serial.xmit_fifo_size != state->xmit_fifo_size) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (state->flags & ~ASYNC_USR_MASK))) + return -EPERM; + state->flags = ((state->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + state->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + new_serial.irq = irq_cannonicalize(new_serial.irq); + + if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || + (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) || + (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) || + (new_serial.type == PORT_STARTECH)) { + return -EINVAL; + } + + if ((new_serial.type != state->type) || + (new_serial.xmit_fifo_size <= 0)) + new_serial.xmit_fifo_size = + uart_config[new_serial.type].dfl_xmit_fifo_size; + + /* Make sure address is not already in use */ + if (new_serial.type) { + for (i = 0 ; i < NR_PORTS; i++) + if ((state != &rs_table[i]) && + (rs_table[i].port == new_port) && + rs_table[i].type) + return -EADDRINUSE; + } + + if ((change_port || change_irq) && (state->count > 1)) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + state->baud_base = new_serial.baud_base; + state->flags = ((state->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | + (info->flags & ASYNC_INTERNAL_FLAGS)); + state->custom_divisor = new_serial.custom_divisor; + state->close_delay = new_serial.close_delay * HZ/100; + state->closing_wait = new_serial.closing_wait * HZ/100; + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + info->xmit_fifo_size = state->xmit_fifo_size = + new_serial.xmit_fifo_size; + + if ((state->type != PORT_UNKNOWN) && state->port) { + release_region(state->port,8); + } + state->type = new_serial.type; + if (change_port || change_irq) { + /* + * We need to shutdown the serial port at the old + * port/irq combination. + */ + shutdown(info); + state->irq = new_serial.irq; + info->port = state->port = new_port; + info->hub6 = state->hub6 = new_serial.hub6; + if (info->hub6) + info->io_type = state->io_type = SERIAL_IO_HUB6; + else if (info->io_type == SERIAL_IO_HUB6) + info->io_type = state->io_type = SERIAL_IO_PORT; + } + if ((state->type != PORT_UNKNOWN) && state->port) { + request_region(state->port,8,"serial(set)"); + } + + +check_and_exit: + if (!state->port || !state->type) + return 0; + if (info->flags & ASYNC_INITIALIZED) { + if (((old_state.flags & ASYNC_SPD_MASK) != + (state->flags & ASYNC_SPD_MASK)) || + (old_state.custom_divisor != state->custom_divisor)) { + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + change_speed(info, 0); + } + } else { + retval = startup(info); + } + return retval; +} +#endif + + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct async_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct icount; + unsigned long flags; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + //case TIOCMGET: + // return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + //case TIOCMSET: + // return set_modem_info(info, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + return get_serial_info(info, + (struct serial_struct *) arg); + //case TIOCSSERIAL: + // return set_serial_info(info, + //(struct serial_struct *) arg); + //case TIOCSERCONFIG: + // return do_autoconfig(info); + + //case TIOCSERGETLSR: /* Get line status register */ + // return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + if (copy_to_user((struct async_struct *) arg, + info, sizeof(struct async_struct))) + return -EFAULT; + return 0; + + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: +#if 0 + save_flags(flags); + cli(); + /* note the counters on entry */ + cprev = info->state->icount; + restore_flags(flags); + /* Force modem status interrupts on */ + info->IER |= UART_IER_MSI; + serial_out(info, UART_IER, info->IER); + while (1) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + save_flags(flags); cli(); + cnow = info->state->icount; /* atomic copy */ + restore_flags(flags); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ +#endif + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + save_flags(flags); + cli(); + cnow = info->state->icount; + restore_flags(flags); + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + if (copy_to_user((void *)arg, &icount, sizeof(icount))) + return -EFAULT; + return 0; + case TIOCSERGWILD: + case TIOCSERSWILD: + /* "setserial -W" is called in Debian boot */ + printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); + return 0; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ +#if 0 + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (I_IXOFF(tty)) + rs_send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) + info->MCR &= ~UART_MCR_RTS; + + save_flags(flags); cli(); + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); +#endif +} + + +static void rs_unthrottle(struct tty_struct * tty) +{ +#if 0 + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + rs_send_xchar(tty, START_CHAR(tty)); + } + //if (tty->termios->c_cflag & CRTSCTS) + // info->MCR |= UART_MCR_RTS; + save_flags(flags); + cli(); + //serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); +#endif +} + + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ +#if 0 + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + unsigned int cflag = tty->termios->c_cflag; + + if ((cflag == old_termios->c_cflag) + && (RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(cflag & CBAUD)) { + info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); + save_flags(flags); cli(); + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (cflag & CBAUD)) { + info->MCR |= UART_MCR_DTR; + if (!(tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) { + info->MCR |= UART_MCR_RTS; + } + save_flags(flags); cli(); + serial_out(info, UART_MCR, info->MCR); + restore_flags(flags); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } +#endif +} + + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + save_flags(flags); + cli(); + + if (info->IER & UART_TX_INT_EN) { + info->IER &= ~UART_TX_INT_EN; + serial_out(info, UART_CR_REG, info->IER); + } + restore_flags(flags); +} + + + +static void rs_start(struct tty_struct *tty) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + save_flags(flags); + cli(); + + if (info->xmit.head != info->xmit.tail + && info->xmit.buf + && !(info->IER & UART_TX_INT_EN)) { + info->IER |= UART_TX_INT_EN; + serial_out(info, UART_CR_REG, info->IER); + } + restore_flags(flags); +} + + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void rs_hangup(struct tty_struct *tty) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + struct serial_state *state = info->state; + + state = info->state; + + rs_flush_buffer(tty); + + if (info->flags & ASYNC_CLOSING) + return; + + info->event = 0; + state->count = 0; +// info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~(ASYNC_NORMAL_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + + +/* + * rs_break() --- routine which turns the break handling on or off + */ +static void rs_break(struct tty_struct *tty, int break_state) +{ + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long flags; + + if (!CONFIGURED_SERIAL_PORT(info)) + return; + + save_flags(flags); + cli(); + if (break_state == -1) + info->LCR |= UART_SEND_BREAK; + else + info->LCR &= ~UART_SEND_BREAK; + + serial_out(info, UART_LCR_H_REG, info->LCR); + restore_flags(flags); +} + + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void rs_send_xchar(struct tty_struct *tty, char ch) +{ + struct async_struct *info = (struct async_struct *)tty->driver_data; + + info->x_char = ch; + if (ch) { + /* Make sure transmit interrupts are on */ + info->IER |= UART_TX_INT_EN; + serial_out(info, UART_CR_REG, info->IER); + } +} + + +/* + * rs_wait_until_sent() --- wait until the transmitter is empty + */ +static void rs_wait_until_sent(struct tty_struct *tty, int timeout) +{ +#if 0 + struct async_struct * info = (struct async_struct *)tty->driver_data; + unsigned long orig_jiffies, char_time; + int lsr; + + if (info->state->type == PORT_UNKNOWN) + return; + + if (info->xmit_fifo_size == 0) + return; /* Just in case.... */ + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout && timeout < char_time) + char_time = timeout; + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than info->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*info->timeout. + */ + if (!timeout || timeout > 2*info->timeout) + timeout = 2*info->timeout; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...", lsr, jiffies); +#endif + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + set_current_state(TASK_RUNNING); +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); +#endif +#endif +} + +/* + * /proc fs routines.... + */ + +static inline int line_info(char *buf, struct serial_state *state) +{ +#if 0 + struct async_struct *info = state->info, scr_info; + char stat_buf[30], control, status; + int ret; + unsigned long flags; + + ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d", + state->line, uart_config[state->type].name, + state->port, state->irq); + + if (!state->port || (state->type == PORT_UNKNOWN)) { + ret += sprintf(buf+ret, "\n"); + return ret; + } + + /* + * Figure out the current RS-232 lines + */ + if (!info) { + info = &scr_info; /* This is just for serial_{in,out} */ + + info->magic = SERIAL_MAGIC; + info->port = state->port; + info->flags = state->flags; + info->quot = 0; + info->tty = 0; + } + save_flags(flags); cli(); + status = serial_in(info, UART_MSR); + control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR); + restore_flags(flags); + + stat_buf[0] = 0; + stat_buf[1] = 0; + if (control & UART_MCR_RTS) + strcat(stat_buf, "|RTS"); + if (status & UART_MSR_CTS) + strcat(stat_buf, "|CTS"); + if (control & UART_MCR_DTR) + strcat(stat_buf, "|DTR"); + if (status & UART_MSR_DSR) + strcat(stat_buf, "|DSR"); + if (status & UART_MSR_DCD) + strcat(stat_buf, "|CD"); + if (status & UART_MSR_RI) + strcat(stat_buf, "|RI"); + + if (info->quot) { + ret += sprintf(buf+ret, " baud:%d", + state->baud_base / info->quot); + } + + ret += sprintf(buf+ret, " tx:%d rx:%d", + state->icount.tx, state->icount.rx); + + if (state->icount.frame) + ret += sprintf(buf+ret, " fe:%d", state->icount.frame); + + if (state->icount.parity) + ret += sprintf(buf+ret, " pe:%d", state->icount.parity); + + if (state->icount.brk) + ret += sprintf(buf+ret, " brk:%d", state->icount.brk); + + if (state->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + return ret; +#endif + return 0; +} + + +int rs_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int i, len = 0, l; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n", + serial_version, LOCAL_VERSTRING, serial_revdate); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + l = line_info(page + len, &rs_table[i]); + len += l; + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (off-begin); + return ((count < begin+len-off) ? count : begin+len-off); +} + + +/* + * This routine must be called by kernel at boot time + */ +int __init serial5120_init(void) +{ + memset(&dev_tty_driver, 0, sizeof(struct tty_driver)); + + dev_tty_driver.magic = TTY_DRIVER_MAGIC; + dev_tty_driver.driver_name = "/dev/ttyS0"; + dev_tty_driver.name = "ttyS0"; + dev_tty_driver.major = TTY_MAJOR; + dev_tty_driver.minor_start = 64; + dev_tty_driver.num = 1; + dev_tty_driver.type = TTY_DRIVER_TYPE_SERIAL; + dev_tty_driver.subtype = SERIAL_TYPE_NORMAL; + dev_tty_driver.init_termios = tty_std_termios; + dev_tty_driver.init_termios.c_cflag = + B115200 | CS8 | CREAD | HUPCL | CLOCAL; + dev_tty_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; +// dev_tty_driver.refcount = &serial_refcount; +// dev_tty_driver.table = serial_table; + dev_tty_driver.termios = serial_termios; + dev_tty_driver.termios_locked = serial_termios_locked; + + dev_tty_driver.open = rs_open; + dev_tty_driver.close = rs_close; + dev_tty_driver.write = rs_write; + dev_tty_driver.put_char = rs_put_char; + dev_tty_driver.flush_chars = rs_flush_chars; + dev_tty_driver.write_room = rs_write_room; + dev_tty_driver.chars_in_buffer = rs_chars_in_buffer; + dev_tty_driver.flush_buffer = rs_flush_buffer; + dev_tty_driver.ioctl = rs_ioctl; + dev_tty_driver.throttle = rs_throttle; + dev_tty_driver.unthrottle = rs_unthrottle; + dev_tty_driver.set_termios = rs_set_termios; + dev_tty_driver.stop = rs_stop; + dev_tty_driver.start = rs_start; + dev_tty_driver.hangup = rs_hangup; + dev_tty_driver.break_ctl = rs_break; + dev_tty_driver.send_xchar = rs_send_xchar; + dev_tty_driver.wait_until_sent = rs_wait_until_sent; + dev_tty_driver.read_proc = rs_read_proc; + + if (tty_register_driver(&dev_tty_driver)) + panic("Couldn't register /dev/ttyS0 driver\n"); + + return 0; +} + +__initcall(serial5120_init); diff -ruN linux-2.6.10/arch/mips/am5120/setup.c linux-2.6.10-adm.1/arch/mips/am5120/setup.c --- linux-2.6.10/arch/mips/am5120/setup.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/am5120/setup.c 2005-01-27 21:06:17.000000000 +0100 @@ -0,0 +1,119 @@ +/***************************************************************************** +; +; (C) Unpublished Work of ADMtek Incorporated. All Rights Reserved. +; +; THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL, +; PROPRIETARY AND TRADESECRET INFORMATION OF ADMTEK INCORPORATED. +; ACCESS TO THIS WORK IS RESTRICTED TO (I) ADMTEK EMPLOYEES WHO HAVE A +; NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR ASSIGNMENTS +; AND (II) ENTITIES OTHER THAN ADMTEK WHO HAVE ENTERED INTO APPROPRIATE +; LICENSE AGREEMENTS. NO PART OF THIS WORK MAY BE USED, PRACTICED, +; PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, +; ABBRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, +; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ADMTEK. +; ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD +; SUBJECT THE PERPERTRATOR TO CRIMINAL AND CIVIL LIABILITY. +; +;------------------------------------------------------------------------------ +; +; Project : ADM5120 +; Creator : daniell@xxxxxxxxxxxxx +; File : arch/mips/am5120/setup.c +; Date : 2003.3.4 +; Abstract: +; +;Modification History: +; +;*****************************************************************************/ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/serial.h> +#include <linux/types.h> +#include <linux/string.h> /* for memset */ + +#include <asm/reboot.h> +#include <asm/io.h> +#include <asm/time.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/am5120/adm5120.h> + + +//extern struct rtc_ops am5120_rtc_ops; +//extern struct rtc_ops *rtc_ops; + +void mips_timer_setup(struct irqaction *irq); +void mips_time_init(void); + +int am5120_pci_module; + + +void am5120_restart(char *command) +{ + int i; + + /* Disable All ports*/ + ADM5120_SW_REG(Port_conf0_REG) |= SW_DISABLE_PORT_MASK; + + /* Disable CPU port */ + ADM5120_SW_REG(CPUp_conf_REG) |= SW_CPU_PORT_DISABLE; + + // Wait until switch DMA idle. At least 1ms is required!!!! + for (i=0; i <1000000; i++); + + ADM5120_SW_REG(SftRest_REG) = SOFTWARE_RESET; +} + + +void am5120_halt(void) +{ + printk(KERN_NOTICE "\n** You can safely turn off the power\n"); + while (1); +} + + +void am5120_power_off(void) +{ + am5120_halt(); +} + +static int __init am5120_setup(void) +{ + printk("ADM5120 board setup\n"); + + board_time_init = mips_time_init; + board_timer_setup = mips_timer_setup; + + _machine_restart = am5120_restart; + _machine_halt = am5120_halt; + _machine_power_off = am5120_power_off; + +// rtc_ops = &am5120_rtc_ops; + + set_io_port_base(KSEG1); + + /* check pci in existence or not */ + if (ADM5120_SW_REG(CODE_REG) & CPU_PQFP_MODE) + { + printk("System no PCI BIOS\n"); + am5120_pci_module = 0; + } + else + { + printk("System has PCI BIOS\n"); + am5120_pci_module = 1; + } + return 0; +} + +early_initcall(am5120_setup); + +const char *get_system_type(void) +{ + return "ADM5120 Board"; +} diff -ruN linux-2.6.10/arch/mips/am5120/time.c linux-2.6.10-adm.1/arch/mips/am5120/time.c --- linux-2.6.10/arch/mips/am5120/time.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/am5120/time.c 2005-01-27 21:06:17.000000000 +0100 @@ -0,0 +1,98 @@ +/* + * Carsten Langgaard, carstenl@xxxxxxxx + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@xxxxxxxxx) + * + * ######################################################################## + * + * 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. + * + * ######################################################################## + * + * Setting up the clock on the MIPS boards. + * + */ + +#include <linux/types.h> +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/sched.h> +#include <linux/spinlock.h> + +#include <asm/mipsregs.h> +#include <asm/ptrace.h> +#include <asm/hardirq.h> +#include <asm/div64.h> +#include <asm/cpu.h> +#include <asm/am5120/adm5120.h> + +#include <linux/interrupt.h> +#include <linux/timex.h> +#include <asm/time.h> +#include <asm/mipsregs.h> + + +unsigned int mips_counter_frequency; + +#define ALLINTS (IE_IRQ0 | IE_IRQ5 | STATUS_IE) + +#define MIPS_CPU_TIMER_IRQ 7 + + +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, regs); +} + + +void __init mips_time_init(void) +{ + unsigned long clock; + + clock = (ADM5120_SW_REG(CODE_REG) & CODE_CLK_MASK) >> CODE_CLK_SHIFT; + + switch (clock) + { + case CPU_CLK_175MHZ: + mips_counter_frequency = CPU_SPEED_175M; + printk("CPU clock: 175MHz\n"); + break; + + case CPU_CLK_200MHZ: + mips_counter_frequency = CPU_SPEED_200M; + printk("CPU clock: 200MHz\n"); + break; + + case CPU_CLK_225MHZ: + mips_counter_frequency = CPU_SPEED_225M; + printk("CPU clock: 225MHz\n"); + break; + + case CPU_CLK_250MHZ: + mips_counter_frequency = CPU_SPEED_250M; + printk("CPU clock: 250MHz\n"); + break; + } +} + + +void __init mips_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); +} diff -ruN linux-2.6.10/arch/mips/kernel/head.S linux-2.6.10-adm.1/arch/mips/kernel/head.S --- linux-2.6.10/arch/mips/kernel/head.S 2004-12-24 22:35:01.000000000 +0100 +++ linux-2.6.10-adm.1/arch/mips/kernel/head.S 2005-01-27 21:06:16.000000000 +0100 @@ -127,12 +127,16 @@ * Necessary for machines which link their kernels at KSEG0. */ .fill 0x400 +#ifdef CONFIG_MIPS_AM5120 + /* AM5120 bootloader jumps to 0x6d8 */ + .fill 0x2d8 + j kernel_entry +#endif EXPORT(stext) # used for profiling EXPORT(_stext) __INIT - NESTED(kernel_entry, 16, sp) # kernel entry point setup_c0_status_pri diff -ruN linux-2.6.10/include/asm-mips/am5120/adm5120.h linux-2.6.10-adm.1/include/asm-mips/am5120/adm5120.h --- linux-2.6.10/include/asm-mips/am5120/adm5120.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/include/asm-mips/am5120/adm5120.h 2005-01-27 21:06:27.000000000 +0100 @@ -0,0 +1,1084 @@ +/***************************************************************************** +; +; (C) Unpublished Work of ADMtek Incorporated. All Rights Reserved. +; +; THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL, +; PROPRIETARY AND TRADESECRET INFORMATION OF ADMTEK INCORPORATED. +; ACCESS TO THIS WORK IS RESTRICTED TO (I) ADMTEK EMPLOYEES WHO HAVE A +; NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR ASSIGNMENTS +; AND (II) ENTITIES OTHER THAN ADMTEK WHO HAVE ENTERED INTO APPROPRIATE +; LICENSE AGREEMENTS. NO PART OF THIS WORK MAY BE USED, PRACTICED, +; PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, +; ABBRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, +; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ADMTEK. +; ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD +; SUBJECT THE PERPERTRATOR TO CRIMINAL AND CIVIL LIABILITY. +; +;------------------------------------------------------------------------------ +; +; Project : ADM5120 +; Creator : +; File : include/asm/am5120/adm5120.h +; Date : 2003.3.10 +; Abstract: +; +;Modification History: +; +; Jeroen Vreeken (pe1rxq@xxxxxxxxx) +; Changed UART_BAUDDIV() to minimize for rounding errors. +; Reformatted (somebody likes 4 character tabs....) +; +;*****************************************************************************/ + + +#ifndef __ADM5120_H__ +#define __ADM5120_H__ + + +#include <asm/addrspace.h> + + +/*========================= Physical Memory Map ============================*/ +#define SDRAM_BASE 0x00000000 +#define SMEM1_BASE 0x10000000 + +#define EXTIO0_BASE 0x10C00000 +#define EXTIO1_BASE 0x10E00000 +#define MPMC_BASE 0x11000000 +#define USBHOST_BASE 0x11200000 +#define PCIMEM_BASE 0x11400000 +#define PCIIO_BASE 0x11500000 +#define PCICFG_BASE 0x115FFFF0 +#define MIPS_BASE 0x11A00000 +#define SWCTRL_BASE 0x12000000 + +#define INTC_BASE 0x12200000 +#define SYSC_BASE 0x12400000 + +#define UART0_BASE 0x12600000 +#define UART1_BASE 0x12800000 + +#define SMEM0_BASE 0x1FC00000 + + +/*======================= MIPS interrupt ===================*/ +#define MIPSINT_SOFT0 0 +#define MIPSINT_SOFT1 1 +#define MIPSINT_IRQ 2 +#define MIPSINT_FIQ 3 +#define MIPSINT_REV0 4 +#define MIPSINT_REV1 5 +#define MIPSINT_REV2 6 +#define MIPSINT_TIMER 7 + +#define STATUS_IE 0x00000001 + +/*==================== MultiPort Memory Controller (MPMC) ==================*/ +/* registers offset */ +#define MPMC_CONTROL_REG 0x0000 +#define MPMC_STATUS_REG 0x0004 +#define MPMC_CONFIG_REG 0x0008 + +#define MPMC_DM_CONTROL_REG 0x0020 +#define MPMC_DM_REFRESH_REG 0x0024 + +#define MPMC_DM_TRP_REG 0x0030 +#define MPMC_DM_TRAS_REG 0x0034 +#define MPMC_DM_TSREX_REG 0x0038 +#define MPMC_DM_TAPR_REG 0x003C +#define MPMC_DM_TDAL_REG 0x0040 +#define MPMC_DM_TWR_REG 0x0044 +#define MPMC_DM_TRC_REG 0x0048 +#define MPMC_DM_TRFC_REG 0x004C +#define MPMC_DM_TXSR_REG 0x0050 +#define MPMC_DM_TRRD_REG 0x0054 +#define MPMC_DM_TMRD_REG 0x0058 + +#define MPMC_SM_EXTWAIT_REG 0x0080 + +#define MPMC_DM_CONFIG0_REG 0x0100 +#define MPMC_DM_RASCAS0_REG 0x0104 + +#define MPMC_DM_CONFIG1_REG 0x0120 +#define MPMC_DM_RASCAS1_REG 0x0124 + +#define MPMC_SM_CONFIG0_REG 0x0200 +#define MPMC_SM_WAITWEN0_REG 0x0204 +#define MPMC_SM_WAITOEN0_REG 0x0208 +#define MPMC_SM_WAITRD0_REG 0x020C +#define MPMC_SM_WAITPAGE0_REG 0x0210 +#define MPMC_SM_WAITWR0_REG 0x0214 +#define MPMC_SM_WAITTURN0_REG 0x0218 + +#define MPMC_SM_CONFIG1_REG 0x0220 +#define MPMC_SM_WAITWEN1_REG 0x0224 +#define MPMC_SM_WAITOEN1_REG 0x0228 +#define MPMC_SM_WAITRD1_REG 0x022C +#define MPMC_SM_WAITPAGE1_REG 0x0230 +#define MPMC_SM_WAITWR1_REG 0x0234 +#define MPMC_SM_WAITTURN1_REG 0x0238 + +#define MPMC_SM_CONFIG2_REG 0x0240 +#define MPMC_SM_WAITWEN2_REG 0x0244 +#define MPMC_SM_WAITOEN2_REG 0x0248 +#define MPMC_SM_WAITRD2_REG 0x024C +#define MPMC_SM_WAITPAGE2_REG 0x0250 +#define MPMC_SM_WAITWR2_REG 0x0254 +#define MPMC_SM_WAITTURN2_REG 0x0258 + +#define MPMC_SM_CONFIG3_REG 0x0260 +#define MPMC_SM_WAITWEN3_REG 0x0264 +#define MPMC_SM_WAITOEN3_REG 0x0268 +#define MPMC_SM_WAITRD3_REG 0x026C +#define MPMC_SM_WAITPAGE3_REG 0x0270 +#define MPMC_SM_WAITWR3_REG 0x0274 +#define MPMC_SM_WAITTURN3_REG 0x0278 + +/* Macro for access MPMC register */ +#define MPMC_REG(_offset) \ + (*((volatile unsigned long *)(KSEG1ADDR(MPMC_BASE + (_offset))))) + + +/* MPMC_CONTROL_REG (offset: 0x0000) */ +#define MPMC_DRAIN_W_BUF 0x00000008 +#define MPMC_LOW_POWER_MODE 0x00000004 +#define MPMC_ADDR_MIRROR 0x00000002 +#define MPMC_ENABLE 0x00000001 +#define MPMC_CONTROL_MASK 0x0000000f + +/* MPMC_STATUS_REG (offset: 0x0004) */ +#define MPMC_SREFACK 0x00000004 +#define MPMC_WBUF_DIRTY 0x00000002 +#define MPMC_BUSY 0x00000001 +#define MPMC_STATUS_MASK 0x00000007 + +/* MPMC_CONFIG_REG (offset: 0x0008) */ +#define MPMC_CLK_RATIO_1_1 0x00000000 +#define MPMC_CLK_RATIO_1_2 0x00000100 +#define MPMC_LITTLE_ENDIAN 0x00000000 +#define MPMC_BIG_ENDIAN 0x00000001 +#define MPMC_CONFIG_MASK 0x00000101 + +/* MPMC_DM_CONTROL_REG (offset: 0x0020) */ +#define DM_PVHHOUT_HI_VOLTAGE 0x00008000 +#define DM_RPOUT_HI_VOLTAGE 0x00004000 +#define DM_DEEP_SLEEP_MODE 0x00002000 + +#define DM_SDRAM_NOP 0x00000180 +#define DM_SDRAM_PRECHARGE_ALL 0x00000100 +#define DM_SDRAM_MODE_SETTING 0x00000080 +#define DM_SDRAM_NORMAL_OP 0x00000000 +#define DM_SDRAM_OPMODE_MASK 0x00000180 + +#define DM_SELF_REFRESH_MODE 0x00000004 +#define DM_CLKOUT_ALWAYS 0x00000002 +#define DM_CLKEN_ALWAYS 0x00000001 + +#define MPMC_DM_CONTROL_MASK 0x0000e187 + + +/* MPMC_DM_REFRESH_REG (offset:0x0024) */ +#define MPMC_DM_REFRESH_MASK 0x00000300 + +/* MPMC_DM_TRP_REG (offset: 0x0030) */ +#define MPMC_DM_TRP_MASK 0x0000000f + +/* MPMC_DM_TRAS_REG (offset: 0x0034) */ +#define MPMC_DM_TRAS_MASK 0x0000000f + +/* MPMC_DM_TSREX_REG (offset: 0x0038) */ +#define MPMC_DM_TSREX_MASK 0x0000000f + +/* MPMC_DM_TAPR_REG (offset: 0x003C) */ +#define MPMC_DM_TAPR_MASK 0x0000000f + +/* MPMC_DM_TDAL_REG (offset: 0x0040) */ +#define MPMC_DM_TDAL_MASK 0x0000000f + +/* MPMC_DM_TWR_REG (offset: 0x0044) */ +#define MPMC_DM_TWR_MASK 0x0000000f + +/* MPMC_DM_TRC_REG (offset: 0x0048) */ +#define MPMC_DM_TRC_MASK 0x0000001f + +/* MPMC_DM_TRFC_REG (offset: 0x004C) */ +#define MPMC_DM_TRFC_MASK 0x0000001f + +/* MPMC_DM_TXSR_REG (offset: 0x0050) */ +#define MPMC_DM_TXSR_MASK 0x0000001f + +/* MPMC_DM_TRRD_REG (offset: 0x0054) */ +#define MPMC_DM_TRRD_MASK 0x0000000f + +/* MPMC_DM_TMRD_REG (offset: 0x0058) */ +#define MPMC_DM_TMRD_MASK 0x0000000f + +/* MPMC_SM_EXTWAIT_REG (offset: 0x0080) */ +#define MPMC_SM_EXTWAIT_MASK 0x0000003f + + +/* MPMC_DM_CONFIG0_REG (offset: 0x0100) */ +/* MPMC_DM_CONFIG1_REG (offset: 0x0120) */ +#define DM_CFG_ROW_WIDTH_13BIT 0x20000000 +#define DM_CFG_ROW_WIDTH_12BIT 0x10000000 +#define DM_CFG_ROW_WIDTH_11BIT 0x00000000 +#define DM_CFG_ROW_WIDTH_MASK 0x30000000 +#define DM_CFG_ROW_WIDTH_SHIFT 28 + +#define DM_CFG_2BANK_DEV 0x00000000 +#define DM_CFG_4BANK_DEV 0x04000000 +#define DM_CFG_BANK_SHIFT 26 + +#define DM_CFG_COL_WIDTH_11BIT 0x01400000 +#define DM_CFG_COL_WIDTH_10BIT 0x01000000 +#define DM_CFG_COL_WIDTH_9BIT 0x00c00000 +#define DM_CFG_COL_WIDTH_8BIT 0x00800000 +#define DM_CFG_COL_WIDTH_7BIT 0x00400000 +#define DM_CFG_COL_WIDTH_6BIT 0x00000000 +#define DM_CFG_COL_WIDTH_MASK 0x01c00000 +#define DM_CFG_COL_WIDTH_SHIFT 22 + +#define DM_CFG_WRITE_PROTECT 0x00100000 +#define DM_CFG_BUFFER_EN 0x00080000 + +#define DM_CFG_ADDR_MAPPING_MASK 0x00005F80 + +#define DM_CFG_DEV_SYNC_FLASH 0x00000010 +#define DM_CFG_DEV_LOWPOWER_SDRAM 0x00000008 +#define DM_CFG_DEV_SDRAM 0x00000000 +#define DM_CFG_DEV_MASK 0x00000018 + + +/* MPMC_DM_RASCAS0_REG (offset: 0x0104) */ +/* MPMC_DM_RASCAS1_REG (offset: 0x0124) */ + +#define DM_CAS_LATENCY_3 0x00000300 +#define DM_CAS_LATENCY_2 0x00000200 +#define DM_CAS_LATENCY_1 0x00000100 + +#define DM_RAS_LATENCY_3 0x00000003 +#define DM_RAS_LATENCY_2 0x00000002 +#define DM_RAS_LATENCY_1 0x00000001 + + +/* MPMC_SM_CONFIG0_REG (offset: 0x0200) */ +/* MPMC_SM_CONFIG1_REG (offset: 0x0220) */ +/* MPMC_SM_CONFIG2_REG (offset: 0x0240) */ +/* MPMC_SM_CONFIG3_REG (offset: 0x0260) */ + +#define SM_WRITE_PROTECT 0x00100000 +#define SM_WRITEBUF_ENABLE 0x00080000 +#define SM_EXTENDED_WAIT 0x00000100 +#define SM_PB 0x00000080 +#define SM_CS_HIGH 0x00000040 +#define SM_PAGE_MODE 0x00000008 + +#define SM_MEM_WIDTH_32BIT 0x00000002 +#define SM_MEM_WIDTH_16BIT 0x00000001 +#define SM_MEM_WIDTH_8BIT 0x00000000 + +#define MPMC_SM_CONFIG_MASK 0x001801cb + + +/* MPMC_SM_WAITWEN0_REG (offset: 0x0204) */ +/* MPMC_SM_WAITWEN1_REG (offset: 0x0224) */ +/* MPMC_SM_WAITWEN2_REG (offset: 0x0244) */ +/* MPMC_SM_WAITWEN3_REG (offset: 0x0264) */ +#define MPMC_SM_WAITWEN_MASK 0x0000000f + + +/* MPMC_SM_WAITOEN0_REG (offset: 0x0208) */ +/* MPMC_SM_WAITOEN1_REG (offset: 0x0228) */ +/* MPMC_SM_WAITOEN2_REG (offset: 0x0248) */ +/* MPMC_SM_WAITOEN3_REG (offset: 0x0268) */ +#define MPMC_SM_WAITOEN_MASK 0x0000000f + +/* MPMC_SM_WAITRD0_REG (offset: 0x020C) */ +/* MPMC_SM_WAITRD1_REG (offset: 0x022C) */ +/* MPMC_SM_WAITRD2_REG (offset: 0x024C) */ +/* MPMC_SM_WAITRD3_REG (offset: 0x026C) */ +#define MPMC_SM_WAITRD_MASK 0x0000001f + +/* MPMC_SM_WAITPAGE0_REG (offset: 0x0210) */ +/* MPMC_SM_WAITPAGE1_REG (offset: 0x0230) */ +/* MPMC_SM_WAITPAGE2_REG (offset: 0x0250) */ +/* MPMC_SM_WAITPAGE3_REG (offset: 0x0270) */ +#define MPMC_SM_WAITPAGE_MASK 0x0000001f + + +/* MPMC_SM_WAITWR0_REG (offset: 0x0214) */ +/* MPMC_SM_WAITWR1_REG (offset: 0x0234) */ +/* MPMC_SM_WAITWR2_REG (offset: 0x0254) */ +/* MPMC_SM_WAITWR3_REG (offset: 0x0274) */ +#define MPMC_SM_WAITWR_MASK 0x0000001f + + +/* MPMC_SM_WAITTURN0_REG (offset: 0x0218) */ +/* MPMC_SM_WAITTURN1_REG (offset: 0x0238) */ +/* MPMC_SM_WAITTURN2_REG (offset: 0x0258) */ +/* MPMC_SM_WAITTURN3_REG (offset: 0x0278) */ +#define MPMC_SM_WAITTURN_MASK 0x0000000f + + +/* SDRAM mode register */ +/* ref: SDRAM data sheet. Ex: Micron MT48LC4M16A2 data sheet. */ +#define SDRAM_BTLEN_1 0x0000 +#define SDRAM_BTLEN_2 0x0001 +#define SDRAM_BTLEN_4 0x0002 +#define SDRAM_BTLEN_8 0x0003 +#define SDRAM_BTLEN_FULLPAGE 0x0007 +#define SDRAM_BTLEN_MASK 0x0007 + +#define SDRAM_BT_SEQUENCIAL 0x0000 +#define SDRAM_BT_INTERLEVED 0x0008 + +#define SDRAM_CAS_LATENCY_2 0x0020 +#define SDRAM_CAS_LATENCY_3 0x0030 +#define SDRAM_CAS_LATENCY_MASK 0x0030 + +#define SDRAM_OPMODE_STANDARD 0x0000 +#define SDRAM_OPMODE_MASK 0x0180 + +#define SDRAM_WBTMODE_ENABLE 0x0000 +#define SDRAM_WBTMODE_DISABLE 0x0200 + +#define SDRAM_MODEREG_MASK 0x03FF + + + +/*========================== Interrupt Controller ==========================*/ +/* registers offset */ +#define IRQ_STATUS_REG 0x00 /* Read */ +#define IRQ_RAW_STATUS_REG 0x04 /* Read */ +#define IRQ_ENABLE_REG 0x08 /* Read/Write */ +#define IRQ_DISABLE_REG 0x0C /* Write */ +#define IRQ_SOFT_REG 0x10 /* Write */ + +#define IRQ_MODE_REG 0x14 /* Read/Write */ +#define FIQ_STATUS_REG 0x18 /* Read */ + +/* test registers */ +#define IRQ_TESTSRC_REG 0x1c /* Read/Write */ +#define IRQ_SRCSEL_REG 0x20 /* Read/Write */ +#define IRQ_LEVEL_REG 0x24 /* Read/Write */ + +/* Macro for accessing Interrupt controller register */ +#define ADM5120_INTC_REG(_reg) \ + (*((volatile unsigned long *)(KSEG1ADDR(INTC_BASE + (_reg))))) + +/* interrupt levels */ +#define INT_LVL_TIMER 0 /* Timer */ +#define INT_LVL_UART0 1 /* Uart 0 */ +#define INT_LVL_UART1 2 /* Uart 1 */ +#define INT_LVL_USBHOST 3 /* USB Host */ +#define INT_LVL_EXTIO_0 4 /* External I/O 0 */ +#define INT_LVL_EXTIO_1 5 /* External I/O 1 */ +#define INT_LVL_PCI_0 6 /* PCI 0 */ +#define INT_LVL_PCI_1 7 /* PCI 1 */ +#define INT_LVL_PCI_2 8 /* PCI 2 */ +#define INT_LVL_SWITCH 9 /* Switch */ +#define INT_LVL_MAX INT_LVL_SWITCH + +/* interrupts */ +#define IRQ_TIMER (0x1 << INT_LVL_TIMER) +#define IRQ_UART0 (0x1 << INT_LVL_UART0) +#define IRQ_UART1 (0x1 << INT_LVL_UART1) +#define IRQ_USBHOST (0x1 << INT_LVL_USBHOST) +#define IRQ_EXTIO_0 (0x1 << INT_LVL_EXTIO_0) +#define IRQ_EXTIO_1 (0x1 << INT_LVL_EXTIO_1) +#define IRQ_PCI_INT0 (0x1 << INT_LVL_PCI_0) +#define IRQ_PCI_INT1 (0x1 << INT_LVL_PCI_1) +#define IRQ_PCI_INT2 (0x1 << INT_LVL_PCI_2) +#define IRQ_SWITCH (0x1 << INT_LVL_SWITCH) + +#define IRQ_MASK 0x3ff + + +/* IRQ LEVEL reg */ +#define IRQ_EXTIO0_ACT_LOW IRQ_EXTIO_0 +#define IRQ_EXTIO1_ACT_LOW IRQ_EXTIO_1 +#define IRQ_PCIINT0_ACT_LOW IRQ_PCI_INT0 +#define IRQ_PCIINT1_ACT_LOW IRQ_PCI_INT1 +#define IRQ_PCIINT2_ACT_LOW IRQ_PCI_INT2 + +#define IRQ_LEVEL_MASK 0x01F0 + +/*========================= Switch Control Register ========================*/ +/* Control Register */ +#define CODE_REG 0x0000 +#define SftRest_REG 0x0004 +#define Boot_done_REG 0x0008 +#define SWReset_REG 0x000C +#define Global_St_REG 0x0010 +#define PHY_st_REG 0x0014 +#define Port_st_REG 0x0018 +#define Mem_control_REG 0x001C +#define SW_conf_REG 0x0020 +#define CPUp_conf_REG 0x0024 +#define Port_conf0_REG 0x0028 +#define Port_conf1_REG 0x002C +#define Port_conf2_REG 0x0030 + +#define VLAN_G1_REG 0x0040 +#define VLAN_G2_REG 0x0044 +#define Send_trig_REG 0x0048 +#define Srch_cmd_REG 0x004C +#define ADDR_st0_REG 0x0050 +#define ADDR_st1_REG 0x0054 +#define MAC_wt0_REG 0x0058 +#define MAC_wt1_REG 0x005C +#define BW_cntl0_REG 0x0060 +#define BW_cntl1_REG 0x0064 +#define PHY_cntl0_REG 0x0068 +#define PHY_cntl1_REG 0x006C +#define FC_th_REG 0x0070 +#define Adj_port_th_REG 0x0074 +#define Port_th_REG 0x0078 +#define PHY_cntl2_REG 0x007C +#define PHY_cntl3_REG 0x0080 +#define Pri_cntl_REG 0x0084 +#define VLAN_pri_REG 0x0088 +#define TOS_en_REG 0x008C +#define TOS_map0_REG 0x0090 +#define TOS_map1_REG 0x0094 +#define Custom_pri1_REG 0x0098 +#define Custom_pri2_REG 0x009C + +#define Empty_cnt_REG 0x00A4 +#define Port_cnt_sel_REG 0x00A8 +#define Port_cnt_REG 0x00AC +#define SW_Int_st_REG 0x00B0 +#define SW_Int_mask_REG 0x00B4 + +// GPIO config +#define GPIO_conf0_REG 0x00B8 +#define GPIO_conf2_REG 0x00BC + +// Watch dog +#define Watchdog0_REG 0x00C0 +#define Watchdog1_REG 0x00C4 + +#define Swap_in_REG 0x00C8 +#define Swap_out_REG 0x00CC + +// Tx/Rx Descriptors +#define Send_HBaddr_REG 0x00D0 +#define Send_LBaddr_REG 0x00D4 +#define Recv_HBaddr_REG 0x00D8 +#define Recv_LBaddr_REG 0x00DC +#define Send_HWaddr_REG 0x00E0 +#define Send_LWaddr_REG 0x00E4 +#define Recv_HWaddr_REG 0x00E8 +#define Recv_LWaddr_REG 0x00EC + +// Timer Control +#define Timer_int_REG 0x00F0 +#define Timer_REG 0x00F4 + +// LED control +#define Port0_LED_REG 0x0100 +#define Port1_LED_REG 0x0104 +#define Port2_LED_REG 0x0108 +#define Port3_LED_REG 0x010c +#define Port4_LED_REG 0x0110 + + +/* Macros for accessing Switch control register */ +#define ADM5120_SW_REG(_reg) \ + (*((volatile unsigned long *)(KSEG1ADDR(SWCTRL_BASE + (_reg))))) + + + +/* CODE_REG */ +#define CODE_ID_MASK 0x00FFFF +#define CODE_ADM5120_ID 0x5120 + +#define CODE_REV_MASK 0x0F0000 +#define CODE_REV_SHIFT 16 +#define CODE_REV_ADM5120_0 0x8 + +#define CODE_CLK_MASK 0x300000 +#define CODE_CLK_SHIFT 20 + +#define CPU_CLK_175MHZ 0x0 +#define CPU_CLK_200MHZ 0x1 +#define CPU_CLK_225MHZ 0x2 +#define CPU_CLK_250MHZ 0x3 + +#define CPU_SPEED_175M (175000000/2) +#define CPU_SPEED_200M (200000000/2) +#define CPU_SPEED_225M (225000000/2) +#define CPU_SPEED_250M (250000000/2) + +#define CPU_NAND_BOOT 0x01000000 +#define CPU_DCACHE_2K_WAY (0x1 << 25) +#define CPU_DCACHE_2WAY (0x1 << 26) +#define CPU_ICACHE_2K_WAY (0x1 << 27) +#define CPU_ICACHE_2WAY (0x1 << 28) + +#define CPU_GMII_SUPPORT 0x20000000 + +#define CPU_PQFP_MODE (0x1 << 29) + +#define CPU_CACHE_LINE_SIZE 16 + +/* SftRest_REG */ +#define SOFTWARE_RESET 0x1 + +/* Boot_done_REG */ +#define BOOT_DONE 0x1 + +/* SWReset_REG */ +#define SWITCH_RESET 0x1 + +/* Global_St_REG */ +#define DATA_BUF_BIST_FAILED (0x1 << 0) +#define LINK_TAB_BIST_FAILED (0x1 << 1) +#define MC_TAB_BIST_FAILED (0x1 << 2) +#define ADDR_TAB_BIST_FAILED (0x1 << 3) +#define DCACHE_D_FAILED (0x3 << 4) +#define DCACHE_T_FAILED (0x1 << 6) +#define ICACHE_D_FAILED (0x3 << 7) +#define ICACHE_T_FAILED (0x1 << 9) +#define BIST_FAILED_MASK 0x03FF + +#define ALLMEM_TEST_DONE (0x1 << 10) + +#define SKIP_BLK_CNT_MASK 0x1FF000 +#define SKIP_BLK_CNT_SHIFT 12 + + +/* PHY_st_REG */ +#define PORT_LINK_MASK 0x0000001F +#define PORT_MII_LINKFAIL 0x00000020 +#define PORT_SPEED_MASK 0x00001F00 + +#define PORT_GMII_SPD_MASK 0x00006000 +#define PORT_GMII_SPD_10M 0x00000000 +#define PORT_GMII_SPD_100M 0x00002000 +#define PORT_GMII_SPD_1000M 0x00004000 + +#define PORT_DUPLEX_MASK 0x003F0000 +#define PORT_FLOWCTRL_MASK 0x1F000000 + +#define PORT_GMII_FLOWCTRL_MASK 0x60000000 +#define PORT_GMII_FC_ON 0x20000000 +#define PORT_GMII_RXFC_ON 0x20000000 +#define PORT_GMII_TXFC_ON 0x40000000 + +/* Port_st_REG */ +#define PORT_SECURE_ST_MASK 0x001F +#define MII_PORT_TXC_ERR 0x0080 + +/* Mem_control_REG */ +#define SDRAM_SIZE_4MBYTES 0x0001 +#define SDRAM_SIZE_8MBYTES 0x0002 +#define SDRAM_SIZE_16MBYTES 0x0003 +#define SDRAM_SIZE_64MBYTES 0x0004 +#define SDRAM_SIZE_128MBYTES 0x0005 +#define SDRAM_SIZE_MASK 0x0007 + +#define MEMCNTL_SDRAM1_EN (0x1 << 5) + +#define ROM_SIZE_DISABLE 0x0000 +#define ROM_SIZE_512KBYTES 0x0001 +#define ROM_SIZE_1MBYTES 0x0002 +#define ROM_SIZE_2MBYTES 0x0003 +#define ROM_SIZE_4MBYTES 0x0004 +#define ROM_SIZE_8MBYTES 0x0005 +#define ROM_SIZE_MASK 0x0007 + +#define ROM0_SIZE_SHIFT 8 +#define ROM1_SIZE_SHIFT 16 + + +/* SW_conf_REG */ +#define SW_AGE_TIMER_MASK 0x000000F0 +#define SW_AGE_TIMER_DISABLE 0x00000000 +#define SW_AGE_TIMER_FAST 0x00000080 +#define SW_AGE_TIMER_300SEC 0x00000010 +#define SW_AGE_TIMER_600SEC 0x00000020 +#define SW_AGE_TIMER_1200SEC 0x00000030 +#define SW_AGE_TIMER_2400SEC 0x00000040 +#define SW_AGE_TIMER_4800SEC 0x00000050 +#define SW_AGE_TIMER_9600SEC 0x00000060 +#define SW_AGE_TIMER_19200SEC 0x00000070 +//#define SW_AGE_TIMER_38400SEC 0x00000070 + +#define SW_BC_PREV_MASK 0x00000300 +#define SW_BC_PREV_DISABLE 0x00000000 +#define SW_BC_PREV_64BC 0x00000100 +#define SW_BC_PREV_48BC 0x00000200 +#define SW_BC_PREV_32BC 0x00000300 + +#define SW_MAX_LEN_MASK 0x00000C00 +#define SW_MAX_LEN_1536 0x00000000 +#define SW_MAX_LEN_1522 0x00000800 +#define SW_MAX_LEN_1518 0x00000400 + +#define SW_DIS_COLABT 0x00001000 + +#define SW_HASH_ALG_MASK 0x00006000 +#define SW_HASH_ALG_DIRECT 0x00000000 +#define SW_HASH_ALG_XOR48 0x00002000 +#define SW_HASH_ALG_XOR32 0x00004000 + +#define SW_DISABLE_BACKOFF_TIMER 0x00008000 + +#define SW_BP_NUM_MASK 0x000F0000 +#define SW_BP_NUM_SHIFT 16 +#define SW_BP_MODE_MASK 0x00300000 +#define SW_BP_MODE_DISABLE 0x00000000 +#define SW_BP_MODE_JAM 0x00100000 +#define SW_BP_MODE_JAMALL 0x00200000 +#define SW_BP_MODE_CARRIER 0x00300000 +#define SW_RESRV_MC_FILTER 0x00400000 +#define SW_BISR_DISABLE 0x00800000 + +#define SW_DIS_MII_WAS_TX 0x01000000 +#define SW_BISS_EN 0x02000000 +#define SW_BISS_TH_MASK 0x0C000000 +#define SW_BISS_TH_SHIFT 26 +#define SW_REQ_LATENCY_MASK 0xF0000000 +#define SW_REQ_LATENCY_SHIFT 28 + + +/* CPUp_conf_REG */ +#define SW_CPU_PORT_DISABLE 0x00000001 +#define SW_PADING_CRC 0x00000002 +#define SW_BRIDGE_MODE 0x00000004 + +#define SW_DIS_UN_SHIFT 9 +#define SW_DIS_UN_MASK (0x3F << SW_DIS_UN_SHIFT) +#define SW_DIS_MC_SHIFT 16 +#define SW_DIS_MC_MASK (0x3F << SW_DIS_MC_SHIFT) +#define SW_DIS_BC_SHIFT 24 +#define SW_DIS_BC_MASK (0x3F << SW_DIS_BC_SHIFT) + + +/* Port_conf0_REG */ +#define SW_DISABLE_PORT_MASK 0x0000003F +#define SW_EN_MC_MASK 0x00003F00 +#define SW_EN_MC_SHIFT 8 +#define SW_EN_BP_MASK 0x003F0000 +#define SW_EN_BP_SHIFT 16 +#define SW_EN_FC_MASK 0x3F000000 +#define SW_EN_FC_SHIFT 24 + + +/* Port_conf1_REG */ +#define SW_DIS_SA_LEARN_MASK 0x0000003F +#define SW_PORT_BLOCKING_MASK 0x00000FC0 +#define SW_PORT_BLOCKING_SHIFT 6 +#define SW_PORT_BLOCKING_ON 0x1 + +#define SW_PORT_BLOCKING_MODE_MASK 0x0003F000 +#define SW_PORT_BLOCKING_MODE_SHIFT 12 +#define SW_PORT_BLOCKING_CTRLONLY 0x1 + +#define SW_EN_PORT_AGE_MASK 0x03F00000 +#define SW_EN_PORT_AGE_SHIFT 20 +#define SW_EN_SA_SECURED_MASK 0xFC000000 +#define SW_EN_SA_SECURED_SHIFT 26 + + +/* Port_conf2_REG */ +#define SW_GMII_AN_EN 0x00000001 +#define SW_GMII_FORCE_SPD_MASK 0x00000006 +#define SW_GMII_FORCE_SPD_10M 0 +#define SW_GMII_FORCE_SPD_100M 0x2 +#define SW_GMII_FORCE_SPD_1000M 0x4 + +#define SW_GMII_FORCE_FULL_DUPLEX 0x00000008 + +#define SW_GMII_FORCE_RXFC 0x00000010 +#define SW_GMII_FORCE_TXFC 0x00000020 + +#define SW_GMII_EN 0x00000040 +#define SW_GMII_REVERSE 0x00000080 + +#define SW_GMII_TXC_CHECK_EN 0x00000100 + +#define SW_LED_FLASH_TIME_MASK 0x00030000 +#define SW_LED_FLASH_TIME_30MS 0x00000000 +#define SW_LED_FLASH_TIME_60MS 0x00010000 +#define SW_LED_FLASH_TIME_240MS 0x00020000 +#define SW_LED_FLASH_TIME_480MS 0x00030000 + + +/* Send_trig_REG */ +#define SEND_TRIG_LOW 0x0001 +#define SEND_TRIG_HIGH 0x0002 + + +/* Srch_cmd_REG */ +#define SW_MAC_SEARCH_START 0x000001 +#define SW_MAX_SEARCH_AGAIN 0x000002 + + +/* MAC_wt0_REG */ +#define SW_MAC_WRITE 0x00000001 +#define SW_MAC_WRITE_DONE 0x00000002 +#define SW_MAC_FILTER_EN 0x00000004 +#define SW_MAC_VLANID_SHIFT 3 +#define SW_MAC_VLANID_MASK 0x00000038 +#define SW_MAC_VLANID_EN 0x00000040 +#define SW_MAC_PORTMAP_MASK 0x00001F80 +#define SW_MAC_PORTMAP_SHIFT 7 +#define SW_MAC_AGE_MASK (0x7 << 13) +#define SW_MAC_AGE_STATIC (0x7 << 13) +#define SW_MAC_AGE_VALID (0x1 << 13) +#define SW_MAC_AGE_EMPTY 0 + +/* BW_cntl0_REG */ +#define SW_PORT_TX_NOLIMIT 0 +#define SW_PORT_TX_64K 1 +#define SW_PORT_TX_128K 2 +#define SW_PORT_TX_256K 3 +#define SW_PORT_TX_512K 4 +#define SW_PORT_TX_1M 5 +#define SW_PORT_TX_4M 6 +#define SW_PORT_TX_10MK 7 + +/* BW_cntl1_REG */ +#define SW_TRAFFIC_SHAPE_IPG (0x1 << 31) + +/* PHY_cntl0_REG */ +#define SW_PHY_ADDR_MASK 0x0000001F +#define PHY_ADDR_MAX 0x1f +#define SW_PHY_REG_ADDR_MASK 0x00001F00 +#define SW_PHY_REG_ADDR_SHIFT 8 +#define PHY_REG_ADDR_MAX 0x1f +#define SW_PHY_WRITE 0x00002000 +#define SW_PHY_READ 0x00004000 +#define SW_PHY_WDATA_MASK 0xFFFF0000 +#define SW_PHY_WDATA_SHIFT 16 + + +/* PHY_cntl1_REG */ +#define SW_PHY_WRITE_DONE 0x00000001 +#define SW_PHY_READ_DONE 0x00000002 +#define SW_PHY_RDATA_MASK 0xFFFF0000 +#define SW_PHY_RDATA_SHIFT 16 + +/* FC_th_REG */ +/* Adj_port_th_REG */ +/* Port_th_REG */ + +/* PHY_cntl2_REG */ +#define SW_PHY_AN_MASK 0x0000001F +#define SW_PHY_SPD_MASK 0x000003E0 +#define SW_PHY_SPD_SHIFT 5 +#define SW_PHY_DPX_MASK 0x00007C00 +#define SW_PHY_DPX_SHIFT 10 +#define SW_FORCE_FC_MASK 0x000F8000 +#define SW_FORCE_FC_SHIFT 15 +#define SW_PHY_NORMAL_MASK 0x01F00000 +#define SW_PHY_NORMAL_SHIFT 20 +#define SW_PHY_AUTOMDIX_MASK 0x3E000000 +#define SW_PHY_AUTOMDIX_SHIFT 25 +#define SW_PHY_REC_MCCAVERAGE 0x40000000 + + +/* PHY_cntl3_REG */ +/* Pri_cntl_REG */ +/* VLAN_pri_REG */ +/* TOS_en_REG */ +/* TOS_map0_REG */ +/* TOS_map1_REG */ +/* Custom_pri1_REG */ +/* Custom_pri2_REG */ +/* Empty_cnt_REG */ +/* Port_cnt_sel_REG */ +/* Port_cnt_REG */ + + +/* SW_Int_st_REG & SW_Int_mask_REG */ +#define SEND_H_DONE_INT 0x0000001 +#define SEND_L_DONE_INT 0x0000002 +#define RX_H_DONE_INT 0x0000004 +#define RX_L_DONE_INT 0x0000008 +#define RX_H_DESC_FULL_INT 0x0000010 +#define RX_L_DESC_FULL_INT 0x0000020 +#define PORT0_QUE_FULL_INT 0x0000040 +#define PORT1_QUE_FULL_INT 0x0000080 +#define PORT2_QUE_FULL_INT 0x0000100 +#define PORT3_QUE_FULL_INT 0x0000200 +#define PORT4_QUE_FULL_INT 0x0000400 +#define PORT5_QUE_FULL_INT 0x0000800 + +#define CPU_QUE_FULL_INT 0x0002000 +#define GLOBAL_QUE_FULL_INT 0x0004000 +#define MUST_DROP_INT 0x0008000 +#define BC_STORM_INT 0x0010000 + +#define PORT_STATUS_CHANGE_INT 0x0040000 +#define INTRUDER_INT 0x0080000 +#define WATCHDOG0_EXPR_INT 0x0100000 +#define WATCHDOG1_EXPR_INT 0x0200000 +#define RX_DESC_ERR_INT 0x0400000 +#define SEND_DESC_ERR_INT 0x0800000 +#define CPU_HOLD_INT 0x1000000 +#define SWITCH_INT_MASK 0x1FDEFFF + + +/* GPIO_conf0_REG */ +#define GPIO0_INPUT_MODE 0x00000001 +#define GPIO1_INPUT_MODE 0x00000002 +#define GPIO2_INPUT_MODE 0x00000004 +#define GPIO3_INPUT_MODE 0x00000008 +#define GPIO4_INPUT_MODE 0x00000010 +#define GPIO5_INPUT_MODE 0x00000020 +#define GPIO6_INPUT_MODE 0x00000040 +#define GPIO7_INPUT_MODE 0x00000080 + +#define GPIO0_OUTPUT_MODE 0 +#define GPIO1_OUTPUT_MODE 0 +#define GPIO2_OUTPUT_MODE 0 +#define GPIO3_OUTPUT_MODE 0 +#define GPIO4_OUTPUT_MODE 0 +#define GPIO5_OUTPUT_MODE 0 +#define GPIO6_OUTPUT_MODE 0 +#define GPIO7_OUTPUT_MODE 0 + +#define GPIO0_INPUT_MASK 0x00000100 +#define GPIO1_INPUT_MASK 0x00000200 +#define GPIO2_INPUT_MASK 0x00000400 +#define GPIO3_INPUT_MASK 0x00000800 +#define GPIO4_INPUT_MASK 0x00001000 +#define GPIO5_INPUT_MASK 0x00002000 +#define GPIO6_INPUT_MASK 0x00004000 +#define GPIO7_INPUT_MASK 0x00008000 + +#define GPIO0_OUTPUT_EN 0x00010000 +#define GPIO1_OUTPUT_EN 0x00020000 +#define GPIO2_OUTPUT_EN 0x00040000 +#define GPIO3_OUTPUT_EN 0x00080000 +#define GPIO4_OUTPUT_EN 0x00100000 +#define GPIO5_OUTPUT_EN 0x00200000 +#define GPIO6_OUTPUT_EN 0x00400000 +#define GPIO7_OUTPUT_EN 0x00800000 + +#define GPIO_CONF0_OUTEN_MASK 0x00ff0000 + +#define GPIO0_OUTPUT_HI 0x01000000 +#define GPIO1_OUTPUT_HI 0x02000000 +#define GPIO2_OUTPUT_HI 0x04000000 +#define GPIO3_OUTPUT_HI 0x08000000 +#define GPIO4_OUTPUT_HI 0x10000000 +#define GPIO5_OUTPUT_HI 0x20000000 +#define GPIO6_OUTPUT_HI 0x40000000 +#define GPIO7_OUTPUT_HI 0x80000000 + +#define GPIO0_OUTPUT_LOW 0 +#define GPIO1_OUTPUT_LOW 0 +#define GPIO2_OUTPUT_LOW 0 +#define GPIO3_OUTPUT_LOW 0 +#define GPIO4_OUTPUT_LOW 0 +#define GPIO5_OUTPUT_LOW 0 +#define GPIO6_OUTPUT_LOW 0 +#define GPIO7_OUTPUT_LOW 0 + + +/* GPIO_conf2_REG */ +#define EXTIO_WAIT_EN (0x1 << 6) +#define EXTIO_CS1_INT1_EN (0x1 << 5) +#define EXTIO_CS0_INT0_EN (0x1 << 4) + +/* Watchdog0_REG, Watchdog1_REG */ +#define WATCHDOG0_RESET_EN 0x80000000 +#define WATCHDOG1_DROP_EN 0x80000000 + +#define WATCHDOG_TIMER_SET_MASK 0x7FFF0000 +#define WATCHDOG_TIMER_SET_SHIFT 16 +#define WATCHDOG_TIMER_MASK 0x00007FFF + + +/* Timer_int_REG */ +#define SW_TIMER_INT_DISABLE 0x10000 +#define SW_TIMER_INT 0x1 + +/* Timer_REG */ +#define SW_TIMER_EN 0x10000 +#define SW_TIMER_MASK 0xffff +#define SW_TIMER_10MS_TICKS 0x3D09 +#define SW_TIMER_1MS_TICKS 0x61A +#define SW_TIMER_100US_TICKS 0x9D + + +/* Port0_LED_REG, Port1_LED_REG, Port2_LED_REG, Port3_LED_REG, Port4_LED_REG*/ +#define GPIOL_INPUT_MODE 0x00 +#define GPIOL_OUTPUT_FLASH 0x01 +#define GPIOL_OUTPUT_LOW 0x02 +#define GPIOL_OUTPUT_HIGH 0x03 +#define GPIOL_LINK_LED 0x04 +#define GPIOL_SPEED_LED 0x05 +#define GPIOL_DUPLEX_LED 0x06 +#define GPIOL_ACT_LED 0x07 +#define GPIOL_COL_LED 0x08 +#define GPIOL_LINK_ACT_LED 0x09 +#define GPIOL_DUPLEX_COL_LED 0x0A +#define GPIOL_10MLINK_ACT_LED 0x0B +#define GPIOL_100MLINK_ACT_LED 0x0C +#define GPIOL_CTRL_MASK 0x0F + +#define GPIOL_INPUT_MASK 0x7000 +#define GPIOL_INPUT_0_MASK 0x1000 +#define GPIOL_INPUT_1_MASK 0x2000 +#define GPIOL_INPUT_2_MASK 0x4000 + +#define PORT_LED0_SHIFT 0 +#define PORT_LED1_SHIFT 4 +#define PORT_LED2_SHIFT 8 + + +/*=========================== UART Control Register ========================*/ +#define UART_DR_REG 0x00 +#define UART_RSR_REG 0x04 +#define UART_ECR_REG 0x04 +#define UART_LCR_H_REG 0x08 +#define UART_LCR_M_REG 0x0c +#define UART_LCR_L_REG 0x10 +#define UART_CR_REG 0x14 +#define UART_FR_REG 0x18 +#define UART_IIR_REG 0x1c +#define UART_ICR_REG 0x1C +#define UART_ILPR_REG 0x20 + +/* rsr/ecr reg */ +#define UART_OVERRUN_ERR 0x08 +#define UART_BREAK_ERR 0x04 +#define UART_PARITY_ERR 0x02 +#define UART_FRAMING_ERR 0x01 +#define UART_RX_STATUS_MASK 0x0f +#define UART_RX_ERROR ( UART_BREAK_ERR | UART_PARITY_ERR | UART_FRAMING_ERR) + +/* lcr_h reg */ +#define UART_SEND_BREAK 0x01 +#define UART_PARITY_EN 0x02 +#define UART_EVEN_PARITY 0x04 +#define UART_TWO_STOP_BITS 0x08 +#define UART_ENABLE_FIFO 0x10 + +#define UART_WLEN_5BITS 0x00 +#define UART_WLEN_6BITS 0x20 +#define UART_WLEN_7BITS 0x40 +#define UART_WLEN_8BITS 0x60 +#define UART_WLEN_MASK 0x60 + +/* cr reg */ +#define UART_PORT_EN 0x01 +#define UART_SIREN 0x02 +#define UART_SIRLP 0x04 +#define UART_MODEM_STATUS_INT_EN 0x08 +#define UART_RX_INT_EN 0x10 +#define UART_TX_INT_EN 0x20 +#define UART_RX_TIMEOUT_INT_EN 0x40 +#define UART_LOOPBACK_EN 0x80 + +/* fr reg */ +#define UART_CTS 0x01 +#define UART_DSR 0x02 +#define UART_DCD 0x04 +#define UART_BUSY 0x08 +#define UART_RX_FIFO_EMPTY 0x10 +#define UART_TX_FIFO_FULL 0x20 +#define UART_RX_FIFO_FULL 0x40 +#define UART_TX_FIFO_EMPTY 0x80 + +/* iir/icr reg */ +#define UART_MODEM_STATUS_INT 0x01 +#define UART_RX_INT 0x02 +#define UART_TX_INT 0x04 +#define UART_RX_TIMEOUT_INT 0x08 + +#define UART_INT_MASK 0x0f + +#define ADM5120_UARTCLK_FREQ 62500000 + +/* This is slightly different from the ADM5120 manual, this method has better + rounding for higher baudrates + - Jeroen + */ +#define UART_BAUDDIV(_rate) \ + ((unsigned long)(((ADM5120_UARTCLK_FREQ)/(8*(_rate))+1)/2 - 1)) + +/* uart_baudrate */ +#define UART_230400bps_DIVISOR UART_BAUDDIV(230400) +#define UART_115200bps_DIVISOR UART_BAUDDIV(115200) +#define UART_76800bps_DIVISOR UART_BAUDDIV(76800) +#define UART_57600bps_DIVISOR UART_BAUDDIV(57600) +#define UART_38400bps_DIVISOR UART_BAUDDIV(38400) +#define UART_19200bps_DIVISOR UART_BAUDDIV(19200) +#define UART_14400bps_DIVISOR UART_BAUDDIV(14400) +#define UART_9600bps_DIVISOR UART_BAUDDIV(9600) +#define UART_2400bps_DIVISOR UART_BAUDDIV(2400) +#define UART_1200bps_DIVISOR UART_BAUDDIV(1200) + + +/* Cache Controller */ +//#define ADM5120_CACHE_CTRL_BASE 0x70000000 +#define ADM5120_CACHE_LINE_SIZE 16 +//#define ADM5120_CACHE_CTRL_REGSIZE 4 + + +/********** GPIO macro *************/ +#define GPIO_MEASURE 0x000f00f0 //enable output status of pin 0, 1, 2, 3 + +#define GPIO_MEASURE_INIT() \ +do { \ + ADM5120_SW_REG(GPIO_conf0_REG) = GPIO_MEASURE; \ +} while (0) + + +#define GPIO_SET_HI(num) \ +do { \ + ADM5120_SW_REG(GPIO_conf0_REG) |= 1 << (24 + num); \ +} while (0) + + +#define GPIO_SET_LOW(num) \ +do { \ + ADM5120_SW_REG(GPIO_conf0_REG) &= ~(1 << (24 + num)); \ +} while (0) + + +#define GPIO_TOGGLE(num) \ +do { \ + ADM5120_SW_REG(GPIO_conf0_REG) ^= (1 << (24 + num)); \ +} while (0) + + +#define BOOT_LINE_SIZE 256 +#define BSP_STR_LEN 64 + +/* + * System configuration + */ +typedef struct BOARD_CFG_S +{ + unsigned long blmagic; + unsigned char bootline[BOOT_LINE_SIZE+1]; + + unsigned long macmagic; + unsigned char mac[4][8]; + + unsigned long idmagic; + unsigned char serial[BSP_STR_LEN+1]; + + unsigned long vermagic; + unsigned char ver[BSP_STR_LEN+1]; + +} BOARD_CFG_T, *PBOARD_CFG_T; + + +#define BL_MAGIC 0x6c62676d +#define MAC_MAGIC 0x636d676d +#define VER_MAGIC 0x7276676d +#define ID_MAGIC 0x6469676d + + + + + +#endif /* __ADM5120_H__ */ diff -ruN linux-2.6.10/include/asm-mips/am5120/mx.h linux-2.6.10-adm.1/include/asm-mips/am5120/mx.h --- linux-2.6.10/include/asm-mips/am5120/mx.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/include/asm-mips/am5120/mx.h 2005-01-27 21:06:27.000000000 +0100 @@ -0,0 +1,69 @@ +/***************************************************************************** +; +; (C) Unpublished Work of ADMtek Technology, Corp. All Rights Reserved. +; +; THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL, +; PROPRIETARY AND TRADESECRET INFORMATION OF ADMTEK TECHNOLOGY CORP. +; ACCESS TO THIS WORK IS RESTRICTED TO (I) ADMTEK EMPLOYEES WHO HAVE A +; NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR ASSIGNMENTS +; AND (II) ENTITIES OTHER THAN ADMTEK WHO HAVE ENTERED INTO APPROPRIATE +; LICENSE AGREEMENTS. NO PART OF THIS WORK MAY BE USED, PRACTICED, +; PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, +; ABBRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, +; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ADMTEK. +; ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD +; SUBJECT THE PERPERTRATOR TO CRIMINAL AND CIVIL LIABILITY. +;------------------------------------------------------------------------------ +; +; Project : Common plateform +; Creator : Simon +; File : nv_drv.h +; +;Modification History: +; Location Resonder Modification Description +; ------------ ---------- ---------------------------------------------- +; +;*****************************************************************************/ +#if __cplusplus +extern "C" { +#endif + +#ifndef _FLASH_H_ +#define _FLASH_H_ + +enum FLASH_E +{ + FLASH_NOT_FIT_IN = -2, + FLASH_ERROR = -1, + FLASH_OK = 0, + FLASH_PARTIAL_DONE +}; + +typedef struct FLASH_DESC_S +{ + struct FLASH_DESC_S *next; + int flash_size; + int addr_inc; + int byte_width; + char *start; + unsigned long *blocks; + int num; + int (*erase)(struct FLASH_DESC_S *cp, char *flash, int cells); + int (*read) (struct FLASH_DESC_S *cp, char *flash, char *dst, int cells); + int (*write)(struct FLASH_DESC_S *cp, char *flash, char *src, int cells); +} +FLASH_DESC; + + +int flash_init(); +int flash_add(FLASH_DESC *cp); +int flash_erase(char *flash, int size); +int flash_read (char *flash, char *dst, int size); +int flash_write(char *flash, char *src, int size); + + +#endif /* _FLASH_H_ */ + +#if __cplusplus +} +#endif diff -ruN linux-2.6.10/include/asm-mips/am5120/mx29lv320b.h linux-2.6.10-adm.1/include/asm-mips/am5120/mx29lv320b.h --- linux-2.6.10/include/asm-mips/am5120/mx29lv320b.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/include/asm-mips/am5120/mx29lv320b.h 2005-01-27 21:06:27.000000000 +0100 @@ -0,0 +1,61 @@ +/***************************************************************************** +; +; (C) Unpublished Work of ADMtek Incorporated. All Rights Reserved. +; +; THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL, +; PROPRIETARY AND TRADESECRET INFORMATION OF ADMTEK INCORPORATED. +; ACCESS TO THIS WORK IS RESTRICTED TO (I) ADMTEK EMPLOYEES WHO HAVE A +; NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR ASSIGNMENTS +; AND (II) ENTITIES OTHER THAN ADMTEK WHO HAVE ENTERED INTO APPROPRIATE +; LICENSE AGREEMENTS. NO PART OF THIS WORK MAY BE USED, PRACTICED, +; PERFORMED, COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, +; ABBRIDGED, CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, +; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ADMTEK. +; ANY USE OR EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD +; SUBJECT THE PERPERTRATOR TO CRIMINAL AND CIVIL LIABILITY. +; +;------------------------------------------------------------------------------ +; +; Project : ADM5120 +; Creator : +; File : include/asm/am5120/mx29lv320b.h +; Date : 2003.07.30 +; Abstract: +; +;Modification History: +; +; +;*****************************************************************************/ + + +#ifndef __MX29LV320B_H__ +#define __MX29LV320B_H__ + +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> + +#define FLASH_PHYS_ADDR 0x1FC00000 +#define FLASH_SIZE 0x200000 + +#define FLASH_PARTITION1_ADDR 0x00000000 +#define FLASH_PARTITION1_SIZE 0x00200000 + +struct map_info mx29lv320b_map = { + .name = "MX29LV320B flash device", + .size = FLASH_SIZE, + .buswidth = 2, +}; + +struct mtd_partition mx29lv320b_parts[] = { + { + .name = "Flash Disk 1", + .offset = FLASH_PARTITION1_ADDR, + .size = FLASH_PARTITION1_SIZE + } +}; + +#define PARTITION_COUNT (sizeof(mx29lv320b_parts)/sizeof(struct mtd_partition)) + +#endif /* __MX29LV320B_H__ */ + diff -ruN linux-2.6.10/include/asm-mips/am5120/prom.h linux-2.6.10-adm.1/include/asm-mips/am5120/prom.h --- linux-2.6.10/include/asm-mips/am5120/prom.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-adm.1/include/asm-mips/am5120/prom.h 2005-01-27 21:06:27.000000000 +0100 @@ -0,0 +1,49 @@ +/* + * Carsten Langgaard, carstenl@xxxxxxxx + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * MIPS boards bootprom interface for the Linux kernel. + * + */ + +#ifndef _MIPS_PROM_H +#define _MIPS_PROM_H + +extern char *prom_getcmdline(void); +extern char *prom_getenv(char *name); +extern void setup_prom_printf(int tty_no); +extern void prom_printf(char *fmt, ...); +extern void prom_init_cmdline(void); +extern void prom_meminit(void); +extern void prom_fixup_mem_map(unsigned long start_mem, unsigned long end_mem); +extern void prom_free_prom_memory (void); +extern void mips_display_message(const char *str); +extern void mips_display_word(unsigned int num); +extern int get_ethernet_addr(char *ethernet_addr); + +/* Memory descriptor management. */ +#define PROM_MAX_PMEMBLOCKS 32 +struct prom_pmemblock { + unsigned long base; /* Within KSEG0. */ + unsigned int size; /* In bytes. */ + unsigned int type; /* free or prom memory */ +}; + +#endif /* !(_MIPS_PROM_H) */ diff -ruN linux-2.6.10/include/asm-mips/bootinfo.h linux-2.6.10-adm.1/include/asm-mips/bootinfo.h --- linux-2.6.10/include/asm-mips/bootinfo.h 2004-12-24 22:34:26.000000000 +0100 +++ linux-2.6.10-adm.1/include/asm-mips/bootinfo.h 2005-01-27 21:06:26.000000000 +0100 @@ -212,6 +212,12 @@ #define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */ #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */ +/* + * 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); diff -ruN linux-2.6.10/include/linux/init.h linux-2.6.10-adm.1/include/linux/init.h --- linux-2.6.10/include/linux/init.h 2004-12-24 22:33:50.000000000 +0100 +++ linux-2.6.10-adm.1/include/linux/init.h 2005-01-27 21:06:29.000000000 +0100 @@ -86,6 +86,8 @@ static initcall_t __initcall_##fn __attribute_used__ \ __attribute__((__section__(".initcall" level ".init"))) = fn +#define early_initcall(fn) __define_initcall(".early1",fn) + #define core_initcall(fn) __define_initcall("1",fn) #define postcore_initcall(fn) __define_initcall("2",fn) #define arch_initcall(fn) __define_initcall("3",fn)