Commit a85be436 authored by Ralf Bächle's avatar Ralf Bächle Committed by Linus Torvalds

[PATCH] Alchemy update

This is an update of the AMD Alchemy support for 2.5.

(This is way behind what we have for 2.4 but forward porting is non-trivial
and work in progress.)
parent 9451f92d
......@@ -5,14 +5,14 @@
#
# Makefile for the Alchemy Au1000 CPU, generic files.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
obj-y := prom.o dbg_io.o int-handler.o irq.o puts.o time.o reset.o
obj-$(CONFIG_AU1000_UART) += serial.o
obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
obj-$(CONFIG_BLK_DEV_INITRD) += ramdisk.o
EXTRA_AFLAGS := $(CFLAGS)
obj-y += prom.o int-handler.o dma.o irq.o puts.o \
time.o reset.o clocks.o power.o
ramdisk.o:
mkramobj ramdisk ramdisk.o
obj-$(CONFIG_AU1X00_USB_DEVICE) += usbdev.o
obj-$(CONFIG_KGDB) += dbg_io.o
obj-$(CONFIG_RTC) += rtc.o
/*
* BRIEF MODULE DESCRIPTION
* Simple Au1000 clocks routines.
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <asm/au1000.h>
static unsigned int au1x00_clock; // Hz
static unsigned int lcd_clock; // KHz
static unsigned long uart_baud_base;
/*
* Set the au1000_clock
*/
void set_au1x00_speed(unsigned int new_freq)
{
au1x00_clock = new_freq;
}
unsigned int get_au1x00_speed(void)
{
return au1x00_clock;
}
/*
* The UART baud base is not known at compile time ... if
* we want to be able to use the same code on different
* speed CPUs.
*/
unsigned long get_au1x00_uart_baud_base(void)
{
return uart_baud_base;
}
void set_au1x00_uart_baud_base(unsigned long new_baud_base)
{
uart_baud_base = new_baud_base;
}
/*
* Calculate the Au1x00's LCD clock based on the current
* cpu clock and the system bus clock, and try to keep it
* below 40 MHz (the Pb1000 board can lock-up if the LCD
* clock is over 40 MHz).
*/
void set_au1x00_lcd_clock(void)
{
unsigned int static_cfg0;
unsigned int sys_busclk =
(get_au1x00_speed()/1000) /
((int)(au_readl(SYS_POWERCTRL)&0x03) + 2);
static_cfg0 = au_readl(MEM_STCFG0);
if (static_cfg0 & (1<<11))
lcd_clock = sys_busclk / 5; /* note: BCLK switching fails with D5 */
else
lcd_clock = sys_busclk / 4;
if (lcd_clock > 50000) /* Epson MAX */
printk("%s: warning: LCD clock too high (%d KHz)\n",
__FUNCTION__, lcd_clock);
}
unsigned int get_au1x00_lcd_clock(void)
{
return lcd_clock;
}
EXPORT_SYMBOL(get_au1x00_lcd_clock);
......@@ -3,13 +3,13 @@
#include <asm/io.h>
#include <asm/au1000.h>
#ifdef CONFIG_REMOTE_DEBUG
#ifdef CONFIG_KGDB
/*
* FIXME the user should be able to select the
* uart to be used for debugging.
*/
#define DEBUG_BASE UART2_ADDR
#define DEBUG_BASE UART_DEBUG_BASE
/**/
/* we need uint32 uint8 */
......@@ -53,8 +53,11 @@ typedef unsigned int uint32;
#define UART_MOD_CNTRL 0x100 /* Module Control */
/* memory-mapped read/write of the port */
#define UART16550_READ(y) (inl(DEBUG_BASE + y) & 0xff)
#define UART16550_WRITE(y,z) (outl(z&0xff, DEBUG_BASE + y))
#define UART16550_READ(y) (au_readl(DEBUG_BASE + y) & 0xff)
#define UART16550_WRITE(y,z) (au_writel(z&0xff, DEBUG_BASE + y))
extern unsigned long get_au1x00_uart_baud_base(void);
extern unsigned long cal_r4koff(void);
void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
{
......@@ -68,16 +71,16 @@ void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
UART16550_WRITE(UART_IER, 0);
/* set up baud rate */
{
{
uint32 divisor;
/* set divisor */
divisor = get_au1000_uart_baud() / baud;
divisor = get_au1x00_uart_baud_base() / baud;
UART16550_WRITE(UART_CLK, divisor & 0xffff);
}
/* set data format */
UART16550_WRITE(UART_LCR, data | parity | stop);
UART16550_WRITE(UART_LCR, (data | parity | stop));
}
static int remoteDebugInitialized = 0;
......@@ -99,7 +102,8 @@ uint8 getDebugChar(void)
int putDebugChar(uint8 byte)
{
int i;
// int i;
if (!remoteDebugInitialized) {
remoteDebugInitialized = 1;
debugInit(UART16550_BAUD_115200,
......
/*
*
* BRIEF MODULE DESCRIPTION
* A DMA channel allocator for Au1000. API is modeled loosely off of
* linux/kernel/dma.c.
*
* Copyright 2000 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* stevel@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <asm/au1000.h>
#include <asm/au1000_dma.h>
#include <asm/system.h>
/*
* A note on resource allocation:
*
* All drivers needing DMA channels, should allocate and release them
* through the public routines `request_dma()' and `free_dma()'.
*
* In order to avoid problems, all processes should allocate resources in
* the same sequence and release them in the reverse order.
*
* So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ.
* When releasing them, first release the IRQ, then release the DMA. The
* main reason for this order is that, if you are requesting the DMA buffer
* done interrupt, you won't know the irq number until the DMA channel is
* returned from request_dma.
*/
spinlock_t au1000_dma_spin_lock = SPIN_LOCK_UNLOCKED;
struct dma_chan au1000_dma_table[NUM_AU1000_DMA_CHANNELS] = {
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,},
{dev_id:-1,}
};
// Device FIFO addresses and default DMA modes
static const struct {
unsigned int fifo_addr;
unsigned int dma_mode;
} dma_dev_table[DMA_NUM_DEV] = {
{UART0_ADDR + UART_TX, 0},
{UART0_ADDR + UART_RX, 0},
{0, 0},
{0, 0},
{AC97C_DATA, DMA_DW16 }, // coherent
{AC97C_DATA, DMA_DR | DMA_DW16 }, // coherent
{UART3_ADDR + UART_TX, DMA_DW8 | DMA_NC},
{UART3_ADDR + UART_RX, DMA_DR | DMA_DW8 | DMA_NC},
{USBD_EP0RD, DMA_DR | DMA_DW8 | DMA_NC},
{USBD_EP0WR, DMA_DW8 | DMA_NC},
{USBD_EP2WR, DMA_DW8 | DMA_NC},
{USBD_EP3WR, DMA_DW8 | DMA_NC},
{USBD_EP4RD, DMA_DR | DMA_DW8 | DMA_NC},
{USBD_EP5RD, DMA_DR | DMA_DW8 | DMA_NC},
{I2S_DATA, DMA_DW32 | DMA_NC},
{I2S_DATA, DMA_DR | DMA_DW32 | DMA_NC}
};
int au1000_dma_read_proc(char *buf, char **start, off_t fpos,
int length, int *eof, void *data)
{
int i, len = 0;
struct dma_chan *chan;
for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++) {
if ((chan = get_dma_chan(i)) != NULL) {
len += sprintf(buf + len, "%2d: %s\n",
i, chan->dev_str);
}
}
if (fpos >= len) {
*start = buf;
*eof = 1;
return 0;
}
*start = buf + fpos;
if ((len -= fpos) > length)
return length;
*eof = 1;
return len;
}
void dump_au1000_dma_channel(unsigned int dmanr)
{
struct dma_chan *chan;
if (dmanr > NUM_AU1000_DMA_CHANNELS)
return;
chan = &au1000_dma_table[dmanr];
printk(KERN_INFO "Au1000 DMA%d Register Dump:\n", dmanr);
printk(KERN_INFO " mode = 0x%08x\n",
au_readl(chan->io + DMA_MODE_SET));
printk(KERN_INFO " addr = 0x%08x\n",
au_readl(chan->io + DMA_PERIPHERAL_ADDR));
printk(KERN_INFO " start0 = 0x%08x\n",
au_readl(chan->io + DMA_BUFFER0_START));
printk(KERN_INFO " start1 = 0x%08x\n",
au_readl(chan->io + DMA_BUFFER1_START));
printk(KERN_INFO " count0 = 0x%08x\n",
au_readl(chan->io + DMA_BUFFER0_COUNT));
printk(KERN_INFO " count1 = 0x%08x\n",
au_readl(chan->io + DMA_BUFFER1_COUNT));
}
/*
* Finds a free channel, and binds the requested device to it.
* Returns the allocated channel number, or negative on error.
* Requests the DMA done IRQ if irqhandler != NULL.
*/
int request_au1000_dma(int dev_id, const char *dev_str,
void (*irqhandler)(int, void *, struct pt_regs *),
unsigned long irqflags,
void *irq_dev_id)
{
struct dma_chan *chan;
int i, ret;
if (dev_id < 0 || dev_id >= DMA_NUM_DEV)
return -EINVAL;
for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++) {
if (au1000_dma_table[i].dev_id < 0)
break;
}
if (i == NUM_AU1000_DMA_CHANNELS)
return -ENODEV;
chan = &au1000_dma_table[i];
if (irqhandler) {
chan->irq = AU1000_DMA_INT_BASE + i;
chan->irq_dev = irq_dev_id;
if ((ret = request_irq(chan->irq, irqhandler, irqflags,
dev_str, chan->irq_dev))) {
chan->irq = 0;
chan->irq_dev = NULL;
return ret;
}
} else {
chan->irq = 0;
chan->irq_dev = NULL;
}
// fill it in
chan->io = DMA_CHANNEL_BASE + i * DMA_CHANNEL_LEN;
chan->dev_id = dev_id;
chan->dev_str = dev_str;
chan->fifo_addr = dma_dev_table[dev_id].fifo_addr;
chan->mode = dma_dev_table[dev_id].dma_mode;
/* initialize the channel before returning */
init_dma(i);
return i;
}
void free_au1000_dma(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan) {
printk("Trying to free DMA%d\n", dmanr);
return;
}
disable_dma(dmanr);
if (chan->irq)
free_irq(chan->irq, chan->irq_dev);
chan->irq = 0;
chan->irq_dev = NULL;
chan->dev_id = -1;
}
......@@ -9,7 +9,6 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
......@@ -40,32 +39,30 @@ NESTED(au1000_IRQ, PT_SIZE, sp)
1:
andi a0, t0, CAUSEF_IP2 # Interrupt Controller 0, Request 0
beq a0, zero, 2f
move a0,sp
beq a0, zero, 2f
move a0,sp
jal intc0_req0_irqdispatch
j ret_from_irq
2:
andi a0, t0, CAUSEF_IP3 # Interrupt Controller 0, Request 1
beq a0, zero, 3f
move a0,sp
beq a0, zero, 3f
move a0,sp
jal intc0_req1_irqdispatch
j ret_from_irq
3:
andi a0, t0, CAUSEF_IP4 # Interrupt Controller 1, Request 0
beq a0, zero, 4f
move a0,sp
beq a0, zero, 4f
move a0,sp
jal intc1_req0_irqdispatch
j ret_from_irq
4:
andi a0, t0, CAUSEF_IP5 # Interrupt Controller 1, Request 1
beq a0, zero, 5f
move a0, sp
beq a0, zero, 5f
move a0, sp
jal intc1_req1_irqdispatch
j ret_from_irq
5:
5:
move a0, sp
jal mips_spurious_interrupt
done:
j ret_from_irq
j spurious_interrupt
END(au1000_IRQ)
......@@ -28,6 +28,7 @@
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/signal.h>
......@@ -47,7 +48,21 @@
#include <asm/system.h>
#include <asm/au1000.h>
#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
#if defined(CONFIG_MIPS_PB1000)
#include <asm/pb1000.h>
#elif defined(CONFIG_MIPS_PB1500)
#include <asm/pb1500.h>
#elif defined(CONFIG_MIPS_PB1100)
#include <asm/pb1100.h>
#elif defined(CONFIG_MIPS_DB1000)
#include <asm/db1x00.h>
#elif defined(CONFIG_MIPS_DB1100)
#include <asm/db1x00.h>
#elif defined(CONFIG_MIPS_DB1500)
#include <asm/db1x00.h>
#else
#error unsupported Alchemy board
#endif
#undef DEBUG_IRQ
#ifdef DEBUG_IRQ
......@@ -63,16 +78,13 @@
#define EXT_INTC1_REQ1 5 /* IP 5 */
#define MIPS_TIMER_IP 7 /* IP 7 */
#ifdef CONFIG_REMOTE_DEBUG
#ifdef CONFIG_KGDB
extern void breakpoint(void);
#endif
extern asmlinkage void au1000_IRQ(void);
extern void set_debug_traps(void);
extern irq_cpustat_t irq_stat [];
extern irq_desc_t irq_desc[NR_IRQS];
extern irq_cpustat_t irq_stat [NR_CPUS];
unsigned int local_bh_count[NR_CPUS];
unsigned int local_irq_count[NR_CPUS];
......@@ -82,154 +94,113 @@ static void end_irq(unsigned int irq_nr);
static inline void mask_and_ack_level_irq(unsigned int irq_nr);
static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr);
static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr);
static inline void local_enable_irq(unsigned int irq_nr);
static inline void local_disable_irq(unsigned int irq_nr);
inline void local_enable_irq(unsigned int irq_nr);
inline void local_disable_irq(unsigned int irq_nr);
unsigned long spurious_interrupts;
extern unsigned int do_IRQ(int irq, struct pt_regs *regs);
extern void __init init_generic_irq(void);
static inline void sync(void)
{
__asm volatile ("sync");
}
/* Function for careful CP0 interrupt mask access */
static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
{
unsigned long status = read_32bit_cp0_register(CP0_STATUS);
status &= ~((clr_mask & 0xFF) << 8);
status |= (set_mask & 0xFF) << 8;
write_32bit_cp0_register(CP0_STATUS, status);
}
static inline void mask_cpu_irq_input(unsigned int irq_nr)
{
modify_cp0_intmask(irq_nr, 0);
}
static inline void unmask_cpu_irq_input(unsigned int irq_nr)
{
modify_cp0_intmask(0, irq_nr);
}
static void disable_cpu_irq_input(unsigned int irq_nr)
{
unsigned long flags;
save_and_cli(flags);
mask_cpu_irq_input(irq_nr);
restore_flags(flags);
}
static void enable_cpu_irq_input(unsigned int irq_nr)
{
unsigned long flags;
save_and_cli(flags);
unmask_cpu_irq_input(irq_nr);
restore_flags(flags);
}
#ifdef CONFIG_PM
extern void counter0_irq(int irq, void *dev_id, struct pt_regs *regs);
#endif
static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED;
static void setup_local_irq(unsigned int irq_nr, int type, int int_req)
{
if (irq_nr > AU1000_MAX_INTR) return;
/* Config2[n], Config1[n], Config0[n] */
if (irq_nr > AU1000_LAST_INTC0_INT) {
switch (type) {
case INTC_INT_RISE_EDGE: /* 0:0:1 */
outl(1<<irq_nr,INTC1_CONFIG2_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG0_SET);
au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
au_writel(1<<(irq_nr-32), IC1_CFG1CLR);
au_writel(1<<(irq_nr-32), IC1_CFG0SET);
break;
case INTC_INT_FALL_EDGE: /* 0:1:0 */
outl(1<<irq_nr, INTC1_CONFIG2_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG1_SET);
outl(1<<irq_nr, INTC1_CONFIG0_CLEAR);
au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
au_writel(1<<(irq_nr-32), IC1_CFG1SET);
au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
break;
case INTC_INT_HIGH_LEVEL: /* 1:0:1 */
outl(1<<irq_nr, INTC1_CONFIG2_SET);
outl(1<<irq_nr, INTC1_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG0_SET);
au_writel(1<<(irq_nr-32), IC1_CFG2SET);
au_writel(1<<(irq_nr-32), IC1_CFG1CLR);
au_writel(1<<(irq_nr-32), IC1_CFG0SET);
break;
case INTC_INT_LOW_LEVEL: /* 1:1:0 */
outl(1<<irq_nr, INTC1_CONFIG2_SET);
outl(1<<irq_nr, INTC1_CONFIG1_SET);
outl(1<<irq_nr, INTC1_CONFIG0_CLEAR);
au_writel(1<<(irq_nr-32), IC1_CFG2SET);
au_writel(1<<(irq_nr-32), IC1_CFG1SET);
au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
break;
case INTC_INT_DISABLED: /* 0:0:0 */
outl(1<<irq_nr, INTC1_CONFIG0_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG2_CLEAR);
au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
au_writel(1<<(irq_nr-32), IC1_CFG1CLR);
au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
break;
default: /* disable the interrupt */
printk("unexpected int type %d (irq %d)\n", type, irq_nr);
outl(1<<irq_nr, INTC1_CONFIG0_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC1_CONFIG2_CLEAR);
au_writel(1<<(irq_nr-32), IC1_CFG0CLR);
au_writel(1<<(irq_nr-32), IC1_CFG1CLR);
au_writel(1<<(irq_nr-32), IC1_CFG2CLR);
return;
}
if (int_req) /* assign to interrupt request 1 */
outl(1<<irq_nr, INTC1_ASSIGN_REQ_CLEAR);
au_writel(1<<(irq_nr-32), IC1_ASSIGNCLR);
else /* assign to interrupt request 0 */
outl(1<<irq_nr, INTC1_ASSIGN_REQ_SET);
outl(1<<irq_nr, INTC1_SOURCE_SET);
outl(1<<irq_nr, INTC1_MASK_CLEAR);
au_writel(1<<(irq_nr-32), IC1_ASSIGNSET);
au_writel(1<<(irq_nr-32), IC1_SRCSET);
au_writel(1<<(irq_nr-32), IC1_MASKCLR);
au_writel(1<<(irq_nr-32), IC1_WAKECLR);
}
else {
switch (type) {
case INTC_INT_RISE_EDGE: /* 0:0:1 */
outl(1<<irq_nr,INTC0_CONFIG2_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG0_SET);
au_writel(1<<irq_nr, IC0_CFG2CLR);
au_writel(1<<irq_nr, IC0_CFG1CLR);
au_writel(1<<irq_nr, IC0_CFG0SET);
break;
case INTC_INT_FALL_EDGE: /* 0:1:0 */
outl(1<<irq_nr, INTC0_CONFIG2_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG1_SET);
outl(1<<irq_nr, INTC0_CONFIG0_CLEAR);
au_writel(1<<irq_nr, IC0_CFG2CLR);
au_writel(1<<irq_nr, IC0_CFG1SET);
au_writel(1<<irq_nr, IC0_CFG0CLR);
break;
case INTC_INT_HIGH_LEVEL: /* 1:0:1 */
outl(1<<irq_nr, INTC0_CONFIG2_SET);
outl(1<<irq_nr, INTC0_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG0_SET);
au_writel(1<<irq_nr, IC0_CFG2SET);
au_writel(1<<irq_nr, IC0_CFG1CLR);
au_writel(1<<irq_nr, IC0_CFG0SET);
break;
case INTC_INT_LOW_LEVEL: /* 1:1:0 */
outl(1<<irq_nr, INTC0_CONFIG2_SET);
outl(1<<irq_nr, INTC0_CONFIG1_SET);
outl(1<<irq_nr, INTC0_CONFIG0_CLEAR);
au_writel(1<<irq_nr, IC0_CFG2SET);
au_writel(1<<irq_nr, IC0_CFG1SET);
au_writel(1<<irq_nr, IC0_CFG0CLR);
break;
case INTC_INT_DISABLED: /* 0:0:0 */
outl(1<<irq_nr, INTC0_CONFIG0_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG2_CLEAR);
au_writel(1<<irq_nr, IC0_CFG0CLR);
au_writel(1<<irq_nr, IC0_CFG1CLR);
au_writel(1<<irq_nr, IC0_CFG2CLR);
break;
default: /* disable the interrupt */
printk("unexpected int type %d (irq %d)\n", type, irq_nr);
outl(1<<irq_nr, INTC0_CONFIG0_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG1_CLEAR);
outl(1<<irq_nr, INTC0_CONFIG2_CLEAR);
au_writel(1<<irq_nr, IC0_CFG0CLR);
au_writel(1<<irq_nr, IC0_CFG1CLR);
au_writel(1<<irq_nr, IC0_CFG2CLR);
return;
}
if (int_req) /* assign to interrupt request 1 */
outl(1<<irq_nr, INTC0_ASSIGN_REQ_CLEAR);
au_writel(1<<irq_nr, IC0_ASSIGNCLR);
else /* assign to interrupt request 0 */
outl(1<<irq_nr, INTC0_ASSIGN_REQ_SET);
outl(1<<irq_nr, INTC0_SOURCE_SET);
outl(1<<irq_nr, INTC0_MASK_CLEAR);
au_writel(1<<irq_nr, IC0_ASSIGNSET);
au_writel(1<<irq_nr, IC0_SRCSET);
au_writel(1<<irq_nr, IC0_MASKCLR);
au_writel(1<<irq_nr, IC0_WAKECLR);
}
sync();
au_sync();
}
static unsigned int startup_irq(unsigned int irq_nr)
{
local_enable_irq(irq_nr);
return 0;
return 0;
}
......@@ -240,71 +211,133 @@ static void shutdown_irq(unsigned int irq_nr)
}
static inline void local_enable_irq(unsigned int irq_nr)
inline void local_enable_irq(unsigned int irq_nr)
{
if (irq_nr > AU1000_LAST_INTC0_INT) {
outl(1<<irq_nr, INTC1_MASK_SET);
au_writel(1<<(irq_nr-32), IC1_MASKSET);
au_writel(1<<(irq_nr-32), IC1_WAKESET);
}
else {
outl(1<<irq_nr, INTC0_MASK_SET);
au_writel(1<<irq_nr, IC0_MASKSET);
au_writel(1<<irq_nr, IC0_WAKESET);
}
sync();
au_sync();
}
static inline void local_disable_irq(unsigned int irq_nr)
inline void local_disable_irq(unsigned int irq_nr)
{
if (irq_nr > AU1000_LAST_INTC0_INT) {
outl(1<<irq_nr, INTC1_MASK_CLEAR);
au_writel(1<<(irq_nr-32), IC1_MASKCLR);
au_writel(1<<(irq_nr-32), IC1_WAKECLR);
}
else {
outl(1<<irq_nr, INTC0_MASK_CLEAR);
au_writel(1<<irq_nr, IC0_MASKCLR);
au_writel(1<<irq_nr, IC0_WAKECLR);
}
sync();
au_sync();
}
static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr)
{
if (irq_nr > AU1000_LAST_INTC0_INT) {
outl(1<<irq_nr, INTC1_R_EDGE_DETECT_CLEAR);
outl(1<<irq_nr, INTC1_MASK_CLEAR);
au_writel(1<<(irq_nr-32), IC1_RISINGCLR);
au_writel(1<<(irq_nr-32), IC1_MASKCLR);
}
else {
outl(1<<irq_nr, INTC0_R_EDGE_DETECT_CLEAR);
outl(1<<irq_nr, INTC0_MASK_CLEAR);
au_writel(1<<irq_nr, IC0_RISINGCLR);
au_writel(1<<irq_nr, IC0_MASKCLR);
}
sync();
au_sync();
}
static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr)
{
if (irq_nr > AU1000_LAST_INTC0_INT) {
outl(1<<irq_nr, INTC1_F_EDGE_DETECT_CLEAR);
outl(1<<irq_nr, INTC1_MASK_CLEAR);
au_writel(1<<(irq_nr-32), IC1_FALLINGCLR);
au_writel(1<<(irq_nr-32), IC1_MASKCLR);
}
else {
outl(1<<irq_nr, INTC0_F_EDGE_DETECT_CLEAR);
outl(1<<irq_nr, INTC0_MASK_CLEAR);
au_writel(1<<irq_nr, IC0_FALLINGCLR);
au_writel(1<<irq_nr, IC0_MASKCLR);
}
au_sync();
}
static inline void mask_and_ack_level_irq(unsigned int irq_nr)
{
local_disable_irq(irq_nr);
sync();
au_sync();
#if defined(CONFIG_MIPS_PB1000)
if (irq_nr == AU1000_GPIO_15) {
au_writel(0x8000, PB1000_MDR); /* ack int */
au_sync();
}
#endif
return;
}
static void end_irq(unsigned int irq_nr)
{
if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
local_enable_irq(irq_nr);
}
#if defined(CONFIG_MIPS_PB1000)
if (irq_nr == AU1000_GPIO_15) {
au_writel(0x4000, PB1000_MDR); /* enable int */
au_sync();
}
#endif
}
unsigned long save_local_and_disable(int controller)
{
int i;
unsigned long flags, mask;
spin_lock_irqsave(&irq_lock, flags);
if (controller) {
mask = au_readl(IC1_MASKSET);
for (i=32; i<64; i++) {
local_disable_irq(i);
}
}
else {
mask = au_readl(IC0_MASKSET);
for (i=0; i<32; i++) {
local_disable_irq(i);
}
}
spin_unlock_irqrestore(&irq_lock, flags);
return mask;
}
void restore_local_and_enable(int controller, unsigned long mask)
{
int i;
unsigned long flags, new_mask;
spin_lock_irqsave(&irq_lock, flags);
for (i=0; i<32; i++) {
if (mask & (1<<i)) {
if (controller)
local_enable_irq(i+32);
else
local_enable_irq(i);
}
}
if (controller)
new_mask = au_readl(IC1_MASKSET);
else
printk("warning: end_irq %d did not enable\n", irq_nr);
new_mask = au_readl(IC0_MASKSET);
spin_unlock_irqrestore(&irq_lock, flags);
}
......@@ -319,7 +352,7 @@ static struct hw_interrupt_type rise_edge_irq_type = {
NULL
};
/*
static struct hw_interrupt_type fall_edge_irq_type = {
"Au1000 Fall Edge",
startup_irq,
......@@ -330,7 +363,7 @@ static struct hw_interrupt_type fall_edge_irq_type = {
end_irq,
NULL
};
*/
static struct hw_interrupt_type level_irq_type = {
"Au1000 Level",
......@@ -343,11 +376,12 @@ static struct hw_interrupt_type level_irq_type = {
NULL
};
void enable_cpu_timer(void)
#ifdef CONFIG_PM
void startup_match20_interrupt(void)
{
enable_cpu_irq_input(1<<MIPS_TIMER_IP); /* timer interrupt */
local_enable_irq(AU1000_TOY_MATCH2_INT);
}
#endif
void __init init_IRQ(void)
......@@ -355,61 +389,158 @@ void __init init_IRQ(void)
int i;
unsigned long cp0_status;
cp0_status = read_32bit_cp0_register(CP0_STATUS);
cp0_status = read_c0_status();
memset(irq_desc, 0, sizeof(irq_desc));
set_except_vector(0, au1000_IRQ);
init_generic_irq();
/*
* Setup high priority interrupts on int_request0; low priority on
* int_request1
*/
for (i = 0; i <= NR_IRQS; i++) {
for (i = 0; i <= AU1000_MAX_INTR; i++) {
switch (i) {
case AU1000_UART0_INT:
case AU1000_UART3_INT:
#ifdef CONFIG_MIPS_PB1000
case AU1000_UART1_INT:
case AU1000_UART2_INT:
case AU1000_SSI0_INT:
case AU1000_SSI1_INT:
#endif
#ifdef CONFIG_MIPS_PB1100
case AU1000_UART1_INT:
case AU1000_SSI0_INT:
case AU1000_SSI1_INT:
#endif
case AU1000_DMA_INT_BASE:
case AU1000_DMA_INT_BASE+1:
case AU1000_DMA_INT_BASE+2:
case AU1000_DMA_INT_BASE+3:
case AU1000_DMA_INT_BASE+4:
case AU1000_DMA_INT_BASE+5:
case AU1000_DMA_INT_BASE+6:
case AU1000_DMA_INT_BASE+7:
case AU1000_IRDA_TX_INT:
case AU1000_IRDA_RX_INT:
case AU1000_MAC0_DMA_INT:
#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_DB1500)
case AU1000_MAC1_DMA_INT:
#endif
case AU1500_GPIO_204:
setup_local_irq(i, INTC_INT_HIGH_LEVEL, 0);
irq_desc[i].handler = &level_irq_type;
break;
#ifdef CONFIG_MIPS_PB1000
case AU1000_GPIO_15:
#endif
case AU1000_USB_HOST_INT:
#if defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_DB1500)
case AU1000_PCI_INTA:
case AU1000_PCI_INTB:
case AU1000_PCI_INTC:
case AU1000_PCI_INTD:
case AU1500_GPIO_201:
case AU1500_GPIO_202:
case AU1500_GPIO_203:
case AU1500_GPIO_205:
case AU1500_GPIO_207:
#endif
#ifdef CONFIG_MIPS_PB1100
case AU1000_GPIO_9: // PCMCIA Card Fully_Interted#
case AU1000_GPIO_10: // PCMCIA_STSCHG#
case AU1000_GPIO_11: // PCMCIA_IRQ#
case AU1000_GPIO_13: // DC_IRQ#
case AU1000_GPIO_23: // 2-wire SCL
#endif
#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500)
case AU1000_GPIO_0: // PCMCIA Card 0 Fully_Interted#
case AU1000_GPIO_1: // PCMCIA Card 0 STSCHG#
case AU1000_GPIO_2: // PCMCIA Card 0 IRQ#
case AU1000_GPIO_3: // PCMCIA Card 1 Fully_Interted#
case AU1000_GPIO_4: // PCMCIA Card 1 STSCHG#
case AU1000_GPIO_5: // PCMCIA Card 1 IRQ#
#endif
setup_local_irq(i, INTC_INT_LOW_LEVEL, 0);
irq_desc[i].handler = &level_irq_type;
break;
case AU1000_ACSYNC_INT:
case AU1000_AC97C_INT:
case AU1000_TOY_INT:
case AU1000_TOY_MATCH0_INT:
case AU1000_TOY_MATCH1_INT:
case AU1000_USB_DEV_SUS_INT:
case AU1000_USB_DEV_REQ_INT:
case AU1000_RTC_INT:
case AU1000_RTC_MATCH0_INT:
case AU1000_RTC_MATCH1_INT:
case AU1000_RTC_MATCH2_INT:
setup_local_irq(i, INTC_INT_RISE_EDGE, 0);
irq_desc[i].handler = &rise_edge_irq_type;
break;
// Careful if you change match 2 request!
// The interrupt handler is called directly
// from the low level dispatch code.
case AU1000_TOY_MATCH2_INT:
setup_local_irq(i, INTC_INT_RISE_EDGE, 1);
irq_desc[i].handler = &rise_edge_irq_type;
break;
default: /* active high, level interrupt */
setup_local_irq(i, INTC_INT_HIGH_LEVEL, 1);
setup_local_irq(i, INTC_INT_HIGH_LEVEL, 0);
irq_desc[i].handler = &level_irq_type;
break;
}
}
set_cp0_status(ALLINTS);
#ifdef CONFIG_REMOTE_DEBUG
set_c0_status(ALLINTS);
#ifdef CONFIG_KGDB
/* If local serial I/O used for debug port, enter kgdb at once */
puts("Waiting for kgdb to connect...");
set_debug_traps();
breakpoint();
breakpoint();
#endif
}
void mips_spurious_interrupt(struct pt_regs *regs)
{
spurious_interrupts++;
}
/*
* Interrupts are nested. Even if an interrupt handler is registered
* as "fast", we might get another interrupt before we return from
* intcX_reqX_irqdispatch().
*/
void intc0_req0_irqdispatch(struct pt_regs *regs)
{
int irq = 0, i;
unsigned long int_request;
static unsigned long intc0_req0 = 0;
intc0_req0 |= au_readl(IC0_REQ0INT);
int_request = inl(INTC0_REQ0_INT);
if (!intc0_req0) return;
if (!int_request) return;
/*
* Because of the tight timing of SETUP token to reply
* transactions, the USB devices-side packet complete
* interrupt needs the highest priority.
*/
if ((intc0_req0 & (1<<AU1000_USB_DEV_REQ_INT))) {
intc0_req0 &= ~(1<<AU1000_USB_DEV_REQ_INT);
do_IRQ(AU1000_USB_DEV_REQ_INT, regs);
return;
}
for (i=0; i<32; i++) {
if ((int_request & 0x1)) {
if ((intc0_req0 & (1<<i))) {
intc0_req0 &= ~(1<<i);
do_IRQ(irq, regs);
break;
}
irq++;
int_request >>= 1;
}
}
......@@ -417,55 +548,84 @@ void intc0_req0_irqdispatch(struct pt_regs *regs)
void intc0_req1_irqdispatch(struct pt_regs *regs)
{
int irq = 0, i;
unsigned long int_request;
static unsigned long intc0_req1 = 0;
int_request = inl(INTC0_REQ1_INT);
intc0_req1 = au_readl(IC0_REQ1INT);
if (!int_request) return;
if (!intc0_req1) return;
for (i=0; i<32; i++) {
if ((int_request & 0x1)) {
do_IRQ(irq, regs);
if ((intc0_req1 & (1<<i))) {
intc0_req1 &= ~(1<<i);
#ifdef CONFIG_PM
if (i == AU1000_TOY_MATCH2_INT) {
mask_and_ack_rise_edge_irq(irq);
counter0_irq(irq, NULL, regs);
local_enable_irq(irq);
}
else
#endif
{
do_IRQ(irq, regs);
}
break;
}
irq++;
int_request >>= 1;
}
}
/*
* Interrupt Controller 1:
* interrupts 32 - 63
*/
void intc1_req0_irqdispatch(struct pt_regs *regs)
{
int irq = 0, i;
unsigned long int_request;
static unsigned long intc1_req0 = 0;
int_request = inl(INTC1_REQ0_INT);
intc1_req0 |= au_readl(IC1_REQ0INT);
if (!int_request) return;
if (!intc1_req0) return;
#if defined(CONFIG_MIPS_PB1000) && defined(DEBUG_IRQ)
au_writel(1, CPLD_AUX0); /* debug led 0 */
#endif
for (i=0; i<32; i++) {
if ((int_request & 0x1)) {
do_IRQ(irq, regs);
if ((intc1_req0 & (1<<i))) {
intc1_req0 &= ~(1<<i);
#if defined(CONFIG_MIPS_PB1000) && defined(DEBUG_IRQ)
au_writel(2, CPLD_AUX0); /* turn on debug led 1 */
do_IRQ(irq+32, regs);
au_writel(0, CPLD_AUX0); /* turn off debug led 1 */
#else
do_IRQ(irq+32, regs);
#endif
break;
}
irq++;
int_request >>= 1;
}
#if defined(CONFIG_MIPS_PB1000) && defined(DEBUG_IRQ)
au_writel(0, CPLD_AUX0);
#endif
}
void intc1_req1_irqdispatch(struct pt_regs *regs)
{
int irq = 0, i;
unsigned long int_request;
static unsigned long intc1_req1 = 0;
int_request = inl(INTC1_REQ1_INT);
intc1_req1 |= au_readl(IC1_REQ1INT);
if (!int_request) return;
if (!intc1_req1) return;
for (i=0; i<32; i++) {
if ((int_request & 0x1)) {
do_IRQ(irq, regs);
if ((intc1_req1 & (1<<i))) {
intc1_req1 &= ~(1<<i);
do_IRQ(irq+32, regs);
break;
}
irq++;
int_request >>= 1;
}
}
/*
* BRIEF MODULE DESCRIPTION
* Au1000 Power Management routines.
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* Some of the routines are right out of init/main.c, whose
* copyrights apply here.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <asm/string.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/au1000.h>
#define DEBUG 1
#ifdef DEBUG
# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
#else
# define DPRINTK(fmt, args...)
#endif
extern void au1k_wait(void);
static void calibrate_delay(void);
extern void set_au1000_speed(unsigned int new_freq);
extern unsigned int get_au1000_speed(void);
extern unsigned long get_au1000_uart_baud_base(void);
extern void set_au1000_uart_baud_base(unsigned long new_baud_base);
extern unsigned long save_local_and_disable(int controller);
extern void restore_local_and_enable(int controller, unsigned long mask);
extern void local_enable_irq(unsigned int irq_nr);
/* Quick acpi hack. This will have to change! */
#define CTL_ACPI 9999
#define ACPI_S1_SLP_TYP 19
#define ACPI_SLEEP 21
#ifdef CONFIG_PM
static spinlock_t pm_lock = SPIN_LOCK_UNLOCKED;
unsigned long suspend_mode;
void wakeup_from_suspend(void)
{
suspend_mode = 0;
}
int au_sleep(void)
{
unsigned long wakeup, flags;
spin_lock_irqsave(&pm_lock,flags);
flush_cache_all();
/* pin 6 is gpio */
au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD);
/* gpio 6 can cause a wake up event */
wakeup = au_readl(SYS_WAKEMSK);
wakeup &= ~(1 << 8); /* turn off match20 wakeup */
wakeup |= 1 << 6; /* turn on gpio 6 wakeup */
au_writel(wakeup, SYS_WAKEMSK);
au_writel(1, SYS_WAKESRC); /* clear cause */
au_writel(1, SYS_SLPPWR); /* prepare to sleep */
__asm__("la $4, 1f\n\t"
"lui $5, 0xb190\n\t"
"ori $5, 0x18\n\t"
"sw $4, 0($5)\n\t"
"li $4, 1\n\t"
"lui $5, 0xb190\n\t"
"ori $5, 0x7c\n\t"
"sw $4, 0($5)\n\t" "sync\n\t" "1:\t\n\t" "nop\n\t");
/* after a wakeup, the cpu vectors back to 0x1fc00000 so
* it's up to the boot code to get us back here.
*/
spin_unlock_irqrestore(&pm_lock, flags);
return 0;
}
static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
void *buffer, size_t * len)
{
int retval = 0;
if (!write) {
*len = 0;
} else {
retval = pm_send_all(PM_SUSPEND, (void *) 2);
if (retval)
return retval;
au_sleep();
retval = pm_send_all(PM_RESUME, (void *) 0);
}
return retval;
}
static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
void *buffer, size_t * len)
{
int retval = 0;
if (!write) {
*len = 0;
} else {
retval = pm_send_all(PM_SUSPEND, (void *) 2);
if (retval)
return retval;
suspend_mode = 1;
au1k_wait();
retval = pm_send_all(PM_RESUME, (void *) 0);
}
return retval;
}
static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
void *buffer, size_t * len)
{
int retval = 0, i;
unsigned long val, pll;
#define TMPBUFLEN 64
#define MAX_CPU_FREQ 396
char buf[8], *p;
unsigned long flags, intc0_mask, intc1_mask;
unsigned long old_baud_base, old_cpu_freq, baud_rate, old_clk,
old_refresh;
unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh;
spin_lock_irqsave(&pm_lock, flags);
if (!write) {
*len = 0;
} else {
/* Parse the new frequency */
if (*len > TMPBUFLEN - 1) {
spin_unlock_irqrestore(&pm_lock, flags);
return -EFAULT;
}
if (copy_from_user(buf, buffer, *len)) {
spin_unlock_irqrestore(&pm_lock, flags);
return -EFAULT;
}
buf[*len] = 0;
p = buf;
val = simple_strtoul(p, &p, 0);
if (val > MAX_CPU_FREQ) {
spin_unlock_irqrestore(&pm_lock, flags);
return -EFAULT;
}
pll = val / 12;
if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */
/* revisit this for higher speed cpus */
spin_unlock_irqrestore(&pm_lock, flags);
return -EFAULT;
}
old_baud_base = get_au1000_uart_baud_base();
old_cpu_freq = get_au1000_speed();
new_cpu_freq = pll * 12 * 1000000;
new_baud_base = (new_cpu_freq / 4) / 16;
set_au1000_speed(new_cpu_freq);
set_au1000_uart_baud_base(new_baud_base);
old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff;
new_refresh =
((old_refresh * new_cpu_freq) /
old_cpu_freq) | (au_readl(MEM_SDREFCFG) & ~0x1ffffff);
au_writel(pll, SYS_CPUPLL);
au_sync_delay(1);
au_writel(new_refresh, MEM_SDREFCFG);
au_sync_delay(1);
for (i = 0; i < 4; i++) {
if (au_readl
(UART_BASE + UART_MOD_CNTRL +
i * 0x00100000) == 3) {
old_clk =
au_readl(UART_BASE + UART_CLK +
i * 0x00100000);
// baud_rate = baud_base/clk
baud_rate = old_baud_base / old_clk;
/* we won't get an exact baud rate and the error
* could be significant enough that our new
* calculation will result in a clock that will
* give us a baud rate that's too far off from
* what we really want.
*/
if (baud_rate > 100000)
baud_rate = 115200;
else if (baud_rate > 50000)
baud_rate = 57600;
else if (baud_rate > 30000)
baud_rate = 38400;
else if (baud_rate > 17000)
baud_rate = 19200;
else
(baud_rate = 9600);
// new_clk = new_baud_base/baud_rate
new_clk = new_baud_base / baud_rate;
au_writel(new_clk,
UART_BASE + UART_CLK +
i * 0x00100000);
au_sync_delay(10);
}
}
}
/* We don't want _any_ interrupts other than
* match20. Otherwise our calibrate_delay()
* calculation will be off, potentially a lot.
*/
intc0_mask = save_local_and_disable(0);
intc1_mask = save_local_and_disable(1);
local_enable_irq(AU1000_TOY_MATCH2_INT);
spin_unlock_irqrestore(&pm_lock, flags);
calibrate_delay();
restore_local_and_enable(0, intc0_mask);
restore_local_and_enable(1, intc1_mask);
return retval;
}
static struct ctl_table pm_table[] = {
{ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, &pm_do_suspend},
{ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &pm_do_sleep},
{CTL_ACPI, "freq", NULL, 0, 0600, NULL, &pm_do_freq},
{0}
};
static struct ctl_table pm_dir_table[] = {
{CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
{0}
};
/*
* Initialize power interface
*/
static int __init pm_init(void)
{
register_sysctl_table(pm_dir_table, 1);
return 0;
}
__initcall(pm_init);
/*
* This is right out of init/main.c
*/
/* This is the number of bits of precision for the loops_per_jiffy. Each
bit takes on average 1.5/HZ seconds. This (like the original) is a little
better than 1% */
#define LPS_PREC 8
static void calibrate_delay(void)
{
unsigned long ticks, loopbit;
int lps_precision = LPS_PREC;
loops_per_jiffy = (1 << 12);
while (loops_per_jiffy <<= 1) {
/* wait for "start of" clock tick */
ticks = jiffies;
while (ticks == jiffies)
/* nothing */ ;
/* Go .. */
ticks = jiffies;
__delay(loops_per_jiffy);
ticks = jiffies - ticks;
if (ticks)
break;
}
/* Do a binary approximation to get loops_per_jiffy set to equal one clock
(up to lps_precision bits) */
loops_per_jiffy >>= 1;
loopbit = loops_per_jiffy;
while (lps_precision-- && (loopbit >>= 1)) {
loops_per_jiffy |= loopbit;
ticks = jiffies;
while (ticks == jiffies);
ticks = jiffies;
__delay(loops_per_jiffy);
if (jiffies != ticks) /* longer than 1 tick */
loops_per_jiffy &= ~loopbit;
}
}
void au1k_wait(void)
{
__asm__("nop\n\t" "nop\n\t");
}
#endif /* CONFIG_PM */
......@@ -4,11 +4,11 @@
* PROM library initialisation code, assuming a version of
* pmon is the boot code.
*
* Copyright 2000 MontaVista Software Inc.
* Copyright 2000,2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This file was derived from Carsten Langgaard's
* This file was derived from Carsten Langgaard's
* arch/mips/mips-boards/xx files.
*
* Carsten Langgaard, carstenl@mips.com
......@@ -35,7 +35,7 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
......@@ -44,22 +44,23 @@
/* #define DEBUG_CMDLINE */
char arcs_cmdline[COMMAND_LINE_SIZE];
int prom_argc;
char **prom_argv, **prom_envp;
char arcs_cmdline[CL_SIZE];
extern int prom_argc;
extern char **prom_argv, **prom_envp;
typedef struct {
char *name;
/* char *val; */
} t_env_var;
typedef struct
{
char *name;
/* char *val; */
}t_env_var;
char * __init prom_getcmdline(void)
char * prom_getcmdline(void)
{
return &(arcs_cmdline[0]);
}
void __init prom_init_cmdline(void)
void prom_init_cmdline(void)
{
char *cp;
int actr;
......@@ -101,20 +102,57 @@ char *prom_getenv(char *envname)
return(NULL);
}
static inline unsigned char str2hexnum(unsigned char c)
inline unsigned char str2hexnum(unsigned char c)
{
if(c >= '0' && c <= '9')
return c - '0';
return c - '0';
if(c >= 'a' && c <= 'f')
return c - 'a' + 10;
return c - 'a' + 10;
if(c >= 'A' && c <= 'F')
return c - 'A' + 10;
return 0; /* foo */
}
int __init page_is_ram(unsigned long pagenr)
inline void str2eaddr(unsigned char *ea, unsigned char *str)
{
return 1;
int i;
for(i = 0; i < 6; i++) {
unsigned char num;
if((*str == '.') || (*str == ':'))
str++;
num = str2hexnum(*str++) << 4;
num |= (str2hexnum(*str++));
ea[i] = num;
}
}
void prom_free_prom_memory (void)
int get_ethernet_addr(char *ethernet_addr)
{
char *ethaddr_str;
ethaddr_str = prom_getenv("ethaddr");
if (!ethaddr_str) {
printk("ethaddr not set in boot prom\n");
return -1;
}
str2eaddr(ethernet_addr, ethaddr_str);
#if 0
{
int i;
printk("get_ethernet_addr: ");
for (i=0; i<5; i++)
printk("%02x:", (unsigned char)*(ethernet_addr+i));
printk("%02x\n", *(ethernet_addr+i));
}
#endif
return 0;
}
void prom_free_prom_memory (void) {}
EXPORT_SYMBOL(prom_getcmdline);
EXPORT_SYMBOL(get_ethernet_addr);
......@@ -29,8 +29,9 @@
*/
#include <linux/types.h>
#include <asm/au1000.h>
#define SERIAL_BASE 0xB1100000 /* au1000, uart 0 */
#define SERIAL_BASE UART_BASE
#define SER_CMD 0x7
#define SER_DATA 0x1
#define TX_BUSY 0x20
......
......@@ -27,7 +27,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/io.h>
......@@ -35,23 +35,107 @@
#include <asm/processor.h>
#include <asm/reboot.h>
#include <asm/system.h>
#include <asm/au1000.h>
extern int au_sleep(void);
void au1000_restart(char *command)
{
set_cp0_status(ST0_BEV | ST0_ERL);
set_cp0_config(CONF_CM_UNCACHED);
/* Set all integrated peripherals to disabled states */
u32 prid = read_c0_prid();
printk(KERN_NOTICE "\n** Resetting Integrated Peripherals\n");
switch (prid & 0xFF000000)
{
case 0x00000000: /* Au1000 */
au_writel(0x02, 0xb0000010); /* ac97_enable */
au_writel(0x08, 0xb017fffc); /* usbh_enable - early errata */
asm("sync");
au_writel(0x00, 0xb017fffc); /* usbh_enable */
au_writel(0x00, 0xb0200058); /* usbd_enable */
au_writel(0x00, 0xb0300040); /* ir_enable */
au_writel(0x00, 0xb0520000); /* macen0 */
au_writel(0x00, 0xb0520004); /* macen1 */
au_writel(0x00, 0xb1000008); /* i2s_enable */
au_writel(0x00, 0xb1100100); /* uart0_enable */
au_writel(0x00, 0xb1200100); /* uart1_enable */
au_writel(0x00, 0xb1300100); /* uart2_enable */
au_writel(0x00, 0xb1400100); /* uart3_enable */
au_writel(0x02, 0xb1600100); /* ssi0_enable */
au_writel(0x02, 0xb1680100); /* ssi1_enable */
au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */
au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */
au_writel(0x00, 0xb1900028); /* sys_clksrc */
au_writel(0x00, 0xb1900100); /* sys_pininputen */
break;
case 0x01000000: /* Au1500 */
au_writel(0x02, 0xb0000010); /* ac97_enable */
au_writel(0x08, 0xb017fffc); /* usbh_enable - early errata */
asm("sync");
au_writel(0x00, 0xb017fffc); /* usbh_enable */
au_writel(0x00, 0xb0200058); /* usbd_enable */
au_writel(0x00, 0xb1520000); /* macen0 */
au_writel(0x00, 0xb1520004); /* macen1 */
au_writel(0x00, 0xb1100100); /* uart0_enable */
au_writel(0x00, 0xb1400100); /* uart3_enable */
au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */
au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */
au_writel(0x00, 0xb1900028); /* sys_clksrc */
au_writel(0x00, 0xb1900100); /* sys_pininputen */
break;
case 0x02000000: /* Au1100 */
au_writel(0x02, 0xb0000010); /* ac97_enable */
au_writel(0x08, 0xb017fffc); /* usbh_enable - early errata */
asm("sync");
au_writel(0x00, 0xb017fffc); /* usbh_enable */
au_writel(0x00, 0xb0200058); /* usbd_enable */
au_writel(0x00, 0xb0300040); /* ir_enable */
au_writel(0x00, 0xb0520000); /* macen0 */
au_writel(0x00, 0xb1000008); /* i2s_enable */
au_writel(0x00, 0xb1100100); /* uart0_enable */
au_writel(0x00, 0xb1200100); /* uart1_enable */
au_writel(0x00, 0xb1400100); /* uart3_enable */
au_writel(0x02, 0xb1600100); /* ssi0_enable */
au_writel(0x02, 0xb1680100); /* ssi1_enable */
au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */
au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */
au_writel(0x00, 0xb1900028); /* sys_clksrc */
au_writel(0x00, 0xb1900100); /* sys_pininputen */
break;
default:
break;
}
set_c0_status(ST0_BEV | ST0_ERL);
set_c0_config(CONF_CM_UNCACHED);
flush_cache_all();
write_32bit_cp0_register(CP0_WIRED, 0);
write_c0_wired(0);
#if defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500)
/* Do a HW reset if the board can do it */
au_writel(0x00000000, 0xAE00001C);
#endif
__asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
}
void au1000_halt(void)
{
printk(KERN_NOTICE "\n** You can safely turn off the power\n");
#ifdef CONFIG_PM
au_sleep();
/* should not get here */
printk(KERN_ERR "Unable to put cpu in sleep mode\n");
while(1);
#else
while (1)
__asm__(".set\tmips3\n\t"
"wait\n\t"
".set\tmips0");
#endif
}
void au1000_power_off(void)
......
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* RTC routines for PC style attached Dallas chip.
*
* Copyright (C) 1998, 2001 by Ralf Baechle
*/
#include <linux/mc146818rtc.h>
#include <asm/io.h>
#include <asm/au1000.h>
#define PB1500_RTC_ADDR 0xAC000000
unsigned char std_rtc_read_data(unsigned long offset)
{
offset <<= 2;
return (u8)(au_readl(offset + PB1500_RTC_ADDR) & 0xff);
}
static void std_rtc_write_data(unsigned char data, unsigned long offset)
{
offset <<= 2;
au_writel(data, offset + PB1500_RTC_ADDR);
}
static int std_rtc_bcd_mode(void)
{
return 1;
}
struct rtc_ops pb1500_rtc_ops = {
&std_rtc_read_data,
&std_rtc_write_data,
&std_rtc_bcd_mode
};
/*
*
* BRIEF MODULE DESCRIPTION
* Au1000 serial port driver.
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* Derived almost entirely from drivers/char/serial.c:
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997,
* 1998, 1999 Theodore Ts'o
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
static char *serial_version = "1.01";
static char *serial_revdate = "2001-02-08";
#include <linux/config.h>
#include <linux/version.h>
#undef SERIAL_PARANOIA_CHECK
#define CONFIG_SERIAL_NOPAUSE_IO
#define SERIAL_DO_RESTART
/* Set of debugging defines */
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW
#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
#undef SERIAL_DEBUG_PCI
#undef SERIAL_DEBUG_AUTOCONF
#ifdef MODULE
#undef CONFIG_AU1000_SERIAL_CONSOLE
#endif
#define CONFIG_SERIAL_RSA
#define RS_STROBE_TIME (10*HZ)
#define RS_ISR_PASS_LIMIT 256
/*
* End of serial driver configuration section.
*/
#include <linux/module.h>
#include <linux/types.h>
#ifdef LOCAL_HEADERS
#include "serial_local.h"
#else
#include <linux/serial.h>
#include <linux/serialP.h>
#include <asm/au1000.h>
#include <asm/serial.h>
#define LOCAL_VERSTRING ""
#endif
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.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 <asm/uaccess.h>
#include <linux/delay.h>
#ifdef CONFIG_AU1000_SERIAL_CONSOLE
#include <linux/console.h>
#endif
#ifdef CONFIG_MAGIC_SYSRQ
#include <linux/sysrq.h>
#endif
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#ifdef CONFIG_MAC_SERIAL
#define SERIAL_DEV_OFFSET 2
#else
#define SERIAL_DEV_OFFSET 0
#endif
#ifdef SERIAL_INLINE
#define _INLINE_ inline
#else
#define _INLINE_
#endif
static char *serial_name = "Serial driver";
static DECLARE_TASK_QUEUE(tq_serial);
static struct tty_driver *serial_driver;
static struct timer_list serial_timer;
extern unsigned long get_au1000_uart_baud(void);
/* serial subtype definitions */
#ifndef SERIAL_TYPE_NORMAL
#define SERIAL_TYPE_NORMAL 1
#endif
/* number of characters left in xmit buffer before we ask for more */
#define WAKEUP_CHARS 256
/*
* IRQ_timeout - How long the timeout should be for each IRQ
* should be after the IRQ has been active.
*/
static struct async_struct *IRQ_ports[NR_IRQS];
static int IRQ_timeout[NR_IRQS];
#ifdef CONFIG_AU1000_SERIAL_CONSOLE
static struct console sercons;
static int lsr_break_flag;
#endif
#if defined(CONFIG_AU1000_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
static unsigned long break_pressed; /* break, really ... */
#endif
static void autoconfig(struct serial_state * state);
static void change_speed(struct async_struct *info, struct termios *old);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
/*
* Here we define the default xmit fifo size used for each type of
* UART
*/
static struct serial_uart_config uart_config[] = {
{ "unknown", 1, 0 },
{ "8250", 1, 0 },
{ "16450", 1, 0 },
{ "16550", 1, 0 },
{ 0, 0}
};
static struct serial_state rs_table[RS_TABLE_SIZE] = {
SERIAL_PORT_DFNS /* Defined in serial.h */
};
#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
#ifndef PREPARE_FUNC
#define PREPARE_FUNC(dev) (dev->prepare)
#define ACTIVATE_FUNC(dev) (dev->activate)
#define DEACTIVATE_FUNC(dev) (dev->deactivate)
#endif
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
#define DBG_CNT(s) printk("(%s): [%x], refc=%d, serc=%d, ttyc=%d -> %s\n", \
tty->name, (info->flags), serial_driver->refcount, info->count,tty->count,s)
#else
#define DBG_CNT(s)
#endif
/*
* tmp_buf is used as a temporary buffer by serial_write. We need to
* lock it in case the copy_from_user blocks while swapping in a page,
* and some other program tries to do a serial write at the same time.
* Since the lock will only come under contention when the system is
* swapping and available memory is low, it makes sense to share one
* buffer across all the serial ports, since it significantly saves
* memory if large numbers of serial ports are open.
*/
static unsigned char *tmp_buf;
#ifdef DECLARE_MUTEX
static DECLARE_MUTEX(tmp_buf_sem);
#else
static struct semaphore tmp_buf_sem = MUTEX;
#endif
static inline int serial_paranoia_check(struct async_struct *info,
char *name, const char *routine)
{
#ifdef SERIAL_PARANOIA_CHECK
static const char *badmagic =
"Warning: bad magic number for serial struct (%s) in %s\n";
static const char *badinfo =
"Warning: null async_struct for (%s) in %s\n";
if (!info) {
printk(badinfo, name, routine);
return 1;
}
if (info->magic != SERIAL_MAGIC) {
printk(badmagic, name, routine);
return 1;
}
#endif
return 0;
}
static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
{
return (inl(info->port+offset) & 0xff);
}
static _INLINE_ void serial_out(struct async_struct *info, int offset, int value)
{
outl(value & 0xff, info->port+offset);
}
/*
* We used to support using pause I/O for certain machines. We
* haven't supported this for a while, but just in case it's badly
* needed for certain old 386 machines, I've left these #define's
* in....
*/
#define serial_inp(info, offset) serial_in(info, offset)
#define serial_outp(info, offset, value) serial_out(info, offset, value)
/*
* ------------------------------------------------------------
* 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;
if (serial_paranoia_check(info, tty->name, "rs_stop"))
return;
save_flags(flags); cli();
if (info->IER & UART_IER_THRI) {
info->IER &= ~UART_IER_THRI;
serial_out(info, UART_IER, 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;
if (serial_paranoia_check(info, tty->name, "rs_start"))
return;
save_flags(flags); cli();
if (info->xmit.head != info->xmit.tail
&& info->xmit.buf
&& !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
restore_flags(flags);
}
/*
* ----------------------------------------------------------------------
*
* Here starts the interrupt handling routines. All of the following
* subroutines are declared as inline and are folded into
* rs_interrupt(). They were separated out for readability's sake.
*
* Note: rs_interrupt() is a "fast" interrupt, which means that it
* runs with interrupts turned off. People who may want to modify
* rs_interrupt() should try to keep the interrupt handler as fast as
* possible. After you are done making modifications, it is not a bad
* idea to do:
*
* gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
*
* and look at the resulting assemble code in serial.s.
*
* - Ted Ts'o (tytso@mit.edu), 7-Mar-93
* -----------------------------------------------------------------------
*/
/*
* This routine is used by the interrupt handler to schedule
* processing in the software interrupt portion of the driver.
*/
static _INLINE_ void rs_sched_event(struct async_struct *info,
int event)
{
info->event |= 1 << event;
queue_task(&info->tqueue, &tq_serial);
mark_bh(SERIAL_BH);
}
static _INLINE_ void receive_chars(struct async_struct *info,
int *status, struct pt_regs * regs)
{
struct tty_struct *tty = info->tty;
unsigned char ch;
int ignored = 0;
struct async_icount *icount;
icount = &info->state->icount;
do {
ch = serial_inp(info, UART_RX);
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:%02x...", ch, *status);
#endif
*tty->flip.flag_buf_ptr = 0;
if (*status & (UART_LSR_BI | UART_LSR_PE |
UART_LSR_FE | UART_LSR_OE)) {
/*
* For statistics only
*/
if (*status & UART_LSR_BI) {
*status &= ~(UART_LSR_FE | UART_LSR_PE);
icount->brk++;
/*
* We do the SysRQ and SAK checking
* here because otherwise the break
* may get masked by ignore_status_mask
* or read_status_mask.
*/
#if defined(CONFIG_AU1000_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
if (info->line == sercons.index) {
if (!break_pressed) {
break_pressed = jiffies;
goto ignore_char;
}
break_pressed = 0;
}
#endif
if (info->flags & ASYNC_SAK)
do_SAK(tty);
} else if (*status & UART_LSR_PE)
icount->parity++;
else if (*status & UART_LSR_FE)
icount->frame++;
if (*status & UART_LSR_OE)
icount->overrun++;
/*
* Now check to see if character should be
* ignored, and mask off conditions which
* should be ignored.
*/
if (*status & info->ignore_status_mask) {
if (++ignored > 100)
break;
goto ignore_char;
}
*status &= info->read_status_mask;
#ifdef CONFIG_AU1000_SERIAL_CONSOLE
if (info->line == sercons.index) {
/* Recover the break flag from console xmit */
*status |= lsr_break_flag;
lsr_break_flag = 0;
}
#endif
if (*status & (UART_LSR_BI)) {
#ifdef SERIAL_DEBUG_INTR
printk("handling break....");
#endif
*tty->flip.flag_buf_ptr = TTY_BREAK;
} else if (*status & UART_LSR_PE)
*tty->flip.flag_buf_ptr = TTY_PARITY;
else if (*status & UART_LSR_FE)
*tty->flip.flag_buf_ptr = TTY_FRAME;
if (*status & UART_LSR_OE) {
/*
* Overrun is special, since it's
* reported immediately, and doesn't
* affect the current character
*/
tty->flip.count++;
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
*tty->flip.flag_buf_ptr = TTY_OVERRUN;
if (tty->flip.count >= TTY_FLIPBUF_SIZE)
goto ignore_char;
}
}
#if defined(CONFIG_AU1000_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
if (break_pressed && info->line == sercons.index) {
if (ch != 0 &&
time_before(jiffies, break_pressed + HZ*5)) {
handle_sysrq(ch, regs, NULL);
break_pressed = 0;
goto ignore_char;
}
break_pressed = 0;
}
#endif
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
tty->flip.count++;
ignore_char:
*status = serial_inp(info, UART_LSR);
} while (*status & UART_LSR_DR);
tty_flip_buffer_push(tty);
}
static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
{
int count;
if (info->x_char) {
serial_outp(info, UART_TX, 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_IER_THRI;
serial_out(info, UART_IER, info->IER);
return;
}
count = info->xmit_fifo_size;
do {
serial_out(info, UART_TX, 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 (--count > 0);
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_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
}
static _INLINE_ void check_modem_status(struct async_struct *info)
{
int status;
struct async_icount *icount;
status = serial_in(info, UART_MSR);
if (status & UART_MSR_ANY_DELTA) {
icount = &info->state->icount;
/* update input line counters */
if (status & UART_MSR_TERI)
icount->rng++;
if (status & UART_MSR_DDSR)
icount->dsr++;
if (status & UART_MSR_DDCD) {
icount->dcd++;
#ifdef CONFIG_HARD_PPS
if ((info->flags & ASYNC_HARDPPS_CD) &&
(status & UART_MSR_DCD))
hardpps();
#endif
}
if (status & UART_MSR_DCTS)
icount->cts++;
wake_up_interruptible(&info->delta_msr_wait);
}
if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
printk("ttys%d CD now %s...", info->line,
(status & UART_MSR_DCD) ? "on" : "off");
#endif
if (status & UART_MSR_DCD)
wake_up_interruptible(&info->open_wait);
else {
#ifdef SERIAL_DEBUG_OPEN
printk("doing serial hangup...");
#endif
if (info->tty)
tty_hangup(info->tty);
}
}
if (info->flags & ASYNC_CTS_FLOW) {
if (info->tty->hw_stopped) {
if (status & UART_MSR_CTS) {
#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
printk("CTS tx start...");
#endif
info->tty->hw_stopped = 0;
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
return;
}
} else {
if (!(status & UART_MSR_CTS)) {
#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
printk("CTS tx stop...");
#endif
info->tty->hw_stopped = 1;
info->IER &= ~UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
}
}
}
/*
* This is the serial driver's interrupt routine for a single port
*/
static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
{
int status;
int pass_counter = 0;
struct async_struct * info;
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt_single(%d)...", irq);
#endif
info = IRQ_ports[irq];
if (!info || !info->tty)
return;
do {
status = serial_inp(info, UART_LSR);
#ifdef SERIAL_DEBUG_INTR
printk("status = %x...", status);
#endif
if (status & UART_LSR_DR)
receive_chars(info, &status, regs);
check_modem_status(info);
if (status & UART_LSR_THRE)
transmit_chars(info, 0);
if (pass_counter++ > RS_ISR_PASS_LIMIT) {
#if 0
printk("rs_single loop break.\n");
#endif
break;
}
} while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
info->last_active = jiffies;
#ifdef SERIAL_DEBUG_INTR
printk("end.\n");
#endif
}
/*
* -------------------------------------------------------------------
* Here ends the serial interrupt routines.
* -------------------------------------------------------------------
*/
/*
* This routine is used to handle the "bottom half" processing for the
* serial driver, known also the "software interrupt" processing.
* This processing is done at the kernel interrupt level, after the
* rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
* is where time-consuming activities which can not be done in the
* interrupt driver proper are done; the interrupt driver schedules
* them using rs_sched_event(), and they get done here.
*/
static void do_serial_bh(void)
{
run_task_queue(&tq_serial);
}
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
}
}
/*
* This subroutine is called when the RS_TIMER goes off. It is used
* by the serial driver to handle ports that do not have an interrupt
* (irq=0). This doesn't work very well for 16450's, but gives barely
* passable results for a 16550A. (Although at the expense of much
* CPU overhead).
*/
static void rs_timer(unsigned long dummy)
{
static unsigned long last_strobe;
struct async_struct *info;
unsigned int i;
unsigned long flags;
if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
for (i=0; i < NR_IRQS; i++) {
info = IRQ_ports[i];
if (!info)
continue;
save_flags(flags); cli();
rs_interrupt_single(i, NULL, NULL);
restore_flags(flags);
}
}
last_strobe = jiffies;
mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
#if 0
if (IRQ_ports[0]) {
save_flags(flags); cli();
rs_interrupt_single(0, NULL, NULL);
restore_flags(flags);
mod_timer(&serial_timer, jiffies + IRQ_timeout[0]);
}
#endif
}
/*
* ---------------------------------------------------------------
* Low level utility subroutines for the serial driver: routines to
* figure out the appropriate timeout for an interrupt chain, routines
* to initialize and startup a serial port, and routines to shutdown a
* serial port. Useful stuff like that.
* ---------------------------------------------------------------
*/
/*
* This routine figures out the correct timeout for a particular IRQ.
* It uses the smallest timeout of all of the serial ports in a
* particular interrupt chain. Now only used for IRQ 0....
*/
static void figure_IRQ_timeout(int irq)
{
struct async_struct *info;
int timeout = 60*HZ; /* 60 seconds === a long time :-) */
info = IRQ_ports[irq];
if (!info) {
IRQ_timeout[irq] = 60*HZ;
return;
}
while (info) {
if (info->timeout < timeout)
timeout = info->timeout;
info = info->next_port;
}
if (!irq)
timeout = timeout / 2;
IRQ_timeout[irq] = (timeout > 3) ? timeout-2 : 1;
}
static int startup(struct async_struct * info)
{
unsigned long flags;
int retval=0;
void (*handler)(int, void *, struct pt_regs *);
struct serial_state *state= info->state;
unsigned long page;
page = get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
save_flags(flags); cli();
if (info->flags & ASYNC_INITIALIZED) {
free_page(page);
goto errout;
}
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;
if (inl(UART_MOD_CNTRL + state->port) != 0x3) {
outl(3, UART_MOD_CNTRL + state->port);
}
#ifdef SERIAL_DEBUG_OPEN
printk("starting up ttys%d (irq %d)...", info->line, state->irq);
#endif
/*
* Clear the FIFO buffers and disable them
* (they will be reenabled in change_speed())
*/
if (uart_config[state->type].flags & UART_CLEAR_FIFO) {
serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
serial_outp(info, UART_FCR, 0);
}
/*
* Clear the interrupt registers.
*/
(void) serial_inp(info, UART_LSR);
(void) serial_inp(info, UART_RX);
(void) serial_inp(info, UART_IIR);
(void) serial_inp(info, UART_MSR);
/*
* At this point there's no way the LSR could still be 0xFF;
* if it is, then bail out, because there's likely no UART
* here.
*/
if (!(info->flags & ASYNC_BUGGY_UART) &&
(serial_inp(info, UART_LSR) == 0xff)) {
printk("LSR safety check engaged!\n");
if (capable(CAP_SYS_ADMIN)) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
} else
retval = -ENODEV;
goto errout;
}
/*
* Allocate the IRQ if necessary
*/
#if 0
/* au1000, uart0 irq is 0 */
if (state->irq && (!IRQ_ports[state->irq] || !IRQ_ports[state->irq]->next_port)) {
#endif
if ((!IRQ_ports[state->irq] || !IRQ_ports[state->irq]->next_port)) {
if (IRQ_ports[state->irq]) {
retval = -EBUSY;
goto errout;
} else
handler = rs_interrupt_single;
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);
retval = 0;
}
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;
figure_IRQ_timeout(state->irq);
/*
* Now, initialize the UART
*/
serial_outp(info, UART_LCR, UART_LCR_WLEN8);
info->MCR = 0;
if (info->tty->termios->c_cflag & CBAUD)
info->MCR = UART_MCR_DTR | UART_MCR_RTS;
{
if (state->irq != 0)
info->MCR |= UART_MCR_OUT2;
}
info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
serial_outp(info, UART_MCR, info->MCR);
/*
* Finally, enable interrupts
*/
info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
serial_outp(info, UART_IER, info->IER); /* enable interrupts */
/*
* And clear the interrupt registers again for luck.
*/
(void)serial_inp(info, UART_LSR);
(void)serial_inp(info, UART_RX);
(void)serial_inp(info, UART_IIR);
(void)serial_inp(info, UART_MSR);
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->xmit.head = info->xmit.tail = 0;
/*
* Set up serial timers...
*/
mod_timer(&serial_timer, jiffies + 2*HZ/100);
/*
* Set up the tty->alt_speed kludge
*/
if (info->tty) {
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
info->tty->alt_speed = 57600;
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
info->tty->alt_speed = 115200;
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
info->tty->alt_speed = 230400;
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
info->tty->alt_speed = 460800;
}
/*
* and set the speed of the serial port
*/
change_speed(info, 0);
info->flags |= ASYNC_INITIALIZED;
restore_flags(flags);
return 0;
errout:
restore_flags(flags);
return retval;
}
/*
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
static void shutdown(struct async_struct * info)
{
unsigned long flags;
struct serial_state *state;
int retval;
if (!(info->flags & ASYNC_INITIALIZED))
return;
state = info->state;
#ifdef SERIAL_DEBUG_OPEN
printk("Shutting down serial port %d (irq %d)....", info->line,
state->irq);
#endif
save_flags(flags); cli(); /* Disable interrupts */
/*
* clear delta_msr_wait queue to avoid mem leaks: we may free the irq
* here so the queue might never be waken up
*/
wake_up_interruptible(&info->delta_msr_wait);
/*
* First unlink the serial port from the IRQ chain...
*/
if (info->next_port)
info->next_port->prev_port = info->prev_port;
if (info->prev_port)
info->prev_port->next_port = info->next_port;
else
IRQ_ports[state->irq] = info->next_port;
figure_IRQ_timeout(state->irq);
/*
* Free the IRQ, if necessary
*/
// if (state->irq && (!IRQ_ports[state->irq] ||
if ((!IRQ_ports[state->irq] ||
!IRQ_ports[state->irq]->next_port)) {
if (IRQ_ports[state->irq]) {
free_irq(state->irq, &IRQ_ports[state->irq]);
retval = request_irq(state->irq, rs_interrupt_single,
SA_SHIRQ, "serial",
&IRQ_ports[state->irq]);
if (retval)
printk("serial shutdown: request_irq: error %d"
" Couldn't reacquire IRQ.\n", retval);
} else
free_irq(state->irq, &IRQ_ports[state->irq]);
}
if (info->xmit.buf) {
unsigned long pg = (unsigned long) info->xmit.buf;
info->xmit.buf = 0;
free_page(pg);
}
info->IER = 0;
serial_outp(info, UART_IER, 0x00); /* disable all intrs */
info->MCR &= ~UART_MCR_OUT2;
info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
/* disable break condition */
serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
serial_outp(info, UART_MCR, info->MCR);
/* disable FIFO's */
serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
serial_outp(info, UART_FCR, 0);
(void)serial_in(info, UART_RX); /* read data port to reset things */
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
info->flags &= ~ASYNC_INITIALIZED;
restore_flags(flags);
}
/*
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
static void change_speed(struct async_struct *info,
struct termios *old_termios)
{
int quot = 0, baud_base, baud;
unsigned cflag, cval, fcr = 0;
int bits;
unsigned long flags;
if (!info->tty || !info->tty->termios)
return;
cflag = info->tty->termios->c_cflag;
if (!CONFIGURED_SERIAL_PORT(info))
return;
/* byte size and parity */
switch (cflag & CSIZE) {
case CS5: cval = 0x00; bits = 7; break;
case CS6: cval = 0x01; bits = 8; break;
case CS7: cval = 0x02; bits = 9; break;
case CS8: cval = 0x03; bits = 10; break;
/* Never happens, but GCC is too dumb to figure it out */
default: cval = 0x00; bits = 7; break;
}
if (cflag & CSTOPB) {
cval |= 0x04;
bits++;
}
if (cflag & PARENB) {
cval |= UART_LCR_PARITY;
bits++;
}
if (!(cflag & PARODD))
cval |= UART_LCR_EPAR;
#ifdef CMSPAR
if (cflag & CMSPAR)
cval |= UART_LCR_SPAR;
#endif
/* Determine divisor based on baud rate */
baud = tty_get_baud_rate(info->tty);
if (!baud) {
baud = 9600; /* B0 transition handled in rs_set_termios */
}
baud_base = info->state->baud_base;
//if (baud == 38400 &&
if (((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) {
quot = info->state->custom_divisor;
}
else {
if (baud == 134)
/* Special case since 134 is really 134.5 */
quot = (2*baud_base / 269);
else if (baud)
quot = baud_base / baud;
}
/* If the quotient is zero refuse the change */
if (!quot && old_termios) {
info->tty->termios->c_cflag &= ~CBAUD;
info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
baud = tty_get_baud_rate(info->tty);
if (!baud)
baud = 9600;
if (baud == 38400 &&
((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
quot = info->state->custom_divisor;
else {
if (baud == 134)
/* Special case since 134 is really 134.5 */
quot = (2*baud_base / 269);
else if (baud)
quot = baud_base / baud;
}
}
/* As a last resort, if the quotient is zero, default to 9600 bps */
if (!quot)
quot = baud_base / 9600;
info->quot = quot;
info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
info->timeout += HZ/50; /* Add .02 seconds of slop */
/* Set up FIFO's */
if (uart_config[info->state->type].flags & UART_USE_FIFO) {
if ((info->state->baud_base / quot) < 2400)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_1;
else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIGGER_8;
}
/* CTS flow control flag and modem status interrupts */
info->IER &= ~UART_IER_MSI;
if (info->flags & ASYNC_HARDPPS_CD)
info->IER |= UART_IER_MSI;
if (cflag & CRTSCTS) {
info->flags |= ASYNC_CTS_FLOW;
info->IER |= UART_IER_MSI;
} else
info->flags &= ~ASYNC_CTS_FLOW;
if (cflag & CLOCAL)
info->flags &= ~ASYNC_CHECK_CD;
else {
info->flags |= ASYNC_CHECK_CD;
info->IER |= UART_IER_MSI;
}
serial_out(info, UART_IER, info->IER);
/*
* Set up parity check flag
*/
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (I_INPCK(info->tty))
info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
info->read_status_mask |= UART_LSR_BI;
/*
* Characters to ignore
*/
info->ignore_status_mask = 0;
if (I_IGNPAR(info->tty))
info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
if (I_IGNBRK(info->tty)) {
info->ignore_status_mask |= UART_LSR_BI;
/*
* If we're ignore parity and break indicators, ignore
* overruns too. (For real raw support).
*/
if (I_IGNPAR(info->tty))
info->ignore_status_mask |= UART_LSR_OE;
}
/*
* !!! ignore all characters if CREAD is not set
*/
if ((cflag & CREAD) == 0)
info->ignore_status_mask |= UART_LSR_DR;
save_flags(flags); cli();
serial_outp(info, UART_CLK, quot & 0xffff);
serial_outp(info, UART_LCR, cval);
info->LCR = cval; /* Save LCR */
restore_flags(flags);
}
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 (serial_paranoia_check(info, tty->name, "rs_put_char"))
return;
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 (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
return;
if (info->xmit.head == info->xmit.tail
|| tty->stopped
|| tty->hw_stopped
|| !info->xmit.buf)
return;
save_flags(flags); cli();
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
restore_flags(flags);
}
static int rs_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
int c, ret = 0;
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_write"))
return 0;
if (!tty || !info->xmit.buf || !tmp_buf)
return 0;
save_flags(flags);
if (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_IER_THRI)) {
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
return ret;
}
static int rs_write_room(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
if (serial_paranoia_check(info, tty->name, "rs_write_room"))
return 0;
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;
if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
return 0;
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;
if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
return;
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);
}
/*
* 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;
if (serial_paranoia_check(info, tty->name, "rs_send_char"))
return;
info->x_char = ch;
if (ch) {
/* Make sure transmit interrupts are on */
info->IER |= UART_IER_THRI;
serial_out(info, UART_IER, info->IER);
}
}
/*
* ------------------------------------------------------------
* 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)
{
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 (serial_paranoia_check(info, tty->name, "rs_throttle"))
return;
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);
}
static void rs_unthrottle(struct tty_struct * tty)
{
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 (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
return;
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);
}
/*
* ------------------------------------------------------------
* rs_ioctl() and friends
* ------------------------------------------------------------
*/
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;
}
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_canonicalize(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;
}
/*
* get_lsr_info - get line status register info
*
* Purpose: Let user call ioctl() to get info when the UART physically
* is emptied. On bus types like RS485, the transmitter must
* release the bus after transmitting. This must be done when
* the transmit shift register is empty, not be done when the
* transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
static int get_lsr_info(struct async_struct * info, unsigned int *value)
{
unsigned char status;
unsigned int result;
unsigned long flags;
save_flags(flags); cli();
status = serial_in(info, UART_LSR);
restore_flags(flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
/*
* If we're about to load something into the transmit
* register, we'll pretend the transmitter isn't empty to
* avoid a race condition (depending on when the transmit
* interrupt happens).
*/
if (info->x_char ||
((CIRC_CNT(info->xmit.head, info->xmit.tail,
SERIAL_XMIT_SIZE) > 0) &&
!info->tty->stopped && !info->tty->hw_stopped))
result &= TIOCSER_TEMT;
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
return 0;
}
static int get_modem_info(struct async_struct * info, unsigned int *value)
{
unsigned char control, status;
unsigned int result;
unsigned long flags;
control = info->MCR;
save_flags(flags); cli();
status = serial_in(info, UART_MSR);
restore_flags(flags);
result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
#ifdef TIOCM_OUT1
| ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
| ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
#endif
| ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
| ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
| ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
| ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
if (copy_to_user(value, &result, sizeof(int)))
return -EFAULT;
return 0;
}
static int set_modem_info(struct async_struct * info, unsigned int cmd,
unsigned int *value)
{
unsigned int arg;
unsigned long flags;
if (copy_from_user(&arg, value, sizeof(int)))
return -EFAULT;
switch (cmd) {
case TIOCMBIS:
if (arg & TIOCM_RTS)
info->MCR |= UART_MCR_RTS;
if (arg & TIOCM_DTR)
info->MCR |= UART_MCR_DTR;
#ifdef TIOCM_OUT1
if (arg & TIOCM_OUT1)
info->MCR |= UART_MCR_OUT1;
if (arg & TIOCM_OUT2)
info->MCR |= UART_MCR_OUT2;
#endif
if (arg & TIOCM_LOOP)
info->MCR |= UART_MCR_LOOP;
break;
case TIOCMBIC:
if (arg & TIOCM_RTS)
info->MCR &= ~UART_MCR_RTS;
if (arg & TIOCM_DTR)
info->MCR &= ~UART_MCR_DTR;
#ifdef TIOCM_OUT1
if (arg & TIOCM_OUT1)
info->MCR &= ~UART_MCR_OUT1;
if (arg & TIOCM_OUT2)
info->MCR &= ~UART_MCR_OUT2;
#endif
if (arg & TIOCM_LOOP)
info->MCR &= ~UART_MCR_LOOP;
break;
case TIOCMSET:
info->MCR = ((info->MCR & ~(UART_MCR_RTS |
#ifdef TIOCM_OUT1
UART_MCR_OUT1 |
UART_MCR_OUT2 |
#endif
UART_MCR_LOOP |
UART_MCR_DTR))
| ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
#ifdef TIOCM_OUT1
| ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
| ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
#endif
| ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0)
| ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
break;
default:
return -EINVAL;
}
save_flags(flags); cli();
info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */
serial_out(info, UART_MCR, info->MCR);
restore_flags(flags);
return 0;
}
static int do_autoconfig(struct async_struct * info)
{
int retval;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (info->state->count > 1)
return -EBUSY;
shutdown(info);
autoconfig(info->state);
retval = startup(info);
if (retval)
return retval;
return 0;
}
/*
* 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 (serial_paranoia_check(info, tty->name, "rs_break"))
return;
if (!CONFIGURED_SERIAL_PORT(info))
return;
save_flags(flags); cli();
if (break_state == -1)
info->LCR |= UART_LCR_SBC;
else
info->LCR &= ~UART_LCR_SBC;
serial_out(info, UART_LCR, info->LCR);
restore_flags(flags);
}
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 (serial_paranoia_check(info, tty->name, "rs_ioctl"))
return -ENODEV;
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:
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 */
/*
* 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;
}
static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
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;
change_speed(info, old_termios);
/* 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);
}
}
/*
* ------------------------------------------------------------
* 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;
if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
return;
state = info->state;
save_flags(flags); cli();
if (tty_hung_up_p(filp)) {
DBG_CNT("before DEC-hung");
MOD_DEC_USE_COUNT;
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;
}
if (state->count) {
DBG_CNT("before DEC-2");
MOD_DEC_USE_COUNT;
restore_flags(flags);
return;
}
info->flags |= ASYNC_CLOSING;
restore_flags(flags);
/*
* 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_CLOSING);
wake_up_interruptible(&info->close_wait);
MOD_DEC_USE_COUNT;
}
/*
* rs_wait_until_sent() --- wait until the transmitter is empty
*/
static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
{
struct async_struct * info = (struct async_struct *)tty->driver_data;
unsigned long orig_jiffies, char_time;
int lsr;
if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
return;
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
}
/*
* 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;
if (serial_paranoia_check(info, tty->name, "rs_hangup"))
return;
state = info->state;
rs_flush_buffer(tty);
if (info->flags & ASYNC_CLOSING)
return;
shutdown(info);
info->event = 0;
state->count = 0;
info->flags &= ~ASYNC_NORMAL_ACTIVE;
info->tty = 0;
wake_up_interruptible(&info->open_wait);
}
/*
* ------------------------------------------------------------
* rs_open() and friends
* ------------------------------------------------------------
*/
static int block_til_ready(struct tty_struct *tty, struct file * filp,
struct async_struct *info)
{
DECLARE_WAITQUEUE(wait, current);
struct serial_state *state = info->state;
int retval;
int do_clocal = 0, extra_count = 0;
unsigned long flags;
/*
* If the device is in the middle of being closed, then block
* until it's done, and then try again.
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
if (info->flags & ASYNC_CLOSING)
interruptible_sleep_on(&info->close_wait);
#ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
#else
return -EAGAIN;
#endif
}
/*
* If non-blocking mode is set, or the port is not enabled,
* then make the check up front and then exit.
*/
if ((filp->f_flags & O_NONBLOCK) ||
(tty->flags & (1 << TTY_IO_ERROR))) {
info->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
if (tty->termios->c_cflag & CLOCAL)
do_clocal = 1;
/*
* Block waiting for the carrier detect and the line to become
* free (i.e., not in use by the callout). While we are in
* this loop, state->count is dropped by one, so that
* rs_close() knows when to free things. We restore it upon
* exit, either normal or abnormal.
*/
retval = 0;
add_wait_queue(&info->open_wait, &wait);
#ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready before block: ttys%d, count = %d\n",
state->line, state->count);
#endif
save_flags(flags); cli();
if (!tty_hung_up_p(filp)) {
extra_count = 1;
state->count--;
}
restore_flags(flags);
info->blocked_open++;
while (1) {
save_flags(flags); cli();
if (tty->termios->c_cflag & CBAUD)
serial_out(info, UART_MCR,
serial_inp(info, UART_MCR) |
(UART_MCR_DTR | UART_MCR_RTS));
restore_flags(flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
!(info->flags & ASYNC_INITIALIZED)) {
#ifdef SERIAL_DO_RESTART
if (info->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
retval = -ERESTARTSYS;
#else
retval = -EAGAIN;
#endif
break;
}
if (!(info->flags & ASYNC_CLOSING) &&
(do_clocal || (serial_in(info, UART_MSR) &
UART_MSR_DCD)))
break;
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
#ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready blocking: ttys%d, count = %d\n",
info->line, state->count);
#endif
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
if (extra_count)
state->count++;
info->blocked_open--;
#ifdef SERIAL_DEBUG_OPEN
printk("block_til_ready after blocking: ttys%d, count = %d\n",
info->line, state->count);
#endif
if (retval)
return retval;
info->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
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;
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;
}
/*
* 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;
MOD_INC_USE_COUNT;
line = tty->index;
if ((line < 0) || (line >= NR_PORTS)) {
MOD_DEC_USE_COUNT;
return -ENODEV;
}
retval = get_async_struct(line, &info);
if (retval) {
MOD_DEC_USE_COUNT;
return retval;
}
tty->driver_data = info;
info->tty = tty;
if (serial_paranoia_check(info, tty->name, "rs_open")) {
MOD_DEC_USE_COUNT;
return -ENODEV;
}
#ifdef SERIAL_DEBUG_OPEN
printk("rs_open %s, count = %d\n", tty->name, 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) {
MOD_DEC_USE_COUNT;
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);
MOD_DEC_USE_COUNT;
#ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
#else
return -EAGAIN;
#endif
}
/*
* Start up serial port
*/
retval = startup(info);
if (retval) {
MOD_DEC_USE_COUNT;
return retval;
}
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
MOD_DEC_USE_COUNT;
return retval;
}
#ifdef CONFIG_AU1000_SERIAL_CONSOLE
if (sercons.cflag && sercons.index == line) {
tty->termios->c_cflag = sercons.cflag;
sercons.cflag = 0;
change_speed(info, 0);
}
#endif
#ifdef SERIAL_DEBUG_OPEN
printk("rs_open %s successful...", tty->name);
#endif
return 0;
}
/*
* /proc fs routines....
*/
static inline int line_info(char *buf, struct serial_state *state)
{
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;
}
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);
}
/*
* ---------------------------------------------------------------------
* rs_init() and friends
*
* rs_init() is called at boot-time to initialize the serial driver.
* ---------------------------------------------------------------------
*/
/*
* This routine prints out the appropriate serial driver version
* number, and identifies which options were configured into this
* driver.
*/
static char serial_options[] __initdata =
" no serial options enabled\n";
#undef SERIAL_OPT
static _INLINE_ void show_serial_version(void)
{
printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name,
serial_version, LOCAL_VERSTRING, serial_revdate,
serial_options);
}
/*
* This routine is called by rs_init() to initialize a specific serial
* port. It determines what type of UART chip this serial port is
* using: 8250, 16450, 16550, 16550A. The important question is
* whether or not this UART is a 16550A or not, since this will
* determine whether or not we can use its FIFO features or not.
*/
static void autoconfig(struct serial_state * state)
{
struct async_struct *info, scr_info;
unsigned long flags;
#ifdef SERIAL_DEBUG_AUTOCONF
printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line,
state->port, (unsigned) state->iomem_base);
#endif
if (!CONFIGURED_SERIAL_PORT(state))
return;
if (inl(UART_MOD_CNTRL + state->port) != 0x3) {
outl(3, UART_MOD_CNTRL + state->port);
}
state->type = PORT_16550;
info = &scr_info; /* This is just for serial_{in,out} */
info->magic = SERIAL_MAGIC;
info->state = state;
info->port = state->port;
info->flags = state->flags;
info->io_type = state->io_type;
info->iomem_base = state->iomem_base;
info->iomem_reg_shift = state->iomem_reg_shift;
save_flags(flags); cli();
state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size;
if (info->port) {
request_region(info->port,8,"serial(auto)");
}
/*
* Reset the UART.
*/
serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
serial_outp(info, UART_FCR, 0);
(void)serial_in(info, UART_RX);
serial_outp(info, UART_IER, 0);
restore_flags(flags);
}
int register_serial(struct serial_struct *req);
void unregister_serial(int line);
EXPORT_SYMBOL(register_serial);
EXPORT_SYMBOL(unregister_serial);
static struct tty_operations serial_ops = {
.open = rs_open,
.close = rs_close,
.write = rs_write,
.put_char = rs_put_char,
.flush_chars = rs_flush_chars,
.write_room = rs_write_room,
.chars_in_buffer = rs_chars_in_buffer,
.flush_buffer = rs_flush_buffer,
.ioctl = rs_ioctl,
.throttle = rs_throttle,
.unthrottle = rs_unthrottle,
.set_termios = rs_set_termios,
.stop = rs_stop,
.start = rs_start,
.hangup = rs_hangup,
.break_ctl = rs_break,
.send_xchar = rs_send_xchar,
.wait_until_sent = rs_wait_until_sent,
.read_proc = rs_read_proc,
};
/*
* The serial driver boot-time initialization code!
*/
static int __init rs_init(void)
{
int i;
struct serial_state * state;
serial_driver = alloc_tty_driver(NR_PORTS);
if (!serial_driver)
return -ENOMEM;
init_bh(SERIAL_BH, do_serial_bh);
init_timer(&serial_timer);
serial_timer.function = rs_timer;
mod_timer(&serial_timer, jiffies + RS_STROBE_TIME);
for (i = 0; i < NR_IRQS; i++) {
IRQ_ports[i] = 0;
IRQ_timeout[i] = 0;
}
#ifdef CONFIG_AU1000_SERIAL_CONSOLE
/*
* The interrupt of the serial console port
* can't be shared.
*/
if (sercons.flags & CON_CONSDEV) {
for(i = 0; i < NR_PORTS; i++)
if (i != sercons.index &&
rs_table[i].irq == rs_table[sercons.index].irq)
rs_table[i].irq = 0;
}
#endif
show_serial_version();
/* Initialize the tty_driver structure */
serial_driver->driver_name = "serial";
serial_driver->devfs_name = "tts/";
serial_driver->name = "ttyS";
serial_driver->major = TTY_MAJOR;
serial_driver->minor_start = 64 + SERIAL_DEV_OFFSET;
serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
serial_driver->subtype = SERIAL_TYPE_NORMAL;
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
tty_set_operations(serial_driver, &serial_ops);
if (tty_register_driver(serial_driver))
panic("Couldn't register serial driver\n");
for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
state->baud_base = get_au1000_uart_baud();
state->magic = SSTATE_MAGIC;
state->line = i;
state->type = PORT_UNKNOWN;
state->custom_divisor = 0;
state->close_delay = 5*HZ/10;
state->closing_wait = 30*HZ;
state->icount.cts = state->icount.dsr =
state->icount.rng = state->icount.dcd = 0;
state->icount.rx = state->icount.tx = 0;
state->icount.frame = state->icount.parity = 0;
state->icount.overrun = state->icount.brk = 0;
state->irq = irq_canonicalize(state->irq);
if (state->hub6)
state->io_type = SERIAL_IO_HUB6;
if (state->port && check_region(state->port,8)) {
continue;
}
if (state->flags & ASYNC_BOOT_AUTOCONF) {
autoconfig(state);
}
}
for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
if (state->type == PORT_UNKNOWN) {
continue;
}
printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n",
state->line + SERIAL_DEV_OFFSET,
(state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
state->port, state->irq,
uart_config[state->type].name);
tty_register_device(serial_driver, state->line, NULL);
}
return 0;
}
/*
* register_serial and unregister_serial allows for 16x50 serial ports to be
* configured at run-time, to support PCMCIA modems.
*/
/**
* register_serial - configure a 16x50 serial port at runtime
* @req: request structure
*
* Configure the serial port specified by the request. If the
* port exists and is in use an error is returned. If the port
* is not currently in the table it is added.
*
* The port is then probed and if necessary the IRQ is autodetected
* If this fails an error is returned.
*
* On success the port is ready to use and the line number is returned.
*/
int register_serial(struct serial_struct *req)
{
int i;
unsigned long flags;
struct serial_state *state;
struct async_struct *info;
unsigned long port;
port = req->port;
if (HIGH_BITS_OFFSET)
port += (unsigned long) req->port_high << HIGH_BITS_OFFSET;
save_flags(flags); cli();
for (i = 0; i < NR_PORTS; i++) {
if ((rs_table[i].port == port) &&
(rs_table[i].iomem_base == req->iomem_base))
break;
}
if (i == NR_PORTS) {
for (i = 0; i < NR_PORTS; i++)
if ((rs_table[i].type == PORT_UNKNOWN) &&
(rs_table[i].count == 0))
break;
}
if (i == NR_PORTS) {
restore_flags(flags);
return -1;
}
state = &rs_table[i];
if (rs_table[i].count) {
restore_flags(flags);
printk("Couldn't configure serial #%d (port=%ld,irq=%d): "
"device already open\n", i, port, req->irq);
return -1;
}
state->irq = req->irq;
state->port = port;
state->flags = req->flags;
state->io_type = req->io_type;
state->iomem_base = req->iomem_base;
state->iomem_reg_shift = req->iomem_reg_shift;
if (req->baud_base)
state->baud_base = req->baud_base;
if ((info = state->info) != NULL) {
info->port = port;
info->flags = req->flags;
info->io_type = req->io_type;
info->iomem_base = req->iomem_base;
info->iomem_reg_shift = req->iomem_reg_shift;
}
autoconfig(state);
if (state->type == PORT_UNKNOWN) {
restore_flags(flags);
printk("register_serial(): autoconfig failed\n");
return -1;
}
restore_flags(flags);
printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
state->line + SERIAL_DEV_OFFSET,
state->iomem_base ? "iomem" : "port",
state->iomem_base ? (unsigned long)state->iomem_base :
state->port, state->irq, uart_config[state->type].name);
tty_register_device(serial_driver, state->line, NULL);
return state->line + SERIAL_DEV_OFFSET;
}
/**
* unregister_serial - deconfigure a 16x50 serial port
* @line: line to deconfigure
*
* The port specified is deconfigured and its resources are freed. Any
* user of the port is disconnected as if carrier was dropped. Line is
* the port number returned by register_serial().
*/
void unregister_serial(int line)
{
unsigned long flags;
struct serial_state *state = &rs_table[line];
save_flags(flags); cli();
if (state->info && state->info->tty)
tty_hangup(state->info->tty);
state->type = PORT_UNKNOWN;
printk(KERN_INFO "tty%02d unloaded\n", state->line);
/* These will be hidden, because they are devices that will no longer
* be available to the system. (ie, PCMCIA modems, once ejected)
*/
tty_unregister_device(serial_driver, state->line);
restore_flags(flags);
}
static void __exit rs_fini(void)
{
unsigned long flags;
int e1, e2;
int i;
struct async_struct *info;
/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
del_timer_sync(&serial_timer);
save_flags(flags); cli();
remove_bh(SERIAL_BH);
if ((e1 = tty_unregister_driver(serial_driver)))
printk("serial: failed to unregister serial driver (%d)\n",
e1);
restore_flags(flags);
put_tty_driver(serial_driver);
for (i = 0; i < NR_PORTS; i++) {
if ((info = rs_table[i].info)) {
rs_table[i].info = NULL;
kfree(info);
}
if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) {
release_region(rs_table[i].port, 8);
}
}
if (tmp_buf) {
unsigned long pg = (unsigned long) tmp_buf;
tmp_buf = NULL;
free_page(pg);
}
}
module_init(rs_init);
module_exit(rs_fini);
MODULE_DESCRIPTION("Au1000 serial driver");
/*
* ------------------------------------------------------------
* Serial console driver
* ------------------------------------------------------------
*/
#ifdef CONFIG_AU1000_SERIAL_CONSOLE
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
static struct async_struct async_sercons;
/*
* Wait for transmitter & holding register to empty
*/
static inline void wait_for_xmitr(struct async_struct *info)
{
unsigned int status, tmout = 0xffffff;
do {
status = serial_in(info, UART_LSR);
if (status & UART_LSR_BI)
lsr_break_flag = UART_LSR_BI;
if (--tmout == 0)
break;
} while((status & BOTH_EMPTY) != BOTH_EMPTY);
}
/*
* 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)
{
static struct async_struct *info = &async_sercons;
int ier;
unsigned i;
/*
* First save the IER then disable the interrupts
*/
ier = serial_in(info, UART_IER);
serial_out(info, UART_IER, 0x00);
/*
* Now, do each character
*/
for (i = 0; i < count; i++, s++) {
wait_for_xmitr(info);
/*
* Send the character out.
* If a LF, also do CR...
*/
serial_out(info, UART_TX, *s);
if (*s == 10) {
wait_for_xmitr(info);
serial_out(info, UART_TX, 13);
}
}
/*
* Finally, Wait for transmitter & holding register to empty
* and restore the IER
*/
wait_for_xmitr(info);
serial_out(info, UART_IER, ier);
}
static struct tty_driver *serial_console_device(struct console *c, int *index)
{
*index = c->index - SERIAL_DEV_OFFSET;
return serial_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)
{
static struct async_struct *info;
struct serial_state *state;
unsigned cval;
int baud = 9600;
int bits = 8;
int parity = 'n';
int cflag = CREAD | HUPCL | CLOCAL;
int quot = 0;
char *s;
if (options) {
baud = simple_strtoul(options, NULL, 10);
s = options;
while(*s >= '0' && *s <= '9')
s++;
if (*s) parity = *s++;
if (*s) bits = *s - '0';
}
/*
* Now construct a cflag setting.
*/
switch(baud) {
case 1200:
cflag |= B1200;
break;
case 2400:
cflag |= B2400;
break;
case 4800:
cflag |= B4800;
break;
case 19200:
cflag |= B19200;
break;
case 38400:
cflag |= B38400;
break;
case 57600:
cflag |= B57600;
break;
case 115200:
cflag |= B115200;
break;
case 9600:
default:
cflag |= B9600;
break;
}
switch(bits) {
case 7:
cflag |= CS7;
break;
default:
case 8:
cflag |= CS8;
break;
}
switch(parity) {
case 'o': case 'O':
cflag |= PARODD;
break;
case 'e': case 'E':
cflag |= PARENB;
break;
}
co->cflag = cflag;
/*
* Divisor, bytesize and parity
*/
state = rs_table + co->index;
info = &async_sercons;
info->magic = SERIAL_MAGIC;
info->state = state;
info->port = state->port;
info->flags = state->flags;
info->io_type = state->io_type;
info->iomem_base = state->iomem_base;
info->iomem_reg_shift = state->iomem_reg_shift;
state->baud_base = get_au1000_uart_baud();
quot = state->baud_base / baud;
cval = cflag & (CSIZE | CSTOPB);
cval >>= 4;
if (cflag & PARENB)
cval |= UART_LCR_PARITY;
if (!(cflag & PARODD))
cval |= UART_LCR_EPAR;
/*
* Disable UART interrupts, set DTR and RTS high
* and set speed.
*/
serial_out(info, UART_CLK, quot & 0xffff);
serial_out(info, UART_IER, 0);
serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
/*
* If we read 0xff from the LSR, there is no UART here.
*/
if (serial_in(info, UART_LSR) == 0xff)
return -1;
return 0;
}
static struct console sercons = {
.name = "ttyS",
.write = serial_console_write,
.device = serial_console_device,
.setup = serial_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
/*
* Register console.
*/
static void __init au1000_serial_console_init(void)
{
register_console(&sercons);
}
console_initcall(au1000_serial_console_init);
#endif
/*
Local variables:
compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
End:
*/
......@@ -5,8 +5,6 @@
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
*
* ########################################################################
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
......@@ -20,10 +18,9 @@
* 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>
......@@ -33,27 +30,39 @@
#include <asm/mipsregs.h>
#include <asm/ptrace.h>
#include <asm/time.h>
#include <asm/hardirq.h>
#include <asm/div64.h>
#include <asm/au1000.h>
#include <linux/mc146818rtc.h>
#include <linux/timex.h>
extern void startup_match20_interrupt(void);
extern void do_softirq(void);
extern volatile unsigned long wall_jiffies;
unsigned long missed_heart_beats = 0;
unsigned long uart_baud_base;
static unsigned long r4k_offset; /* Amount to increment compare reg each time */
static unsigned long r4k_cur; /* What counter should be at next timer irq */
extern unsigned int mips_counter_frequency;
/* Cycle counter value at the previous timer interrupt.. */
static unsigned int timerhi = 0, timerlo = 0;
#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
#ifdef CONFIG_PM
#define MATCH20_INC 328
extern void startup_match20_interrupt(void);
static unsigned long last_pc0, last_match20;
#endif
static spinlock_t time_lock = SPIN_LOCK_UNLOCKED;
static inline void ack_r4ktimer(unsigned long newval)
{
write_32bit_cp0_register(CP0_COMPARE, newval);
write_c0_compare(newval);
}
/*
* There are a lot of conceptually broken versions of the MIPS timer interrupt
* handler floating around. This one is rather different, but the algorithm
......@@ -62,108 +71,201 @@ static inline void ack_r4ktimer(unsigned long newval)
unsigned long wtimer;
void mips_timer_interrupt(struct pt_regs *regs)
{
int irq = 7;
int irq = 63;
unsigned long count;
int cpu = smp_processor_id();
irq_enter();
kstat_cpu(cpu).irqs[irq]++;
#ifdef CONFIG_PM
printk(KERN_ERR "Unexpected CP0 interrupt\n");
regs->cp0_status &= ~IE_IRQ5; /* disable CP0 interrupt */
return;
#endif
if (r4k_offset == 0)
goto null;
do {
count = read_c0_count();
timerhi += (count < timerlo); /* Wrap around */
timerlo = count;
kstat_cpu(0).irqs[irq]++;
do_timer(regs);
r4k_cur += r4k_offset;
ack_r4ktimer(r4k_cur);
} while (((unsigned long)read_32bit_cp0_register(CP0_COUNT)
} while (((unsigned long)read_c0_count()
- r4k_cur) < 0x7fffffff);
irq_exit();
if (softirq_pending(cpu))
do_softirq();
return;
null:
ack_r4ktimer(0);
}
/*
#ifdef CONFIG_PM
void counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long pc0;
int time_elapsed;
static int jiffie_drift = 0;
kstat_cpu(0).irqs[irq]++;
if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) {
/* should never happen! */
printk(KERN_WARNING "counter 0 w status eror\n");
return;
}
pc0 = au_readl(SYS_TOYREAD);
if (pc0 < last_match20) {
/* counter overflowed */
time_elapsed = (0xffffffff - last_match20) + pc0;
}
else {
time_elapsed = pc0 - last_match20;
}
while (time_elapsed > 0) {
do_timer(regs);
time_elapsed -= MATCH20_INC;
last_match20 += MATCH20_INC;
jiffie_drift++;
}
last_pc0 = pc0;
au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
au_sync();
/* our counter ticks at 10.009765625 ms/tick, we we're running
* almost 10uS too slow per tick.
*/
if (jiffie_drift >= 999) {
jiffie_drift -= 999;
do_timer(regs); /* increment jiffies by one */
}
}
#endif
/*
* Figure out the r4k offset, the amount to increment the compare
* register for each time tick.
* register for each time tick.
* Use the Programmable Counter 1 to do this.
*/
unsigned long cal_r4koff(void)
{
unsigned long count;
unsigned long cpu_pll;
unsigned long cpu_speed;
unsigned long start, end;
unsigned long counter;
int i;
int trim_divide = 16;
unsigned long flags;
counter = inl(PC_COUNTER_CNTRL);
outl(counter | PC_CNTRL_EN1, PC_COUNTER_CNTRL);
spin_lock_irqsave(&time_lock, flags);
while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_T1S);
outl(trim_divide-1, PC1_TRIM); /* RTC now ticks at 32.768/16 kHz */
while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_T1S);
counter = au_readl(SYS_COUNTER_CNTRL);
au_writel(counter | SYS_CNTRL_EN1, SYS_COUNTER_CNTRL);
while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_C1S);
outl (0, PC1_COUNTER_WRITE);
while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_C1S);
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
au_writel(trim_divide-1, SYS_RTCTRIM); /* RTC now ticks at 32.768/16 kHz */
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S);
start = inl(PC1_COUNTER_READ);
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
au_writel (0, SYS_TOYWRITE);
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
start = au_readl(SYS_RTCREAD);
start += 2;
/* wait for the beginning of a new tick */
while (inl(PC1_COUNTER_READ) < start);
while (au_readl(SYS_RTCREAD) < start);
/* Start r4k counter. */
write_32bit_cp0_register(CP0_COUNT, 0);
write_c0_count(0);
end = start + (32768 / trim_divide)/2; /* wait 0.5 seconds */
while (end > inl(PC1_COUNTER_READ));
while (end > au_readl(SYS_RTCREAD));
count = read_32bit_cp0_register(CP0_COUNT);
count = read_c0_count();
cpu_speed = count * 2;
uart_baud_base = (((cpu_speed) / 4) / 16);
mips_counter_frequency = count;
set_au1x00_uart_baud_base(((cpu_speed) / 4) / 16);
spin_unlock_irqrestore(&time_lock, flags);
return (cpu_speed / HZ);
}
static unsigned long __init get_mips_time(void)
void __init au1x_time_init(void)
{
return inl(PC0_COUNTER_READ);
}
void __init time_init(void)
{
unsigned int est_freq, flags;
unsigned int est_freq;
printk("calculating r4koff... ");
r4k_offset = cal_r4koff();
printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
//est_freq = 2*r4k_offset*HZ;
est_freq = r4k_offset*HZ;
//est_freq = 2*r4k_offset*HZ;
est_freq = r4k_offset*HZ;
est_freq += 5000; /* round */
est_freq -= est_freq%10000;
printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
(est_freq%1000000)*100/1000000);
r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
set_au1x00_speed(est_freq);
set_au1x00_lcd_clock(); // program the LCD clock
r4k_cur = (read_c0_count() + r4k_offset);
write_c0_compare(r4k_cur);
write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
set_cp0_status(ALLINTS);
/* no RTC on the pb1000 */
xtime.tv_sec = 0;
//xtime.tv_usec = 0;
/* Read time from the RTC chipset. */
write_seqlock_irqsave (&xtime_lock, flags);
xtime.tv_sec = get_mips_time();
xtime.tv_usec = 0;
write_sequnlock_irqrestore(&xtime_lock, flags);
#ifdef CONFIG_PM
/*
* setup counter 0, since it keeps ticking after a
* 'wait' instruction has been executed. The CP0 timer and
* counter 1 do NOT continue running after 'wait'
*
* It's too early to call request_irq() here, so we handle
* counter 0 interrupt as a special irq and it doesn't show
* up under /proc/interrupts.
*/
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
au_writel(0, SYS_TOYWRITE);
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
au_writel(au_readl(SYS_WAKEMSK) | (1<<8), SYS_WAKEMSK);
au_writel(~0, SYS_WAKESRC);
au_sync();
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
/* setup match20 to interrupt once every 10ms */
last_pc0 = last_match20 = au_readl(SYS_TOYREAD);
au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
au_sync();
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
startup_match20_interrupt();
#endif
//set_c0_status(ALLINTS);
au_sync();
}
/* This is for machines which generate the exact clock. */
#define USECS_PER_JIFFY (1000000/HZ)
#define USECS_PER_JIFFY_FRAC ((1000000ULL << 32) / HZ & 0xffffffff)
void __init au1x_timer_setup(struct irqaction *irq)
{
/* Cycle counter value at the previous timer interrupt.. */
}
static unsigned int timerhi = 0, timerlo = 0;
/* This is for machines which generate the exact clock. */
#define USECS_PER_JIFFY (1000000/HZ)
#define USECS_PER_JIFFY_FRAC (0x100000000*1000000/HZ&0xffffffff)
#ifndef CONFIG_PM
static unsigned long
div64_32(unsigned long v1, unsigned long v2, unsigned long v3)
{
......@@ -171,13 +273,30 @@ div64_32(unsigned long v1, unsigned long v2, unsigned long v3)
do_div64_32(r0, v1, v2, v3);
return r0;
}
#endif
/*
* FIXME: Does playing with the RP bit in c0_status interfere with this code?
*/
static unsigned long do_fast_gettimeoffset(void)
{
#ifdef CONFIG_PM
unsigned long pc0;
unsigned long offset;
pc0 = au_readl(SYS_TOYREAD);
if (pc0 < last_pc0) {
offset = 0xffffffff - last_pc0 + pc0;
printk("offset over: %x\n", (unsigned)offset);
}
else {
offset = (unsigned long)(((pc0 - last_pc0) * 305) / 10);
}
if ((pc0-last_pc0) > 2*MATCH20_INC) {
printk("huge offset %x, last_pc0 %x last_match20 %x pc0 %x\n",
(unsigned)offset, (unsigned)last_pc0,
(unsigned)last_match20, (unsigned)pc0);
}
au_sync();
return offset;
#else
u32 count;
unsigned long res, tmp;
unsigned long r0;
......@@ -206,7 +325,7 @@ static unsigned long do_fast_gettimeoffset(void)
}
/* Get last timer tick in absolute kernel time */
count = read_32bit_cp0_register(CP0_COUNT);
count = read_c0_count();
/* .. relative to previous jiffy (32 bits is enough) */
count -= timerlo;
......@@ -218,73 +337,12 @@ static unsigned long do_fast_gettimeoffset(void)
"r" (quotient));
/*
* Due to possible jiffies inconsistencies, we need to check
* Due to possible jiffies inconsistencies, we need to check
* the result so that we'll get a timer that is monotonic.
*/
if (res >= USECS_PER_JIFFY)
res = USECS_PER_JIFFY-1;
return res;
}
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
unsigned long seq;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
*tv = xtime;
tv->tv_usec += do_fast_gettimeoffset();
/*
* xtime is atomically updated in timer_bh. jiffies - wall_jiffies
* is nonzero if the timer bottom half hasnt executed yet.
*/
if (jiffies - wall_jiffies)
tv->tv_usec += USECS_PER_JIFFY;
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
}
}
void do_settimeofday(struct timeval *tv)
{
write_seqlock_irq (&xtime_lock);
/* This is revolting. We need to set the xtime.tv_usec correctly.
* However, the value in this location is is value at the last tick.
* Discover what correction gettimeofday would have done, and then
* undo it!
*/
tv->tv_usec -= do_fast_gettimeoffset();
if (tv->tv_usec < 0) {
tv->tv_usec += 1000000;
tv->tv_sec--;
}
xtime = *tv;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
write_sequnlock_irq (&xtime_lock);
}
/*
* The UART baud base is not known at compile time ... if
* we want to be able to use the same code on different
* speed CPUs.
*/
unsigned long get_au1000_uart_baud()
{
return uart_baud_base;
#endif
}
/*
* BRIEF MODULE DESCRIPTION
* Au1000 USB Device-Side (device layer)
*
* Copyright 2001-2002 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* stevel@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#define DEBUG
#include <linux/usb.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/au1000.h>
#include <asm/au1000_dma.h>
#include <asm/au1000_usbdev.h>
#ifdef DEBUG
#undef VDEBUG
#ifdef VDEBUG
#define vdbg(fmt, arg...) printk(KERN_DEBUG __FILE__ ": " fmt "\n" , ## arg)
#else
#define vdbg(fmt, arg...) do {} while (0)
#endif
#else
#define vdbg(fmt, arg...) do {} while (0)
#endif
#define MAX(a,b) (((a)>(b))?(a):(b))
#define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL)
#define EP_FIFO_DEPTH 8
typedef enum {
SETUP_STAGE = 0,
DATA_STAGE,
STATUS_STAGE
} ep0_stage_t;
typedef struct {
int read_fifo;
int write_fifo;
int ctrl_stat;
int read_fifo_status;
int write_fifo_status;
} endpoint_reg_t;
typedef struct {
usbdev_pkt_t *head;
usbdev_pkt_t *tail;
int count;
} pkt_list_t;
typedef struct {
int active;
struct usb_endpoint_descriptor *desc;
endpoint_reg_t *reg;
/* Only one of these are used, unless this is the control ep */
pkt_list_t inlist;
pkt_list_t outlist;
unsigned int indma, outdma; /* DMA channel numbers for IN, OUT */
/* following are extracted from endpoint descriptor for easy access */
int max_pkt_size;
int type;
int direction;
/* WE assign endpoint addresses! */
int address;
spinlock_t lock;
} endpoint_t;
static struct usb_dev {
endpoint_t ep[6];
ep0_stage_t ep0_stage;
struct usb_device_descriptor * dev_desc;
struct usb_interface_descriptor* if_desc;
struct usb_config_descriptor * conf_desc;
u8 * full_conf_desc;
struct usb_string_descriptor * str_desc[6];
/* callback to function layer */
void (*func_cb)(usbdev_cb_type_t type, unsigned long arg,
void *cb_data);
void* cb_data;
usbdev_state_t state; // device state
int suspended; // suspended flag
int address; // device address
int interface;
int num_ep;
u8 alternate_setting;
u8 configuration; // configuration value
int remote_wakeup_en;
} usbdev;
static endpoint_reg_t ep_reg[] = {
// FIFO's 0 and 1 are EP0 default control
{USBD_EP0RD, USBD_EP0WR, USBD_EP0CS, USBD_EP0RDSTAT, USBD_EP0WRSTAT },
{0},
// FIFO 2 is EP2, IN
{ -1, USBD_EP2WR, USBD_EP2CS, -1, USBD_EP2WRSTAT },
// FIFO 3 is EP3, IN
{ -1, USBD_EP3WR, USBD_EP3CS, -1, USBD_EP3WRSTAT },
// FIFO 4 is EP4, OUT
{USBD_EP4RD, -1, USBD_EP4CS, USBD_EP4RDSTAT, -1 },
// FIFO 5 is EP5, OUT
{USBD_EP5RD, -1, USBD_EP5CS, USBD_EP5RDSTAT, -1 }
};
static struct {
unsigned int id;
const char *str;
} ep_dma_id[] = {
{ DMA_ID_USBDEV_EP0_TX, "USBDev EP0 IN" },
{ DMA_ID_USBDEV_EP0_RX, "USBDev EP0 OUT" },
{ DMA_ID_USBDEV_EP2_TX, "USBDev EP2 IN" },
{ DMA_ID_USBDEV_EP3_TX, "USBDev EP3 IN" },
{ DMA_ID_USBDEV_EP4_RX, "USBDev EP4 OUT" },
{ DMA_ID_USBDEV_EP5_RX, "USBDev EP5 OUT" }
};
#define DIR_OUT 0
#define DIR_IN (1<<3)
#define CONTROL_EP USB_ENDPOINT_XFER_CONTROL
#define BULK_EP USB_ENDPOINT_XFER_BULK
static inline endpoint_t *
epaddr_to_ep(struct usb_dev* dev, int ep_addr)
{
if (ep_addr >= 0 && ep_addr < 2)
return &dev->ep[0];
if (ep_addr < 6)
return &dev->ep[ep_addr];
return NULL;
}
static const char* std_req_name[] = {
"GET_STATUS",
"CLEAR_FEATURE",
"RESERVED",
"SET_FEATURE",
"RESERVED",
"SET_ADDRESS",
"GET_DESCRIPTOR",
"SET_DESCRIPTOR",
"GET_CONFIGURATION",
"SET_CONFIGURATION",
"GET_INTERFACE",
"SET_INTERFACE",
"SYNCH_FRAME"
};
static inline const char*
get_std_req_name(int req)
{
return (req >= 0 && req <= 12) ? std_req_name[req] : "UNKNOWN";
}
#if 0
static void
dump_setup(struct usb_ctrlrequest* s)
{
dbg(__FUNCTION__ ": requesttype=%d", s->requesttype);
dbg(__FUNCTION__ ": request=%d %s", s->request,
get_std_req_name(s->request));
dbg(__FUNCTION__ ": value=0x%04x", s->wValue);
dbg(__FUNCTION__ ": index=%d", s->index);
dbg(__FUNCTION__ ": length=%d", s->length);
}
#endif
static inline usbdev_pkt_t *
alloc_packet(endpoint_t * ep, int data_size, void* data)
{
usbdev_pkt_t* pkt =
(usbdev_pkt_t *)kmalloc(sizeof(usbdev_pkt_t) + data_size,
ALLOC_FLAGS);
if (!pkt)
return NULL;
pkt->ep_addr = ep->address;
pkt->size = data_size;
pkt->status = 0;
pkt->next = NULL;
if (data)
memcpy(pkt->payload, data, data_size);
return pkt;
}
/*
* Link a packet to the tail of the enpoint's packet list.
* EP spinlock must be held when calling.
*/
static void
link_tail(endpoint_t * ep, pkt_list_t * list, usbdev_pkt_t * pkt)
{
if (!list->tail) {
list->head = list->tail = pkt;
list->count = 1;
} else {
list->tail->next = pkt;
list->tail = pkt;
list->count++;
}
}
/*
* Unlink and return a packet from the head of the given packet
* list. It is the responsibility of the caller to free the packet.
* EP spinlock must be held when calling.
*/
static usbdev_pkt_t *
unlink_head(pkt_list_t * list)
{
usbdev_pkt_t *pkt;
pkt = list->head;
if (!pkt || !list->count) {
return NULL;
}
list->head = pkt->next;
if (!list->head) {
list->head = list->tail = NULL;
list->count = 0;
} else
list->count--;
return pkt;
}
/*
* Create and attach a new packet to the tail of the enpoint's
* packet list. EP spinlock must be held when calling.
*/
static usbdev_pkt_t *
add_packet(endpoint_t * ep, pkt_list_t * list, int size)
{
usbdev_pkt_t *pkt = alloc_packet(ep, size, NULL);
if (!pkt)
return NULL;
link_tail(ep, list, pkt);
return pkt;
}
/*
* Unlink and free a packet from the head of the enpoint's
* packet list. EP spinlock must be held when calling.
*/
static inline void
free_packet(pkt_list_t * list)
{
kfree(unlink_head(list));
}
/* EP spinlock must be held when calling. */
static inline void
flush_pkt_list(pkt_list_t * list)
{
while (list->count)
free_packet(list);
}
/* EP spinlock must be held when calling */
static inline void
flush_write_fifo(endpoint_t * ep)
{
if (ep->reg->write_fifo_status >= 0) {
au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF |
USBDEV_FSTAT_OF,
ep->reg->write_fifo_status);
//udelay(100);
//au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,
// ep->reg->write_fifo_status);
}
}
/* EP spinlock must be held when calling */
static inline void
flush_read_fifo(endpoint_t * ep)
{
if (ep->reg->read_fifo_status >= 0) {
au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF |
USBDEV_FSTAT_OF,
ep->reg->read_fifo_status);
//udelay(100);
//au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,
// ep->reg->read_fifo_status);
}
}
/* EP spinlock must be held when calling. */
static void
endpoint_flush(endpoint_t * ep)
{
// First, flush all packets
flush_pkt_list(&ep->inlist);
flush_pkt_list(&ep->outlist);
// Now flush the endpoint's h/w FIFO(s)
flush_write_fifo(ep);
flush_read_fifo(ep);
}
/* EP spinlock must be held when calling. */
static void
endpoint_stall(endpoint_t * ep)
{
u32 cs;
warn(__FUNCTION__);
cs = au_readl(ep->reg->ctrl_stat) | USBDEV_CS_STALL;
au_writel(cs, ep->reg->ctrl_stat);
}
/* EP spinlock must be held when calling. */
static void
endpoint_unstall(endpoint_t * ep)
{
u32 cs;
warn(__FUNCTION__);
cs = au_readl(ep->reg->ctrl_stat) & ~USBDEV_CS_STALL;
au_writel(cs, ep->reg->ctrl_stat);
}
static void
endpoint_reset_datatoggle(endpoint_t * ep)
{
// FIXME: is this possible?
}
/* EP spinlock must be held when calling. */
static int
endpoint_fifo_read(endpoint_t * ep)
{
int read_count = 0;
u8 *bufptr;
usbdev_pkt_t *pkt = ep->outlist.tail;
if (!pkt)
return -EINVAL;
bufptr = &pkt->payload[pkt->size];
while (au_readl(ep->reg->read_fifo_status) & USBDEV_FSTAT_FCNT_MASK) {
*bufptr++ = au_readl(ep->reg->read_fifo) & 0xff;
read_count++;
pkt->size++;
}
return read_count;
}
#if 0
/* EP spinlock must be held when calling. */
static int
endpoint_fifo_write(endpoint_t * ep, int index)
{
int write_count = 0;
u8 *bufptr;
usbdev_pkt_t *pkt = ep->inlist.head;
if (!pkt)
return -EINVAL;
bufptr = &pkt->payload[index];
while ((au_readl(ep->reg->write_fifo_status) &
USBDEV_FSTAT_FCNT_MASK) < EP_FIFO_DEPTH) {
if (bufptr < pkt->payload + pkt->size) {
au_writel(*bufptr++, ep->reg->write_fifo);
write_count++;
} else {
break;
}
}
return write_count;
}
#endif
/*
* This routine is called to restart transmission of a packet.
* The endpoint's TSIZE must be set to the new packet's size,
* and DMA to the write FIFO needs to be restarted.
* EP spinlock must be held when calling.
*/
static void
kickstart_send_packet(endpoint_t * ep)
{
u32 cs;
usbdev_pkt_t *pkt = ep->inlist.head;
vdbg(__FUNCTION__ ": ep%d, pkt=%p", ep->address, pkt);
if (!pkt) {
err(__FUNCTION__ ": head=NULL! list->count=%d",
ep->inlist.count);
return;
}
dma_cache_wback_inv((unsigned long)pkt->payload, pkt->size);
/*
* make sure FIFO is empty
*/
flush_write_fifo(ep);
cs = au_readl(ep->reg->ctrl_stat) & USBDEV_CS_STALL;
cs |= (pkt->size << USBDEV_CS_TSIZE_BIT);
au_writel(cs, ep->reg->ctrl_stat);
if (get_dma_active_buffer(ep->indma) == 1) {
set_dma_count1(ep->indma, pkt->size);
set_dma_addr1(ep->indma, virt_to_phys(pkt->payload));
enable_dma_buffer1(ep->indma); // reenable
} else {
set_dma_count0(ep->indma, pkt->size);
set_dma_addr0(ep->indma, virt_to_phys(pkt->payload));
enable_dma_buffer0(ep->indma); // reenable
}
if (dma_halted(ep->indma))
start_dma(ep->indma);
}
/*
* This routine is called when a packet in the inlist has been
* completed. Frees the completed packet and starts sending the
* next. EP spinlock must be held when calling.
*/
static usbdev_pkt_t *
send_packet_complete(endpoint_t * ep)
{
usbdev_pkt_t *pkt = unlink_head(&ep->inlist);
if (pkt) {
pkt->status =
(au_readl(ep->reg->ctrl_stat) & USBDEV_CS_NAK) ?
PKT_STATUS_NAK : PKT_STATUS_ACK;
vdbg(__FUNCTION__ ": ep%d, %s pkt=%p, list count=%d",
ep->address, (pkt->status & PKT_STATUS_NAK) ?
"NAK" : "ACK", pkt, ep->inlist.count);
}
/*
* The write fifo should already be drained if things are
* working right, but flush it anyway just in case.
*/
flush_write_fifo(ep);
// begin transmitting next packet in the inlist
if (ep->inlist.count) {
kickstart_send_packet(ep);
}
return pkt;
}
/*
* Add a new packet to the tail of the given ep's packet
* inlist. The transmit complete interrupt frees packets from
* the head of this list. EP spinlock must be held when calling.
*/
static int
send_packet(struct usb_dev* dev, usbdev_pkt_t *pkt, int async)
{
pkt_list_t *list;
endpoint_t* ep;
if (!pkt || !(ep = epaddr_to_ep(dev, pkt->ep_addr)))
return -EINVAL;
if (!pkt->size)
return 0;
list = &ep->inlist;
if (!async && list->count) {
halt_dma(ep->indma);
flush_pkt_list(list);
}
link_tail(ep, list, pkt);
vdbg(__FUNCTION__ ": ep%d, pkt=%p, size=%d, list count=%d",
ep->address, pkt, pkt->size, list->count);
if (list->count == 1) {
/*
* if the packet count is one, it means the list was empty,
* and no more data will go out this ep until we kick-start
* it again.
*/
kickstart_send_packet(ep);
}
return pkt->size;
}
/*
* This routine is called to restart reception of a packet.
* EP spinlock must be held when calling.
*/
static void
kickstart_receive_packet(endpoint_t * ep)
{
usbdev_pkt_t *pkt;
// get and link a new packet for next reception
if (!(pkt = add_packet(ep, &ep->outlist, ep->max_pkt_size))) {
err(__FUNCTION__ ": could not alloc new packet");
return;
}
if (get_dma_active_buffer(ep->outdma) == 1) {
clear_dma_done1(ep->outdma);
set_dma_count1(ep->outdma, ep->max_pkt_size);
set_dma_count0(ep->outdma, 0);
set_dma_addr1(ep->outdma, virt_to_phys(pkt->payload));
enable_dma_buffer1(ep->outdma); // reenable
} else {
clear_dma_done0(ep->outdma);
set_dma_count0(ep->outdma, ep->max_pkt_size);
set_dma_count1(ep->outdma, 0);
set_dma_addr0(ep->outdma, virt_to_phys(pkt->payload));
enable_dma_buffer0(ep->outdma); // reenable
}
if (dma_halted(ep->outdma))
start_dma(ep->outdma);
}
/*
* This routine is called when a packet in the outlist has been
* completed (received) and we need to prepare for a new packet
* to be received. Halts DMA and computes the packet size from the
* remaining DMA counter. Then prepares a new packet for reception
* and restarts DMA. FIXME: what if another packet comes in
* on top of the completed packet? Counter would be wrong.
* EP spinlock must be held when calling.
*/
static usbdev_pkt_t *
receive_packet_complete(endpoint_t * ep)
{
usbdev_pkt_t *pkt = ep->outlist.tail;
u32 cs;
halt_dma(ep->outdma);
cs = au_readl(ep->reg->ctrl_stat);
if (!pkt)
return NULL;
pkt->size = ep->max_pkt_size - get_dma_residue(ep->outdma);
if (pkt->size)
dma_cache_inv((unsigned long)pkt->payload, pkt->size);
/*
* need to pull out any remaining bytes in the FIFO.
*/
endpoint_fifo_read(ep);
/*
* should be drained now, but flush anyway just in case.
*/
flush_read_fifo(ep);
pkt->status = (cs & USBDEV_CS_NAK) ? PKT_STATUS_NAK : PKT_STATUS_ACK;
if (ep->address == 0 && (cs & USBDEV_CS_SU))
pkt->status |= PKT_STATUS_SU;
vdbg(__FUNCTION__ ": ep%d, %s pkt=%p, size=%d",
ep->address, (pkt->status & PKT_STATUS_NAK) ?
"NAK" : "ACK", pkt, pkt->size);
kickstart_receive_packet(ep);
return pkt;
}
/*
****************************************************************************
* Here starts the standard device request handlers. They are
* all called by do_setup() via a table of function pointers.
****************************************************************************
*/
static ep0_stage_t
do_get_status(struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
switch (setup->bRequestType) {
case 0x80: // Device
// FIXME: send device status
break;
case 0x81: // Interface
// FIXME: send interface status
break;
case 0x82: // End Point
// FIXME: send endpoint status
break;
default:
// Invalid Command
endpoint_stall(&dev->ep[0]); // Stall End Point 0
break;
}
return STATUS_STAGE;
}
static ep0_stage_t
do_clear_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
switch (setup->bRequestType) {
case 0x00: // Device
if ((le16_to_cpu(setup->wValue) & 0xff) == 1)
dev->remote_wakeup_en = 0;
else
endpoint_stall(&dev->ep[0]);
break;
case 0x02: // End Point
if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
endpoint_t *ep =
epaddr_to_ep(dev,
le16_to_cpu(setup->wIndex) & 0xff);
endpoint_unstall(ep);
endpoint_reset_datatoggle(ep);
} else
endpoint_stall(&dev->ep[0]);
break;
}
return SETUP_STAGE;
}
static ep0_stage_t
do_reserved(struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
// Invalid request, stall End Point 0
endpoint_stall(&dev->ep[0]);
return SETUP_STAGE;
}
static ep0_stage_t
do_set_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
switch (setup->bRequestType) {
case 0x00: // Device
if ((le16_to_cpu(setup->wValue) & 0xff) == 1)
dev->remote_wakeup_en = 1;
else
endpoint_stall(&dev->ep[0]);
break;
case 0x02: // End Point
if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
endpoint_t *ep =
epaddr_to_ep(dev,
le16_to_cpu(setup->wIndex) & 0xff);
endpoint_stall(ep);
} else
endpoint_stall(&dev->ep[0]);
break;
}
return SETUP_STAGE;
}
static ep0_stage_t
do_set_address(struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
int new_state = dev->state;
int new_addr = le16_to_cpu(setup->wValue);
dbg(__FUNCTION__ ": our address=%d", new_addr);
if (new_addr > 127) {
// usb spec doesn't tell us what to do, so just go to
// default state
new_state = DEFAULT;
dev->address = 0;
} else if (dev->address != new_addr) {
dev->address = new_addr;
new_state = ADDRESS;
}
if (dev->state != new_state) {
dev->state = new_state;
/* inform function layer of usbdev state change */
dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);
}
return SETUP_STAGE;
}
static ep0_stage_t
do_get_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
int strnum, desc_len = le16_to_cpu(setup->wLength);
switch (le16_to_cpu(setup->wValue) >> 8) {
case USB_DT_DEVICE:
// send device descriptor!
desc_len = desc_len > dev->dev_desc->bLength ?
dev->dev_desc->bLength : desc_len;
dbg("sending device desc, size=%d", desc_len);
send_packet(dev, alloc_packet(&dev->ep[0], desc_len,
dev->dev_desc), 0);
break;
case USB_DT_CONFIG:
// If the config descr index in low-byte of
// setup->wValue is valid, send config descr,
// otherwise stall ep0.
if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
// send config descriptor!
if (desc_len <= USB_DT_CONFIG_SIZE) {
dbg("sending partial config desc, size=%d",
desc_len);
send_packet(dev,
alloc_packet(&dev->ep[0],
desc_len,
dev->conf_desc),
0);
} else {
int len = dev->conf_desc->wTotalLength;
dbg("sending whole config desc,"
" size=%d, our size=%d", desc_len, len);
desc_len = desc_len > len ? len : desc_len;
send_packet(dev,
alloc_packet(&dev->ep[0],
desc_len,
dev->full_conf_desc),
0);
}
} else
endpoint_stall(&dev->ep[0]);
break;
case USB_DT_STRING:
// If the string descr index in low-byte of setup->wValue
// is valid, send string descr, otherwise stall ep0.
strnum = le16_to_cpu(setup->wValue) & 0xff;
if (strnum >= 0 && strnum < 6) {
struct usb_string_descriptor *desc =
dev->str_desc[strnum];
desc_len = desc_len > desc->bLength ?
desc->bLength : desc_len;
dbg("sending string desc %d", strnum);
send_packet(dev,
alloc_packet(&dev->ep[0], desc_len,
desc), 0);
} else
endpoint_stall(&dev->ep[0]);
break;
default:
// Invalid request
err("invalid get desc=%d, stalled",
le16_to_cpu(setup->wValue) >> 8);
endpoint_stall(&dev->ep[0]); // Stall endpoint 0
break;
}
return STATUS_STAGE;
}
static ep0_stage_t
do_set_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
// TODO: implement
// there will be an OUT data stage (the descriptor to set)
return DATA_STAGE;
}
static ep0_stage_t
do_get_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
// send dev->configuration
dbg("sending config");
send_packet(dev, alloc_packet(&dev->ep[0], 1, &dev->configuration),
0);
return STATUS_STAGE;
}
static ep0_stage_t
do_set_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
// set active config to low-byte of setup->wValue
dev->configuration = le16_to_cpu(setup->wValue) & 0xff;
dbg("set config, config=%d", dev->configuration);
if (!dev->configuration && dev->state > DEFAULT) {
dev->state = ADDRESS;
/* inform function layer of usbdev state change */
dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);
} else if (dev->configuration == 1) {
dev->state = CONFIGURED;
/* inform function layer of usbdev state change */
dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);
} else {
// FIXME: "respond with request error" - how?
}
return SETUP_STAGE;
}
static ep0_stage_t
do_get_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
// interface must be zero.
if ((le16_to_cpu(setup->wIndex) & 0xff) || dev->state == ADDRESS) {
// FIXME: respond with "request error". how?
} else if (dev->state == CONFIGURED) {
// send dev->alternate_setting
dbg("sending alt setting");
send_packet(dev, alloc_packet(&dev->ep[0], 1,
&dev->alternate_setting), 0);
}
return STATUS_STAGE;
}
static ep0_stage_t
do_set_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
if (dev->state == ADDRESS) {
// FIXME: respond with "request error". how?
} else if (dev->state == CONFIGURED) {
dev->interface = le16_to_cpu(setup->wIndex) & 0xff;
dev->alternate_setting =
le16_to_cpu(setup->wValue) & 0xff;
// interface and alternate_setting must be zero
if (dev->interface || dev->alternate_setting) {
// FIXME: respond with "request error". how?
}
}
return SETUP_STAGE;
}
static ep0_stage_t
do_synch_frame(struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
// TODO
return SETUP_STAGE;
}
typedef ep0_stage_t (*req_method_t)(struct usb_dev* dev,
struct usb_ctrlrequest* setup);
/* Table of the standard device request handlers */
static const req_method_t req_method[] = {
do_get_status,
do_clear_feature,
do_reserved,
do_set_feature,
do_reserved,
do_set_address,
do_get_descriptor,
do_set_descriptor,
do_get_configuration,
do_set_configuration,
do_get_interface,
do_set_interface,
do_synch_frame
};
// SETUP packet request dispatcher
static void
do_setup (struct usb_dev* dev, struct usb_ctrlrequest* setup)
{
req_method_t m;
dbg(__FUNCTION__ ": req %d %s", setup->bRequestType,
get_std_req_name(setup->bRequestType));
if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD ||
(setup->bRequestType & USB_RECIP_MASK) != USB_RECIP_DEVICE) {
err(__FUNCTION__ ": invalid requesttype 0x%02x",
setup->bRequestType);
return;
}
if ((setup->bRequestType & 0x80) == USB_DIR_OUT && setup->wLength)
dbg(__FUNCTION__ ": OUT phase! length=%d", setup->wLength);
if (setup->bRequestType < sizeof(req_method)/sizeof(req_method_t))
m = req_method[setup->bRequestType];
else
m = do_reserved;
dev->ep0_stage = (*m)(dev, setup);
}
/*
* A SETUP, DATA0, or DATA1 packet has been received
* on the default control endpoint's fifo.
*/
static void
process_ep0_receive (struct usb_dev* dev)
{
endpoint_t *ep0 = &dev->ep[0];
usbdev_pkt_t *pkt;
spin_lock(&ep0->lock);
// complete packet and prepare a new packet
pkt = receive_packet_complete(ep0);
if (!pkt) {
// FIXME: should put a warn/err here.
spin_unlock(&ep0->lock);
return;
}
// unlink immediately from endpoint.
unlink_head(&ep0->outlist);
// override current stage if h/w says it's a setup packet
if (pkt->status & PKT_STATUS_SU)
dev->ep0_stage = SETUP_STAGE;
switch (dev->ep0_stage) {
case SETUP_STAGE:
vdbg("SU bit is %s in setup stage",
(pkt->status & PKT_STATUS_SU) ? "set" : "not set");
if (pkt->size == sizeof(struct usb_ctrlrequest)) {
#ifdef VDEBUG
if (pkt->status & PKT_STATUS_ACK)
vdbg("received SETUP");
else
vdbg("received NAK SETUP");
#endif
do_setup(dev, (struct usb_ctrlrequest*)pkt->payload);
} else
err(__FUNCTION__ ": wrong size SETUP received");
break;
case DATA_STAGE:
/*
* this setup has an OUT data stage. Of the standard
* device requests, only set_descriptor has this stage,
* so this packet is that descriptor. TODO: drop it for
* now, set_descriptor not implemented.
*
* Need to place a byte in the write FIFO here, to prepare
* to send a zero-length DATA ack packet to the host in the
* STATUS stage.
*/
au_writel(0, ep0->reg->write_fifo);
dbg("received OUT stage DATAx on EP0, size=%d", pkt->size);
dev->ep0_stage = SETUP_STAGE;
break;
case STATUS_STAGE:
// this setup had an IN data stage, and host is ACK'ing
// the packet we sent during that stage.
if (pkt->size != 0)
warn("received non-zero ACK on EP0??");
#ifdef VDEBUG
else
vdbg("received ACK on EP0");
#endif
dev->ep0_stage = SETUP_STAGE;
break;
}
spin_unlock(&ep0->lock);
// we're done processing the packet, free it
kfree(pkt);
}
/*
* A DATA0/1 packet has been received on one of the OUT endpoints (4 or 5)
*/
static void
process_ep_receive (struct usb_dev* dev, endpoint_t *ep)
{
usbdev_pkt_t *pkt;
spin_lock(&ep->lock);
pkt = receive_packet_complete(ep);
spin_unlock(&ep->lock);
dev->func_cb(CB_PKT_COMPLETE, (unsigned long)pkt, dev->cb_data);
}
/* This ISR handles the receive complete and suspend events */
static void
req_sus_intr (int irq, void *dev_id, struct pt_regs *regs)
{
struct usb_dev *dev = (struct usb_dev *) dev_id;
u32 status;
status = au_readl(USBD_INTSTAT);
au_writel(status, USBD_INTSTAT); // ack'em
if (status & (1<<0))
process_ep0_receive(dev);
if (status & (1<<4))
process_ep_receive(dev, &dev->ep[4]);
if (status & (1<<5))
process_ep_receive(dev, &dev->ep[5]);
}
/* This ISR handles the DMA done events on EP0 */
static void
dma_done_ep0_intr(int irq, void *dev_id, struct pt_regs *regs)
{
struct usb_dev *dev = (struct usb_dev *) dev_id;
usbdev_pkt_t* pkt;
endpoint_t *ep0 = &dev->ep[0];
u32 cs0, buff_done;
spin_lock(&ep0->lock);
cs0 = au_readl(ep0->reg->ctrl_stat);
// first check packet transmit done
if ((buff_done = get_dma_buffer_done(ep0->indma)) != 0) {
// transmitted a DATAx packet during DATA stage
// on control endpoint 0
// clear DMA done bit
if (buff_done & DMA_D0)
clear_dma_done0(ep0->indma);
if (buff_done & DMA_D1)
clear_dma_done1(ep0->indma);
pkt = send_packet_complete(ep0);
if (pkt)
kfree(pkt);
}
/*
* Now check packet receive done. Shouldn't get these,
* the receive packet complete intr should happen
* before the DMA done intr occurs.
*/
if ((buff_done = get_dma_buffer_done(ep0->outdma)) != 0) {
// clear DMA done bit
if (buff_done & DMA_D0)
clear_dma_done0(ep0->outdma);
if (buff_done & DMA_D1)
clear_dma_done1(ep0->outdma);
//process_ep0_receive(dev);
}
spin_unlock(&ep0->lock);
}
/* This ISR handles the DMA done events on endpoints 2,3,4,5 */
static void
dma_done_ep_intr(int irq, void *dev_id, struct pt_regs *regs)
{
struct usb_dev *dev = (struct usb_dev *) dev_id;
int i;
for (i = 2; i < 6; i++) {
u32 buff_done;
usbdev_pkt_t* pkt;
endpoint_t *ep = &dev->ep[i];
if (!ep->active) continue;
spin_lock(&ep->lock);
if (ep->direction == USB_DIR_IN) {
buff_done = get_dma_buffer_done(ep->indma);
if (buff_done != 0) {
// transmitted a DATAx pkt on the IN ep
// clear DMA done bit
if (buff_done & DMA_D0)
clear_dma_done0(ep->indma);
if (buff_done & DMA_D1)
clear_dma_done1(ep->indma);
pkt = send_packet_complete(ep);
spin_unlock(&ep->lock);
dev->func_cb(CB_PKT_COMPLETE,
(unsigned long)pkt,
dev->cb_data);
spin_lock(&ep->lock);
}
} else {
/*
* Check packet receive done (OUT ep). Shouldn't get
* these, the rx packet complete intr should happen
* before the DMA done intr occurs.
*/
buff_done = get_dma_buffer_done(ep->outdma);
if (buff_done != 0) {
// received a DATAx pkt on the OUT ep
// clear DMA done bit
if (buff_done & DMA_D0)
clear_dma_done0(ep->outdma);
if (buff_done & DMA_D1)
clear_dma_done1(ep->outdma);
//process_ep_receive(dev, ep);
}
}
spin_unlock(&ep->lock);
}
}
/***************************************************************************
* Here begins the external interface functions
***************************************************************************
*/
/*
* allocate a new packet
*/
int
usbdev_alloc_packet(int ep_addr, int data_size, usbdev_pkt_t** pkt)
{
endpoint_t * ep = epaddr_to_ep(&usbdev, ep_addr);
usbdev_pkt_t* lpkt = NULL;
if (!ep || !ep->active || ep->address < 2)
return -ENODEV;
if (data_size > ep->max_pkt_size)
return -EINVAL;
lpkt = *pkt = alloc_packet(ep, data_size, NULL);
if (!lpkt)
return -ENOMEM;
return 0;
}
/*
* packet send
*/
int
usbdev_send_packet(int ep_addr, usbdev_pkt_t * pkt)
{
unsigned long flags;
int count;
endpoint_t * ep;
if (!pkt || !(ep = epaddr_to_ep(&usbdev, pkt->ep_addr)) ||
!ep->active || ep->address < 2)
return -ENODEV;
if (ep->direction != USB_DIR_IN)
return -EINVAL;
spin_lock_irqsave(&ep->lock, flags);
count = send_packet(&usbdev, pkt, 1);
spin_unlock_irqrestore(&ep->lock, flags);
return count;
}
/*
* packet receive
*/
int
usbdev_receive_packet(int ep_addr, usbdev_pkt_t** pkt)
{
unsigned long flags;
usbdev_pkt_t* lpkt = NULL;
endpoint_t *ep = epaddr_to_ep(&usbdev, ep_addr);
if (!ep || !ep->active || ep->address < 2)
return -ENODEV;
if (ep->direction != USB_DIR_OUT)
return -EINVAL;
spin_lock_irqsave(&ep->lock, flags);
if (ep->outlist.count > 1)
lpkt = unlink_head(&ep->outlist);
spin_unlock_irqrestore(&ep->lock, flags);
if (!lpkt) {
/* no packet available */
*pkt = NULL;
return -ENODATA;
}
*pkt = lpkt;
return lpkt->size;
}
/*
* return total queued byte count on the endpoint.
*/
int
usbdev_get_byte_count(int ep_addr)
{
unsigned long flags;
pkt_list_t *list;
usbdev_pkt_t *scan;
int count = 0;
endpoint_t * ep = epaddr_to_ep(&usbdev, ep_addr);
if (!ep || !ep->active || ep->address < 2)
return -ENODEV;
if (ep->direction == USB_DIR_IN) {
list = &ep->inlist;
spin_lock_irqsave(&ep->lock, flags);
for (scan = list->head; scan; scan = scan->next)
count += scan->size;
spin_unlock_irqrestore(&ep->lock, flags);
} else {
list = &ep->outlist;
spin_lock_irqsave(&ep->lock, flags);
if (list->count > 1) {
for (scan = list->head; scan != list->tail;
scan = scan->next)
count += scan->size;
}
spin_unlock_irqrestore(&ep->lock, flags);
}
return count;
}
void
usbdev_exit(void)
{
endpoint_t *ep;
int i;
au_writel(0, USBD_INTEN); // disable usb dev ints
au_writel(0, USBD_ENABLE); // disable usb dev
free_irq(AU1000_USB_DEV_REQ_INT, &usbdev);
free_irq(AU1000_USB_DEV_SUS_INT, &usbdev);
// free all control endpoint resources
ep = &usbdev.ep[0];
free_au1000_dma(ep->indma);
free_au1000_dma(ep->outdma);
endpoint_flush(ep);
// free ep resources
for (i = 2; i < 6; i++) {
ep = &usbdev.ep[i];
if (!ep->active) continue;
if (ep->direction == USB_DIR_IN) {
free_au1000_dma(ep->indma);
} else {
free_au1000_dma(ep->outdma);
}
endpoint_flush(ep);
}
if (usbdev.full_conf_desc)
kfree(usbdev.full_conf_desc);
}
int
usbdev_init(struct usb_device_descriptor* dev_desc,
struct usb_config_descriptor* config_desc,
struct usb_interface_descriptor* if_desc,
struct usb_endpoint_descriptor* ep_desc,
struct usb_string_descriptor* str_desc[],
void (*cb)(usbdev_cb_type_t, unsigned long, void *),
void* cb_data)
{
endpoint_t *ep0;
int i, ret=0;
u8* fcd;
if (dev_desc->bNumConfigurations > 1 ||
config_desc->bNumInterfaces > 1 ||
if_desc->bNumEndpoints > 4) {
err("Only one config, one i/f, and no more "
"than 4 ep's allowed");
ret = -EINVAL;
goto out;
}
if (!cb) {
err("Function-layer callback required");
ret = -EINVAL;
goto out;
}
if (dev_desc->bMaxPacketSize0 != USBDEV_EP0_MAX_PACKET_SIZE) {
warn("EP0 Max Packet size must be %d",
USBDEV_EP0_MAX_PACKET_SIZE);
dev_desc->bMaxPacketSize0 = USBDEV_EP0_MAX_PACKET_SIZE;
}
memset(&usbdev, 0, sizeof(struct usb_dev));
usbdev.state = DEFAULT;
usbdev.dev_desc = dev_desc;
usbdev.if_desc = if_desc;
usbdev.conf_desc = config_desc;
for (i=0; i<6; i++)
usbdev.str_desc[i] = str_desc[i];
usbdev.func_cb = cb;
usbdev.cb_data = cb_data;
/* Initialize default control endpoint */
ep0 = &usbdev.ep[0];
ep0->active = 1;
ep0->type = CONTROL_EP;
ep0->max_pkt_size = USBDEV_EP0_MAX_PACKET_SIZE;
spin_lock_init(&ep0->lock);
ep0->desc = NULL; // ep0 has no descriptor
ep0->address = 0;
ep0->direction = 0;
ep0->reg = &ep_reg[0];
/* Initialize the other requested endpoints */
for (i = 0; i < if_desc->bNumEndpoints; i++) {
struct usb_endpoint_descriptor* epd = &ep_desc[i];
endpoint_t *ep;
if ((epd->bEndpointAddress & 0x80) == USB_DIR_IN) {
ep = &usbdev.ep[2];
ep->address = 2;
if (ep->active) {
ep = &usbdev.ep[3];
ep->address = 3;
if (ep->active) {
err("too many IN ep's requested");
ret = -ENODEV;
goto out;
}
}
} else {
ep = &usbdev.ep[4];
ep->address = 4;
if (ep->active) {
ep = &usbdev.ep[5];
ep->address = 5;
if (ep->active) {
err("too many OUT ep's requested");
ret = -ENODEV;
goto out;
}
}
}
ep->active = 1;
epd->bEndpointAddress &= ~0x0f;
epd->bEndpointAddress |= (u8)ep->address;
ep->direction = epd->bEndpointAddress & 0x80;
ep->type = epd->bmAttributes & 0x03;
ep->max_pkt_size = epd->wMaxPacketSize;
spin_lock_init(&ep->lock);
ep->desc = epd;
ep->reg = &ep_reg[ep->address];
}
/*
* initialize the full config descriptor
*/
usbdev.full_conf_desc = fcd = kmalloc(config_desc->wTotalLength,
ALLOC_FLAGS);
if (!fcd) {
err("failed to alloc full config descriptor");
ret = -ENOMEM;
goto out;
}
memcpy(fcd, config_desc, USB_DT_CONFIG_SIZE);
fcd += USB_DT_CONFIG_SIZE;
memcpy(fcd, if_desc, USB_DT_INTERFACE_SIZE);
fcd += USB_DT_INTERFACE_SIZE;
for (i = 0; i < if_desc->bNumEndpoints; i++) {
memcpy(fcd, &ep_desc[i], USB_DT_ENDPOINT_SIZE);
fcd += USB_DT_ENDPOINT_SIZE;
}
/* Now we're ready to enable the controller */
au_writel(0x0002, USBD_ENABLE);
udelay(100);
au_writel(0x0003, USBD_ENABLE);
udelay(100);
/* build and send config table based on ep descriptors */
for (i = 0; i < 6; i++) {
endpoint_t *ep;
if (i == 1)
continue; // skip dummy ep
ep = &usbdev.ep[i];
if (ep->active) {
au_writel((ep->address << 4) | 0x04, USBD_CONFIG);
au_writel(((ep->max_pkt_size & 0x380) >> 7) |
(ep->direction >> 4) | (ep->type << 4),
USBD_CONFIG);
au_writel((ep->max_pkt_size & 0x7f) << 1, USBD_CONFIG);
au_writel(0x00, USBD_CONFIG);
au_writel(ep->address, USBD_CONFIG);
} else {
u8 dir = (i==2 || i==3) ? DIR_IN : DIR_OUT;
au_writel((i << 4) | 0x04, USBD_CONFIG);
au_writel(((16 & 0x380) >> 7) | dir |
(BULK_EP << 4), USBD_CONFIG);
au_writel((16 & 0x7f) << 1, USBD_CONFIG);
au_writel(0x00, USBD_CONFIG);
au_writel(i, USBD_CONFIG);
}
}
/*
* Enable Receive FIFO Complete interrupts only. Transmit
* complete is being handled by the DMA done interrupts.
*/
au_writel(0x31, USBD_INTEN);
/*
* Controller is now enabled, request DMA and IRQ
* resources.
*/
/* request the USB device transfer complete interrupt */
if (request_irq(AU1000_USB_DEV_REQ_INT, req_sus_intr, SA_INTERRUPT,
"USBdev req", &usbdev)) {
err("Can't get device request intr");
ret = -ENXIO;
goto out;
}
/* request the USB device suspend interrupt */
if (request_irq(AU1000_USB_DEV_SUS_INT, req_sus_intr, SA_INTERRUPT,
"USBdev sus", &usbdev)) {
err("Can't get device suspend intr");
ret = -ENXIO;
goto out;
}
/* Request EP0 DMA and IRQ */
if ((ep0->indma = request_au1000_dma(ep_dma_id[0].id,
ep_dma_id[0].str,
dma_done_ep0_intr,
SA_INTERRUPT,
&usbdev)) < 0) {
err("Can't get %s DMA", ep_dma_id[0].str);
ret = -ENXIO;
goto out;
}
if ((ep0->outdma = request_au1000_dma(ep_dma_id[1].id,
ep_dma_id[1].str,
NULL, 0, NULL)) < 0) {
err("Can't get %s DMA", ep_dma_id[1].str);
ret = -ENXIO;
goto out;
}
// Flush the ep0 buffers and FIFOs
endpoint_flush(ep0);
// start packet reception on ep0
kickstart_receive_packet(ep0);
/* Request DMA and IRQ for the other endpoints */
for (i = 2; i < 6; i++) {
endpoint_t *ep = &usbdev.ep[i];
if (!ep->active)
continue;
// Flush the endpoint buffers and FIFOs
endpoint_flush(ep);
if (ep->direction == USB_DIR_IN) {
ep->indma =
request_au1000_dma(ep_dma_id[ep->address].id,
ep_dma_id[ep->address].str,
dma_done_ep_intr,
SA_INTERRUPT,
&usbdev);
if (ep->indma < 0) {
err("Can't get %s DMA",
ep_dma_id[ep->address].str);
ret = -ENXIO;
goto out;
}
} else {
ep->outdma =
request_au1000_dma(ep_dma_id[ep->address].id,
ep_dma_id[ep->address].str,
NULL, 0, NULL);
if (ep->outdma < 0) {
err("Can't get %s DMA",
ep_dma_id[ep->address].str);
ret = -ENXIO;
goto out;
}
// start packet reception on OUT endpoint
kickstart_receive_packet(ep);
}
}
out:
if (ret)
usbdev_exit();
return ret;
}
EXPORT_SYMBOL(usbdev_init);
EXPORT_SYMBOL(usbdev_exit);
EXPORT_SYMBOL(usbdev_alloc_packet);
EXPORT_SYMBOL(usbdev_receive_packet);
EXPORT_SYMBOL(usbdev_send_packet);
EXPORT_SYMBOL(usbdev_get_byte_count);
#
# Copyright 2000 MontaVista Software Inc.
# Author: MontaVista Software, Inc.
# ppopov@mvista.com or source@mvista.com
#
# Makefile for the Alchemy Semiconductor PB1000 board.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
.S.s:
$(CPP) $(CFLAGS) $< -o $*.s
.S.o:
$(CC) $(CFLAGS) -c $< -o $*.o
O_TARGET := db1x00.o
obj-y := init.o setup.o
/*
*
* BRIEF MODULE DESCRIPTION
* PB1000 board setup
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
int prom_argc;
char **prom_argv, **prom_envp;
extern void __init prom_init_cmdline(void);
extern char *prom_getenv(char *envname);
const char *get_system_type(void)
{
return "Alchemy Db1000";
}
int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
{
unsigned char *memsize_str;
unsigned long memsize;
prom_argc = argc;
prom_argv = argv;
prom_envp = envp;
mips_machgroup = MACH_GROUP_ALCHEMY;
mips_machtype = MACH_DB1000; /* set the platform # */
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
if (!memsize_str) {
memsize = 0x04000000;
} else {
memsize = simple_strtol(memsize_str, NULL, 0);
}
add_memory_region(0, memsize, BOOT_MEM_RAM);
return 0;
}
/*
*
* BRIEF MODULE DESCRIPTION
* Alchemy Db1000 board setup.
*
* Copyright 2000 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/mc146818rtc.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/keyboard.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/pgtable.h>
#include <asm/au1000.h>
#include <asm/db1x00.h>
#ifdef CONFIG_BLK_DEV_INITRD
extern unsigned long initrd_start, initrd_end;
extern void * __rd_start, * __rd_end;
#endif
#ifdef CONFIG_BLK_DEV_IDE
extern struct ide_ops std_ide_ops;
extern struct ide_ops *ide_ops;
#endif
extern struct rtc_ops no_rtc_ops;
extern char * __init prom_getcmdline(void);
extern void au1000_restart(char *);
extern void au1000_halt(void);
extern void au1000_power_off(void);
extern struct resource ioport_resource;
extern struct resource iomem_resource;
#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_SOC_AU1500)
extern phys_t (*fixup_bigphys_addr)(phys_t phys_addr, phys_t size);
static phys_t db_fixup_bigphys_addr(phys_t phys_addr, phys_t size);
#endif
void __init au1x00_setup(void)
{
char *argptr;
u32 pin_func, static_cfg0;
u32 sys_freqctrl, sys_clksrc;
u32 prid = read_c0_prid();
argptr = prom_getcmdline();
/* Various early Au1000 Errata corrected by this */
set_c0_config(1<<19); /* Config[OD] */
#ifdef CONFIG_AU1X00_SERIAL_CONSOLE
if ((argptr = strstr(argptr, "console=")) == NULL) {
argptr = prom_getcmdline();
strcat(argptr, " console=ttyS0,115200");
}
#endif
#ifdef CONFIG_FB_AU1100
if ((argptr = strstr(argptr, "video=")) == NULL) {
argptr = prom_getcmdline();
/* default panel */
//strcat(argptr, " video=au1100fb:panel:Sharp_320x240_16");
strcat(argptr, " video=au1100fb:panel:s10,nohwcursor");
}
#endif
#if defined(CONFIG_SOUND_AU1X00) && !defined(CONFIG_SOC_AU1000)
// au1000 does not support vra, au1500 and au1100 do
strcat(argptr, " au1000_audio=vra");
argptr = prom_getcmdline();
#endif
rtc_ops = &no_rtc_ops;
_machine_restart = au1000_restart;
_machine_halt = au1000_halt;
_machine_power_off = au1000_power_off;
#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_SOC_AU1500)
fixup_bigphys_addr = db_fixup_bigphys_addr;
#endif
// IO/MEM resources.
set_io_port_base(0);
#ifdef CONFIG_SOC_AU1500
ioport_resource.start = 0x00000000;
#else
/* don't allow any legacy ports probing */
ioport_resource.start = 0x10000000;
#endif
ioport_resource.end = 0xffffffff;
iomem_resource.start = 0x10000000;
iomem_resource.end = 0xffffffff;
#ifdef CONFIG_BLK_DEV_INITRD
ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
initrd_start = (unsigned long)&__rd_start;
initrd_end = (unsigned long)&__rd_end;
#endif
//
// NOTE:
//
// YAMON (specifically reset_db1500.s) enables 32khz osc
// YAMON (specifically reset_db1x00.s) setups all clocking and GPIOs
// YAMON (specifically reset_db1500.s) setups all PCI
//
#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
#ifdef CONFIG_USB_OHCI
if ((argptr = strstr(argptr, "usb_ohci=")) == NULL) {
char usb_args[80];
argptr = prom_getcmdline();
memset(usb_args, 0, sizeof(usb_args));
sprintf(usb_args, " usb_ohci=base:0x%x,len:0x%x,irq:%d",
USB_OHCI_BASE, USB_OHCI_LEN, AU1000_USB_HOST_INT);
strcat(argptr, usb_args);
}
#endif
#ifdef CONFIG_USB_OHCI
// enable host controller and wait for reset done
au_writel(0x08, USB_HOST_CONFIG);
udelay(1000);
au_writel(0x0E, USB_HOST_CONFIG);
udelay(1000);
au_readl(USB_HOST_CONFIG); // throw away first read
while (!(au_readl(USB_HOST_CONFIG) & 0x10))
au_readl(USB_HOST_CONFIG);
#endif
#ifdef CONFIG_AU1X00_USB_DEVICE
// 2nd USB port is USB device
pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
au_writel(pin_func, SYS_PINFUNC);
#endif
#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
#ifdef CONFIG_FB
// Needed if PCI video card in use
conswitchp = &dummy_con;
#endif
#ifndef CONFIG_SERIAL_NONSTANDARD
/* don't touch the default serial console */
au_writel(0, UART_ADDR + UART_CLK);
#endif
//au_writel(0, UART3_ADDR + UART_CLK);
#ifdef CONFIG_BLK_DEV_IDE
ide_ops = &std_ide_ops;
#endif
#if 0
//// FIX!!! must be valid for au1000, au1500 and au1100
/* Enable Au1000 BCLK switching */
switch (prid & 0x000000FF)
{
case 0x00: /* DA */
case 0x01: /* HA */
case 0x02: /* HB */
break;
default: /* HC and newer */
au_writel(0x00000060, 0xb190003c);
break;
}
#endif
au_writel(0, 0xAE000010); /* turn off pcmcia power */
#ifdef CONFIG_MIPS_DB1000
printk("AMD Alchemy Au1000/Db1000 Board\n");
#endif
#ifdef CONFIG_MIPS_DB1500
printk("AMD Alchemy Au1500/Db1500 Board\n");
#endif
#ifdef CONFIG_MIPS_DB1100
printk("AMD Alchemy Au1100/Db1100 Board\n");
#endif
}
#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_SOC_AU1500)
static phys_t db_fixup_bigphys_addr(phys_t phys_addr, phys_t size)
{
u32 pci_start = (u32)Au1500_PCI_MEM_START;
u32 pci_end = (u32)Au1500_PCI_MEM_END;
/* Don't fixup 36 bit addresses */
if ((phys_addr >> 32) != 0) return phys_addr;
/* check for pci memory window */
if ((phys_addr >= pci_start) && ((phys_addr + size) < pci_end)) {
return (phys_t)((phys_addr - pci_start) +
Au1500_PCI_MEM_START);
}
else
return phys_addr;
}
#endif
......@@ -5,5 +5,13 @@
#
# Makefile for the Alchemy Semiconductor PB1000 board.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
USE_STANDARD_AS_RULE := true
O_TARGET := pb1000.o
obj-y := init.o setup.o
......@@ -33,27 +33,39 @@
#include <linux/bootmem.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
extern int prom_argc;
extern char **prom_argv, **prom_envp;
int prom_argc;
char **prom_argv, **prom_envp;
extern void __init prom_init_cmdline(void);
extern char *prom_getenv(char *envname);
const char *get_system_type(void)
{
return "Alchemy Pb1000";
}
int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
{
unsigned char *memsize_str;
unsigned long memsize;
prom_argc = argc;
prom_argv = argv;
prom_envp = envp;
mips_machgroup = MACH_GROUP_ALCHEMY;
mips_machtype = MACH_PB1000;
mips_machtype = MACH_PB1000;
prom_init_cmdline();
add_memory_region(1, 64 << 20, BOOT_MEM_RAM);
memsize_str = prom_getenv("memsize");
if (!memsize_str) {
memsize = 0x04000000;
} else {
memsize = simple_strtol(memsize_str, NULL, 0);
}
add_memory_region(0, memsize, BOOT_MEM_RAM);
return 0;
}
/*
*
* BRIEF MODULE DESCRIPTION
* Au1000-based board setup.
* Alchemy Pb1000 board setup.
*
* Copyright 2000 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
......@@ -31,88 +31,271 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/mc146818rtc.h>
#include <linux/major.h>
#include <linux/kdev_t.h>
#include <linux/root_dev.h>
#include <linux/delay.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/pgtable.h>
#include <asm/au1000.h>
#include <asm/pb1000.h>
#if defined(CONFIG_AU1000_SERIAL_CONSOLE)
extern void console_setup(char *, int *);
#ifdef CONFIG_USB_OHCI
// Enable the workaround for the OHCI DoneHead
// register corruption problem.
#define CONFIG_AU1000_OHCI_FIX
#endif
#if defined(CONFIG_AU1X00_SERIAL_CONSOLE)
char serial_console[20];
#endif
void (*__wbflush) (void);
#ifdef CONFIG_BLK_DEV_INITRD
extern unsigned long initrd_start, initrd_end;
extern void * __rd_start, * __rd_end;
#endif
#ifdef CONFIG_BLK_DEV_IDE
extern struct ide_ops std_ide_ops;
extern struct ide_ops *ide_ops;
#endif
extern struct rtc_ops no_rtc_ops;
extern char * __init prom_getcmdline(void);
extern void au1000_restart(void);
extern void au1000_restart(char *);
extern void au1000_halt(void);
extern void au1000_power_off(void);
extern struct resource ioport_resource;
extern struct resource iomem_resource;
struct {
struct resource ram;
struct resource io;
struct resource sram;
struct resource flash;
struct resource boot;
struct resource pcmcia;
struct resource lcd;
} au1000_resources = {
{ "RAM", 0, 0x3FFFFFF, IORESOURCE_MEM },
{ "I/O", 0x10000000, 0x119FFFFF },
{ "SRAM", 0x1e000000, 0x1E03FFFF },
{ "System Flash", 0x1F800000, 0x1FBFFFFF },
{ "Boot ROM", 0x1FC00000, 0x1FFFFFFF },
{ "PCMCIA", 0x20000000, 0x27FFFFFF },
{ "LCD", 0x60000000, 0x603FFFFF },
};
void au1000_wbflush(void)
{
__asm__ volatile ("sync");
}
void __init au1000_setup(void)
void __init au1x00_setup(void)
{
char *argptr;
u32 pin_func, static_cfg0;
u32 sys_freqctrl, sys_clksrc;
u32 prid = read_c0_prid();
argptr = prom_getcmdline();
#ifdef CONFIG_AU1000_SERIAL_CONSOLE
if ((argptr = strstr(argptr, "console=ttyS0")) == NULL) {
/* Various early Au1000 Errata corrected by this */
set_c0_config(1<<19); /* Config[OD] */
#ifdef CONFIG_AU1X00_SERIAL_CONSOLE
if ((argptr = strstr(argptr, "console=")) == NULL) {
argptr = prom_getcmdline();
strcat(argptr, " console=ttyS0,115200");
}
#endif
#endif
//set_cp0_status(ST0_FR,0);
rtc_ops = &no_rtc_ops;
__wbflush = au1000_wbflush;
_machine_restart = au1000_restart;
_machine_halt = au1000_halt;
_machine_power_off = au1000_power_off;
/*
* IO/MEM resources.
*/
mips_io_port_base = KSEG1;
ioport_resource.start = au1000_resources.io.start;
ioport_resource.end = au1000_resources.lcd.end;
// IO/MEM resources.
set_io_port_base(0);
ioport_resource.start = 0x10000000;
ioport_resource.end = 0xffffffff;
iomem_resource.start = 0x10000000;
iomem_resource.end = 0xffffffff;
#ifdef CONFIG_BLK_DEV_INITRD
ROOT_DEV = Root_RAM0;
initrd_start = (unsigned long)&__rd_start;
initrd_end = (unsigned long)&__rd_end;
#endif
outl(PC_CNTRL_E0 | PC_CNTRL_EN0 | PC_CNTRL_EN0, PC_COUNTER_CNTRL);
while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_T0S);
outl(0x8000-1, PC0_TRIM);
// set AUX clock to 12MHz * 8 = 96 MHz
au_writel(8, SYS_AUXPLL);
au_writel(0, SYS_PINSTATERD);
udelay(100);
printk("Alchemy Semi PB1000 Board\n");
printk("Au1000/PB1000 port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n");
}
#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
#ifdef CONFIG_USB_OHCI
if ((argptr = strstr(argptr, "usb_ohci=")) == NULL) {
char usb_args[80];
argptr = prom_getcmdline();
memset(usb_args, 0, sizeof(usb_args));
sprintf(usb_args, " usb_ohci=base:0x%x,len:0x%x,irq:%d",
USB_OHCI_BASE, USB_OHCI_LEN, AU1000_USB_HOST_INT);
strcat(argptr, usb_args);
}
#endif
/* zero and disable FREQ2 */
sys_freqctrl = au_readl(SYS_FREQCTRL0);
sys_freqctrl &= ~0xFFF00000;
au_writel(sys_freqctrl, SYS_FREQCTRL0);
/* zero and disable USBH/USBD clocks */
sys_clksrc = au_readl(SYS_CLKSRC);
sys_clksrc &= ~0x00007FE0;
au_writel(sys_clksrc, SYS_CLKSRC);
sys_freqctrl = au_readl(SYS_FREQCTRL0);
sys_freqctrl &= ~0xFFF00000;
sys_clksrc = au_readl(SYS_CLKSRC);
sys_clksrc &= ~0x00007FE0;
switch (prid & 0x000000FF)
{
case 0x00: /* DA */
case 0x01: /* HA */
case 0x02: /* HB */
/* CPU core freq to 48MHz to slow it way down... */
au_writel(4, SYS_CPUPLL);
/*
* Setup 48MHz FREQ2 from CPUPLL for USB Host
*/
/* FRDIV2=3 -> div by 8 of 384MHz -> 48MHz */
sys_freqctrl |= ((3<<22) | (1<<21) | (0<<20));
au_writel(sys_freqctrl, SYS_FREQCTRL0);
/* CPU core freq to 384MHz */
au_writel(0x20, SYS_CPUPLL);
printk("Au1000: 48MHz OHCI workaround enabled\n");
break;
default: /* HC and newer */
// FREQ2 = aux/2 = 48 MHz
sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
au_writel(sys_freqctrl, SYS_FREQCTRL0);
break;
}
/*
* Route 48MHz FREQ2 into USB Host and/or Device
*/
#ifdef CONFIG_USB_OHCI
sys_clksrc |= ((4<<12) | (0<<11) | (0<<10));
#endif
#ifdef CONFIG_AU1X00_USB_DEVICE
sys_clksrc |= ((4<<7) | (0<<6) | (0<<5));
#endif
au_writel(sys_clksrc, SYS_CLKSRC);
#ifdef CONFIG_USB_OHCI
// enable host controller and wait for reset done
au_writel(0x08, USB_HOST_CONFIG);
udelay(1000);
au_writel(0x0E, USB_HOST_CONFIG);
udelay(1000);
au_readl(USB_HOST_CONFIG); // throw away first read
while (!(au_readl(USB_HOST_CONFIG) & 0x10))
au_readl(USB_HOST_CONFIG);
#endif
// configure pins GPIO[14:9] as GPIO
pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8080);
#ifndef CONFIG_AU1X00_USB_DEVICE
// 2nd USB port is USB host
pin_func |= 0x8000;
#endif
au_writel(pin_func, SYS_PINFUNC);
au_writel(0x2800, SYS_TRIOUTCLR);
au_writel(0x0030, SYS_OUTPUTCLR);
#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
// make gpio 15 an input (for interrupt line)
pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x100);
// we don't need I2S, so make it available for GPIO[31:29]
pin_func |= (1<<5);
au_writel(pin_func, SYS_PINFUNC);
au_writel(0x8000, SYS_TRIOUTCLR);
#ifdef CONFIG_FB
conswitchp = &dummy_con;
#endif
static_cfg0 = au_readl(MEM_STCFG0) & (u32)(~0xc00);
au_writel(static_cfg0, MEM_STCFG0);
// configure RCE2* for LCD
au_writel(0x00000004, MEM_STCFG2);
// MEM_STTIME2
au_writel(0x09000000, MEM_STTIME2);
// Set 32-bit base address decoding for RCE2*
au_writel(0x10003ff0, MEM_STADDR2);
// PCI CPLD setup
// expand CE0 to cover PCI
au_writel(0x11803e40, MEM_STADDR1);
// burst visibility on
au_writel(au_readl(MEM_STCFG0) | 0x1000, MEM_STCFG0);
au_writel(0x83, MEM_STCFG1); // ewait enabled, flash timing
au_writel(0x33030a10, MEM_STTIME1); // slower timing for FPGA
/* setup the static bus controller */
au_writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */
au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */
au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
#ifdef CONFIG_FB_E1356
if ((argptr = strstr(argptr, "video=")) == NULL) {
argptr = prom_getcmdline();
strcat(argptr, " video=e1356fb:system:pb1000,mmunalign:1");
}
#endif // CONFIG_FB_E1356
#ifdef CONFIG_PCI
au_writel(0, PCI_BRIDGE_CONFIG); // set extend byte to 0
au_writel(0, SDRAM_MBAR); // set mbar to 0
au_writel(0x2, SDRAM_CMD); // enable memory accesses
au_sync_delay(1);
#endif
#ifndef CONFIG_SERIAL_NONSTANDARD
/* don't touch the default serial console */
au_writel(0, UART0_ADDR + UART_CLK);
#endif
au_writel(0, UART1_ADDR + UART_CLK);
au_writel(0, UART2_ADDR + UART_CLK);
au_writel(0, UART3_ADDR + UART_CLK);
#ifdef CONFIG_BLK_DEV_IDE
ide_ops = &std_ide_ops;
#endif
// setup irda clocks
// aux clock, divide by 2, clock from 2/4 divider
au_writel(au_readl(SYS_CLKSRC) | 0x7, SYS_CLKSRC);
pin_func = au_readl(SYS_PINFUNC) & (u32)(~(1<<2)); // clear IRTXD
au_writel(pin_func, SYS_PINFUNC);
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S);
au_writel(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL);
au_sync();
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S);
au_writel(0, SYS_TOYTRIM);
/* Enable Au1000 BCLK switching - note: sed1356 must not use
* its BCLK (Au1000 LCLK) for any timings */
switch (prid & 0x000000FF)
{
case 0x00: /* DA */
case 0x01: /* HA */
case 0x02: /* HB */
break;
default: /* HC and newer */
au_writel(0x00000060, 0xb190003c);
break;
}
}
#
# Copyright 2000,2001 MontaVista Software Inc.
# Author: MontaVista Software, Inc.
# ppopov@mvista.com or source@mvista.com
#
# Makefile for the Alchemy Semiconductor Pb1100 board.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
USE_STANDARD_AS_RULE := true
O_TARGET := pb1100.o
obj-y := init.o setup.o
/*
*
* BRIEF MODULE DESCRIPTION
* Pb1100 board setup
*
* Copyright 2002 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
int prom_argc;
char **prom_argv, **prom_envp;
extern void __init prom_init_cmdline(void);
extern char *prom_getenv(char *envname);
const char *get_system_type(void)
{
return "Alchemy Pb1100";
}
int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
{
unsigned char *memsize_str;
unsigned long memsize;
prom_argc = argc;
prom_argv = argv;
prom_envp = envp;
mips_machgroup = MACH_GROUP_ALCHEMY;
mips_machtype = MACH_PB1100;
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
if (!memsize_str) {
memsize = 0x04000000;
} else {
memsize = simple_strtol(memsize_str, NULL, 0);
}
add_memory_region(0, memsize, BOOT_MEM_RAM);
return 0;
}
/*
*
* BRIEF MODULE DESCRIPTION
* Alchemy Pb1100 board setup.
*
* Copyright 2002 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/mc146818rtc.h>
#include <linux/delay.h>
#include <linux/major.h>
#include <linux/kdev_t.h>
#include <linux/root_dev.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/pgtable.h>
#include <asm/au1000.h>
#include <asm/pb1100.h>
#ifdef CONFIG_USB_OHCI
// Enable the workaround for the OHCI DoneHead
// register corruption problem.
#define CONFIG_AU1000_OHCI_FIX
#endif
#if defined(CONFIG_AU1X00_SERIAL_CONSOLE)
extern void console_setup(char *, int *);
char serial_console[20];
#endif
#ifdef CONFIG_BLK_DEV_INITRD
extern unsigned long initrd_start, initrd_end;
extern void * __rd_start, * __rd_end;
#endif
#ifdef CONFIG_BLK_DEV_IDE
extern struct ide_ops std_ide_ops;
extern struct ide_ops *ide_ops;
#endif
#ifdef CONFIG_RTC
extern struct rtc_ops pb1500_rtc_ops;
#endif
extern char * __init prom_getcmdline(void);
extern void au1000_restart(char *);
extern void au1000_halt(void);
extern void au1000_power_off(void);
extern struct resource ioport_resource;
extern struct resource iomem_resource;
void __init au1x00_setup(void)
{
char *argptr;
u32 pin_func, static_cfg0;
u32 sys_freqctrl, sys_clksrc;
argptr = prom_getcmdline();
/* NOTE: The memory map is established by YAMON 2.08+ */
/* Various early Au1000 Errata corrected by this */
set_c0_config(1<<19); /* Config[OD] */
#ifdef CONFIG_AU1X00_SERIAL_CONSOLE
if ((argptr = strstr(argptr, "console=")) == NULL) {
argptr = prom_getcmdline();
strcat(argptr, " console=ttyS0,115200");
}
#endif
#ifdef CONFIG_SOUND_AU1X00
strcat(argptr, " au1000_audio=vra");
argptr = prom_getcmdline();
#endif
_machine_restart = au1000_restart;
_machine_halt = au1000_halt;
_machine_power_off = au1000_power_off;
// IO/MEM resources.
set_io_port_base(0);
ioport_resource.start = 0x10000000;
ioport_resource.end = 0xffffffff;
iomem_resource.start = 0x10000000;
iomem_resource.end = 0xffffffff;
#ifdef CONFIG_BLK_DEV_INITRD
ROOT_DEV = Root_RAM0;
initrd_start = (unsigned long)&__rd_start;
initrd_end = (unsigned long)&__rd_end;
#endif
// set AUX clock to 12MHz * 8 = 96 MHz
au_writel(8, SYS_AUXPLL);
au_writel(0, SYS_PININPUTEN);
udelay(100);
#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
#ifdef CONFIG_USB_OHCI
if ((argptr = strstr(argptr, "usb_ohci=")) == NULL) {
char usb_args[80];
argptr = prom_getcmdline();
memset(usb_args, 0, sizeof(usb_args));
sprintf(usb_args, " usb_ohci=base:0x%x,len:0x%x,irq:%d",
USB_OHCI_BASE, USB_OHCI_LEN, AU1000_USB_HOST_INT);
strcat(argptr, usb_args);
}
#endif
// configure pins GPIO[14:9] as GPIO
pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80);
/* zero and disable FREQ2 */
sys_freqctrl = au_readl(SYS_FREQCTRL0);
sys_freqctrl &= ~0xFFF00000;
au_writel(sys_freqctrl, SYS_FREQCTRL0);
/* zero and disable USBH/USBD/IrDA clock */
sys_clksrc = au_readl(SYS_CLKSRC);
sys_clksrc &= ~0x0000001F;
au_writel(sys_clksrc, SYS_CLKSRC);
sys_freqctrl = au_readl(SYS_FREQCTRL0);
sys_freqctrl &= ~0xFFF00000;
sys_clksrc = au_readl(SYS_CLKSRC);
sys_clksrc &= ~0x0000001F;
// FREQ2 = aux/2 = 48 MHz
sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
au_writel(sys_freqctrl, SYS_FREQCTRL0);
/*
* Route 48MHz FREQ2 into USBH/USBD/IrDA
*/
sys_clksrc |= ((4<<2) | (0<<1) | 0 );
au_writel(sys_clksrc, SYS_CLKSRC);
/* setup the static bus controller */
au_writel(0x00000002, MEM_STCFG3); /* type = PCMCIA */
au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */
au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
// get USB Functionality pin state (device vs host drive pins)
pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
#ifndef CONFIG_AU1X00_USB_DEVICE
// 2nd USB port is USB host
pin_func |= 0x8000;
#endif
au_writel(pin_func, SYS_PINFUNC);
#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
#ifdef CONFIG_USB_OHCI
// enable host controller and wait for reset done
au_writel(0x08, USB_HOST_CONFIG);
udelay(1000);
au_writel(0x0c, USB_HOST_CONFIG);
udelay(1000);
au_readl(USB_HOST_CONFIG);
while (!(au_readl(USB_HOST_CONFIG) & 0x10))
;
au_readl(USB_HOST_CONFIG);
#endif
#ifdef CONFIG_FB
conswitchp = &dummy_con;
#endif
#ifdef CONFIG_FB_AU1100
if ((argptr = strstr(argptr, "video=")) == NULL) {
argptr = prom_getcmdline();
/* default panel */
strcat(argptr, " video=au1100fb:panel:Sharp_320x240_16");
}
#endif
#ifdef CONFIG_FB_E1356
if ((argptr = strstr(argptr, "video=")) == NULL) {
argptr = prom_getcmdline();
strcat(argptr, " video=e1356fb:system:pb1500");
}
#endif
#ifndef CONFIG_SERIAL_NONSTANDARD
/* don't touch the default serial console */
au_writel(0, UART0_ADDR + UART_CLK);
#endif
au_writel(0, UART1_ADDR + UART_CLK);
au_writel(0, UART3_ADDR + UART_CLK);
#ifdef CONFIG_BLK_DEV_IDE
ide_ops = &std_ide_ops;
#endif
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S);
au_writel(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL);
au_sync();
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S);
au_writel(0, SYS_TOYTRIM);
au_writel(0x00000060, 0xb190003c);
#ifdef CONFIG_RTC
rtc_ops = &pb1500_rtc_ops;
// Enable the RTC if not already enabled
if (!(readb(0xac000028) & 0x20)) {
writeb(readb(0xac000028) | 0x20, 0xac000028);
au_sync();
}
// Put the clock in BCD mode
if (readb(0xac00002C) & 0x4) { /* reg B */
writeb(readb(0xac00002c) & ~0x4, 0xac00002c);
au_sync();
}
#endif
}
#
# Copyright 2000,2001 MontaVista Software Inc.
# Author: MontaVista Software, Inc.
# ppopov@mvista.com or source@mvista.com
#
# Makefile for the Alchemy Semiconductor Pb1500 board.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
lib-y := init.o setup.o
/*
*
* BRIEF MODULE DESCRIPTION
* PB1500 board setup
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/sched.h>
int prom_argc;
char **prom_argv, **prom_envp;
extern void __init prom_init_cmdline(void);
extern char *prom_getenv(char *envname);
const char *get_system_type(void)
{
return "Alchemy Pb1500";
}
int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
{
unsigned char *memsize_str;
unsigned long memsize;
prom_argc = argc;
prom_argv = argv;
prom_envp = envp;
mips_machgroup = MACH_GROUP_ALCHEMY;
mips_machtype = MACH_PB1500;
prom_init_cmdline();
memsize_str = prom_getenv("memsize");
if (!memsize_str) {
memsize = 0x04000000;
} else {
memsize = simple_strtol(memsize_str, NULL, 0);
}
add_memory_region(0, memsize, BOOT_MEM_RAM);
return 0;
}
/*
*
* BRIEF MODULE DESCRIPTION
* Alchemy Pb1000 board setup.
*
* Copyright 2000 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/mc146818rtc.h>
#include <linux/delay.h>
#include <linux/major.h>
#include <linux/kdev_t.h>
#include <linux/root_dev.h>
#include <asm/cpu.h>
#include <asm/time.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/reboot.h>
#include <asm/pgtable.h>
#include <asm/au1000.h>
#include <asm/pb1500.h>
#ifdef CONFIG_USB_OHCI
// Enable the workaround for the OHCI DoneHead
// register corruption problem.
#define CONFIG_AU1000_OHCI_FIX
#endif
#ifdef CONFIG_BLK_DEV_INITRD
extern unsigned long initrd_start, initrd_end;
extern void * __rd_start, * __rd_end;
#endif
#ifdef CONFIG_BLK_DEV_IDE
extern struct ide_ops std_ide_ops;
extern struct ide_ops *ide_ops;
#endif
#ifdef CONFIG_RTC
extern struct rtc_ops pb1500_rtc_ops;
#endif
extern char * __init prom_getcmdline(void);
extern void __init au1x_time_init(void);
extern void __init au1x_timer_setup(struct irqaction *irq);
extern void au1000_restart(char *);
extern void au1000_halt(void);
extern void au1000_power_off(void);
extern struct resource ioport_resource;
extern struct resource iomem_resource;
#ifdef CONFIG_64BIT_PHYS_ADDR
extern phys_t (*fixup_bigphys_addr)(phys_t phys_addr, phys_t size);
static phys_t pb1500_fixup_bigphys_addr(phys_t phys_addr, phys_t size);
#endif
void __init au1x00_setup(void)
{
char *argptr;
u32 pin_func, static_cfg0;
u32 sys_freqctrl, sys_clksrc;
argptr = prom_getcmdline();
/* NOTE: The memory map is established by YAMON 2.08+ */
/* Various early Au1500 Errata corrected by this */
set_c0_config(1<<19); /* Config[OD] */
board_time_init = au1x_time_init;
board_timer_setup = au1x_timer_setup;
#ifdef CONFIG_SERIAL_AU1X00_CONSOLE
if ((argptr = strstr(argptr, "console=")) == NULL) {
argptr = prom_getcmdline();
strcat(argptr, " console=ttyS0,115200");
}
#endif
#ifdef CONFIG_SOUND_AU1X00
strcat(argptr, " au1000_audio=vra");
argptr = prom_getcmdline();
#endif
_machine_restart = au1000_restart;
_machine_halt = au1000_halt;
_machine_power_off = au1000_power_off;
#ifdef CONFIG_64BIT_PHYS_ADDR
fixup_bigphys_addr = pb1500_fixup_bigphys_addr;
#endif
// IO/MEM resources.
set_io_port_base(0);
ioport_resource.start = 0x00000000;
ioport_resource.end = 0xffffffff;
iomem_resource.start = 0x10000000;
iomem_resource.end = 0xffffffff;
#ifdef CONFIG_BLK_DEV_INITRD
ROOT_DEV = Root_RAM0;
initrd_start = (unsigned long)&__rd_start;
initrd_end = (unsigned long)&__rd_end;
#endif
// set AUX clock to 12MHz * 8 = 96 MHz
au_writel(8, SYS_AUXPLL);
au_writel(0, SYS_PINSTATERD);
udelay(100);
#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
#ifdef CONFIG_USB_OHCI
if ((argptr = strstr(argptr, "usb_ohci=")) == NULL) {
char usb_args[80];
argptr = prom_getcmdline();
memset(usb_args, 0, sizeof(usb_args));
sprintf(usb_args, " usb_ohci=base:0x%x,len:0x%x,irq:%d",
USB_OHCI_BASE, USB_OHCI_LEN, AU1000_USB_HOST_INT);
strcat(argptr, usb_args);
}
#endif
/* GPIO201 is input for PCMCIA card detect */
/* GPIO203 is input for PCMCIA interrupt request */
au_writel(au_readl(GPIO2_DIR) & (u32)(~((1<<1)|(1<<3))), GPIO2_DIR);
/* zero and disable FREQ2 */
sys_freqctrl = au_readl(SYS_FREQCTRL0);
sys_freqctrl &= ~0xFFF00000;
au_writel(sys_freqctrl, SYS_FREQCTRL0);
/* zero and disable USBH/USBD clocks */
sys_clksrc = au_readl(SYS_CLKSRC);
sys_clksrc &= ~0x00007FE0;
au_writel(sys_clksrc, SYS_CLKSRC);
sys_freqctrl = au_readl(SYS_FREQCTRL0);
sys_freqctrl &= ~0xFFF00000;
sys_clksrc = au_readl(SYS_CLKSRC);
sys_clksrc &= ~0x00007FE0;
// FREQ2 = aux/2 = 48 MHz
sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
au_writel(sys_freqctrl, SYS_FREQCTRL0);
/*
* Route 48MHz FREQ2 into USB Host and/or Device
*/
#ifdef CONFIG_USB_OHCI
sys_clksrc |= ((4<<12) | (0<<11) | (0<<10));
#endif
#ifdef CONFIG_AU1X00_USB_DEVICE
sys_clksrc |= ((4<<7) | (0<<6) | (0<<5));
#endif
au_writel(sys_clksrc, SYS_CLKSRC);
pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
#ifndef CONFIG_AU1X00_USB_DEVICE
// 2nd USB port is USB host
pin_func |= 0x8000;
#endif
au_writel(pin_func, SYS_PINFUNC);
#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
#ifdef CONFIG_USB_OHCI
// enable host controller and wait for reset done
au_writel(0x08, USB_HOST_CONFIG);
udelay(1000);
au_writel(0x0c, USB_HOST_CONFIG);
udelay(1000);
au_readl(USB_HOST_CONFIG);
while (!(au_readl(USB_HOST_CONFIG) & 0x10))
;
au_readl(USB_HOST_CONFIG);
#endif
#ifdef CONFIG_FB
conswitchp = &dummy_con;
#endif
#ifdef CONFIG_FB_E1356
if ((argptr = strstr(argptr, "video=")) == NULL) {
argptr = prom_getcmdline();
strcat(argptr, " video=e1356fb:system:pb1500");
}
#elif defined (CONFIG_FB_XPERT98)
if ((argptr = strstr(argptr, "video=")) == NULL) {
argptr = prom_getcmdline();
strcat(argptr, " video=atyfb:1024x768-8@70");
}
#endif // CONFIG_FB_E1356
#ifndef CONFIG_SERIAL_AU1X00_CONSOLE
/* don't touch the default serial console */
au_writel(0, UART0_ADDR + UART_CLK);
#endif
au_writel(0, UART3_ADDR + UART_CLK);
#ifdef CONFIG_BLK_DEV_IDE
ide_ops = &std_ide_ops;
#endif
#ifdef CONFIG_PCI
// Setup PCI bus controller
au_writel(0, Au1500_PCI_CMEM);
au_writel(0x00003fff, Au1500_CFG_BASE);
#if defined(__MIPSEB__)
au_writel(0xf | (2<<6) | (1<<4), Au1500_PCI_CFG);
#else
au_writel(0xf, Au1500_PCI_CFG);
#endif
au_writel(0xf0000000, Au1500_PCI_MWMASK_DEV);
au_writel(0, Au1500_PCI_MWBASE_REV_CCL);
au_writel(0x02a00356, Au1500_PCI_STATCMD);
au_writel(0x00003c04, Au1500_PCI_HDRTYPE);
au_writel(0x00000008, Au1500_PCI_MBAR);
au_sync();
#endif
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_E0S);
au_writel(SYS_CNTRL_E0 | SYS_CNTRL_EN0, SYS_COUNTER_CNTRL);
au_sync();
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S);
au_writel(0, SYS_TOYTRIM);
/* Enable BCLK switching */
au_writel(0x00000060, 0xb190003c);
#ifdef CONFIG_RTC
rtc_ops = &pb1500_rtc_ops;
// Enable the RTC if not already enabled
if (!(au_readl(0xac000028) & 0x20)) {
printk("enabling clock ...\n");
au_writel((au_readl(0xac000028) | 0x20), 0xac000028);
}
// Put the clock in BCD mode
if (readl(0xac00002C) & 0x4) { /* reg B */
au_writel(au_readl(0xac00002c) & ~0x4, 0xac00002c);
au_sync();
}
#endif
}
#ifdef CONFIG_64BIT_PHYS_ADDR
static phys_t pb1500_fixup_bigphys_addr(phys_t phys_addr,
phys_t size)
{
u32 pci_start = (u32)Au1500_PCI_MEM_START;
u32 pci_end = (u32)Au1500_PCI_MEM_END;
/* Don't fixup 36 bit addresses */
if ((phys_addr >> 32) != 0) return phys_addr;
/* check for pci memory window */
if ((phys_addr >= pci_start) && ((phys_addr + size) < pci_end)) {
return (phys_t)((phys_addr - pci_start) +
Au1500_PCI_MEM_START);
}
else
return phys_addr;
}
#endif
......@@ -2,133 +2,276 @@
# Automatically generated make config: don't edit
#
CONFIG_MIPS=y
# CONFIG_SMP is not set
CONFIG_MIPS32=y
# CONFIG_MIPS64 is not set
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
#
# General setup
#
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_EMBEDDED is not set
CONFIG_FUTEX=y
CONFIG_EPOLL=y
#
# Loadable module support
#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_OBSOLETE_MODPARM=y
CONFIG_MODVERSIONS=y
CONFIG_KMOD=y
#
# Machine selection
#
# CONFIG_ACER_PICA_61 is not set
# CONFIG_ALGOR_P4032 is not set
# CONFIG_BAGET_MIPS is not set
# CONFIG_CASIO_E55 is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_DECSTATION is not set
# CONFIG_DDB5074 is not set
# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_LASAT is not set
# CONFIG_HP_LASERJET is not set
# CONFIG_IBM_WORKPAD is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MALTA is not set
# CONFIG_NINO is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MIPS_MALTA is not set
# CONFIG_MIPS_SEAD is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_MOMENCO_OCELOT_G is not set
# CONFIG_MOMENCO_OCELOT_C is not set
# CONFIG_DDB5074 is not set
# CONFIG_DDB5476 is not set
# CONFIG_DDB5477 is not set
# CONFIG_NEC_OSPREY is not set
# CONFIG_NEC_EAGLE is not set
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP32 is not set
# CONFIG_SOC_AU1X00 is not set
# CONFIG_SIBYTE_SB1xxx_SOC is not set
# CONFIG_SNI_RM200_PCI is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MIPS_IVR is not set
CONFIG_MIPS_PB1000=y
# CONFIG_TANBAC_TB0226 is not set
# CONFIG_TANBAC_TB0229 is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_VICTOR_MPC30X is not set
# CONFIG_ZAO_CAPCELLA is not set
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
# CONFIG_MCA is not set
# CONFIG_SBUS is not set
CONFIG_MIPS_AU1000=y
CONFIG_NEW_IRQ=y
# CONFIG_ISA is not set
# CONFIG_EISA is not set
# CONFIG_PCI is not set
# CONFIG_I8259 is not set
#
# Loadable module support
#
# CONFIG_MODULES is not set
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_FB=y
#
# CPU selection
#
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS64 is not set
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_TX39XX is not set
# CONFIG_CPU_VR41XX is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_NEVADA is not set
# CONFIG_CPU_R8000 is not set
# CONFIG_CPU_R10000 is not set
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_SB1 is not set
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS64 is not set
CONFIG_CPU_HAS_PREFETCH=y
# CONFIG_VTAG_ICACHE is not set
CONFIG_64BIT_PHYS_ADDR=y
CONFIG_CPU_ADVANCED=y
CONFIG_CPU_HAS_LLSC=y
# CONFIG_CPU_HAS_LLDSCD is not set
CONFIG_CPU_HAS_WB=y
CONFIG_CPU_HAS_SYNC=y
# CONFIG_PREEMPT is not set
CONFIG_KALLSYMS=y
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
#
# General setup
# Bus options (PCI, PCMCIA, EISA, ISA, TC)
#
CONFIG_MMU=y
CONFIG_HOTPLUG=y
#
# PCMCIA/CardBus support
#
CONFIG_PCMCIA=m
# CONFIG_TCIC is not set
#
# PCI Hotplug Support
#
#
# Executable file formats
#
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_KCORE_ELF=y
CONFIG_ELF_KERNEL=y
# CONFIG_BINFMT_AOUT is not set
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
CONFIG_NET=y
# CONFIG_HOTPLUG is not set
# CONFIG_PCMCIA is not set
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
#
# Memory Technology Devices (MTD)
#
# CONFIG_MTD is not set
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_CONCAT is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_CMDLINE_PARTS is not set
#
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
#
# RAM/ROM/Flash chip drivers
#
CONFIG_MTD_CFI=y
# CONFIG_MTD_JEDECPROBE is not set
CONFIG_MTD_GEN_PROBE=y
# CONFIG_MTD_CFI_ADV_OPTIONS is not set
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CFI_AMDSTD=y
# CONFIG_MTD_CFI_STAA is not set
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
# CONFIG_MTD_OBSOLETE_CHIPS is not set
#
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# CONFIG_MTD_PHYSMAP is not set
# CONFIG_MTD_UCLINUX is not set
#
# Self-contained MTD device drivers
#
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_MTDRAM is not set
# CONFIG_MTD_BLKMTD is not set
#
# Disk-On-Chip Device Drivers
#
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
#
# NAND Flash Device Drivers
#
# CONFIG_MTD_NAND is not set
#
# Parallel port support
#
# CONFIG_PARPORT is not set
#
# Plug and Play support
#
# CONFIG_PNP is not set
#
# Generic Driver Options
#
# CONFIG_FW_LOADER is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_INITRD is not set
#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
#
# IDE, ATA and ATAPI Block devices
#
CONFIG_BLK_DEV_IDE=y
#
# Please see Documentation/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
# CONFIG_IDEDISK_STROKE is not set
CONFIG_BLK_DEV_IDECS=m
# CONFIG_BLK_DEV_IDECD is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_IDE_TASK_IOCTL is not set
CONFIG_IDE_TASKFILE_IO=y
#
# IDE chipset support/bugfixes
#
#
# SCSI device support
#
# CONFIG_SCSI is not set
#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
# CONFIG_BLK_DEV_MD is not set
# CONFIG_MD_LINEAR is not set
# CONFIG_MD_RAID0 is not set
# CONFIG_MD_RAID1 is not set
# CONFIG_MD_RAID5 is not set
# CONFIG_BLK_DEV_LVM is not set
#
# Fusion MPT device support
#
#
# I2O device support
#
#
# Networking support
#
CONFIG_NET=y
#
# Networking options
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK is not set
# CONFIG_NETLINK_DEV is not set
# CONFIG_NETFILTER is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_NET_KEY=y
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
......@@ -138,22 +281,27 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_ARPD is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
# CONFIG_XFRM_USER is not set
#
#
# SCTP Configuration (EXPERIMENTAL)
#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_LLC is not set
# CONFIG_DECNET is not set
# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
......@@ -166,69 +314,29 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_NET_SCHED is not set
#
# Telephony Support
#
# CONFIG_PHONE is not set
# CONFIG_PHONE_IXJ is not set
# CONFIG_PHONE_IXJ_PCMCIA is not set
#
# ATA/IDE/MFM/RLL support
#
# CONFIG_IDE is not set
# CONFIG_BLK_DEV_IDE_MODES is not set
# CONFIG_BLK_DEV_HD is not set
#
# SCSI support
#
# CONFIG_SCSI is not set
#
# Network device support
# Network testing
#
# CONFIG_NET_PKTGEN is not set
CONFIG_NETDEVICES=y
#
# ARCnet devices
#
# CONFIG_ARCNET is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_ETHERTAP is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
CONFIG_MIPS_AU1000_ENET=y
# CONFIG_SUNLANCE is not set
# CONFIG_SUNBMAC is not set
# CONFIG_SUNQE is not set
# CONFIG_SUNLANCE is not set
# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_NET_ISA is not set
# CONFIG_NET_PCI is not set
# CONFIG_NET_POCKET is not set
# CONFIG_MII is not set
#
# Ethernet (1000 Mbit)
#
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
# CONFIG_MYRI_SBUS is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_PLIP is not set
#
# Ethernet (10000 Mbit)
#
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
......@@ -238,11 +346,8 @@ CONFIG_MIPS_AU1000_ENET=y
# CONFIG_NET_RADIO is not set
#
# Token Ring devices
# Token Ring devices (depends on LLC=y)
#
# CONFIG_TR is not set
# CONFIG_NET_FC is not set
# CONFIG_RCPCI is not set
# CONFIG_SHAPER is not set
#
......@@ -250,6 +355,19 @@ CONFIG_MIPS_AU1000_ENET=y
#
# CONFIG_WAN is not set
#
# PCMCIA network device support
#
CONFIG_NET_PCMCIA=y
CONFIG_PCMCIA_3C589=m
# CONFIG_PCMCIA_3C574 is not set
# CONFIG_PCMCIA_FMVJ18X is not set
# CONFIG_PCMCIA_PCNET is not set
# CONFIG_PCMCIA_NMCLAN is not set
# CONFIG_PCMCIA_SMC91C92 is not set
# CONFIG_PCMCIA_XIRC2PS is not set
# CONFIG_PCMCIA_AXNET is not set
#
# Amateur Radio support
#
......@@ -258,44 +376,131 @@ CONFIG_MIPS_AU1000_ENET=y
#
# IrDA (infrared) support
#
# CONFIG_IRDA is not set
CONFIG_IRDA=y
#
# IrDA protocols
#
CONFIG_IRLAN=m
CONFIG_IRCOMM=m
# CONFIG_IRDA_ULTRA is not set
#
# IrDA options
#
CONFIG_IRDA_CACHE_LAST_LSAP=y
CONFIG_IRDA_FAST_RR=y
# CONFIG_IRDA_DEBUG is not set
#
# Infrared-port device drivers
#
#
# SIR device drivers
#
# CONFIG_IRTTY_SIR is not set
#
# Dongle support
#
# CONFIG_DONGLE is not set
#
# Old SIR device drivers
#
# CONFIG_IRTTY_OLD is not set
# CONFIG_IRPORT_SIR is not set
#
# Old Serial dongle support
#
# CONFIG_DONGLE_OLD is not set
#
# FIR device drivers
#
# CONFIG_NSC_FIR is not set
# CONFIG_WINBOND_FIR is not set
# CONFIG_TOSHIBA_OLD is not set
# CONFIG_TOSHIBA_FIR is not set
# CONFIG_SMC_IRCC_OLD is not set
# CONFIG_SMC_IRCC_FIR is not set
# CONFIG_ALI_FIR is not set
# CONFIG_VLSI_FIR is not set
#
# ISDN subsystem
#
# CONFIG_ISDN is not set
# CONFIG_ISDN_BOOL is not set
#
# Telephony Support
#
# CONFIG_PHONE is not set
#
# Input device support
#
CONFIG_INPUT=y
#
# Userland interfaces
#
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
# CONFIG_INPUT_EVDEV is not set
# CONFIG_INPUT_EVBUG is not set
#
# Input I/O drivers
#
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
# CONFIG_SERIO is not set
#
# Old CD-ROM drivers (not SCSI, not IDE)
# Input Device Drivers
#
# CONFIG_CD_NO_IDESCSI is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
#
# Character devices
#
# CONFIG_VT is not set
# CONFIG_SERIAL is not set
# CONFIG_SERIAL_EXTENDED is not set
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_COMPUTONE is not set
# CONFIG_ROCKETPORT is not set
# CONFIG_CYCLADES is not set
# CONFIG_DIGIEPCA is not set
# CONFIG_DIGI is not set
# CONFIG_ESPSERIAL is not set
# CONFIG_MOXA_INTELLIO is not set
# CONFIG_MOXA_SMARTIO is not set
# CONFIG_ISI is not set
# CONFIG_SYNCLINK is not set
# CONFIG_SYNCLINKMP is not set
# CONFIG_N_HDLC is not set
# CONFIG_RISCOM8 is not set
# CONFIG_SPECIALIX is not set
# CONFIG_SX is not set
# CONFIG_RIO is not set
# CONFIG_STALDRV is not set
# CONFIG_SERIAL_TX3912 is not set
# CONFIG_SERIAL_TX3912_CONSOLE is not set
CONFIG_AU1000_UART=y
CONFIG_AU1000_SERIAL_CONSOLE=y
#
# Serial drivers
#
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
......@@ -305,36 +510,35 @@ CONFIG_UNIX98_PTY_COUNT=256
# CONFIG_I2C is not set
#
# Mice
# I2C Hardware Sensors Mainboard support
#
# CONFIG_BUSMOUSE is not set
# CONFIG_MOUSE is not set
#
# Joysticks
# I2C Hardware Sensors Chip support
#
# CONFIG_INPUT_GAMEPORT is not set
# CONFIG_I2C_SENSOR is not set
#
# Input core support is needed for gameports
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set
#
# Input core support is needed for joysticks
# IPMI
#
# CONFIG_QIC02_TAPE is not set
# CONFIG_IPMI_HANDLER is not set
#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_INTEL_RNG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# CONFIG_SONYPI is not set
#
# Ftape, the floppy tape device driver
......@@ -343,224 +547,169 @@ CONFIG_UNIX98_PTY_COUNT=256
# CONFIG_AGP is not set
# CONFIG_DRM is not set
#
# PCMCIA character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_HANGCHECK_TIMER is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
#
# Digital Video Broadcasting Devices
#
# CONFIG_DVB is not set
#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT3_FS is not set
# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_QUOTA is not set
CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=y
# CONFIG_REISERFS_FS is not set
# CONFIG_REISERFS_CHECK is not set
# CONFIG_REISERFS_PROC_INFO is not set
#
# CD-ROM/DVD Filesystems
#
# CONFIG_ISO9660_FS is not set
# CONFIG_UDF_FS is not set
#
# DOS/FAT/NT Filesystems
#
# CONFIG_FAT_FS is not set
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set
CONFIG_DEVPTS_FS=y
CONFIG_DEVPTS_FS_XATTR=y
CONFIG_DEVPTS_FS_SECURITY=y
# CONFIG_TMPFS is not set
CONFIG_RAMFS=y
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_CMS_FS is not set
# CONFIG_EXT3_FS is not set
# CONFIG_JBD is not set
# CONFIG_JBD_DEBUG is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_JFFS_FS is not set
# CONFIG_JFFS2_FS is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
# CONFIG_JFFS2_FS_NAND is not set
# CONFIG_CRAMFS is not set
# CONFIG_TMPFS is not set
# CONFIG_RAMFS is not set
CONFIG_ISO9660_FS=y
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
# CONFIG_FREEVXFS_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_NTFS_DEBUG is not set
# CONFIG_NTFS_RW is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set
# CONFIG_DEVFS_MOUNT is not set
# CONFIG_DEVFS_DEBUG is not set
# CONFIG_DEVPTS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
# CONFIG_UDF_FS is not set
# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
# CONFIG_UFS_FS_WRITE is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
# CONFIG_INTERMEZZO_FS is not set
CONFIG_NFS_FS=y
# CONFIG_NFS_V3 is not set
CONFIG_ROOT_NFS=y
# CONFIG_NFS_V4 is not set
# CONFIG_NFSD is not set
# CONFIG_NFSD_V3 is not set
CONFIG_SUNRPC=y
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
# CONFIG_EXPORTFS is not set
CONFIG_SUNRPC=y
# CONFIG_SUNRPC_GSS is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_NCPFS_PACKET_SIGNING is not set
# CONFIG_NCPFS_IOCTL_LOCKING is not set
# CONFIG_NCPFS_STRONG is not set
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
# CONFIG_NCPFS_SMALLDOS is not set
# CONFIG_NCPFS_NLS is not set
# CONFIG_NCPFS_EXTRAS is not set
# CONFIG_CODA_FS is not set
# CONFIG_INTERMEZZO_FS is not set
# CONFIG_AFS_FS is not set
#
# Partition Types
#
CONFIG_PARTITION_ADVANCED=y
# CONFIG_ACORN_PARTITION is not set
# CONFIG_OSF_PARTITION is not set
# CONFIG_AMIGA_PARTITION is not set
# CONFIG_ATARI_PARTITION is not set
# CONFIG_MAC_PARTITION is not set
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_BSD_DISKLABEL is not set
# CONFIG_MINIX_SUBPARTITION is not set
# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_UNIXWARE_DISKLABEL is not set
# CONFIG_LDM_PARTITION is not set
CONFIG_SGI_PARTITION=y
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_SMB_NLS is not set
# CONFIG_NLS is not set
#
# Sound
#
# CONFIG_SOUND is not set
#
# USB support
# Graphics support
#
# CONFIG_USB is not set
# CONFIG_FB_VIRTUAL is not set
#
# USB Controllers
# Console display driver support
#
# CONFIG_USB_UHCI is not set
# CONFIG_USB_UHCI_ALT is not set
# CONFIG_USB_OHCI is not set
# CONFIG_VGA_CONSOLE is not set
# CONFIG_MDA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE is not set
#
# USB Device Class drivers
# Logo configuration
#
# CONFIG_USB_AUDIO is not set
# CONFIG_USB_BLUETOOTH is not set
# CONFIG_USB_STORAGE is not set
# CONFIG_USB_STORAGE_DEBUG is not set
# CONFIG_USB_STORAGE_DATAFAB is not set
# CONFIG_USB_STORAGE_FREECOM is not set
# CONFIG_USB_STORAGE_JUMPSHOT is not set
# CONFIG_USB_STORAGE_DPCM is not set
# CONFIG_USB_STORAGE_SDDR09 is not set
# CONFIG_USB_ACM is not set
# CONFIG_USB_PRINTER is not set
# CONFIG_LOGO is not set
#
# USB Human Interface Devices (HID)
#
#
# Input core support is needed for USB HID
#
#
# USB Imaging devices
# Sound
#
# CONFIG_USB_DC2XX is not set
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_SCANNER is not set
# CONFIG_USB_MICROTEK is not set
# CONFIG_USB_HPUSBSCSI is not set
CONFIG_SOUND=y
#
# USB Multimedia devices
# Advanced Linux Sound Architecture
#
# CONFIG_SND is not set
#
# Video4Linux support is needed for USB Multimedia device support
# Open Sound System
#
# CONFIG_USB_DABUSB is not set
# CONFIG_SOUND_PRIME is not set
#
# USB Network adaptors
# USB support
#
# CONFIG_USB_PLUSB is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_KAWETH is not set
# CONFIG_USB_CATC is not set
# CONFIG_USB_CDCETHER is not set
# CONFIG_USB_USBNET is not set
# CONFIG_USB_GADGET is not set
#
# USB port drivers
# Bluetooth support
#
# CONFIG_USB_USS720 is not set
# CONFIG_BT is not set
#
# USB Serial Converter support
# Kernel hacking
#
# CONFIG_USB_SERIAL is not set
# CONFIG_USB_SERIAL_GENERIC is not set
# CONFIG_USB_SERIAL_BELKIN is not set
# CONFIG_USB_SERIAL_WHITEHEAT is not set
# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
# CONFIG_USB_SERIAL_EMPEG is not set
# CONFIG_USB_SERIAL_FTDI_SIO is not set
# CONFIG_USB_SERIAL_VISOR is not set
# CONFIG_USB_SERIAL_EDGEPORT is not set
# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
# CONFIG_USB_SERIAL_KEYSPAN is not set
# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
# CONFIG_USB_SERIAL_MCT_U232 is not set
# CONFIG_USB_SERIAL_PL2303 is not set
# CONFIG_USB_SERIAL_CYBERJACK is not set
# CONFIG_USB_SERIAL_OMNINET is not set
CONFIG_CROSSCOMPILE=y
# CONFIG_DEBUG_KERNEL is not set
#
# Miscellaneous USB drivers
# Security options
#
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_ID75 is not set
# CONFIG_SECURITY is not set
#
# Input core support
# Cryptographic options
#
# CONFIG_INPUT is not set
# CONFIG_INPUT_KEYBDEV is not set
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_EVDEV is not set
# CONFIG_CRYPTO is not set
#
# Kernel hacking
# Library routines
#
CONFIG_CROSSCOMPILE=y
# CONFIG_REMOTE_DEBUG is not set
# CONFIG_GDB_CONSOLE is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_MIPS_UNCACHED is not set
# CONFIG_CRC32 is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
#
# Automatically generated make config: don't edit
#
CONFIG_MIPS=y
CONFIG_MIPS32=y
# CONFIG_MIPS64 is not set
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
#
# General setup
#
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_EMBEDDED is not set
CONFIG_FUTEX=y
CONFIG_EPOLL=y
#
# Loadable module support
#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_OBSOLETE_MODPARM=y
CONFIG_MODVERSIONS=y
CONFIG_KMOD=y
#
# Machine selection
#
# CONFIG_ACER_PICA_61 is not set
# CONFIG_BAGET_MIPS is not set
# CONFIG_CASIO_E55 is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_LASAT is not set
# CONFIG_HP_LASERJET is not set
# CONFIG_IBM_WORKPAD is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MIPS_MALTA is not set
# CONFIG_MIPS_SEAD is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_MOMENCO_OCELOT_G is not set
# CONFIG_MOMENCO_OCELOT_C is not set
# CONFIG_DDB5074 is not set
# CONFIG_DDB5476 is not set
# CONFIG_DDB5477 is not set
# CONFIG_NEC_OSPREY is not set
# CONFIG_NEC_EAGLE is not set
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP32 is not set
# CONFIG_SOC_AU1X00 is not set
# CONFIG_SIBYTE_SB1xxx_SOC is not set
# CONFIG_SNI_RM200_PCI is not set
# CONFIG_TANBAC_TB0226 is not set
# CONFIG_TANBAC_TB0229 is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_VICTOR_MPC30X is not set
# CONFIG_ZAO_CAPCELLA is not set
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_FB=y
#
# CPU selection
#
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS64 is not set
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_TX39XX is not set
# CONFIG_CPU_VR41XX is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_NEVADA is not set
# CONFIG_CPU_R8000 is not set
# CONFIG_CPU_R10000 is not set
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_SB1 is not set
CONFIG_CPU_HAS_PREFETCH=y
# CONFIG_VTAG_ICACHE is not set
CONFIG_64BIT_PHYS_ADDR=y
CONFIG_CPU_ADVANCED=y
CONFIG_CPU_HAS_LLSC=y
# CONFIG_CPU_HAS_LLDSCD is not set
CONFIG_CPU_HAS_WB=y
CONFIG_CPU_HAS_SYNC=y
# CONFIG_PREEMPT is not set
CONFIG_KALLSYMS=y
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
#
# Bus options (PCI, PCMCIA, EISA, ISA, TC)
#
CONFIG_MMU=y
CONFIG_HOTPLUG=y
#
# PCMCIA/CardBus support
#
CONFIG_PCMCIA=m
# CONFIG_TCIC is not set
#
# PCI Hotplug Support
#
#
# Executable file formats
#
CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
# Memory Technology Devices (MTD)
#
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_CONCAT is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_CMDLINE_PARTS is not set
#
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
#
# RAM/ROM/Flash chip drivers
#
CONFIG_MTD_CFI=y
# CONFIG_MTD_JEDECPROBE is not set
CONFIG_MTD_GEN_PROBE=y
# CONFIG_MTD_CFI_ADV_OPTIONS is not set
CONFIG_MTD_CFI_INTELEXT=y
# CONFIG_MTD_CFI_AMDSTD is not set
# CONFIG_MTD_CFI_STAA is not set
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
# CONFIG_MTD_OBSOLETE_CHIPS is not set
#
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# CONFIG_MTD_PHYSMAP is not set
# CONFIG_MTD_UCLINUX is not set
#
# Self-contained MTD device drivers
#
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_MTDRAM is not set
# CONFIG_MTD_BLKMTD is not set
#
# Disk-On-Chip Device Drivers
#
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
#
# NAND Flash Device Drivers
#
# CONFIG_MTD_NAND is not set
#
# Parallel port support
#
# CONFIG_PARPORT is not set
#
# Plug and Play support
#
# CONFIG_PNP is not set
#
# Generic Driver Options
#
# CONFIG_FW_LOADER is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_INITRD is not set
#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
#
# IDE, ATA and ATAPI Block devices
#
CONFIG_BLK_DEV_IDE=y
#
# Please see Documentation/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
# CONFIG_IDEDISK_STROKE is not set
CONFIG_BLK_DEV_IDECS=m
# CONFIG_BLK_DEV_IDECD is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_IDE_TASK_IOCTL is not set
CONFIG_IDE_TASKFILE_IO=y
#
# IDE chipset support/bugfixes
#
#
# SCSI device support
#
# CONFIG_SCSI is not set
#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
#
# Fusion MPT device support
#
#
# I2O device support
#
#
# Networking support
#
CONFIG_NET=y
#
# Networking options
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
# CONFIG_NETLINK_DEV is not set
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
CONFIG_UNIX=y
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_PNP=y
# CONFIG_IP_PNP_DHCP is not set
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
#
# IP: Netfilter Configuration
#
# CONFIG_IP_NF_CONNTRACK is not set
# CONFIG_IP_NF_QUEUE is not set
# CONFIG_IP_NF_IPTABLES is not set
# CONFIG_IP_NF_ARPTABLES is not set
# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
# CONFIG_IP_NF_COMPAT_IPFWADM is not set
# CONFIG_IPV6 is not set
# CONFIG_XFRM_USER is not set
#
# SCTP Configuration (EXPERIMENTAL)
#
CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_LLC is not set
# CONFIG_DECNET is not set
# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_ETHERTAP is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
# CONFIG_MII is not set
#
# Ethernet (1000 Mbit)
#
#
# Ethernet (10000 Mbit)
#
CONFIG_PPP=m
CONFIG_PPP_MULTILINK=y
# CONFIG_PPP_FILTER is not set
CONFIG_PPP_ASYNC=m
# CONFIG_PPP_SYNC_TTY is not set
CONFIG_PPP_DEFLATE=m
# CONFIG_PPP_BSDCOMP is not set
CONFIG_PPPOE=m
# CONFIG_SLIP is not set
#
# Wireless LAN (non-hamradio)
#
# CONFIG_NET_RADIO is not set
#
# Token Ring devices (depends on LLC=y)
#
# CONFIG_SHAPER is not set
#
# Wan interfaces
#
# CONFIG_WAN is not set
#
# PCMCIA network device support
#
CONFIG_NET_PCMCIA=y
CONFIG_PCMCIA_3C589=m
# CONFIG_PCMCIA_3C574 is not set
# CONFIG_PCMCIA_FMVJ18X is not set
# CONFIG_PCMCIA_PCNET is not set
# CONFIG_PCMCIA_NMCLAN is not set
# CONFIG_PCMCIA_SMC91C92 is not set
# CONFIG_PCMCIA_XIRC2PS is not set
# CONFIG_PCMCIA_AXNET is not set
#
# Amateur Radio support
#
# CONFIG_HAMRADIO is not set
#
# IrDA (infrared) support
#
CONFIG_IRDA=y
#
# IrDA protocols
#
CONFIG_IRLAN=m
# CONFIG_IRNET is not set
CONFIG_IRCOMM=m
# CONFIG_IRDA_ULTRA is not set
#
# IrDA options
#
CONFIG_IRDA_CACHE_LAST_LSAP=y
CONFIG_IRDA_FAST_RR=y
# CONFIG_IRDA_DEBUG is not set
#
# Infrared-port device drivers
#
#
# SIR device drivers
#
# CONFIG_IRTTY_SIR is not set
#
# Dongle support
#
# CONFIG_DONGLE is not set
#
# Old SIR device drivers
#
# CONFIG_IRTTY_OLD is not set
# CONFIG_IRPORT_SIR is not set
#
# Old Serial dongle support
#
# CONFIG_DONGLE_OLD is not set
#
# FIR device drivers
#
# CONFIG_NSC_FIR is not set
# CONFIG_WINBOND_FIR is not set
# CONFIG_TOSHIBA_OLD is not set
# CONFIG_TOSHIBA_FIR is not set
# CONFIG_SMC_IRCC_OLD is not set
# CONFIG_SMC_IRCC_FIR is not set
# CONFIG_ALI_FIR is not set
# CONFIG_VLSI_FIR is not set
#
# ISDN subsystem
#
# CONFIG_ISDN_BOOL is not set
#
# Telephony Support
#
# CONFIG_PHONE is not set
#
# Input device support
#
CONFIG_INPUT=y
#
# Userland interfaces
#
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
# CONFIG_INPUT_EVDEV is not set
# CONFIG_INPUT_EVBUG is not set
#
# Input I/O drivers
#
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
# CONFIG_SERIO is not set
#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_COMPUTONE is not set
# CONFIG_ROCKETPORT is not set
# CONFIG_CYCLADES is not set
# CONFIG_DIGIEPCA is not set
# CONFIG_DIGI is not set
# CONFIG_MOXA_INTELLIO is not set
# CONFIG_MOXA_SMARTIO is not set
# CONFIG_ISI is not set
# CONFIG_SYNCLINK is not set
# CONFIG_SYNCLINKMP is not set
# CONFIG_N_HDLC is not set
# CONFIG_RISCOM8 is not set
# CONFIG_SPECIALIX is not set
# CONFIG_SX is not set
# CONFIG_RIO is not set
# CONFIG_STALDRV is not set
#
# Serial drivers
#
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
#
# I2C support
#
# CONFIG_I2C is not set
#
# I2C Hardware Sensors Mainboard support
#
#
# I2C Hardware Sensors Chip support
#
# CONFIG_I2C_SENSOR is not set
#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set
#
# IPMI
#
# CONFIG_IPMI_HANDLER is not set
#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
CONFIG_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
# CONFIG_AGP is not set
# CONFIG_DRM is not set
#
# PCMCIA character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_HANGCHECK_TIMER is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
#
# Digital Video Broadcasting Devices
#
# CONFIG_DVB is not set
#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
CONFIG_EXT3_FS_SECURITY=y
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
CONFIG_REISERFS_FS=m
# CONFIG_REISERFS_CHECK is not set
# CONFIG_REISERFS_PROC_INFO is not set
# CONFIG_JFS_FS is not set
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_QUOTA is not set
CONFIG_AUTOFS_FS=m
CONFIG_AUTOFS4_FS=m
#
# CD-ROM/DVD Filesystems
#
# CONFIG_ISO9660_FS is not set
# CONFIG_UDF_FS is not set
#
# DOS/FAT/NT Filesystems
#
# CONFIG_FAT_FS is not set
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set
CONFIG_DEVPTS_FS=y
CONFIG_DEVPTS_FS_XATTR=y
CONFIG_DEVPTS_FS_SECURITY=y
CONFIG_TMPFS=y
CONFIG_RAMFS=y
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
CONFIG_JFFS_FS=m
CONFIG_JFFS_FS_VERBOSE=0
CONFIG_JFFS2_FS=m
CONFIG_JFFS2_FS_DEBUG=0
# CONFIG_JFFS2_FS_NAND is not set
CONFIG_CRAMFS=m
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
#
# Network File Systems
#
CONFIG_NFS_FS=y
# CONFIG_NFS_V3 is not set
# CONFIG_NFS_V4 is not set
CONFIG_NFSD=m
# CONFIG_NFSD_V3 is not set
# CONFIG_NFSD_TCP is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_EXPORTFS=m
CONFIG_SUNRPC=y
# CONFIG_SUNRPC_GSS is not set
CONFIG_SMB_FS=m
# CONFIG_SMB_NLS_DEFAULT is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_INTERMEZZO_FS is not set
# CONFIG_AFS_FS is not set
#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
CONFIG_SMB_NLS=y
CONFIG_NLS=y
#
# Native Language Support
#
CONFIG_NLS_DEFAULT="iso8859-1"
# CONFIG_NLS_CODEPAGE_437 is not set
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
# CONFIG_NLS_CODEPAGE_850 is not set
# CONFIG_NLS_CODEPAGE_852 is not set
# CONFIG_NLS_CODEPAGE_855 is not set
# CONFIG_NLS_CODEPAGE_857 is not set
# CONFIG_NLS_CODEPAGE_860 is not set
# CONFIG_NLS_CODEPAGE_861 is not set
# CONFIG_NLS_CODEPAGE_862 is not set
# CONFIG_NLS_CODEPAGE_863 is not set
# CONFIG_NLS_CODEPAGE_864 is not set
# CONFIG_NLS_CODEPAGE_865 is not set
# CONFIG_NLS_CODEPAGE_866 is not set
# CONFIG_NLS_CODEPAGE_869 is not set
# CONFIG_NLS_CODEPAGE_936 is not set
# CONFIG_NLS_CODEPAGE_950 is not set
# CONFIG_NLS_CODEPAGE_932 is not set
# CONFIG_NLS_CODEPAGE_949 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
# CONFIG_NLS_ISO8859_1 is not set
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
# CONFIG_NLS_ISO8859_4 is not set
# CONFIG_NLS_ISO8859_5 is not set
# CONFIG_NLS_ISO8859_6 is not set
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_13 is not set
# CONFIG_NLS_ISO8859_14 is not set
# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
# CONFIG_NLS_UTF8 is not set
#
# Graphics support
#
# CONFIG_FB_VIRTUAL is not set
#
# Console display driver support
#
# CONFIG_VGA_CONSOLE is not set
# CONFIG_MDA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE is not set
#
# Logo configuration
#
# CONFIG_LOGO is not set
#
# Sound
#
CONFIG_SOUND=y
#
# Advanced Linux Sound Architecture
#
# CONFIG_SND is not set
#
# Open Sound System
#
# CONFIG_SOUND_PRIME is not set
#
# USB support
#
# CONFIG_USB_GADGET is not set
#
# Bluetooth support
#
# CONFIG_BT is not set
#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
# CONFIG_DEBUG_KERNEL is not set
#
# Security options
#
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
# CONFIG_CRYPTO is not set
#
# Library routines
#
# CONFIG_CRC32 is not set
CONFIG_ZLIB_INFLATE=m
CONFIG_ZLIB_DEFLATE=m
#
# Automatically generated make config: don't edit
#
CONFIG_MIPS=y
CONFIG_MIPS32=y
# CONFIG_MIPS64 is not set
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
#
# General setup
#
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_EMBEDDED is not set
CONFIG_FUTEX=y
CONFIG_EPOLL=y
#
# Loadable module support
#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_OBSOLETE_MODPARM=y
CONFIG_MODVERSIONS=y
CONFIG_KMOD=y
#
# Machine selection
#
# CONFIG_ACER_PICA_61 is not set
# CONFIG_BAGET_MIPS is not set
# CONFIG_CASIO_E55 is not set
# CONFIG_MIPS_COBALT is not set
# CONFIG_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_LASAT is not set
# CONFIG_HP_LASERJET is not set
# CONFIG_IBM_WORKPAD is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MIPS_ATLAS is not set
# CONFIG_MIPS_MAGNUM_4000 is not set
# CONFIG_MIPS_MALTA is not set
# CONFIG_MIPS_SEAD is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_MOMENCO_OCELOT_G is not set
# CONFIG_MOMENCO_OCELOT_C is not set
# CONFIG_DDB5074 is not set
# CONFIG_DDB5476 is not set
# CONFIG_DDB5477 is not set
# CONFIG_NEC_OSPREY is not set
# CONFIG_NEC_EAGLE is not set
# CONFIG_OLIVETTI_M700 is not set
# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP32 is not set
CONFIG_SOC_AU1X00=y
# CONFIG_SOC_AU1000 is not set
# CONFIG_SOC_AU1100 is not set
CONFIG_SOC_AU1500=y
# CONFIG_MIPS_PB1000 is not set
# CONFIG_MIPS_PB1100 is not set
CONFIG_MIPS_PB1500=y
# CONFIG_MIPS_DB1000 is not set
# CONFIG_MIPS_DB1100 is not set
# CONFIG_MIPS_DB1500 is not set
# CONFIG_SIBYTE_SB1xxx_SOC is not set
# CONFIG_SNI_RM200_PCI is not set
# CONFIG_TANBAC_TB0226 is not set
# CONFIG_TANBAC_TB0229 is not set
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_VICTOR_MPC30X is not set
# CONFIG_ZAO_CAPCELLA is not set
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_NONCOHERENT_IO=y
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_NEW_PCI=y
# CONFIG_AU1000_USB_DEVICE is not set
# CONFIG_FB is not set
#
# CPU selection
#
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS64 is not set
# CONFIG_CPU_R3000 is not set
# CONFIG_CPU_TX39XX is not set
# CONFIG_CPU_VR41XX is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_NEVADA is not set
# CONFIG_CPU_R8000 is not set
# CONFIG_CPU_R10000 is not set
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_SB1 is not set
CONFIG_CPU_HAS_PREFETCH=y
# CONFIG_VTAG_ICACHE is not set
# CONFIG_64BIT_PHYS_ADDR is not set
# CONFIG_CPU_ADVANCED is not set
CONFIG_CPU_HAS_LLSC=y
CONFIG_CPU_HAS_SYNC=y
# CONFIG_PREEMPT is not set
CONFIG_KALLSYMS=y
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
#
# Bus options (PCI, PCMCIA, EISA, ISA, TC)
#
# CONFIG_PCI is not set
CONFIG_MMU=y
CONFIG_HOTPLUG=y
#
# PCMCIA/CardBus support
#
CONFIG_PCMCIA=m
# CONFIG_TCIC is not set
#
# PCI Hotplug Support
#
#
# Executable file formats
#
CONFIG_KCORE_ELF=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_PM is not set
#
# Memory Technology Devices (MTD)
#
# CONFIG_MTD is not set
#
# Parallel port support
#
# CONFIG_PARPORT is not set
#
# Plug and Play support
#
# CONFIG_PNP is not set
#
# Generic Driver Options
#
# CONFIG_FW_LOADER is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_INITRD is not set
#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
#
# SCSI device support
#
# CONFIG_SCSI is not set
#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
#
# Fusion MPT device support
#
#
# I2O device support
#
#
# Networking support
#
CONFIG_NET=y
#
# Networking options
#
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_NETLINK_DEV=y
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
CONFIG_UNIX=y
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_PNP=y
# CONFIG_IP_PNP_DHCP is not set
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
#
# IP: Netfilter Configuration
#
# CONFIG_IP_NF_CONNTRACK is not set
# CONFIG_IP_NF_QUEUE is not set
# CONFIG_IP_NF_IPTABLES is not set
# CONFIG_IP_NF_ARPTABLES is not set
# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
# CONFIG_IP_NF_COMPAT_IPFWADM is not set
# CONFIG_IPV6 is not set
# CONFIG_XFRM_USER is not set
#
# SCTP Configuration (EXPERIMENTAL)
#
CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_LLC is not set
# CONFIG_DECNET is not set
# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
# CONFIG_NET_HW_FLOWCONTROL is not set
#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
#
# Network testing
#
# CONFIG_NET_PKTGEN is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_ETHERTAP is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
# CONFIG_MII is not set
CONFIG_MIPS_AU1X00_ENET=y
#
# Ethernet (1000 Mbit)
#
#
# Ethernet (10000 Mbit)
#
CONFIG_PPP=m
CONFIG_PPP_MULTILINK=y
# CONFIG_PPP_FILTER is not set
CONFIG_PPP_ASYNC=m
# CONFIG_PPP_SYNC_TTY is not set
CONFIG_PPP_DEFLATE=m
# CONFIG_PPP_BSDCOMP is not set
CONFIG_PPPOE=m
# CONFIG_SLIP is not set
#
# Wireless LAN (non-hamradio)
#
# CONFIG_NET_RADIO is not set
#
# Token Ring devices (depends on LLC=y)
#
# CONFIG_SHAPER is not set
#
# Wan interfaces
#
# CONFIG_WAN is not set
#
# PCMCIA network device support
#
CONFIG_NET_PCMCIA=y
CONFIG_PCMCIA_3C589=m
# CONFIG_PCMCIA_3C574 is not set
# CONFIG_PCMCIA_FMVJ18X is not set
# CONFIG_PCMCIA_PCNET is not set
# CONFIG_PCMCIA_NMCLAN is not set
# CONFIG_PCMCIA_SMC91C92 is not set
# CONFIG_PCMCIA_XIRC2PS is not set
# CONFIG_PCMCIA_AXNET is not set
#
# Amateur Radio support
#
# CONFIG_HAMRADIO is not set
#
# IrDA (infrared) support
#
# CONFIG_IRDA is not set
#
# ISDN subsystem
#
# CONFIG_ISDN_BOOL is not set
#
# Telephony Support
#
# CONFIG_PHONE is not set
#
# Input device support
#
CONFIG_INPUT=y
#
# Userland interfaces
#
CONFIG_INPUT_MOUSEDEV=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_EVBUG is not set
#
# Input I/O drivers
#
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
CONFIG_SERIO=y
# CONFIG_SERIO_I8042 is not set
CONFIG_SERIO_SERPORT=y
# CONFIG_SERIO_CT82C710 is not set
#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
# CONFIG_SERIAL_NONSTANDARD is not set
# CONFIG_AU1X00_GPIO is not set
# CONFIG_TS_AU1X00_ADS7846 is not set
#
# Serial drivers
#
# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_AU1X00=y
CONFIG_SERIAL_AU1X00_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
#
# I2C support
#
# CONFIG_I2C is not set
#
# I2C Hardware Sensors Mainboard support
#
#
# I2C Hardware Sensors Chip support
#
# CONFIG_I2C_SENSOR is not set
#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set
#
# IPMI
#
# CONFIG_IPMI_HANDLER is not set
#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_NVRAM is not set
CONFIG_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
# CONFIG_AGP is not set
# CONFIG_DRM is not set
#
# PCMCIA character devices
#
# CONFIG_SYNCLINK_CS is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_HANGCHECK_TIMER is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
#
# Digital Video Broadcasting Devices
#
# CONFIG_DVB is not set
#
# File systems
#
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
# CONFIG_EXT2_FS_SECURITY is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
CONFIG_REISERFS_FS=m
# CONFIG_REISERFS_CHECK is not set
# CONFIG_REISERFS_PROC_INFO is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_QUOTA is not set
CONFIG_AUTOFS_FS=m
CONFIG_AUTOFS4_FS=m
#
# CD-ROM/DVD Filesystems
#
# CONFIG_ISO9660_FS is not set
# CONFIG_UDF_FS is not set
#
# DOS/FAT/NT Filesystems
#
# CONFIG_FAT_FS is not set
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set
CONFIG_DEVPTS_FS=y
CONFIG_DEVPTS_FS_XATTR=y
CONFIG_DEVPTS_FS_SECURITY=y
CONFIG_TMPFS=y
CONFIG_RAMFS=y
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
CONFIG_CRAMFS=m
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
#
# Network File Systems
#
CONFIG_NFS_FS=y
# CONFIG_NFS_V3 is not set
# CONFIG_NFS_V4 is not set
CONFIG_NFSD=m
# CONFIG_NFSD_V3 is not set
# CONFIG_NFSD_TCP is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_EXPORTFS=m
CONFIG_SUNRPC=y
# CONFIG_SUNRPC_GSS is not set
CONFIG_SMB_FS=m
# CONFIG_SMB_NLS_DEFAULT is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_INTERMEZZO_FS is not set
# CONFIG_AFS_FS is not set
#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
CONFIG_SMB_NLS=y
CONFIG_NLS=y
#
# Native Language Support
#
CONFIG_NLS_DEFAULT="iso8859-1"
# CONFIG_NLS_CODEPAGE_437 is not set
# CONFIG_NLS_CODEPAGE_737 is not set
# CONFIG_NLS_CODEPAGE_775 is not set
# CONFIG_NLS_CODEPAGE_850 is not set
# CONFIG_NLS_CODEPAGE_852 is not set
# CONFIG_NLS_CODEPAGE_855 is not set
# CONFIG_NLS_CODEPAGE_857 is not set
# CONFIG_NLS_CODEPAGE_860 is not set
# CONFIG_NLS_CODEPAGE_861 is not set
# CONFIG_NLS_CODEPAGE_862 is not set
# CONFIG_NLS_CODEPAGE_863 is not set
# CONFIG_NLS_CODEPAGE_864 is not set
# CONFIG_NLS_CODEPAGE_865 is not set
# CONFIG_NLS_CODEPAGE_866 is not set
# CONFIG_NLS_CODEPAGE_869 is not set
# CONFIG_NLS_CODEPAGE_936 is not set
# CONFIG_NLS_CODEPAGE_950 is not set
# CONFIG_NLS_CODEPAGE_932 is not set
# CONFIG_NLS_CODEPAGE_949 is not set
# CONFIG_NLS_CODEPAGE_874 is not set
# CONFIG_NLS_ISO8859_8 is not set
# CONFIG_NLS_CODEPAGE_1250 is not set
# CONFIG_NLS_CODEPAGE_1251 is not set
# CONFIG_NLS_ISO8859_1 is not set
# CONFIG_NLS_ISO8859_2 is not set
# CONFIG_NLS_ISO8859_3 is not set
# CONFIG_NLS_ISO8859_4 is not set
# CONFIG_NLS_ISO8859_5 is not set
# CONFIG_NLS_ISO8859_6 is not set
# CONFIG_NLS_ISO8859_7 is not set
# CONFIG_NLS_ISO8859_9 is not set
# CONFIG_NLS_ISO8859_13 is not set
# CONFIG_NLS_ISO8859_14 is not set
# CONFIG_NLS_ISO8859_15 is not set
# CONFIG_NLS_KOI8_R is not set
# CONFIG_NLS_KOI8_U is not set
# CONFIG_NLS_UTF8 is not set
#
# Graphics support
#
#
# Console display driver support
#
# CONFIG_VGA_CONSOLE is not set
# CONFIG_MDA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
#
# Sound
#
# CONFIG_SOUND is not set
#
# USB support
#
# CONFIG_USB_GADGET is not set
#
# Bluetooth support
#
# CONFIG_BT is not set
#
# Kernel hacking
#
CONFIG_CROSSCOMPILE=y
# CONFIG_DEBUG_KERNEL is not set
#
# Security options
#
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
CONFIG_CRYPTO=y
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_NULL=y
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 is not set
# CONFIG_CRYPTO_SHA1 is not set
# CONFIG_CRYPTO_SHA256 is not set
CONFIG_CRYPTO_SHA512=y
# CONFIG_CRYPTO_DES is not set
# CONFIG_CRYPTO_BLOWFISH is not set
CONFIG_CRYPTO_TWOFISH=y
# CONFIG_CRYPTO_SERPENT is not set
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_DEFLATE=y
# CONFIG_CRYPTO_TEST is not set
#
# Library routines
#
CONFIG_CRC32=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
/*
*
* Alchemy Semi Au1000 pcmcia driver
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* ########################################################################
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
* ########################################################################
*
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/tqueue.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
#include <pcmcia/bulkmem.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/bus_ops.h>
#include "cs_internal.h"
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/au1000.h>
#include <asm/au1000_pcmcia.h>
#ifdef PCMCIA_DEBUG
static int pc_debug;
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pete Popov, MontaVista Software <ppopov@mvista.com>");
MODULE_DESCRIPTION("Linux PCMCIA Card Services: Au1x00 Socket Controller");
#define MAP_SIZE 0x1000000
/* This structure maintains housekeeping state for each socket, such
* as the last known values of the card detect pins, or the Card Services
* callback value associated with the socket:
*/
static struct au1000_pcmcia_socket *pcmcia_socket;
static int socket_count;
/* Returned by the low-level PCMCIA interface: */
static struct pcmcia_low_level *pcmcia_low_level;
/* Event poll timer structure */
static struct timer_list poll_timer;
/* Prototypes for routines which are used internally: */
static int au1000_pcmcia_driver_init(void);
static void au1000_pcmcia_driver_shutdown(void);
static void au1000_pcmcia_task_handler(void *data);
static void au1000_pcmcia_poll_event(unsigned long data);
static void au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs);
static struct tq_struct au1000_pcmcia_task;
#ifdef CONFIG_PROC_FS
static int au1000_pcmcia_proc_status(char *buf, char **start,
off_t pos, int count, int *eof, void *data);
#endif
/* Prototypes for operations which are exported to the
* new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core:
*/
static int au1000_pcmcia_init(u32 sock);
static int au1000_pcmcia_suspend(u32 sock);
static int au1000_pcmcia_register_callback(u32 sock,
void (*handler)(void *, u32), void *info);
static int au1000_pcmcia_inquire_socket(u32 sock, socket_cap_t *cap);
static int au1000_pcmcia_get_status(u32 sock, u_int *value);
static int au1000_pcmcia_get_socket(u32 sock, socket_state_t *state);
static int au1000_pcmcia_set_socket(u32 sock, socket_state_t *state);
static int au1000_pcmcia_get_io_map(u32 sock, struct pccard_io_map *io);
static int au1000_pcmcia_set_io_map(u32 sock, struct pccard_io_map *io);
static int au1000_pcmcia_get_mem_map(u32 sock, struct pccard_mem_map *mem);
static int au1000_pcmcia_set_mem_map(u32 sock, struct pccard_mem_map *mem);
#ifdef CONFIG_PROC_FS
static void au1000_pcmcia_proc_setup(u32 sock, struct proc_dir_entry *base);
#endif
static struct pccard_operations au1000_pcmcia_operations = {
au1000_pcmcia_init,
au1000_pcmcia_suspend,
au1000_pcmcia_register_callback,
au1000_pcmcia_inquire_socket,
au1000_pcmcia_get_status,
au1000_pcmcia_get_socket,
au1000_pcmcia_set_socket,
au1000_pcmcia_get_io_map,
au1000_pcmcia_set_io_map,
au1000_pcmcia_get_mem_map,
au1000_pcmcia_set_mem_map,
#ifdef CONFIG_PROC_FS
au1000_pcmcia_proc_setup
#endif
};
static spinlock_t pcmcia_lock = SPIN_LOCK_UNLOCKED;
static int __init au1000_pcmcia_driver_init(void)
{
servinfo_t info;
struct pcmcia_init pcmcia_init;
struct pcmcia_state state;
unsigned int i;
printk("\nAu1x00 PCMCIA (CS release %s)\n", CS_RELEASE);
#ifndef CONFIG_64BIT_PHYS_ADDR
printk(KERN_ERR "Au1x00 PCMCIA 36 bit IO support not enabled\n");
return -1;
#endif
CardServices(GetCardServicesInfo, &info);
if(info.Revision!=CS_RELEASE_CODE){
printk(KERN_ERR "Card Services release codes do not match\n");
return -1;
}
#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500)
pcmcia_low_level=&pb1x00_pcmcia_ops;
#else
#error Unsupported AU1000 board.
#endif
pcmcia_init.handler=au1000_pcmcia_interrupt;
if((socket_count=pcmcia_low_level->init(&pcmcia_init))<0) {
printk(KERN_ERR "Unable to initialize PCMCIA service.\n");
return -EIO;
}
/* NOTE: the chip select must already be setup */
pcmcia_socket =
kmalloc(sizeof(struct au1000_pcmcia_socket) * socket_count,
GFP_KERNEL);
if (!pcmcia_socket) {
printk(KERN_ERR "Card Services can't get memory \n");
return -1;
}
memset(pcmcia_socket, 0,
sizeof(struct au1000_pcmcia_socket) * socket_count);
/*
* Assuming max of 2 sockets, which the Au1000 supports.
* WARNING: the Pb1000 has two sockets, and both work, but you
* can't use them both at the same time due to glue logic conflicts.
*/
for(i=0; i < socket_count; i++) {
if(pcmcia_low_level->socket_state(i, &state)<0){
printk(KERN_ERR "Unable to get PCMCIA status\n");
return -EIO;
}
pcmcia_socket[i].k_state=state;
pcmcia_socket[i].cs_state.csc_mask=SS_DETECT;
if (i == 0) {
pcmcia_socket[i].virt_io =
(u32)ioremap((ioaddr_t)0xF00000000, 0x1000);
pcmcia_socket[i].phys_attr = (memaddr_t)0xF40000000;
pcmcia_socket[i].phys_mem = (memaddr_t)0xF80000000;
}
else {
pcmcia_socket[i].virt_io =
(u32)ioremap((ioaddr_t)0xF08000000, 0x1000);
pcmcia_socket[i].phys_attr = (memaddr_t)0xF48000000;
pcmcia_socket[i].phys_mem = (memaddr_t)0xF88000000;
}
}
/* Only advertise as many sockets as we can detect: */
if(register_ss_entry(socket_count, &au1000_pcmcia_operations)<0){
printk(KERN_ERR "Unable to register socket service routine\n");
return -ENXIO;
}
/* Start the event poll timer.
* It will reschedule by itself afterwards.
*/
au1000_pcmcia_poll_event(0);
DEBUG(1, "au1000: initialization complete\n");
return 0;
} /* au1000_pcmcia_driver_init() */
module_init(au1000_pcmcia_driver_init);
static void __exit au1000_pcmcia_driver_shutdown(void)
{
int i;
del_timer_sync(&poll_timer);
unregister_ss_entry(&au1000_pcmcia_operations);
pcmcia_low_level->shutdown();
flush_scheduled_tasks();
for(i=0; i < socket_count; i++) {
if (pcmcia_socket[i].virt_io)
iounmap((void *)pcmcia_socket[i].virt_io);
}
DEBUG(1, "au1000: shutdown complete\n");
}
module_exit(au1000_pcmcia_driver_shutdown);
static int au1000_pcmcia_init(unsigned int sock) { return 0; }
static int au1000_pcmcia_suspend(unsigned int sock)
{
return 0;
}
static inline unsigned
au1000_pcmcia_events(struct pcmcia_state *state,
struct pcmcia_state *prev_state,
unsigned int mask, unsigned int flags)
{
unsigned int events=0;
if(state->detect!=prev_state->detect){
DEBUG(2, "%s(): card detect value %u\n",
__FUNCTION__, state->detect);
events |= mask&SS_DETECT;
}
if(state->ready!=prev_state->ready){
DEBUG(2, "%s(): card ready value %u\n",
__FUNCTION__, state->ready);
events |= mask&((flags&SS_IOCARD)?0:SS_READY);
}
*prev_state=*state;
return events;
} /* au1000_pcmcia_events() */
/*
* Au1000_pcmcia_task_handler()
* Processes socket events.
*/
static void au1000_pcmcia_task_handler(void *data)
{
struct pcmcia_state state;
int i, events, irq_status;
for(i=0; i<socket_count; i++) {
if((irq_status = pcmcia_low_level->socket_state(i, &state))<0)
printk(KERN_ERR "low-level PCMCIA error\n");
events = au1000_pcmcia_events(&state,
&pcmcia_socket[i].k_state,
pcmcia_socket[i].cs_state.csc_mask,
pcmcia_socket[i].cs_state.flags);
if(pcmcia_socket[i].handler!=NULL) {
pcmcia_socket[i].handler(pcmcia_socket[i].handler_info,
events);
}
}
} /* au1000_pcmcia_task_handler() */
static struct tq_struct au1000_pcmcia_task = {
routine: au1000_pcmcia_task_handler
};
static void au1000_pcmcia_poll_event(unsigned long dummy)
{
poll_timer.function = au1000_pcmcia_poll_event;
poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD;
add_timer(&poll_timer);
schedule_task(&au1000_pcmcia_task);
}
/*
* au1000_pcmcia_interrupt()
* The actual interrupt work is performed by au1000_pcmcia_task(),
* because the Card Services event handling code performs scheduling
* operations which cannot be executed from within an interrupt context.
*/
static void
au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
{
schedule_task(&au1000_pcmcia_task);
}
static int
au1000_pcmcia_register_callback(unsigned int sock,
void (*handler)(void *, unsigned int), void *info)
{
if(handler==NULL){
pcmcia_socket[sock].handler=NULL;
MOD_DEC_USE_COUNT;
} else {
MOD_INC_USE_COUNT;
pcmcia_socket[sock].handler=handler;
pcmcia_socket[sock].handler_info=info;
}
return 0;
}
/* au1000_pcmcia_inquire_socket()
*
* From the sa1100 socket driver :
*
* Implements the inquire_socket() operation for the in-kernel PCMCIA
* service (formerly SS_InquireSocket in Card Services). We set
* SS_CAP_STATIC_MAP, which disables the memory resource database check.
* (Mapped memory is set up within the socket driver itself.)
*
* In conjunction with the STATIC_MAP capability is a new field,
* `io_offset', recommended by David Hinds. Rather than go through
* the SetIOMap interface (which is not quite suited for communicating
* window locations up from the socket driver), we just pass up
* an offset which is applied to client-requested base I/O addresses
* in alloc_io_space().
*
* Returns: 0 on success, -1 if no pin has been configured for `sock'
*/
static int au1000_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap)
{
struct pcmcia_irq_info irq_info;
if(sock > socket_count){
printk(KERN_ERR "au1000: socket %u not configured\n", sock);
return -1;
}
/* from the sa1100_generic driver: */
/* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
* force_low argument to validate_mem() in rsrc_mgr.c -- since in
* general, the mapped * addresses of the PCMCIA memory regions
* will not be within 0xffff, setting force_low would be
* undesirable.
*
* SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
* resource database; we instead pass up physical address ranges
* and allow other parts of Card Services to deal with remapping.
*
* SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
* not 32-bit CardBus devices.
*/
cap->features=(SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD);
irq_info.sock=sock;
irq_info.irq=-1;
if(pcmcia_low_level->get_irq_info(&irq_info)<0){
printk(KERN_ERR "Error obtaining IRQ info socket %u\n", sock);
return -1;
}
cap->irq_mask=0;
cap->map_size=MAP_SIZE;
cap->pci_irq=irq_info.irq;
cap->io_offset=pcmcia_socket[sock].virt_io;
return 0;
} /* au1000_pcmcia_inquire_socket() */
static int
au1000_pcmcia_get_status(unsigned int sock, unsigned int *status)
{
struct pcmcia_state state;
if((pcmcia_low_level->socket_state(sock, &state))<0){
printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
return -1;
}
pcmcia_socket[sock].k_state = state;
*status = state.detect?SS_DETECT:0;
*status |= state.ready?SS_READY:0;
*status |= pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0;
if(pcmcia_socket[sock].cs_state.flags&SS_IOCARD)
*status |= state.bvd1?SS_STSCHG:0;
else {
if(state.bvd1==0)
*status |= SS_BATDEAD;
else if(state.bvd2 == 0)
*status |= SS_BATWARN;
}
*status|=state.vs_3v?SS_3VCARD:0;
*status|=state.vs_Xv?SS_XVCARD:0;
DEBUG(2, "\tstatus: %s%s%s%s%s%s%s%s\n",
(*status&SS_DETECT)?"DETECT ":"",
(*status&SS_READY)?"READY ":"",
(*status&SS_BATDEAD)?"BATDEAD ":"",
(*status&SS_BATWARN)?"BATWARN ":"",
(*status&SS_POWERON)?"POWERON ":"",
(*status&SS_STSCHG)?"STSCHG ":"",
(*status&SS_3VCARD)?"3VCARD ":"",
(*status&SS_XVCARD)?"XVCARD ":"");
return 0;
} /* au1000_pcmcia_get_status() */
static int
au1000_pcmcia_get_socket(unsigned int sock, socket_state_t *state)
{
*state = pcmcia_socket[sock].cs_state;
return 0;
}
static int
au1000_pcmcia_set_socket(unsigned int sock, socket_state_t *state)
{
struct pcmcia_configure configure;
DEBUG(2, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n"
"\tVcc %d Vpp %d irq %d\n",
(state->csc_mask==0)?"<NONE>":"",
(state->csc_mask&SS_DETECT)?"DETECT ":"",
(state->csc_mask&SS_READY)?"READY ":"",
(state->csc_mask&SS_BATDEAD)?"BATDEAD ":"",
(state->csc_mask&SS_BATWARN)?"BATWARN ":"",
(state->csc_mask&SS_STSCHG)?"STSCHG ":"",
(state->flags==0)?"<NONE>":"",
(state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"",
(state->flags&SS_IOCARD)?"IOCARD ":"",
(state->flags&SS_RESET)?"RESET ":"",
(state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
state->Vcc, state->Vpp, state->io_irq);
configure.sock=sock;
configure.vcc=state->Vcc;
configure.vpp=state->Vpp;
configure.output=(state->flags&SS_OUTPUT_ENA)?1:0;
configure.speaker=(state->flags&SS_SPKR_ENA)?1:0;
configure.reset=(state->flags&SS_RESET)?1:0;
if(pcmcia_low_level->configure_socket(&configure)<0){
printk(KERN_ERR "Unable to configure socket %u\n", sock);
return -1;
}
pcmcia_socket[sock].cs_state = *state;
return 0;
} /* au1000_pcmcia_set_socket() */
static int
au1000_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map)
{
DEBUG(1, "au1000_pcmcia_get_io_map: sock %d\n", sock);
if(map->map>=MAX_IO_WIN){
printk(KERN_ERR "%s(): map (%d) out of range\n",
__FUNCTION__, map->map);
return -1;
}
*map=pcmcia_socket[sock].io_map[map->map];
return 0;
}
int
au1000_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map)
{
unsigned int speed;
unsigned long start;
if(map->map>=MAX_IO_WIN){
printk(KERN_ERR "%s(): map (%d) out of range\n",
__FUNCTION__, map->map);
return -1;
}
if(map->flags&MAP_ACTIVE){
speed=(map->speed>0)?map->speed:AU1000_PCMCIA_IO_SPEED;
pcmcia_socket[sock].speed_io=speed;
}
start=map->start;
if(map->stop==1) {
map->stop=PAGE_SIZE-1;
}
map->start=pcmcia_socket[sock].virt_io;
map->stop=map->start+(map->stop-start);
pcmcia_socket[sock].io_map[map->map]=*map;
DEBUG(3, "set_io_map %d start %x stop %x\n",
map->map, map->start, map->stop);
return 0;
} /* au1000_pcmcia_set_io_map() */
static int
au1000_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map)
{
if(map->map>=MAX_WIN) {
printk(KERN_ERR "%s(): map (%d) out of range\n",
__FUNCTION__, map->map);
return -1;
}
*map=pcmcia_socket[sock].mem_map[map->map];
return 0;
}
static int
au1000_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map)
{
unsigned int speed;
unsigned long start;
u_long flags;
if(map->map>=MAX_WIN){
printk(KERN_ERR "%s(): map (%d) out of range\n",
__FUNCTION__, map->map);
return -1;
}
if(map->flags&MAP_ACTIVE){
speed=(map->speed>0)?map->speed:AU1000_PCMCIA_MEM_SPEED;
/* TBD */
if(map->flags&MAP_ATTRIB){
pcmcia_socket[sock].speed_attr=speed;
}
else {
pcmcia_socket[sock].speed_mem=speed;
}
}
spin_lock_irqsave(&pcmcia_lock, flags);
start=map->sys_start;
if(map->sys_stop==0)
map->sys_stop=MAP_SIZE-1;
if (map->flags & MAP_ATTRIB) {
map->sys_start = pcmcia_socket[sock].phys_attr +
map->card_start;
}
else {
map->sys_start = pcmcia_socket[sock].phys_mem +
map->card_start;
}
map->sys_stop=map->sys_start+(map->sys_stop-start);
pcmcia_socket[sock].mem_map[map->map]=*map;
spin_unlock_irqrestore(&pcmcia_lock, flags);
DEBUG(3, "set_mem_map %d start %x stop %x card_start %x\n",
map->map, map->sys_start, map->sys_stop,
map->card_start);
return 0;
} /* au1000_pcmcia_set_mem_map() */
#if defined(CONFIG_PROC_FS)
static void
au1000_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base)
{
struct proc_dir_entry *entry;
if((entry=create_proc_entry("status", 0, base))==NULL){
printk(KERN_ERR "Unable to install \"status\" procfs entry\n");
return;
}
entry->read_proc=au1000_pcmcia_proc_status;
entry->data=(void *)sock;
}
/* au1000_pcmcia_proc_status()
* Implements the /proc/bus/pccard/??/status file.
*
* Returns: the number of characters added to the buffer
*/
static int
au1000_pcmcia_proc_status(char *buf, char **start, off_t pos,
int count, int *eof, void *data)
{
char *p=buf;
unsigned int sock=(unsigned int)data;
p+=sprintf(p, "k_flags : %s%s%s%s%s%s%s\n",
pcmcia_socket[sock].k_state.detect?"detect ":"",
pcmcia_socket[sock].k_state.ready?"ready ":"",
pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"",
pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"",
pcmcia_socket[sock].k_state.wrprot?"wrprot ":"",
pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"",
pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":"");
p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n",
pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"",
pcmcia_socket[sock].k_state.ready?"SS_READY ":"",
pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"",
pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
"SS_IOCARD ":"",
(pcmcia_socket[sock].cs_state.flags&SS_IOCARD &&
pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"",
((pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
(pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"",
((pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
(pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"",
pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"",
pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":"");
p+=sprintf(p, "mask : %s%s%s%s%s\n",
pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\
"SS_DETECT ":"",
pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\
"SS_READY ":"",
pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\
"SS_BATDEAD ":"",
pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\
"SS_BATWARN ":"",
pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\
"SS_STSCHG ":"");
p+=sprintf(p, "cs_flags : %s%s%s%s%s\n",
pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\
"SS_PWR_AUTO ":"",
pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
"SS_IOCARD ":"",
pcmcia_socket[sock].cs_state.flags&SS_RESET?\
"SS_RESET ":"",
pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\
"SS_SPKR_ENA ":"",
pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\
"SS_OUTPUT_ENA ":"");
p+=sprintf(p, "Vcc : %d\n", pcmcia_socket[sock].cs_state.Vcc);
p+=sprintf(p, "Vpp : %d\n", pcmcia_socket[sock].cs_state.Vpp);
p+=sprintf(p, "irq : %d\n", pcmcia_socket[sock].cs_state.io_irq);
p+=sprintf(p, "I/O : %u\n", pcmcia_socket[sock].speed_io);
p+=sprintf(p, "attribute: %u\n", pcmcia_socket[sock].speed_attr);
p+=sprintf(p, "common : %u\n", pcmcia_socket[sock].speed_mem);
return p-buf;
}
#endif /* defined(CONFIG_PROC_FS) */
/*
*
* Alchemy Semi Pb1x00 boards specific pcmcia routines.
*
* Copyright 2002 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* ########################################################################
*
* This program is free software; you can distribute it and/or modify it
* under the terms of the GNU General Public License (Version 2) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/tqueue.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/version.h>
#include <linux/types.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
#include <pcmcia/bulkmem.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/bus_ops.h>
#include "cs_internal.h"
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/au1000.h>
#include <asm/au1000_pcmcia.h>
#ifdef CONFIG_MIPS_PB1000
#include <asm/pb1000.h>
#define PCMCIA_IRQ AU1000_GPIO_15
#elif defined (CONFIG_MIPS_PB1500)
#include <asm/pb1500.h>
#define PCMCIA_IRQ AU1000_GPIO_11 /* fixme */
#elif defined (CONFIG_MIPS_PB1100)
#include <asm/pb1100.h>
#define PCMCIA_IRQ AU1000_GPIO_11
#endif
static int pb1x00_pcmcia_init(struct pcmcia_init *init)
{
#ifdef CONFIG_MIPS_PB1000
u16 pcr;
pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
au_writel(0x8000, PB1000_MDR); /* clear pcmcia interrupt */
au_sync_delay(100);
au_writel(0x4000, PB1000_MDR); /* enable pcmcia interrupt */
au_sync();
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0);
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1);
au_writel(pcr, PB1000_PCR);
au_sync_delay(20);
return PCMCIA_NUM_SOCKS;
#else /* fixme -- take care of the Pb1500 at some point */
u16 pcr;
pcr = au_readw(PB1100_MEM_PCMCIA) & ~0xf; /* turn off power */
pcr &= ~(PB1100_PC_DEASSERT_RST | PB1100_PC_DRV_EN);
au_writew(pcr, PB1100_MEM_PCMCIA);
au_sync_delay(500);
return PCMCIA_NUM_SOCKS;
#endif
}
static int pb1x00_pcmcia_shutdown(void)
{
#ifdef CONFIG_MIPS_PB1000
u16 pcr;
pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0);
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,1);
au_writel(pcr, PB1000_PCR);
au_sync_delay(20);
return 0;
#else
u16 pcr;
pcr = au_readw(PB1100_MEM_PCMCIA) & ~0xf; /* turn off power */
pcr &= ~(PB1100_PC_DEASSERT_RST | PB1100_PC_DRV_EN);
au_writew(pcr, PB1100_MEM_PCMCIA);
au_sync_delay(2);
return 0;
#endif
}
static int
pb1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
{
u32 inserted0, inserted1;
u16 vs0, vs1;
#ifdef CONFIG_MIPS_PB1000
vs0 = vs1 = (u16)au_readl(PB1000_ACR1);
inserted0 = !(vs0 & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2));
inserted1 = !(vs1 & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2));
vs0 = (vs0 >> 4) & 0x3;
vs1 = (vs1 >> 12) & 0x3;
#else
vs0 = (au_readw(PB1100_BOARD_STATUS) >> 4) & 0x3;
inserted0 = !((au_readl(SYS_PINSTATERD) >> 9) & 0x1); /* gpio 9 */
#endif
state->ready = 0;
state->vs_Xv = 0;
state->vs_3v = 0;
state->detect = 0;
if (sock == 0) {
if (inserted0) {
switch (vs0) {
case 0:
case 2:
state->vs_3v=1;
break;
case 3: /* 5V */
break;
default:
/* return without setting 'detect' */
printk(KERN_ERR "pb1x00 bad VS (%d)\n",
vs0);
return;
}
state->detect = 1;
}
}
else {
if (inserted1) {
switch (vs1) {
case 0:
case 2:
state->vs_3v=1;
break;
case 3: /* 5V */
break;
default:
/* return without setting 'detect' */
printk(KERN_ERR "pb1x00 bad VS (%d)\n",
vs1);
return;
}
state->detect = 1;
}
}
if (state->detect) {
state->ready = 1;
}
state->bvd1=1;
state->bvd2=1;
state->wrprot=0;
return 1;
}
static int pb1x00_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
if(info->sock > PCMCIA_MAX_SOCK) return -1;
/*
* Even in the case of the Pb1000, both sockets are connected
* to the same irq line.
*/
info->irq = PCMCIA_IRQ;
return 0;
}
static int
pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
{
u16 pcr;
if(configure->sock > PCMCIA_MAX_SOCK) return -1;
#ifdef CONFIG_MIPS_PB1000
pcr = au_readl(PB1000_PCR);
if (configure->sock == 0) {
pcr &= ~(PCR_SLOT_0_VCC0 | PCR_SLOT_0_VCC1 |
PCR_SLOT_0_VPP0 | PCR_SLOT_0_VPP1);
}
else {
pcr &= ~(PCR_SLOT_1_VCC0 | PCR_SLOT_1_VCC1 |
PCR_SLOT_1_VPP0 | PCR_SLOT_1_VPP1);
}
pcr &= ~PCR_SLOT_0_RST;
DEBUG(KERN_INFO "Vcc %dV Vpp %dV, pcr %x\n",
configure->vcc, configure->vpp, pcr);
switch(configure->vcc){
case 0: /* Vcc 0 */
switch(configure->vpp) {
case 0:
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_GND,
configure->sock);
break;
case 12:
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_12V,
configure->sock);
break;
case 50:
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_5V,
configure->sock);
break;
case 33:
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_3V,
configure->sock);
break;
default:
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
configure->sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
__FUNCTION__,
configure->vcc,
configure->vpp);
break;
}
break;
case 50: /* Vcc 5V */
switch(configure->vpp) {
case 0:
pcr |= SET_VCC_VPP(VCC_5V,VPP_GND,
configure->sock);
break;
case 50:
pcr |= SET_VCC_VPP(VCC_5V,VPP_5V,
configure->sock);
break;
case 12:
pcr |= SET_VCC_VPP(VCC_5V,VPP_12V,
configure->sock);
break;
case 33:
pcr |= SET_VCC_VPP(VCC_5V,VPP_3V,
configure->sock);
break;
default:
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
configure->sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
__FUNCTION__,
configure->vcc,
configure->vpp);
break;
}
break;
case 33: /* Vcc 3.3V */
switch(configure->vpp) {
case 0:
pcr |= SET_VCC_VPP(VCC_3V,VPP_GND,
configure->sock);
break;
case 50:
pcr |= SET_VCC_VPP(VCC_3V,VPP_5V,
configure->sock);
break;
case 12:
pcr |= SET_VCC_VPP(VCC_3V,VPP_12V,
configure->sock);
break;
case 33:
pcr |= SET_VCC_VPP(VCC_3V,VPP_3V,
configure->sock);
break;
default:
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
configure->sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
__FUNCTION__,
configure->vcc,
configure->vpp);
break;
}
break;
default: /* what's this ? */
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock);
printk(KERN_ERR "%s: bad Vcc %d\n",
__FUNCTION__, configure->vcc);
break;
}
if (configure->sock == 0) {
pcr &= ~(PCR_SLOT_0_RST);
if (configure->reset)
pcr |= PCR_SLOT_0_RST;
}
else {
pcr &= ~(PCR_SLOT_1_RST);
if (configure->reset)
pcr |= PCR_SLOT_1_RST;
}
au_writel(pcr, PB1000_PCR);
au_sync_delay(300);
#else
pcr = au_readw(PB1100_MEM_PCMCIA) & ~0xf;
DEBUG(KERN_INFO "Vcc %dV Vpp %dV, pcr %x, reset %d\n",
configure->vcc, configure->vpp, pcr, configure->reset);
switch(configure->vcc){
case 0: /* Vcc 0 */
pcr |= SET_VCC_VPP(0,0);
break;
case 50: /* Vcc 5V */
switch(configure->vpp) {
case 0:
pcr |= SET_VCC_VPP(2,0);
break;
case 50:
pcr |= SET_VCC_VPP(2,1);
break;
case 12:
pcr |= SET_VCC_VPP(2,2);
break;
case 33:
default:
pcr |= SET_VCC_VPP(0,0);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
__FUNCTION__,
configure->vcc,
configure->vpp);
break;
}
break;
case 33: /* Vcc 3.3V */
switch(configure->vpp) {
case 0:
pcr |= SET_VCC_VPP(1,0);
break;
case 12:
pcr |= SET_VCC_VPP(1,2);
break;
case 33:
pcr |= SET_VCC_VPP(1,1);
break;
case 50:
default:
pcr |= SET_VCC_VPP(0,0);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
__FUNCTION__,
configure->vcc,
configure->vpp);
break;
}
break;
default: /* what's this ? */
pcr |= SET_VCC_VPP(0,0);
printk(KERN_ERR "%s: bad Vcc %d\n",
__FUNCTION__, configure->vcc);
break;
}
au_writew(pcr, PB1100_MEM_PCMCIA);
au_sync_delay(300);
if (!configure->reset) {
pcr |= PB1100_PC_DRV_EN;
au_writew(pcr, PB1100_MEM_PCMCIA);
au_sync_delay(100);
pcr |= PB1100_PC_DEASSERT_RST;
au_writew(pcr, PB1100_MEM_PCMCIA);
au_sync_delay(100);
}
else {
pcr &= ~(PB1100_PC_DEASSERT_RST | PB1100_PC_DRV_EN);
au_writew(pcr, PB1100_MEM_PCMCIA);
au_sync_delay(100);
}
#endif
return 0;
}
struct pcmcia_low_level pb1x00_pcmcia_ops = {
pb1x00_pcmcia_init,
pb1x00_pcmcia_shutdown,
pb1x00_pcmcia_socket_state,
pb1x00_pcmcia_get_irq_info,
pb1x00_pcmcia_configure_socket
};
/*
*
* BRIEF MODULE DESCRIPTION
* Include file for Alchemy Semiconductor's Au1000 CPU.
* Include file for Alchemy Semiconductor's Au1k CPU.
*
* Copyright 2000 MontaVista Software Inc.
* Copyright 2000,2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
......@@ -28,191 +28,191 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* some definitions add by takuzo@sm.sony.co.jp and sato@sm.sony.co.jp
*/
#ifndef _AU1000_H_
#define _AU1000_H_
#include <linux/delay.h>
#include <asm/io.h>
/* cpu pipeline flush */
void static inline au_sync(void)
{
__asm__ volatile ("sync");
}
void static inline au_sync_udelay(int us)
{
__asm__ volatile ("sync");
udelay(us);
}
void static inline au_sync_delay(int ms)
{
__asm__ volatile ("sync");
mdelay(ms);
}
void static inline au_writeb(u8 val, int reg)
{
*(volatile u8 *)(reg) = val;
}
void static inline au_writew(u16 val, int reg)
{
*(volatile u16 *)(reg) = val;
}
void static inline au_writel(u32 val, int reg)
{
*(volatile u32 *)(reg) = val;
}
static inline u8 au_readb(unsigned long port)
{
return (*(volatile u8 *)port);
}
static inline u16 au_readw(unsigned long port)
{
return (*(volatile u16 *)port);
}
static inline u32 au_readl(unsigned long port)
{
return (*(volatile u32 *)port);
}
/* arch/mips/au1000/common/clocks.c */
extern void set_au1x00_speed(unsigned int new_freq);
extern unsigned int get_au1x00_speed(void);
extern void set_au1x00_uart_baud_base(unsigned long new_baud_base);
extern unsigned long get_au1x00_uart_baud_base(void);
extern void set_au1x00_lcd_clock(void);
extern unsigned int get_au1x00_lcd_clock(void);
#ifdef CONFIG_PM
/* no CP0 timer irq */
#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
#else
#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
#endif
/* SDRAM Controller */
#define CS_MODE_0 0x14000000
#define CS_MODE_1 0x14000004
#define CS_MODE_2 0x14000008
#define MEM_SDMODE0 0xB4000000
#define MEM_SDMODE1 0xB4000004
#define MEM_SDMODE2 0xB4000008
#define CS_CONFIG_0 0x1400000C
#define CS_CONFIG_1 0x14000010
#define CS_CONFIG_2 0x14000014
#define MEM_SDADDR0 0xB400000C
#define MEM_SDADDR1 0xB4000010
#define MEM_SDADDR2 0xB4000014
#define REFRESH_CONFIG 0x14000018
#define PRECHARGE_CMD 0x1400001C
#define AUTO_REFRESH_CMD 0x14000020
#define MEM_SDREFCFG 0xB4000018
#define MEM_SDPRECMD 0xB400001C
#define MEM_SDAUTOREF 0xB4000020
#define WRITE_EXTERN_0 0x14000024
#define WRITE_EXTERN_1 0x14000028
#define WRITE_EXTERN_2 0x1400002C
#define MEM_SDWRMD0 0xB4000024
#define MEM_SDWRMD1 0xB4000028
#define MEM_SDWRMD2 0xB400002C
#define SDRAM_SLEEP 0x14000030
#define TOGGLE_CKE 0x14000034
#define MEM_SDSLEEP 0xB4000030
#define MEM_SDSMCKE 0xB4000034
/* Static Bus Controller */
#define STATIC_CONFIG_0 0x14001000
#define STATIC_TIMING_0 0x14001004
#define STATIC_ADDRESS_0 0x14001008
#define STATIC_CONFIG_1 0x14001010
#define STATIC_TIMING_1 0x14001014
#define STATIC_ADDRESS_1 0x14001018
#define STATIC_CONFIG_2 0x14001020
#define STATIC_TIMING_2 0x14001024
#define STATIC_ADDRESS_2 0x14001028
#define STATIC_CONFIG_3 0x14001030
#define STATIC_TIMING_3 0x14001034
#define STATIC_ADDRESS_3 0x14001038
/* DMA Controller 0 */
#define DMA0_MODE_SET 0x14002000
#define DMA0_MODE_CLEAR 0x14002004
#define DMA0_PERIPHERAL_ADDR 0x14002008
#define DMA0_BUFFER0_START 0x1400200C
#define DMA0_BUFFER0_COUNT 0x14002010
#define DMA0_BUFFER1_START 0x14002014
#define DMA0_BUFFER1_COUNT 0x14002018
/* DMA Controller 1 */
#define DMA1_MODE_SET 0x14002100
#define DMA1_MODE_CLEAR 0x14002104
#define DMA1_PERIPHERAL_ADDR 0x14002108
#define DMA1_BUFFER0_START 0x1400210C
#define DMA1_BUFFER0_COUNT 0x14002110
#define DMA1_BUFFER1_START 0x14002114
#define DMA1_BUFFER1_COUNT 0x14002118
/* DMA Controller 2 */
#define DMA2_MODE_SET 0x14002200
#define DMA2_MODE_CLEAR 0x14002204
#define DMA2_PERIPHERAL_ADDR 0x14002208
#define DMA2_BUFFER0_START 0x1400220C
#define DMA2_BUFFER0_COUNT 0x14002210
#define DMA2_BUFFER1_START 0x14002214
#define DMA2_BUFFER1_COUNT 0x14002218
/* DMA Controller 3 */
#define DMA3_MODE_SET 0x14002300
#define DMA3_MODE_CLEAR 0x14002304
#define DMA3_PERIPHERAL_ADDR 0x14002308
#define DMA3_BUFFER0_START 0x1400230C
#define DMA3_BUFFER0_COUNT 0x14002310
#define DMA3_BUFFER1_START 0x14002314
#define DMA3_BUFFER1_COUNT 0x14002318
/* DMA Controller 4 */
#define DMA4_MODE_SET 0x14002400
#define DMA4_MODE_CLEAR 0x14002404
#define DMA4_PERIPHERAL_ADDR 0x14002408
#define DMA4_BUFFER0_START 0x1400240C
#define DMA4_BUFFER0_COUNT 0x14002410
#define DMA4_BUFFER1_START 0x14002414
#define DMA4_BUFFER1_COUNT 0x14002418
/* DMA Controller 5 */
#define DMA5_MODE_SET 0x14002500
#define DMA5_MODE_CLEAR 0x14002504
#define DMA5_PERIPHERAL_ADDR 0x14002508
#define DMA5_BUFFER0_START 0x1400250C
#define DMA5_BUFFER0_COUNT 0x14002510
#define DMA5_BUFFER1_START 0x14002514
#define DMA5_BUFFER1_COUNT 0x14002518
/* DMA Controller 6 */
#define DMA6_MODE_SET 0x14002600
#define DMA6_MODE_CLEAR 0x14002604
#define DMA6_PERIPHERAL_ADDR 0x14002608
#define DMA6_BUFFER0_START 0x1400260C
#define DMA6_BUFFER0_COUNT 0x14002610
#define DMA6_BUFFER1_START 0x14002614
#define DMA6_BUFFER1_COUNT 0x14002618
/* DMA Controller 7 */
#define DMA7_MODE_SET 0x14002700
#define DMA7_MODE_CLEAR 0x14002704
#define DMA7_PERIPHERAL_ADDR 0x14002708
#define DMA7_BUFFER0_START 0x1400270C
#define DMA7_BUFFER0_COUNT 0x14002710
#define DMA7_BUFFER1_START 0x14002714
#define DMA7_BUFFER1_COUNT 0x14002718
#define MEM_STCFG0 0xB4001000
#define MEM_STTIME0 0xB4001004
#define MEM_STADDR0 0xB4001008
#define MEM_STCFG1 0xB4001010
#define MEM_STTIME1 0xB4001014
#define MEM_STADDR1 0xB4001018
#define MEM_STCFG2 0xB4001020
#define MEM_STTIME2 0xB4001024
#define MEM_STADDR2 0xB4001028
#define MEM_STCFG3 0xB4001030
#define MEM_STTIME3 0xB4001034
#define MEM_STADDR3 0xB4001038
/* Interrupt Controller 0 */
#define INTC0_CONFIG0_READ 0x10400040
#define INTC0_CONFIG0_SET 0x10400040
#define INTC0_CONFIG0_CLEAR 0x10400044
#define IC0_CFG0RD 0xB0400040
#define IC0_CFG0SET 0xB0400040
#define IC0_CFG0CLR 0xB0400044
#define INTC0_CONFIG1_READ 0x10400048
#define INTC0_CONFIG1_SET 0x10400048
#define INTC0_CONFIG1_CLEAR 0x1040004C
#define IC0_CFG1RD 0xB0400048
#define IC0_CFG1SET 0xB0400048
#define IC0_CFG1CLR 0xB040004C
#define INTC0_CONFIG2_READ 0x10400050
#define INTC0_CONFIG2_SET 0x10400050
#define INTC0_CONFIG2_CLEAR 0x10400054
#define IC0_CFG2RD 0xB0400050
#define IC0_CFG2SET 0xB0400050
#define IC0_CFG2CLR 0xB0400054
#define INTC0_REQ0_INT 0x10400054
#define INTC0_SOURCE_READ 0x10400058
#define INTC0_SOURCE_SET 0x10400058
#define INTC0_SOURCE_CLEAR 0x1040005C
#define INTC0_REQ1_INT 0x1040005C
#define IC0_REQ0INT 0xB0400054
#define IC0_SRCRD 0xB0400058
#define IC0_SRCSET 0xB0400058
#define IC0_SRCCLR 0xB040005C
#define IC0_REQ1INT 0xB040005C
#define INTC0_ASSIGN_REQ_READ 0x10400060
#define INTC0_ASSIGN_REQ_SET 0x10400060
#define INTC0_ASSIGN_REQ_CLEAR 0x10400064
#define IC0_ASSIGNRD 0xB0400060
#define IC0_ASSIGNSET 0xB0400060
#define IC0_ASSIGNCLR 0xB0400064
#define INTC0_WAKEUP_READ 0x10400068
#define INTC0_WAKEUP_SET 0x10400068
#define INTC0_WAKEUP_CLEAR 0x1040006C
#define IC0_WAKERD 0xB0400068
#define IC0_WAKESET 0xB0400068
#define IC0_WAKECLR 0xB040006C
#define INTC0_MASK_READ 0x10400070
#define INTC0_MASK_SET 0x10400070
#define INTC0_MASK_CLEAR 0x10400074
#define IC0_MASKRD 0xB0400070
#define IC0_MASKSET 0xB0400070
#define IC0_MASKCLR 0xB0400074
#define INTC0_R_EDGE_DETECT 0x10400078
#define INTC0_R_EDGE_DETECT_CLEAR 0x10400078
#define INTC0_F_EDGE_DETECT_CLEAR 0x1040007C
#define IC0_RISINGRD 0xB0400078
#define IC0_RISINGCLR 0xB0400078
#define IC0_FALLINGRD 0xB040007C
#define IC0_FALLINGCLR 0xB040007C
#define INTC0_TEST_BIT 0x10400080
#define IC0_TESTBIT 0xB0400080
/* Interrupt Controller 1 */
#define INTC1_CONFIG0_READ 0x11800040
#define INTC1_CONFIG0_SET 0x11800040
#define INTC1_CONFIG0_CLEAR 0x11800044
#define IC1_CFG0RD 0xB1800040
#define IC1_CFG0SET 0xB1800040
#define IC1_CFG0CLR 0xB1800044
#define INTC1_CONFIG1_READ 0x11800048
#define INTC1_CONFIG1_SET 0x11800048
#define INTC1_CONFIG1_CLEAR 0x1180004C
#define IC1_CFG1RD 0xB1800048
#define IC1_CFG1SET 0xB1800048
#define IC1_CFG1CLR 0xB180004C
#define INTC1_CONFIG2_READ 0x11800050
#define INTC1_CONFIG2_SET 0x11800050
#define INTC1_CONFIG2_CLEAR 0x11800054
#define IC1_CFG2RD 0xB1800050
#define IC1_CFG2SET 0xB1800050
#define IC1_CFG2CLR 0xB1800054
#define INTC1_REQ0_INT 0x11800054
#define INTC1_SOURCE_READ 0x11800058
#define INTC1_SOURCE_SET 0x11800058
#define INTC1_SOURCE_CLEAR 0x1180005C
#define INTC1_REQ1_INT 0x1180005C
#define IC1_REQ0INT 0xB1800054
#define IC1_SRCRD 0xB1800058
#define IC1_SRCSET 0xB1800058
#define IC1_SRCCLR 0xB180005C
#define IC1_REQ1INT 0xB180005C
#define INTC1_ASSIGN_REQ_READ 0x11800060
#define INTC1_ASSIGN_REQ_SET 0x11800060
#define INTC1_ASSIGN_REQ_CLEAR 0x11800064
#define IC1_ASSIGNRD 0xB1800060
#define IC1_ASSIGNSET 0xB1800060
#define IC1_ASSIGNCLR 0xB1800064
#define INTC1_WAKEUP_READ 0x11800068
#define INTC1_WAKEUP_SET 0x11800068
#define INTC1_WAKEUP_CLEAR 0x1180006C
#define IC1_WAKERD 0xB1800068
#define IC1_WAKESET 0xB1800068
#define IC1_WAKECLR 0xB180006C
#define INTC1_MASK_READ 0x11800070
#define INTC1_MASK_SET 0x11800070
#define INTC1_MASK_CLEAR 0x11800074
#define IC1_MASKRD 0xB1800070
#define IC1_MASKSET 0xB1800070
#define IC1_MASKCLR 0xB1800074
#define INTC1_R_EDGE_DETECT 0x11800078
#define INTC1_R_EDGE_DETECT_CLEAR 0x11800078
#define INTC1_F_EDGE_DETECT_CLEAR 0x1180007C
#define IC1_RISINGRD 0xB1800078
#define IC1_RISINGCLR 0xB1800078
#define IC1_FALLINGRD 0xB180007C
#define IC1_FALLINGCLR 0xB180007C
#define INTC1_TEST_BIT 0x11800080
#define IC1_TESTBIT 0xB1800080
/* Interrupt Configuration Modes */
#define INTC_INT_DISABLED 0
......@@ -225,29 +225,31 @@
/* Interrupt Numbers */
#define AU1000_UART0_INT 0
#define AU1000_UART1_INT 1
#define AU1000_UART2_INT 2
#define AU1000_UART1_INT 1 /* au1000 */
#define AU1000_UART2_INT 2 /* au1000 */
#define AU1000_PCI_INTA 1 /* au1500 */
#define AU1000_PCI_INTB 2 /* au1500 */
#define AU1000_UART3_INT 3
#define AU1000_SSI0_INT 4
#define AU1000_SSI1_INT 5
#define AU1000_DMA0_INT 6
#define AU1000_DMA1_INT 7
#define AU1000_DMA2_INT 8
#define AU1000_DMA3_INT 9
#define AU1000_DMA4_INT 10
#define AU1000_DMA5_INT 11
#define AU1000_DMA6_INT 12
#define AU1000_DMA7_INT 13
#define AU1000_PC0_INT 14
#define AU1000_PC0_MATCH0_INT 15
#define AU1000_PC0_MATCH1_INT 16
#define AU1000_PC0_MATCH2_INT 17
#define AU1000_PC1_INT 18
#define AU1000_PC1_MATCH0_INT 19
#define AU1000_PC1_MATCH1_INT 20
#define AU1000_PC1_MATCH2_INT 21
#define AU1000_IRDA_TX_INT 22
#define AU1000_IRDA_RX_INT 23
#define AU1000_SSI0_INT 4 /* au1000 */
#define AU1000_SSI1_INT 5 /* au1000 */
#define AU1000_PCI_INTC 4 /* au1500 */
#define AU1000_PCI_INTD 5 /* au1500 */
#define AU1000_DMA_INT_BASE 6
#define AU1000_TOY_INT 14
#define AU1000_TOY_MATCH0_INT 15
#define AU1000_TOY_MATCH1_INT 16
#define AU1000_TOY_MATCH2_INT 17
#define AU1000_RTC_INT 18
#define AU1000_RTC_MATCH0_INT 19
#define AU1000_RTC_MATCH1_INT 20
#define AU1000_RTC_MATCH2_INT 21
#define AU1000_IRDA_TX_INT 22 /* au1000 */
#define AU1000_IRDA_RX_INT 23 /* au1000 */
#define AU1000_USB_DEV_REQ_INT 24
#define AU1000_USB_DEV_SUS_INT 25
#define AU1000_USB_HOST_INT 26
......@@ -256,9 +258,9 @@
#define AU1000_MAC1_DMA_INT 29
#define AU1000_ETH0_IRQ AU1000_MAC0_DMA_INT
#define AU1000_ETH1_IRQ AU1000_MAC1_DMA_INT
#define AU1000_I2S_UO_INT 30
#define AU1000_AC97_INT 31
#define AU1000_LAST_INTC0_INT AU1000_AC97_INT
#define AU1000_I2S_UO_INT 30 /* au1000 */
#define AU1000_AC97C_INT 31
#define AU1000_LAST_INTC0_INT AU1000_AC97C_INT
#define AU1000_GPIO_0 32
#define AU1000_GPIO_1 33
#define AU1000_GPIO_2 34
......@@ -275,6 +277,8 @@
#define AU1000_GPIO_13 45
#define AU1000_GPIO_14 46
#define AU1000_GPIO_15 47
/* Au1000 only */
#define AU1000_GPIO_16 48
#define AU1000_GPIO_17 49
#define AU1000_GPIO_18 50
......@@ -292,60 +296,162 @@
#define AU1000_GPIO_30 62
#define AU1000_GPIO_31 63
/* Au1500 only */
#define AU1500_GPIO_200 48
#define AU1500_GPIO_201 49
#define AU1500_GPIO_202 50
#define AU1500_GPIO_203 51
#define AU1500_GPIO_20 52
#define AU1500_GPIO_204 53
#define AU1500_GPIO_205 54
#define AU1500_GPIO_23 55
#define AU1500_GPIO_24 56
#define AU1500_GPIO_25 57
#define AU1500_GPIO_26 58
#define AU1500_GPIO_27 59
#define AU1500_GPIO_28 60
#define AU1500_GPIO_206 61
#define AU1500_GPIO_207 62
#define AU1500_GPIO_208_215 63
#define AU1000_MAX_INTR 63
#define AU1100_SD 2
#define AU1100_GPIO_208_215 29
// REDEFINE SECONDARY GPIO BLOCK INTO IC1 CONTROLLER HERE
/* Programmable Counters 0 and 1 */
#define PC_BASE 0x11900000
#define PC_COUNTER_CNTRL (PC_BASE + 0x14)
#define PC_CNTRL_E1S (1<<23)
#define PC_CNTRL_T1S (1<<20)
#define PC_CNTRL_M21 (1<<19)
#define PC_CNTRL_M11 (1<<18)
#define PC_CNTRL_M01 (1<<17)
#define PC_CNTRL_C1S (1<<16)
#define PC_CNTRL_BP (1<<14)
#define PC_CNTRL_EN1 (1<<13)
#define PC_CNTRL_BT1 (1<<12)
#define PC_CNTRL_EN0 (1<<11)
#define PC_CNTRL_BT0 (1<<10)
#define PC_CNTRL_E0 (1<<8)
#define PC_CNTRL_E0S (1<<7)
#define PC_CNTRL_32S (1<<5)
#define PC_CNTRL_T0S (1<<4)
#define PC_CNTRL_M20 (1<<3)
#define PC_CNTRL_M10 (1<<2)
#define PC_CNTRL_M00 (1<<1)
#define PC_CNTRL_C0S (1<<0)
#define SYS_BASE 0xB1900000
#define SYS_COUNTER_CNTRL (SYS_BASE + 0x14)
#define SYS_CNTRL_E1S (1<<23)
#define SYS_CNTRL_T1S (1<<20)
#define SYS_CNTRL_M21 (1<<19)
#define SYS_CNTRL_M11 (1<<18)
#define SYS_CNTRL_M01 (1<<17)
#define SYS_CNTRL_C1S (1<<16)
#define SYS_CNTRL_BP (1<<14)
#define SYS_CNTRL_EN1 (1<<13)
#define SYS_CNTRL_BT1 (1<<12)
#define SYS_CNTRL_EN0 (1<<11)
#define SYS_CNTRL_BT0 (1<<10)
#define SYS_CNTRL_E0 (1<<8)
#define SYS_CNTRL_E0S (1<<7)
#define SYS_CNTRL_32S (1<<5)
#define SYS_CNTRL_T0S (1<<4)
#define SYS_CNTRL_M20 (1<<3)
#define SYS_CNTRL_M10 (1<<2)
#define SYS_CNTRL_M00 (1<<1)
#define SYS_CNTRL_C0S (1<<0)
/* Programmable Counter 0 Registers */
#define PC0_TRIM (PC_BASE + 0)
#define PC0_COUNTER_WRITE (PC_BASE + 4)
#define PC0_MATCH0 (PC_BASE + 8)
#define PC0_MATCH1 (PC_BASE + 0xC)
#define PC0_MATCH2 (PC_BASE + 0x10)
#define PC0_COUNTER_READ (PC_BASE + 0x40)
#define SYS_TOYTRIM (SYS_BASE + 0)
#define SYS_TOYWRITE (SYS_BASE + 4)
#define SYS_TOYMATCH0 (SYS_BASE + 8)
#define SYS_TOYMATCH1 (SYS_BASE + 0xC)
#define SYS_TOYMATCH2 (SYS_BASE + 0x10)
#define SYS_TOYREAD (SYS_BASE + 0x40)
/* Programmable Counter 1 Registers */
#define PC1_TRIM (PC_BASE + 0x44)
#define PC1_COUNTER_WRITE (PC_BASE + 0x48)
#define PC1_MATCH0 (PC_BASE + 0x4C)
#define PC1_MATCH1 (PC_BASE + 0x50)
#define PC1_MATCH2 (PC_BASE + 0x54)
#define PC1_COUNTER_READ (PC_BASE + 0x58)
#define SYS_RTCTRIM (SYS_BASE + 0x44)
#define SYS_RTCWRITE (SYS_BASE + 0x48)
#define SYS_RTCMATCH0 (SYS_BASE + 0x4C)
#define SYS_RTCMATCH1 (SYS_BASE + 0x50)
#define SYS_RTCMATCH2 (SYS_BASE + 0x54)
#define SYS_RTCREAD (SYS_BASE + 0x58)
/* I2S Controller */
#define I2S_DATA 0x11000000
#define I2S_CONFIG_STATUS 0x11000001
#define I2S_CONTROL 0x11000002
#define I2S_DATA 0xB1000000
#define I2S_DATA_MASK (0xffffff)
#define I2S_CONFIG 0xB1000004
#define I2S_CONFIG_XU (1<<25)
#define I2S_CONFIG_XO (1<<24)
#define I2S_CONFIG_RU (1<<23)
#define I2S_CONFIG_RO (1<<22)
#define I2S_CONFIG_TR (1<<21)
#define I2S_CONFIG_TE (1<<20)
#define I2S_CONFIG_TF (1<<19)
#define I2S_CONFIG_RR (1<<18)
#define I2S_CONFIG_RE (1<<17)
#define I2S_CONFIG_RF (1<<16)
#define I2S_CONFIG_PD (1<<11)
#define I2S_CONFIG_LB (1<<10)
#define I2S_CONFIG_IC (1<<9)
#define I2S_CONFIG_FM_BIT 7
#define I2S_CONFIG_FM_MASK (0x3 << I2S_CONFIG_FM_BIT)
#define I2S_CONFIG_FM_I2S (0x0 << I2S_CONFIG_FM_BIT)
#define I2S_CONFIG_FM_LJ (0x1 << I2S_CONFIG_FM_BIT)
#define I2S_CONFIG_FM_RJ (0x2 << I2S_CONFIG_FM_BIT)
#define I2S_CONFIG_TN (1<<6)
#define I2S_CONFIG_RN (1<<5)
#define I2S_CONFIG_SZ_BIT 0
#define I2S_CONFIG_SZ_MASK (0x1F << I2S_CONFIG_SZ_BIT)
#define I2S_CONTROL 0xB1000008
#define I2S_CONTROL_D (1<<1)
#define I2S_CONTROL_CE (1<<0)
/* USB Host Controller */
// We pass USB_OHCI_BASE to ioremap, so it needs to be a physical address
#define USB_OHCI_BASE 0x10100000
#define USB_OHCI_LEN 0x00100000
#define USB_HOST_CONFIG 0xB017fffc
/* USB Device Controller */
#define USBD_EP0RD 0xB0200000
#define USBD_EP0WR 0xB0200004
#define USBD_EP2WR 0xB0200008
#define USBD_EP3WR 0xB020000C
#define USBD_EP4RD 0xB0200010
#define USBD_EP5RD 0xB0200014
#define USBD_INTEN 0xB0200018
#define USBD_INTSTAT 0xB020001C
#define USBDEV_INT_SOF (1<<12)
#define USBDEV_INT_HF_BIT 6
#define USBDEV_INT_HF_MASK (0x3f << USBDEV_INT_HF_BIT)
#define USBDEV_INT_CMPLT_BIT 0
#define USBDEV_INT_CMPLT_MASK (0x3f << USBDEV_INT_CMPLT_BIT)
#define USBD_CONFIG 0xB0200020
#define USBD_EP0CS 0xB0200024
#define USBD_EP2CS 0xB0200028
#define USBD_EP3CS 0xB020002C
#define USBD_EP4CS 0xB0200030
#define USBD_EP5CS 0xB0200034
#define USBDEV_CS_SU (1<<14)
#define USBDEV_CS_NAK (1<<13)
#define USBDEV_CS_ACK (1<<12)
#define USBDEV_CS_BUSY (1<<11)
#define USBDEV_CS_TSIZE_BIT 1
#define USBDEV_CS_TSIZE_MASK (0x3ff << USBDEV_CS_TSIZE_BIT)
#define USBDEV_CS_STALL (1<<0)
#define USBD_EP0RDSTAT 0xB0200040
#define USBD_EP0WRSTAT 0xB0200044
#define USBD_EP2WRSTAT 0xB0200048
#define USBD_EP3WRSTAT 0xB020004C
#define USBD_EP4RDSTAT 0xB0200050
#define USBD_EP5RDSTAT 0xB0200054
#define USBDEV_FSTAT_FLUSH (1<<6)
#define USBDEV_FSTAT_UF (1<<5)
#define USBDEV_FSTAT_OF (1<<4)
#define USBDEV_FSTAT_FCNT_BIT 0
#define USBDEV_FSTAT_FCNT_MASK (0x0f << USBDEV_FSTAT_FCNT_BIT)
#define USBD_ENABLE 0xB0200058
#define USBDEV_ENABLE (1<<1)
#define USBDEV_CE (1<<0)
/* Ethernet Controllers */
#define AU1000_ETH0_BASE 0x10500000
#define AU1000_ETH1_BASE 0x10510000
#define AU1000_ETH0_BASE 0xB0500000
#define AU1000_ETH1_BASE 0xB0510000
#define AU1500_ETH0_BASE 0xB1500000
#define AU1500_ETH1_BASE 0xB1510000
#define AU1100_ETH0_BASE 0xB0500000
/* 4 byte offsets from AU1000_ETH_BASE */
#define MAC_CONTROL 0x0
#define MAC_RX_ENABLE (1<<2)
#define MAC_RX_ENABLE (1<<2)
#define MAC_TX_ENABLE (1<<3)
#define MAC_DEF_CHECK (1<<5)
#define MAC_DEF_CHECK (1<<5)
#define MAC_SET_BL(X) (((X)&0x3)<<6)
#define MAC_AUTO_PAD (1<<8)
#define MAC_DISABLE_RETRY (1<<10)
......@@ -370,7 +476,7 @@
#define MAC_MCAST_LOW 0x10
#define MAC_MII_CNTRL 0x14
#define MAC_MII_BUSY (1<<0)
#define MAC_MII_READ 0
#define MAC_MII_READ 0
#define MAC_MII_WRITE (1<<1)
#define MAC_SET_MII_SELECT_REG(X) (((X)&0x1f)<<6)
#define MAC_SET_MII_SELECT_PHY(X) (((X)&0x1f)<<11)
......@@ -384,11 +490,15 @@
#define MAC_VLAN2_TAG 0x24
/* Ethernet Controller Enable */
#define MAC0_ENABLE 0x10520000
#define MAC1_ENABLE 0x10520004
#define AU1000_MAC0_ENABLE 0xB0520000
#define AU1000_MAC1_ENABLE 0xB0520004
#define AU1500_MAC0_ENABLE 0xB1520000
#define AU1500_MAC1_ENABLE 0xB1520004
#define AU1100_MAC0_ENABLE 0xB0520000
#define MAC_EN_CLOCK_ENABLE (1<<0)
#define MAC_EN_RESET0 (1<<1)
#define MAC_EN_TOSS (1<<2)
#define MAC_EN_TOSS (0<<2)
#define MAC_EN_CACHEABLE (1<<3)
#define MAC_EN_RESET1 (1<<4)
#define MAC_EN_RESET2 (1<<5)
......@@ -396,8 +506,8 @@
/* Ethernet Controller DMA Channels */
#define MAC0_TX_DMA_ADDR 0x14004000
#define MAC1_TX_DMA_ADDR 0x14004200
#define MAC0_TX_DMA_ADDR 0xB4004000
#define MAC1_TX_DMA_ADDR 0xB4004200
/* offsets from MAC_TX_RING_ADDR address */
#define MAC_TX_BUFF0_STATUS 0x0
#define TX_FRAME_ABORTED (1<<0)
......@@ -427,8 +537,8 @@
#define MAC_TX_BUFF3_ADDR 0x34
#define MAC_TX_BUFF3_LEN 0x38
#define MAC0_RX_DMA_ADDR 0x14004100
#define MAC1_RX_DMA_ADDR 0x14004300
#define MAC0_RX_DMA_ADDR 0xB4004100
#define MAC1_RX_DMA_ADDR 0xB4004300
/* offsets from MAC_RX_RING_ADDR */
#define MAC_RX_BUFF0_STATUS 0x0
#define RX_FRAME_LEN_MASK 0x3fff
......@@ -450,7 +560,7 @@
#define RX_FILTER_FAIL (1<<29)
#define RX_PACKET_FILTER (1<<30)
#define RX_MISSED_FRAME (1<<31)
#define RX_ERROR (RX_WDOG_TIMER | RX_RUNT | RX_OVERLEN | \
RX_COLL | RX_MII_ERROR | RX_CRC_ERROR | \
RX_LEN_ERROR | RX_U_CNTRL_FRAME | RX_MISSED_FRAME)
......@@ -468,10 +578,12 @@
/* UARTS 0-3 */
#define UART0_ADDR 0x11100000
#define UART1_ADDR 0x11200000
#define UART2_ADDR 0x11300000
#define UART3_ADDR 0x11400000
#define UART0_ADDR 0xB1100000
#define UART1_ADDR 0xB1200000
#define UART2_ADDR 0xB1300000
#define UART3_ADDR 0xB1400000
#define UART_BASE UART0_ADDR
#define UART_DEBUG_BASE UART2_ADDR
#define UART_RX 0 /* Receive buffer */
#define UART_TX 4 /* Transmit buffer */
......@@ -482,7 +594,7 @@
#define UART_MCR 0x18 /* Modem Control Register */
#define UART_LSR 0x1C /* Line Status Register */
#define UART_MSR 0x20 /* Modem Status Register */
#define UART_CLK 0x28 /* Baud Rat4e Clock Divider */
#define UART_CLK 0x28 /* Baud Rate Clock Divider */
#define UART_MOD_CNTRL 0x100 /* Module Control */
#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
......@@ -566,70 +678,330 @@
/* SSIO */
#define SSI0_STATUS 0x11600000
#define SSI0_INT 0x11600004
#define SSI0_INT_ENABLE 0x11600008
#define SSI0_CONFIG 0x11600020
#define SSI0_ADATA 0x11600024
#define SSI0_CLKDIV 0x11600028
#define SSI0_CONTROL 0x11600100
#define SSI0_STATUS 0xB1600000
#define SSI_STATUS_BF (1<<4)
#define SSI_STATUS_OF (1<<3)
#define SSI_STATUS_UF (1<<2)
#define SSI_STATUS_D (1<<1)
#define SSI_STATUS_B (1<<0)
#define SSI0_INT 0xB1600004
#define SSI_INT_OI (1<<3)
#define SSI_INT_UI (1<<2)
#define SSI_INT_DI (1<<1)
#define SSI0_INT_ENABLE 0xB1600008
#define SSI_INTE_OIE (1<<3)
#define SSI_INTE_UIE (1<<2)
#define SSI_INTE_DIE (1<<1)
#define SSI0_CONFIG 0xB1600020
#define SSI_CONFIG_AO (1<<24)
#define SSI_CONFIG_DO (1<<23)
#define SSI_CONFIG_ALEN_BIT 20
#define SSI_CONFIG_ALEN_MASK (0x7<<20)
#define SSI_CONFIG_DLEN_BIT 16
#define SSI_CONFIG_DLEN_MASK (0x7<<16)
#define SSI_CONFIG_DD (1<<11)
#define SSI_CONFIG_AD (1<<10)
#define SSI_CONFIG_BM_BIT 8
#define SSI_CONFIG_BM_MASK (0x3<<8)
#define SSI_CONFIG_CE (1<<7)
#define SSI_CONFIG_DP (1<<6)
#define SSI_CONFIG_DL (1<<5)
#define SSI_CONFIG_EP (1<<4)
#define SSI0_ADATA 0xB1600024
#define SSI_AD_D (1<<24)
#define SSI_AD_ADDR_BIT 16
#define SSI_AD_ADDR_MASK (0xff<<16)
#define SSI_AD_DATA_BIT 0
#define SSI_AD_DATA_MASK (0xfff<<0)
#define SSI0_CLKDIV 0xB1600028
#define SSI0_CONTROL 0xB1600100
#define SSI_CONTROL_CD (1<<1)
#define SSI_CONTROL_E (1<<0)
/* SSI1 */
#define SSI1_STATUS 0x11680000
#define SSI1_INT 0x11680004
#define SSI1_INT_ENABLE 0x11680008
#define SSI1_CONFIG 0x11680020
#define SSI1_ADATA 0x11680024
#define SSI1_CLKDIV 0x11680028
#define SSI1_CONTROL 0x11680100
#define SSI1_STATUS 0xB1680000
#define SSI1_INT 0xB1680004
#define SSI1_INT_ENABLE 0xB1680008
#define SSI1_CONFIG 0xB1680020
#define SSI1_ADATA 0xB1680024
#define SSI1_CLKDIV 0xB1680028
#define SSI1_ENABLE 0xB1680100
/*
* Register content definitions
*/
#define SSI_STATUS_BF (1<<4)
#define SSI_STATUS_OF (1<<3)
#define SSI_STATUS_UF (1<<2)
#define SSI_STATUS_D (1<<1)
#define SSI_STATUS_B (1<<0)
/* SSI_INT */
#define SSI_INT_OI (1<<3)
#define SSI_INT_UI (1<<2)
#define SSI_INT_DI (1<<1)
/* SSI_INTEN */
#define SSI_INTEN_OIE (1<<3)
#define SSI_INTEN_UIE (1<<2)
#define SSI_INTEN_DIE (1<<1)
#define SSI_CONFIG_AO (1<<24)
#define SSI_CONFIG_DO (1<<23)
#define SSI_CONFIG_ALEN (7<<20)
#define SSI_CONFIG_DLEN (15<<16)
#define SSI_CONFIG_DD (1<<11)
#define SSI_CONFIG_AD (1<<10)
#define SSI_CONFIG_BM (3<<8)
#define SSI_CONFIG_CE (1<<7)
#define SSI_CONFIG_DP (1<<6)
#define SSI_CONFIG_DL (1<<5)
#define SSI_CONFIG_EP (1<<4)
#define SSI_CONFIG_ALEN_N(N) ((N-1)<<20)
#define SSI_CONFIG_DLEN_N(N) ((N-1)<<16)
#define SSI_CONFIG_BM_HI (0<<8)
#define SSI_CONFIG_BM_LO (1<<8)
#define SSI_CONFIG_BM_CY (2<<8)
#define SSI_ADATA_D (1<<24)
#define SSI_ADATA_ADDR (0xFF<<16)
#define SSI_ADATA_DATA (0x0FFF)
#define SSI_ADATA_ADDR_N(N) (N<<16)
#define SSI_ENABLE_CD (1<<1)
#define SSI_ENABLE_E (1<<0)
/* IrDA Controller */
#define IR_RING_PTR_STATUS 0x11500000
#define IR_RING_BASE_ADDR_H 0x11500004
#define IR_RING_BASE_ADDR_L 0x11500008
#define IR_RING_SIZE 0x1150000C
#define IR_RING_PROMPT 0x11500010
#define IR_RING_ADDR_CMPR 0x11500014
#define IR_CONFIG_1 0x11500020
#define IR_SIR_FLAGS 0x11500024
#define IR_ENABLE 0x11500028
#define IR_READ_PHY_CONFIG 0x1150002C
#define IR_WRITE_PHY_CONFIG 0x11500030
#define IR_MAX_PKT_LEN 0x11500034
#define IR_RX_BYTE_CNT 0x11500038
#define IR_CONFIG_2 0x1150003C
#define IR_INTERFACE_CONFIG 0x11500040
#define IRDA_BASE 0xB0300000
#define IR_RING_PTR_STATUS (IRDA_BASE+0x00)
#define IR_RING_BASE_ADDR_H (IRDA_BASE+0x04)
#define IR_RING_BASE_ADDR_L (IRDA_BASE+0x08)
#define IR_RING_SIZE (IRDA_BASE+0x0C)
#define IR_RING_PROMPT (IRDA_BASE+0x10)
#define IR_RING_ADDR_CMPR (IRDA_BASE+0x14)
#define IR_INT_CLEAR (IRDA_BASE+0x18)
#define IR_CONFIG_1 (IRDA_BASE+0x20)
#define IR_RX_INVERT_LED (1<<0)
#define IR_TX_INVERT_LED (1<<1)
#define IR_ST (1<<2)
#define IR_SF (1<<3)
#define IR_SIR (1<<4)
#define IR_MIR (1<<5)
#define IR_FIR (1<<6)
#define IR_16CRC (1<<7)
#define IR_TD (1<<8)
#define IR_RX_ALL (1<<9)
#define IR_DMA_ENABLE (1<<10)
#define IR_RX_ENABLE (1<<11)
#define IR_TX_ENABLE (1<<12)
#define IR_LOOPBACK (1<<14)
#define IR_SIR_MODE (IR_SIR | IR_DMA_ENABLE | \
IR_RX_ALL | IR_RX_ENABLE | IR_SF | IR_16CRC)
#define IR_SIR_FLAGS (IRDA_BASE+0x24)
#define IR_ENABLE (IRDA_BASE+0x28)
#define IR_RX_STATUS (1<<9)
#define IR_TX_STATUS (1<<10)
#define IR_READ_PHY_CONFIG (IRDA_BASE+0x2C)
#define IR_WRITE_PHY_CONFIG (IRDA_BASE+0x30)
#define IR_MAX_PKT_LEN (IRDA_BASE+0x34)
#define IR_RX_BYTE_CNT (IRDA_BASE+0x38)
#define IR_CONFIG_2 (IRDA_BASE+0x3C)
#define IR_MODE_INV (1<<0)
#define IR_ONE_PIN (1<<1)
#define IR_INTERFACE_CONFIG (IRDA_BASE+0x40)
/* GPIO */
#define TSTATE_STATE_READ 0x11900100
#define TSTATE_STATE_SET 0x11900100
#define OUTPUT_STATE_READ 0x11900108
#define OUTPUT_STATE_SET 0x11900108
#define OUTPUT_STATE_CLEAR 0x1190010C
#define PIN_STATE 0x11900110
#define SYS_PINFUNC 0xB190002C
#define SYS_PF_USB (1<<15) /* 2nd USB device/host */
#define SYS_PF_U3 (1<<14) /* GPIO23/U3TXD */
#define SYS_PF_U2 (1<<13) /* GPIO22/U2TXD */
#define SYS_PF_U1 (1<<12) /* GPIO21/U1TXD */
#define SYS_PF_SRC (1<<11) /* GPIO6/SROMCKE */
#define SYS_PF_CK5 (1<<10) /* GPIO3/CLK5 */
#define SYS_PF_CK4 (1<<9) /* GPIO2/CLK4 */
#define SYS_PF_IRF (1<<8) /* GPIO15/IRFIRSEL */
#define SYS_PF_UR3 (1<<7) /* GPIO[14:9]/UART3 */
#define SYS_PF_I2D (1<<6) /* GPIO8/I2SDI */
#define SYS_PF_I2S (1<<5) /* I2S/GPIO[29:31] */
#define SYS_PF_NI2 (1<<4) /* NI2/GPIO[24:28] */
#define SYS_PF_U0 (1<<3) /* U0TXD/GPIO20 */
#define SYS_PF_RD (1<<2) /* IRTXD/GPIO19 */
#define SYS_PF_A97 (1<<1) /* AC97/SSL1 */
#define SYS_PF_S0 (1<<0) /* SSI_0/GPIO[16:18] */
#define SYS_TRIOUTRD 0xB1900100
#define SYS_TRIOUTCLR 0xB1900100
#define SYS_OUTPUTRD 0xB1900108
#define SYS_OUTPUTSET 0xB1900108
#define SYS_OUTPUTCLR 0xB190010C
#define SYS_PINSTATERD 0xB1900110
#define SYS_PININPUTEN 0xB1900110
/* GPIO2, Au1500 only */
#define GPIO2_BASE 0xB1700000
#define GPIO2_DIR (GPIO2_BASE + 0)
#define GPIO2_DATA_EN (GPIO2_BASE + 8)
#define GPIO2_PIN_STATE (GPIO2_BASE + 0xC)
#define GPIO2_INT_ENABLE (GPIO2_BASE + 0x10)
#define GPIO2_ENABLE (GPIO2_BASE + 0x14)
/* Power Management */
#define PM_SCRATCH_0 0x11900018
#define PM_SCRATCH_1 0x1190001C
#define PM_WAKEUP_SOURCE_MASK 0x11900034
#define PM_ENDIANESS 0x11900038
#define PM_POWERUP_CONTROL 0x1190003C
#define PM_WAKEUP_CAUSE 0x1190005C
#define PM_SLEEP_POWER 0x11900078
#define PM_SLEEP 0x1190007C
#define SYS_SCRATCH0 0xB1900018
#define SYS_SCRATCH1 0xB190001C
#define SYS_WAKEMSK 0xB1900034
#define SYS_ENDIAN 0xB1900038
#define SYS_POWERCTRL 0xB190003C
#define SYS_WAKESRC 0xB190005C
#define SYS_SLPPWR 0xB1900078
#define SYS_SLEEP 0xB190007C
/* Clock Controller */
#define FQ_CNTRL_1 0x11900020
#define FQ_CNTRL_2 0x11900024
#define CLOCK_SOURCE_CNTRL 0x11900028
#define CPU_PLL_CNTRL 0x11900060
#define AUX_PLL_CNTRL 0x11900064
#define SYS_FREQCTRL0 0xB1900020
#define SYS_FC_FRDIV2_BIT 22
#define SYS_FC_FRDIV2_MASK (0xff << FQC2_FRDIV2_BIT)
#define SYS_FC_FE2 (1<<21)
#define SYS_FC_FS2 (1<<20)
#define SYS_FC_FRDIV1_BIT 12
#define SYS_FC_FRDIV1_MASK (0xff << FQC2_FRDIV1_BIT)
#define SYS_FC_FE1 (1<<11)
#define SYS_FC_FS1 (1<<10)
#define SYS_FC_FRDIV0_BIT 2
#define SYS_FC_FRDIV0_MASK (0xff << FQC2_FRDIV0_BIT)
#define SYS_FC_FE0 (1<<1)
#define SYS_FC_FS0 (1<<0)
#define SYS_FREQCTRL1 0xB1900024
#define SYS_FC_FRDIV5_BIT 22
#define SYS_FC_FRDIV5_MASK (0xff << FQC2_FRDIV5_BIT)
#define SYS_FC_FE5 (1<<21)
#define SYS_FC_FS5 (1<<20)
#define SYS_FC_FRDIV4_BIT 12
#define SYS_FC_FRDIV4_MASK (0xff << FQC2_FRDIV4_BIT)
#define SYS_FC_FE4 (1<<11)
#define SYS_FC_FS4 (1<<10)
#define SYS_FC_FRDIV3_BIT 2
#define SYS_FC_FRDIV3_MASK (0xff << FQC2_FRDIV3_BIT)
#define SYS_FC_FE3 (1<<1)
#define SYS_FC_FS3 (1<<0)
#define SYS_CLKSRC 0xB1900028
#define SYS_CS_ME1_BIT 27
#define SYS_CS_ME1_MASK (0x7<<CSC_ME1_BIT)
#define SYS_CS_DE1 (1<<26)
#define SYS_CS_CE1 (1<<25)
#define SYS_CS_ME0_BIT 22
#define SYS_CS_ME0_MASK (0x7<<CSC_ME0_BIT)
#define SYS_CS_DE0 (1<<21)
#define SYS_CS_CE0 (1<<20)
#define SYS_CS_MI2_BIT 17
#define SYS_CS_MI2_MASK (0x7<<CSC_MI2_BIT)
#define SYS_CS_DI2 (1<<16)
#define SYS_CS_CI2 (1<<15)
#define SYS_CS_MUH_BIT 12
#define SYS_CS_MUH_MASK (0x7<<CSC_MUH_BIT)
#define SYS_CS_DUH (1<<11)
#define SYS_CS_CUH (1<<10)
#define SYS_CS_MUD_BIT 7
#define SYS_CS_MUD_MASK (0x7<<CSC_MUD_BIT)
#define SYS_CS_DUD (1<<6)
#define SYS_CS_CUD (1<<5)
#define SYS_CS_MIR_BIT 2
#define SYS_CS_MIR_MASK (0x7<<CSC_MIR_BIT)
#define SYS_CS_DIR (1<<1)
#define SYS_CS_CIR (1<<0)
#define SYS_CS_MUX_AUX 0x1
#define SYS_CS_MUX_FQ0 0x2
#define SYS_CS_MUX_FQ1 0x3
#define SYS_CS_MUX_FQ2 0x4
#define SYS_CS_MUX_FQ3 0x5
#define SYS_CS_MUX_FQ4 0x6
#define SYS_CS_MUX_FQ5 0x7
#define SYS_CPUPLL 0xB1900060
#define SYS_AUXPLL 0xB1900064
/* AC97 Controller */
#define AC97_CONFIG 0x10000000
#define AC97_STATUS 0x10000004
#define AC97_DATA 0x10000008
#define AC97_CMD 0x1000000C
#define AC97_CNTRL 0x10000010
#define AC97C_CONFIG 0xB0000000
#define AC97C_RECV_SLOTS_BIT 13
#define AC97C_RECV_SLOTS_MASK (0x3ff << AC97C_RECV_SLOTS_BIT)
#define AC97C_XMIT_SLOTS_BIT 3
#define AC97C_XMIT_SLOTS_MASK (0x3ff << AC97C_XMIT_SLOTS_BIT)
#define AC97C_SG (1<<2)
#define AC97C_SYNC (1<<1)
#define AC97C_RESET (1<<0)
#define AC97C_STATUS 0xB0000004
#define AC97C_XU (1<<11)
#define AC97C_XO (1<<10)
#define AC97C_RU (1<<9)
#define AC97C_RO (1<<8)
#define AC97C_READY (1<<7)
#define AC97C_CP (1<<6)
#define AC97C_TR (1<<5)
#define AC97C_TE (1<<4)
#define AC97C_TF (1<<3)
#define AC97C_RR (1<<2)
#define AC97C_RE (1<<1)
#define AC97C_RF (1<<0)
#define AC97C_DATA 0xB0000008
#define AC97C_CMD 0xB000000C
#define AC97C_WD_BIT 16
#define AC97C_READ (1<<7)
#define AC97C_INDEX_MASK 0x7f
#define AC97C_CNTRL 0xB0000010
#define AC97C_RS (1<<1)
#define AC97C_CE (1<<0)
#ifdef CONFIG_SOC_AU1500
/* Au1500 PCI Controller */
#define Au1500_CFG_BASE 0xB4005000 // virtual, kseg0 addr
#define Au1500_PCI_CMEM (Au1500_CFG_BASE + 0)
#define Au1500_PCI_CFG (Au1500_CFG_BASE + 4)
#define PCI_ERROR ((1<<22) | (1<<23) | (1<<24) | (1<<25) | (1<<26) | (1<<27))
#define Au1500_PCI_B2BMASK_CCH (Au1500_CFG_BASE + 8)
#define Au1500_PCI_B2B0_VID (Au1500_CFG_BASE + 0xC)
#define Au1500_PCI_B2B1_ID (Au1500_CFG_BASE + 0x10)
#define Au1500_PCI_MWMASK_DEV (Au1500_CFG_BASE + 0x14)
#define Au1500_PCI_MWBASE_REV_CCL (Au1500_CFG_BASE + 0x18)
#define Au1500_PCI_ERR_ADDR (Au1500_CFG_BASE + 0x1C)
#define Au1500_PCI_SPEC_INTACK (Au1500_CFG_BASE + 0x20)
#define Au1500_PCI_ID (Au1500_CFG_BASE + 0x100)
#define Au1500_PCI_STATCMD (Au1500_CFG_BASE + 0x104)
#define Au1500_PCI_CLASSREV (Au1500_CFG_BASE + 0x108)
#define Au1500_PCI_HDRTYPE (Au1500_CFG_BASE + 0x10C)
#define Au1500_PCI_MBAR (Au1500_CFG_BASE + 0x110)
#define Au1500_PCI_HDR 0xB4005100 // virtual, kseg0 addr
/* All of our structures, like pci resource, have 32 bit members.
* Drivers are expected to do an ioremap on the PCI MEM resource, but it's
* hard to store 0x4 0000 0000 in a 32 bit type. We require a small patch
* to __ioremap to check for addresses between (u32)Au1500_PCI_MEM_START and
* (u32)Au1500_PCI_MEM_END and change those to the full 36 bit PCI MEM
* addresses. For PCI IO, it's simpler because we get to do the ioremap
* ourselves and then adjust the device's resources.
*/
#define Au1500_EXT_CFG 0x600000000
#define Au1500_EXT_CFG_TYPE1 0x680000000
#define Au1500_PCI_IO_START 0x500000000
#define Au1500_PCI_IO_END 0x5000FFFFF
#define Au1500_PCI_MEM_START 0x440000000
#define Au1500_PCI_MEM_END 0x443FFFFFF
#define PCI_IO_START (Au1500_PCI_IO_START + 0x300)
#define PCI_IO_END (Au1500_PCI_IO_END)
#define PCI_MEM_START (Au1500_PCI_MEM_START)
#define PCI_MEM_END (Au1500_PCI_MEM_END)
#define PCI_FIRST_DEVFN (0<<3)
#define PCI_LAST_DEVFN (19<<3)
#endif
#if defined(CONFIG_SOC_AU1100) || (defined(CONFIG_SOC_AU1000) && !defined(CONFIG_MIPS_PB1000))
/* no PCI bus controller */
#define PCI_IO_START 0
#define PCI_IO_END 0
#define PCI_MEM_START 0
#define PCI_MEM_END 0
#define PCI_FIRST_DEVFN 0
#define PCI_LAST_DEVFN 0
#endif
#endif
/*
* BRIEF MODULE DESCRIPTION
* Defines for using and allocating dma channels on the Alchemy
* Au1000 mips processor.
*
* Copyright 2000 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* stevel@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef __ASM_AU1000_DMA_H
#define __ASM_AU1000_DMA_H
#include <linux/config.h>
#include <asm/io.h> /* need byte IO */
#include <linux/spinlock.h> /* And spinlocks */
#include <linux/delay.h>
#include <asm/system.h>
#define NUM_AU1000_DMA_CHANNELS 8
/* DMA Channel Base Addresses */
#define DMA_CHANNEL_BASE 0xB4002000
#define DMA_CHANNEL_LEN 0x00000100
/* DMA Channel Register Offsets */
#define DMA_MODE_SET 0x00000000
#define DMA_MODE_READ DMA_MODE_SET
#define DMA_MODE_CLEAR 0x00000004
/* DMA Mode register bits follow */
#define DMA_DAH_MASK (0x0f << 20)
#define DMA_DID_BIT 16
#define DMA_DID_MASK (0x0f << DMA_DID_BIT)
#define DMA_BE (1<<13)
#define DMA_DR (1<<12)
#define DMA_TS8 (1<<11)
#define DMA_DW_BIT 9
#define DMA_DW_MASK (0x03 << DMA_DW_BIT)
#define DMA_DW8 (0 << DMA_DW_BIT)
#define DMA_DW16 (1 << DMA_DW_BIT)
#define DMA_DW32 (2 << DMA_DW_BIT)
#define DMA_NC (1<<8)
#define DMA_IE (1<<7)
#define DMA_HALT (1<<6)
#define DMA_GO (1<<5)
#define DMA_AB (1<<4)
#define DMA_D1 (1<<3)
#define DMA_BE1 (1<<2)
#define DMA_D0 (1<<1)
#define DMA_BE0 (1<<0)
#define DMA_PERIPHERAL_ADDR 0x00000008
#define DMA_BUFFER0_START 0x0000000C
#define DMA_BUFFER1_START 0x00000014
#define DMA_BUFFER0_COUNT 0x00000010
#define DMA_BUFFER1_COUNT 0x00000018
#define DMA_BAH_BIT 16
#define DMA_BAH_MASK (0x0f << DMA_BAH_BIT)
#define DMA_COUNT_BIT 0
#define DMA_COUNT_MASK (0xffff << DMA_COUNT_BIT)
/* DMA Device ID's follow */
enum {
DMA_ID_UART0_TX = 0,
DMA_ID_UART0_RX,
DMA_ID_GP04,
DMA_ID_GP05,
DMA_ID_AC97C_TX,
DMA_ID_AC97C_RX,
DMA_ID_UART3_TX,
DMA_ID_UART3_RX,
DMA_ID_USBDEV_EP0_RX,
DMA_ID_USBDEV_EP0_TX,
DMA_ID_USBDEV_EP2_TX,
DMA_ID_USBDEV_EP3_TX,
DMA_ID_USBDEV_EP4_RX,
DMA_ID_USBDEV_EP5_RX,
DMA_ID_I2S_TX,
DMA_ID_I2S_RX,
DMA_NUM_DEV
};
struct dma_chan {
int dev_id; // this channel is allocated if >=0, free otherwise
unsigned int io;
const char *dev_str;
int irq;
void *irq_dev;
unsigned int fifo_addr;
unsigned int mode;
};
/* These are in arch/mips/au1000/common/dma.c */
extern struct dma_chan au1000_dma_table[];
extern int request_au1000_dma(int dev_id,
const char *dev_str,
void (*irqhandler)(int, void *,
struct pt_regs *),
unsigned long irqflags,
void *irq_dev_id);
extern void free_au1000_dma(unsigned int dmanr);
extern int au1000_dma_read_proc(char *buf, char **start, off_t fpos,
int length, int *eof, void *data);
extern void dump_au1000_dma_channel(unsigned int dmanr);
extern spinlock_t au1000_dma_spin_lock;
static __inline__ struct dma_chan *get_dma_chan(unsigned int dmanr)
{
if (dmanr > NUM_AU1000_DMA_CHANNELS
|| au1000_dma_table[dmanr].dev_id < 0)
return NULL;
return &au1000_dma_table[dmanr];
}
static __inline__ unsigned long claim_dma_lock(void)
{
unsigned long flags;
spin_lock_irqsave(&au1000_dma_spin_lock, flags);
return flags;
}
static __inline__ void release_dma_lock(unsigned long flags)
{
spin_unlock_irqrestore(&au1000_dma_spin_lock, flags);
}
/*
* Set the DMA buffer enable bits in the mode register.
*/
static __inline__ void enable_dma_buffer0(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
au_writel(DMA_BE0, chan->io + DMA_MODE_SET);
}
static __inline__ void enable_dma_buffer1(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
au_writel(DMA_BE1, chan->io + DMA_MODE_SET);
}
static __inline__ void enable_dma_buffers(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
au_writel(DMA_BE0 | DMA_BE1, chan->io + DMA_MODE_SET);
}
static __inline__ void start_dma(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
au_writel(DMA_GO, chan->io + DMA_MODE_SET);
}
#define DMA_HALT_POLL 0x5000
static __inline__ void halt_dma(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
int i;
if (!chan)
return;
au_writel(DMA_GO, chan->io + DMA_MODE_CLEAR);
// poll the halt bit
for (i = 0; i < DMA_HALT_POLL; i++)
if (au_readl(chan->io + DMA_MODE_READ) & DMA_HALT)
break;
if (i == DMA_HALT_POLL)
printk(KERN_INFO "halt_dma: HALT poll expired!\n");
}
static __inline__ void disable_dma(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
halt_dma(dmanr);
// now we can disable the buffers
au_writel(~DMA_GO, chan->io + DMA_MODE_CLEAR);
}
static __inline__ int dma_halted(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return 1;
return (au_readl(chan->io + DMA_MODE_READ) & DMA_HALT) ? 1 : 0;
}
/* initialize a DMA channel */
static __inline__ void init_dma(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
u32 mode;
if (!chan)
return;
disable_dma(dmanr);
// set device FIFO address
au_writel(PHYSADDR(chan->fifo_addr),
chan->io + DMA_PERIPHERAL_ADDR);
mode = chan->mode | (chan->dev_id << DMA_DID_BIT);
if (chan->irq)
mode |= DMA_IE;
au_writel(~mode, chan->io + DMA_MODE_CLEAR);
au_writel(mode, chan->io + DMA_MODE_SET);
}
/*
* set mode for a specific DMA channel
*/
static __inline__ void set_dma_mode(unsigned int dmanr, unsigned int mode)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
/*
* set_dma_mode is only allowed to change endianess, direction,
* transfer size, device FIFO width, and coherency settings.
* Make sure anything else is masked off.
*/
mode &= (DMA_BE | DMA_DR | DMA_TS8 | DMA_DW_MASK | DMA_NC);
chan->mode &= ~(DMA_BE | DMA_DR | DMA_TS8 | DMA_DW_MASK | DMA_NC);
chan->mode |= mode;
}
static __inline__ unsigned int get_dma_mode(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return 0;
return chan->mode;
}
static __inline__ int get_dma_active_buffer(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return -1;
return (au_readl(chan->io + DMA_MODE_READ) & DMA_AB) ? 1 : 0;
}
/*
* set the device FIFO address for a specific DMA channel - only
* applicable to GPO4 and GPO5. All the other devices have fixed
* FIFO addresses.
*/
static __inline__ void set_dma_fifo_addr(unsigned int dmanr,
unsigned int a)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
if (chan->dev_id != DMA_ID_GP04 && chan->dev_id != DMA_ID_GP05)
return;
au_writel(PHYSADDR(a), chan->io + DMA_PERIPHERAL_ADDR);
}
/*
* Clear the DMA buffer done bits in the mode register.
*/
static __inline__ void clear_dma_done0(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
au_writel(DMA_D0, chan->io + DMA_MODE_CLEAR);
}
static __inline__ void clear_dma_done1(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
au_writel(DMA_D1, chan->io + DMA_MODE_CLEAR);
}
/*
* This does nothing - not applicable to Au1000 DMA.
*/
static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
{
}
/*
* Set Buffer 0 transfer address for specific DMA channel.
*/
static __inline__ void set_dma_addr0(unsigned int dmanr, unsigned int a)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
au_writel(a, chan->io + DMA_BUFFER0_START);
}
/*
* Set Buffer 1 transfer address for specific DMA channel.
*/
static __inline__ void set_dma_addr1(unsigned int dmanr, unsigned int a)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
au_writel(a, chan->io + DMA_BUFFER1_START);
}
/*
* Set Buffer 0 transfer size (max 64k) for a specific DMA channel.
*/
static __inline__ void set_dma_count0(unsigned int dmanr,
unsigned int count)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
count &= DMA_COUNT_MASK;
au_writel(count, chan->io + DMA_BUFFER0_COUNT);
}
/*
* Set Buffer 1 transfer size (max 64k) for a specific DMA channel.
*/
static __inline__ void set_dma_count1(unsigned int dmanr,
unsigned int count)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
count &= DMA_COUNT_MASK;
au_writel(count, chan->io + DMA_BUFFER1_COUNT);
}
/*
* Set both buffer transfer sizes (max 64k) for a specific DMA channel.
*/
static __inline__ void set_dma_count(unsigned int dmanr,
unsigned int count)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
count &= DMA_COUNT_MASK;
au_writel(count, chan->io + DMA_BUFFER0_COUNT);
au_writel(count, chan->io + DMA_BUFFER1_COUNT);
}
/*
* Returns which buffer has its done bit set in the mode register.
* Returns -1 if neither or both done bits set.
*/
static __inline__ unsigned int get_dma_buffer_done(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return 0;
return au_readl(chan->io + DMA_MODE_READ) & (DMA_D0 | DMA_D1);
}
/*
* Returns the DMA channel's Buffer Done IRQ number.
*/
static __inline__ int get_dma_done_irq(unsigned int dmanr)
{
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return -1;
return chan->irq;
}
/*
* Get DMA residue count. Returns the number of _bytes_ left to transfer.
*/
static __inline__ int get_dma_residue(unsigned int dmanr)
{
int curBufCntReg, count;
struct dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return 0;
curBufCntReg = (au_readl(chan->io + DMA_MODE_READ) & DMA_AB) ?
DMA_BUFFER1_COUNT : DMA_BUFFER0_COUNT;
count = au_readl(chan->io + curBufCntReg) & DMA_COUNT_MASK;
if ((chan->mode & DMA_DW_MASK) == DMA_DW16)
count <<= 1;
else if ((chan->mode & DMA_DW_MASK) == DMA_DW32)
count <<= 2;
return count;
}
#endif /* __ASM_AU1000_DMA_H */
/*
* FILE NAME au1000_gpio.h
*
* BRIEF MODULE DESCRIPTION
* API to Alchemy Au1000 GPIO device.
*
* Author: MontaVista Software, Inc. <source@mvista.com>
* Steve Longerbeam <stevel@mvista.com>
*
* Copyright 2001 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __AU1000_GPIO_H
#define __AU1000_GPIO_H
#include <linux/ioctl.h>
#define AU1000GPIO_IOC_MAGIC 'A'
#define AU1000GPIO_IN _IOR (AU1000GPIO_IOC_MAGIC, 0, int)
#define AU1000GPIO_SET _IOW (AU1000GPIO_IOC_MAGIC, 1, int)
#define AU1000GPIO_CLEAR _IOW (AU1000GPIO_IOC_MAGIC, 2, int)
#define AU1000GPIO_OUT _IOW (AU1000GPIO_IOC_MAGIC, 3, int)
#define AU1000GPIO_TRISTATE _IOW (AU1000GPIO_IOC_MAGIC, 4, int)
#define AU1000GPIO_AVAIL_MASK _IOR (AU1000GPIO_IOC_MAGIC, 5, int)
#ifdef __KERNEL__
extern u32 get_au1000_avail_gpio_mask(void);
extern int au1000gpio_tristate(u32 data);
extern int au1000gpio_in(u32 *data);
extern int au1000gpio_set(u32 data);
extern int au1000gpio_clear(u32 data);
extern int au1000gpio_out(u32 data);
#endif
#endif
/*
*
* Alchemy Semi Au1000 pcmcia driver include file
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* ########################################################################
*
* 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.
*
* ########################################################################
*
*
*/
#ifndef __ASM_AU1000_PCMCIA_H
#define __ASM_AU1000_PCMCIA_H
#define AU1000_PCMCIA_POLL_PERIOD (2*HZ)
#define AU1000_PCMCIA_IO_SPEED (255)
#define AU1000_PCMCIA_MEM_SPEED (300)
#define AU1X_SOCK0_IO 0xF00000000
#define AU1X_SOCK0_PHYS_ATTR 0xF40000000
#define AU1X_SOCK0_PHYS_MEM 0xF80000000
/* pcmcia socket 1 needs external glue logic so the memory map
* differs from board to board.
*/
#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500)
#define AU1X_SOCK1_IO 0xF08000000
#define AU1X_SOCK1_PHYS_ATTR 0xF48000000
#define AU1X_SOCK1_PHYS_MEM 0xF88000000
#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500)
#define AU1X_SOCK1_IO 0xF04000000
#define AU1X_SOCK1_PHYS_ATTR 0xF44000000
#define AU1X_SOCK1_PHYS_MEM 0xF84000000
#endif
struct pcmcia_state {
unsigned detect: 1,
ready: 1,
wrprot: 1,
bvd1: 1,
bvd2: 1,
vs_3v: 1,
vs_Xv: 1;
};
struct pcmcia_configure {
unsigned sock: 8,
vcc: 8,
vpp: 8,
output: 1,
speaker: 1,
reset: 1;
};
struct pcmcia_irq_info {
unsigned int sock;
unsigned int irq;
};
struct au1000_pcmcia_socket {
socket_state_t cs_state;
struct pcmcia_state k_state;
unsigned int irq;
void (*handler)(void *, unsigned int);
void *handler_info;
pccard_io_map io_map[MAX_IO_WIN];
pccard_mem_map mem_map[MAX_WIN];
u32 virt_io;
ioaddr_t phys_attr, phys_mem;
unsigned short speed_io, speed_attr, speed_mem;
};
struct pcmcia_init {
void (*handler)(int irq, void *dev, struct pt_regs *regs);
};
struct pcmcia_low_level {
int (*init)(struct pcmcia_init *);
int (*shutdown)(void);
int (*socket_state)(unsigned sock, struct pcmcia_state *);
int (*get_irq_info)(struct pcmcia_irq_info *);
int (*configure_socket)(const struct pcmcia_configure *);
};
#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500)
extern struct pcmcia_low_level pb1x00_pcmcia_ops;
#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500)
extern struct pcmcia_low_level db1x00_pcmcia_ops;
#else
error unknown Au1000 board
#endif
#endif /* __ASM_AU1000_PCMCIA_H */
/*
* BRIEF MODULE DESCRIPTION
* Au1000 USB Device-Side Driver
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* stevel@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define USBDEV_REV 0x0110 // BCD
#define USBDEV_EP0_MAX_PACKET_SIZE 64
typedef enum {
ATTACHED = 0,
POWERED,
DEFAULT,
ADDRESS,
CONFIGURED
} usbdev_state_t;
typedef enum {
CB_NEW_STATE = 0,
CB_PKT_COMPLETE
} usbdev_cb_type_t;
typedef struct usbdev_pkt {
int ep_addr; // ep addr this packet routed to
int size; // size of payload in bytes
unsigned status; // packet status
struct usbdev_pkt* next; // function layer can't touch this
u8 payload[0]; // the payload
} usbdev_pkt_t;
#define PKT_STATUS_ACK (1<<0)
#define PKT_STATUS_NAK (1<<1)
#define PKT_STATUS_SU (1<<2)
extern int usbdev_init(struct usb_device_descriptor* dev_desc,
struct usb_config_descriptor* config_desc,
struct usb_interface_descriptor* if_desc,
struct usb_endpoint_descriptor* ep_desc,
struct usb_string_descriptor* str_desc[],
void (*cb)(usbdev_cb_type_t, unsigned long, void *),
void* cb_data);
extern void usbdev_exit(void);
extern int usbdev_alloc_packet (int ep_addr, int data_size,
usbdev_pkt_t** pkt);
extern int usbdev_send_packet (int ep_addr, usbdev_pkt_t* pkt);
extern int usbdev_receive_packet(int ep_addr, usbdev_pkt_t** pkt);
extern int usbdev_get_byte_count(int ep_addr);
/*
* Alchemy Semi PB1000 Referrence Board
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* ########################################################################
*
* 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.
*
* ########################################################################
*
*
*/
#ifndef __ASM_PB1000_H
#define __ASM_PB1000_H
/* PCMCIA PB1000 specific defines */
#define PCMCIA_MAX_SOCK 1
#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK+1)
#define PB1000_PCR 0xBE000000
#define PCR_SLOT_0_VPP0 (1<<0)
#define PCR_SLOT_0_VPP1 (1<<1)
#define PCR_SLOT_0_VCC0 (1<<2)
#define PCR_SLOT_0_VCC1 (1<<3)
#define PCR_SLOT_0_RST (1<<4)
#define PCR_SLOT_1_VPP0 (1<<8)
#define PCR_SLOT_1_VPP1 (1<<9)
#define PCR_SLOT_1_VCC0 (1<<10)
#define PCR_SLOT_1_VCC1 (1<<11)
#define PCR_SLOT_1_RST (1<<12)
#define PB1000_MDR 0xBE000004
#define MDR_PI (1<<5) /* pcmcia int latch */
#define MDR_EPI (1<<14) /* enable pcmcia int */
#define MDR_CPI (1<<15) /* clear pcmcia int */
#define PB1000_ACR1 0xBE000008
#define ACR1_SLOT_0_CD1 (1<<0) /* card detect 1 */
#define ACR1_SLOT_0_CD2 (1<<1) /* card detect 2 */
#define ACR1_SLOT_0_READY (1<<2) /* ready */
#define ACR1_SLOT_0_STATUS (1<<3) /* status change */
#define ACR1_SLOT_0_VS1 (1<<4) /* voltage sense 1 */
#define ACR1_SLOT_0_VS2 (1<<5) /* voltage sense 2 */
#define ACR1_SLOT_0_INPACK (1<<6) /* inpack pin status */
#define ACR1_SLOT_1_CD1 (1<<8) /* card detect 1 */
#define ACR1_SLOT_1_CD2 (1<<9) /* card detect 2 */
#define ACR1_SLOT_1_READY (1<<10) /* ready */
#define ACR1_SLOT_1_STATUS (1<<11) /* status change */
#define ACR1_SLOT_1_VS1 (1<<12) /* voltage sense 1 */
#define ACR1_SLOT_1_VS2 (1<<13) /* voltage sense 2 */
#define ACR1_SLOT_1_INPACK (1<<14) /* inpack pin status */
#define CPLD_AUX0 0xBE00000C
#define CPLD_AUX1 0xBE000010
#define CPLD_AUX2 0xBE000014
/* Voltage levels */
/* VPPEN1 - VPPEN0 */
#define VPP_GND ((0<<1) | (0<<0))
#define VPP_5V ((1<<1) | (0<<0))
#define VPP_3V ((0<<1) | (1<<0))
#define VPP_12V ((0<<1) | (1<<0))
#define VPP_HIZ ((1<<1) | (1<<0))
/* VCCEN1 - VCCEN0 */
#define VCC_3V ((0<<1) | (1<<0))
#define VCC_5V ((1<<1) | (0<<0))
#define VCC_HIZ ((0<<1) | (0<<0))
/* VPP/VCC */
#define SET_VCC_VPP(VCC, VPP, SLOT)\
((((VCC)<<2) | ((VPP)<<0)) << ((SLOT)*8))
/* PCI PB1000 specific defines */
/* The reason these defines are here instead of au1000.h is because
* the Au1000 does not have a PCI bus controller so the PCI implementation
* on the some of the older Pb1000 boards was very board specific.
*/
#define PCI_CONFIG_BASE 0xBA020000 /* the only external slot */
#define SDRAM_DEVID 0xBA010000
#define SDRAM_CMD 0xBA010004
#define SDRAM_CLASS 0xBA010008
#define SDRAM_MISC 0xBA01000C
#define SDRAM_MBAR 0xBA010010
#define PCI_IO_DATA_PORT 0xBA800000
#define PCI_IO_ADDR 0xBE00001C
#define PCI_INT_ACK 0xBBC00000
#define PCI_IO_READ 0xBBC00020
#define PCI_IO_WRITE 0xBBC00030
#define PCI_BRIDGE_CONFIG 0xBE000018
#define PCI_IO_START 0x10000000
#define PCI_IO_END 0x1000ffff
#define PCI_MEM_START 0x18000000
#define PCI_MEM_END 0x18ffffff
#define PCI_FIRST_DEVFN 0
#define PCI_LAST_DEVFN 1
static inline u8 au_pci_io_readb(u32 addr)
{
writel(addr, PCI_IO_ADDR);
writel((readl(PCI_BRIDGE_CONFIG) & 0xffffcfff) | (1<<12), PCI_BRIDGE_CONFIG);
return (readl(PCI_IO_DATA_PORT) & 0xff);
}
static inline u16 au_pci_io_readw(u32 addr)
{
writel(addr, PCI_IO_ADDR);
writel((readl(PCI_BRIDGE_CONFIG) & 0xffffcfff) | (1<<13), PCI_BRIDGE_CONFIG);
return (readl(PCI_IO_DATA_PORT) & 0xffff);
}
static inline u32 au_pci_io_readl(u32 addr)
{
writel(addr, PCI_IO_ADDR);
writel((readl(PCI_BRIDGE_CONFIG) & 0xffffcfff), PCI_BRIDGE_CONFIG);
return readl(PCI_IO_DATA_PORT);
}
static inline void au_pci_io_writeb(u8 val, u32 addr)
{
writel(addr, PCI_IO_ADDR);
writel((readl(PCI_BRIDGE_CONFIG) & 0xffffcfff) | (1<<12), PCI_BRIDGE_CONFIG);
writel(val, PCI_IO_DATA_PORT);
}
static inline void au_pci_io_writew(u16 val, u32 addr)
{
writel(addr, PCI_IO_ADDR);
writel((readl(PCI_BRIDGE_CONFIG) & 0xffffcfff) | (1<<13), PCI_BRIDGE_CONFIG);
writel(val, PCI_IO_DATA_PORT);
}
static inline void au_pci_io_writel(u32 val, u32 addr)
{
writel(addr, PCI_IO_ADDR);
writel(readl(PCI_BRIDGE_CONFIG) & 0xffffcfff, PCI_BRIDGE_CONFIG);
writel(val, PCI_IO_DATA_PORT);
}
static inline void set_sdram_extbyte(void)
{
writel(readl(PCI_BRIDGE_CONFIG) & 0xffffff00, PCI_BRIDGE_CONFIG);
}
static inline void set_slot_extbyte(void)
{
writel((readl(PCI_BRIDGE_CONFIG) & 0xffffbf00) | 0x18, PCI_BRIDGE_CONFIG);
}
#endif /* __ASM_PB1000_H */
/*
* Alchemy Semi PB1100 Referrence Board
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* ########################################################################
*
* 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.
*
* ########################################################################
*
*
*/
#ifndef __ASM_PB1100_H
#define __ASM_PB1100_H
#define PB1100_IDENT 0xAE000000
#define BOARD_STATUS_REG 0xAE000004
#define PB1100_ROM_SEL (1<<15)
#define PB1100_ROM_SIZ (1<<14)
#define PB1100_SWAP_BOOT (1<<13)
#define PB1100_FLASH_WP (1<<12)
#define PB1100_ROM_H_STS (1<<11)
#define PB1100_ROM_L_STS (1<<10)
#define PB1100_FLASH_H_STS (1<<9)
#define PB1100_FLASH_L_STS (1<<8)
#define PB1100_SRAM_SIZ (1<<7)
#define PB1100_TSC_BUSY (1<<6)
#define PB1100_PCMCIA_VS_MASK (3<<4)
#define PB1100_RS232_CD (1<<3)
#define PB1100_RS232_CTS (1<<2)
#define PB1100_RS232_DSR (1<<1)
#define PB1100_RS232_RI (1<<0)
#define PB1100_IRDA_RS232 0xAE00000C
#define PB1100_IRDA_FULL (0<<14) /* full power */
#define PB1100_IRDA_SHUTDOWN (1<<14)
#define PB1100_IRDA_TT (2<<14) /* 2/3 power */
#define PB1100_IRDA_OT (3<<14) /* 1/3 power */
#define PB1100_IRDA_FIR (1<<13)
#define PCMCIA_BOARD_REG 0xAE000010
#define PB1100_SD_WP1_RO (1<<15) /* read only */
#define PB1100_SD_WP0_RO (1<<14) /* read only */
#define PB1100_SD_PWR1 (1<<11) /* applies power to SD1 */
#define PB1100_SD_PWR0 (1<<10) /* applies power to SD0 */
#define PB1100_SEL_SD_CONN1 (1<<9)
#define PB1100_SEL_SD_CONN0 (1<<8)
#define PC_DEASSERT_RST (1<<7)
#define PC_DRV_EN (1<<4)
#define PB1100_G_CONTROL 0xAE000014 /* graphics control */
#define PB1100_RST_VDDI 0xAE00001C
#define PB1100_SOFT_RESET (1<<15) /* clear to reset the board */
#define PB1100_VDDI_MASK (0x1F)
#define PB1100_LEDS 0xAE000018
/* 11:8 is 4 discreet LEDs. Clearing a bit illuminates the LED.
* 7:0 is the LED Display's decimal points.
*/
#define PB1100_HEX_LED 0xAE000018
/* PCMCIA PB1100 specific defines */
#define PCMCIA_MAX_SOCK 0
#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK+1)
/* VPP/VCC */
#define SET_VCC_VPP(VCC, VPP) (((VCC)<<2) | ((VPP)<<0))
#endif /* __ASM_PB1100_H */
/*
* Alchemy Semi PB1500 Referrence Board
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* ########################################################################
*
* 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.
*
* ########################################################################
*
*
*/
#ifndef __ASM_PB1500_H
#define __ASM_PB1500_H
#define IDENT_BOARD_REG 0xAE000000
#define BOARD_STATUS_REG 0xAE000004
#define PCI_BOARD_REG 0xAE000010
#define PCMCIA_BOARD_REG 0xAE000010
#define PC_DEASSERT_RST 0x80
#define PC_DRV_EN 0x10
#define PB1500_G_CONTROL 0xAE000014
#define PB1500_RST_VDDI 0xAE00001C
#define PB1500_LEDS 0xAE000018
#define PB1500_HEX_LED 0xAF000004
#define PB1500_HEX_LED_BLANK 0xAF000008
/* PCMCIA PB1500 specific defines */
#define PCMCIA_MAX_SOCK 0
#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK+1)
/* VPP/VCC */
#define SET_VCC_VPP(VCC, VPP) (((VCC)<<2) | ((VPP)<<0))
#endif /* __ASM_PB1500_H */
/*
*
* BRIEF MODULE DESCRIPTION
* Au1000 IrDA driver.
*
* Copyright 2001 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef AU1000_IRCC_H
#define AU1000_IRCC_H
#include <linux/time.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <asm/io.h>
#define NUM_IR_IFF 1
#define NUM_IR_DESC 64
#define RING_SIZE_4 0x0
#define RING_SIZE_16 0x3
#define RING_SIZE_64 0xF
#define MAX_NUM_IR_DESC 64
#define MAX_BUF_SIZE 2048
#define BPS_115200 0
#define BPS_57600 1
#define BPS_38400 2
#define BPS_19200 5
#define BPS_9600 11
#define BPS_2400 47
/* Ring descriptor flags */
#define AU_OWN (1<<7) /* tx,rx */
#define IR_DIS_CRC (1<<6) /* tx */
#define IR_BAD_CRC (1<<5) /* tx */
#define IR_NEED_PULSE (1<<4) /* tx */
#define IR_FORCE_UNDER (1<<3) /* tx */
#define IR_DISABLE_TX (1<<2) /* tx */
#define IR_HW_UNDER (1<<0) /* tx */
#define IR_TX_ERROR (IR_DIS_CRC|IR_BAD_CRC|IR_HW_UNDER)
#define IR_PHY_ERROR (1<<6) /* rx */
#define IR_CRC_ERROR (1<<5) /* rx */
#define IR_MAX_LEN (1<<4) /* rx */
#define IR_FIFO_OVER (1<<3) /* rx */
#define IR_SIR_ERROR (1<<2) /* rx */
#define IR_RX_ERROR (IR_PHY_ERROR|IR_CRC_ERROR| \
IR_MAX_LEN|IR_FIFO_OVER|IR_SIR_ERROR)
typedef struct db_dest {
struct db_dest *pnext;
volatile u32 *vaddr;
dma_addr_t dma_addr;
} db_dest_t;
typedef struct ring_desc {
u8 count_0; /* 7:0 */
u8 count_1; /* 12:8 */
u8 reserved;
u8 flags;
u8 addr_0; /* 7:0 */
u8 addr_1; /* 15:8 */
u8 addr_2; /* 23:16 */
u8 addr_3; /* 31:24 */
} ring_dest_t;
/* Private data for each instance */
struct au1k_private {
db_dest_t *pDBfree;
db_dest_t db[2*NUM_IR_DESC];
volatile ring_dest_t *rx_ring[NUM_IR_DESC];
volatile ring_dest_t *tx_ring[NUM_IR_DESC];
db_dest_t *rx_db_inuse[NUM_IR_DESC];
db_dest_t *tx_db_inuse[NUM_IR_DESC];
u32 rx_head;
u32 tx_head;
u32 tx_tail;
u32 tx_full;
iobuff_t rx_buff;
struct net_device *netdev;
struct net_device_stats stats;
struct timeval stamp;
struct timeval now;
struct qos_info qos;
struct irlap_cb *irlap;
u8 open;
u32 flags; /* Interface flags */
u32 speed;
u32 newspeed;
u32 intr_work_done; /* number of Rx and Tx pkts processed in the isr */
struct timer_list timer;
spinlock_t lock; /* For serializing operations */
struct pm_dev *dev;
};
#endif /* AU1000_IRCC_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment