diff options
Diffstat (limited to 'arch/mips/au1000')
27 files changed, 1224 insertions, 276 deletions
diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile index 594b75e5e08..a1edfd1f643 100644 --- a/arch/mips/au1000/common/Makefile +++ b/arch/mips/au1000/common/Makefile @@ -8,7 +8,7 @@ obj-y += prom.o int-handler.o irq.o puts.o time.o reset.o \ au1xxx_irqmap.o clocks.o platform.o power.o setup.o \ - sleeper.o cputable.o dma.o dbdma.o + sleeper.o cputable.o dma.o dbdma.o gpio.o obj-$(CONFIG_AU1X00_USB_DEVICE) += usbdev.o obj-$(CONFIG_KGDB) += dbg_io.o diff --git a/arch/mips/au1000/common/au1xxx_irqmap.c b/arch/mips/au1000/common/au1xxx_irqmap.c index 8a0f39f67c5..0b2c03c5231 100644 --- a/arch/mips/au1000/common/au1xxx_irqmap.c +++ b/arch/mips/au1000/common/au1xxx_irqmap.c @@ -173,14 +173,14 @@ au1xxx_irq_map_t au1xxx_ic0_map[] = { { AU1550_PSC1_INT, INTC_INT_HIGH_LEVEL, 0}, { AU1550_PSC2_INT, INTC_INT_HIGH_LEVEL, 0}, { AU1550_PSC3_INT, INTC_INT_HIGH_LEVEL, 0}, - { AU1550_TOY_INT, INTC_INT_RISE_EDGE, 0 }, - { AU1550_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, - { AU1550_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, - { AU1550_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 }, - { AU1550_RTC_INT, INTC_INT_RISE_EDGE, 0 }, - { AU1550_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, - { AU1550_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, - { AU1550_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 }, + { AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 }, { AU1550_NAND_INT, INTC_INT_RISE_EDGE, 0}, { AU1550_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 }, { AU1550_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 }, @@ -201,14 +201,14 @@ au1xxx_irq_map_t au1xxx_ic0_map[] = { { AU1200_PSC1_INT, INTC_INT_HIGH_LEVEL, 0}, { AU1200_AES_INT, INTC_INT_HIGH_LEVEL, 0}, { AU1200_CAMERA_INT, INTC_INT_HIGH_LEVEL, 0}, - { AU1200_TOY_INT, INTC_INT_RISE_EDGE, 0 }, - { AU1200_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, - { AU1200_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, - { AU1200_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 }, - { AU1200_RTC_INT, INTC_INT_RISE_EDGE, 0 }, - { AU1200_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, - { AU1200_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, - { AU1200_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 }, + { AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 }, + { AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 }, { AU1200_NAND_INT, INTC_INT_RISE_EDGE, 0}, { AU1200_USB_INT, INTC_INT_HIGH_LEVEL, 0 }, { AU1200_LCD_INT, INTC_INT_HIGH_LEVEL, 0}, diff --git a/arch/mips/au1000/common/cputable.c b/arch/mips/au1000/common/cputable.c index f5521dfccfd..4dbde82c821 100644 --- a/arch/mips/au1000/common/cputable.c +++ b/arch/mips/au1000/common/cputable.c @@ -37,7 +37,8 @@ struct cpu_spec cpu_specs[] = { { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1 }, { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 }, { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 }, - { 0xffffffff, 0x04030200, "Au1200 AA", 0, 1 }, + { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 }, + { 0xffffffff, 0x04030201, "Au1200 AC", 0, 1 }, { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 }, }; diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c index adfc3172aac..d00e8247d6c 100644 --- a/arch/mips/au1000/common/dbdma.c +++ b/arch/mips/au1000/common/dbdma.c @@ -29,6 +29,7 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. * */ + #include <linux/config.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -38,10 +39,12 @@ #include <linux/string.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1xxx_dbdma.h> #include <asm/system.h> + #if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) /* @@ -61,37 +64,10 @@ static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock); */ #define ALIGN_ADDR(x, a) ((((u32)(x)) + (a-1)) & ~(a-1)) -static volatile dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE; -static int dbdma_initialized; +static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE; +static int dbdma_initialized=0; static void au1xxx_dbdma_init(void); -typedef struct dbdma_device_table { - u32 dev_id; - u32 dev_flags; - u32 dev_tsize; - u32 dev_devwidth; - u32 dev_physaddr; /* If FIFO */ - u32 dev_intlevel; - u32 dev_intpolarity; -} dbdev_tab_t; - -typedef struct dbdma_chan_config { - u32 chan_flags; - u32 chan_index; - dbdev_tab_t *chan_src; - dbdev_tab_t *chan_dest; - au1x_dma_chan_t *chan_ptr; - au1x_ddma_desc_t *chan_desc_base; - au1x_ddma_desc_t *get_ptr, *put_ptr, *cur_ptr; - void *chan_callparam; - void (*chan_callback)(int, void *, struct pt_regs *); -} chan_tab_t; - -#define DEV_FLAGS_INUSE (1 << 0) -#define DEV_FLAGS_ANYUSE (1 << 1) -#define DEV_FLAGS_OUT (1 << 2) -#define DEV_FLAGS_IN (1 << 3) - static dbdev_tab_t dbdev_tab[] = { #ifdef CONFIG_SOC_AU1550 /* UARTS */ @@ -157,25 +133,25 @@ static dbdev_tab_t dbdev_tab[] = { { DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, { DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 }, + { DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 4, 8, 0x10600004, 0, 0 }, + { DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 4, 8, 0x10680000, 0, 0 }, + { DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 4, 8, 0x10680004, 0, 0 }, - { DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_AES_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_AES_RX, DEV_FLAGS_IN , 4, 32, 0x10300008, 0, 0 }, + { DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 4, 32, 0x10300004, 0, 0 }, - { DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 }, - { DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 }, + { DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 16, 0x11a0001c, 0, 0 }, + { DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 16, 0x11a0001c, 0, 0 }, { DSCR_CMD0_PSC0_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 }, - { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 }, + { DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 16, 0x11b0001c, 0, 0 }, + { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 16, 0x11b0001c, 0, 0 }, { DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 32, 0x14004020, 0, 0 }, + { DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 32, 0x14004040, 0, 0 }, + { DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 32, 0x14004060, 0, 0 }, { DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, { DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, @@ -184,6 +160,24 @@ static dbdev_tab_t dbdev_tab[] = { { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, { DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, + + /* Provide 16 user definable device types */ + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, }; #define DBDEV_TAB_SIZE (sizeof(dbdev_tab) / sizeof(dbdev_tab_t)) @@ -203,6 +197,36 @@ find_dbdev_id (u32 id) return NULL; } +void * au1xxx_ddma_get_nextptr_virt(au1x_ddma_desc_t *dp) +{ + return phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); +} +EXPORT_SYMBOL(au1xxx_ddma_get_nextptr_virt); + +u32 +au1xxx_ddma_add_device(dbdev_tab_t *dev) +{ + u32 ret = 0; + dbdev_tab_t *p=NULL; + static u16 new_id=0x1000; + + p = find_dbdev_id(0); + if ( NULL != p ) + { + memcpy(p, dev, sizeof(dbdev_tab_t)); + p->dev_id = DSCR_DEV2CUSTOM_ID(new_id,dev->dev_id); + ret = p->dev_id; + new_id++; +#if 0 + printk("add_device: id:%x flags:%x padd:%x\n", + p->dev_id, p->dev_flags, p->dev_physaddr ); +#endif + } + + return ret; +} +EXPORT_SYMBOL(au1xxx_ddma_add_device); + /* Allocate a channel and return a non-zero descriptor if successful. */ u32 @@ -215,7 +239,7 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, int i; dbdev_tab_t *stp, *dtp; chan_tab_t *ctp; - volatile au1x_dma_chan_t *cp; + au1x_dma_chan_t *cp; /* We do the intialization on the first channel allocation. * We have to wait because of the interrupt handler initialization @@ -225,9 +249,6 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, au1xxx_dbdma_init(); dbdma_initialized = 1; - if ((srcid > DSCR_NDEV_IDS) || (destid > DSCR_NDEV_IDS)) - return 0; - if ((stp = find_dbdev_id(srcid)) == NULL) return 0; if ((dtp = find_dbdev_id(destid)) == NULL) return 0; @@ -271,7 +292,6 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, */ ctp = kmalloc(sizeof(chan_tab_t), GFP_KERNEL); chan_tab_ptr[i] = ctp; - ctp->chan_index = chan = i; break; } } @@ -279,10 +299,11 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, if (ctp != NULL) { memset(ctp, 0, sizeof(chan_tab_t)); + ctp->chan_index = chan = i; dcp = DDMA_CHANNEL_BASE; dcp += (0x0100 * chan); ctp->chan_ptr = (au1x_dma_chan_t *)dcp; - cp = (volatile au1x_dma_chan_t *)dcp; + cp = (au1x_dma_chan_t *)dcp; ctp->chan_src = stp; ctp->chan_dest = dtp; ctp->chan_callback = callback; @@ -299,6 +320,9 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, i |= DDMA_CFG_DED; if (dtp->dev_intpolarity) i |= DDMA_CFG_DP; + if ((stp->dev_flags & DEV_FLAGS_SYNC) || + (dtp->dev_flags & DEV_FLAGS_SYNC)) + i |= DDMA_CFG_SYNC; cp->ddma_cfg = i; au_sync(); @@ -309,14 +333,14 @@ au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, rv = (u32)(&chan_tab_ptr[chan]); } else { - /* Release devices. - */ + /* Release devices */ stp->dev_flags &= ~DEV_FLAGS_INUSE; dtp->dev_flags &= ~DEV_FLAGS_INUSE; } } return rv; } +EXPORT_SYMBOL(au1xxx_dbdma_chan_alloc); /* Set the device width if source or destination is a FIFO. * Should be 8, 16, or 32 bits. @@ -344,6 +368,7 @@ au1xxx_dbdma_set_devwidth(u32 chanid, int bits) return rv; } +EXPORT_SYMBOL(au1xxx_dbdma_set_devwidth); /* Allocate a descriptor ring, initializing as much as possible. */ @@ -370,7 +395,8 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries) * and if we try that first we are likely to not waste larger * slabs of memory. */ - desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t), GFP_KERNEL); + desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t), + GFP_KERNEL|GFP_DMA); if (desc_base == 0) return 0; @@ -381,7 +407,7 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries) kfree((const void *)desc_base); i = entries * sizeof(au1x_ddma_desc_t); i += (sizeof(au1x_ddma_desc_t) - 1); - if ((desc_base = (u32)kmalloc(i, GFP_KERNEL)) == 0) + if ((desc_base = (u32)kmalloc(i, GFP_KERNEL|GFP_DMA)) == 0) return 0; desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t)); @@ -403,7 +429,13 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries) cmd0 |= DSCR_CMD0_SID(srcid); cmd0 |= DSCR_CMD0_DID(destid); cmd0 |= DSCR_CMD0_IE | DSCR_CMD0_CV; - cmd0 |= DSCR_CMD0_ST(DSCR_CMD0_ST_CURRENT); + cmd0 |= DSCR_CMD0_ST(DSCR_CMD0_ST_NOCHANGE); + + /* is it mem to mem transfer? */ + if(((DSCR_CUSTOM2DEV_ID(srcid) == DSCR_CMD0_THROTTLE) || (DSCR_CUSTOM2DEV_ID(srcid) == DSCR_CMD0_ALWAYS)) && + ((DSCR_CUSTOM2DEV_ID(destid) == DSCR_CMD0_THROTTLE) || (DSCR_CUSTOM2DEV_ID(destid) == DSCR_CMD0_ALWAYS))) { + cmd0 |= DSCR_CMD0_MEM; + } switch (stp->dev_devwidth) { case 8: @@ -461,9 +493,14 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries) /* If source input is fifo, set static address. */ if (stp->dev_flags & DEV_FLAGS_IN) { - src0 = stp->dev_physaddr; + if ( stp->dev_flags & DEV_FLAGS_BURSTABLE ) + src1 |= DSCR_SRC1_SAM(DSCR_xAM_BURST); + else src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC); + } + if (stp->dev_physaddr) + src0 = stp->dev_physaddr; /* Set up dest1. For now, assume no stride and increment. * A channel attribute update can change this later. @@ -487,10 +524,18 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries) /* If destination output is fifo, set static address. */ if (dtp->dev_flags & DEV_FLAGS_OUT) { - dest0 = dtp->dev_physaddr; + if ( dtp->dev_flags & DEV_FLAGS_BURSTABLE ) + dest1 |= DSCR_DEST1_DAM(DSCR_xAM_BURST); + else dest1 |= DSCR_DEST1_DAM(DSCR_xAM_STATIC); } + if (dtp->dev_physaddr) + dest0 = dtp->dev_physaddr; +#if 0 + printk("did:%x sid:%x cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n", + dtp->dev_id, stp->dev_id, cmd0, cmd1, src0, src1, dest0, dest1 ); +#endif for (i=0; i<entries; i++) { dp->dscr_cmd0 = cmd0; dp->dscr_cmd1 = cmd1; @@ -499,6 +544,8 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries) dp->dscr_dest0 = dest0; dp->dscr_dest1 = dest1; dp->dscr_stat = 0; + dp->sw_context = 0; + dp->sw_status = 0; dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(dp + 1)); dp++; } @@ -511,13 +558,14 @@ au1xxx_dbdma_ring_alloc(u32 chanid, int entries) return (u32)(ctp->chan_desc_base); } +EXPORT_SYMBOL(au1xxx_dbdma_ring_alloc); /* Put a source buffer into the DMA ring. * This updates the source pointer and byte count. Normally used * for memory to fifo transfers. */ u32 -au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes) +_au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags) { chan_tab_t *ctp; au1x_ddma_desc_t *dp; @@ -544,8 +592,24 @@ au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes) */ dp->dscr_source0 = virt_to_phys(buf); dp->dscr_cmd1 = nbytes; - dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ - ctp->chan_ptr->ddma_dbell = 0xffffffff; /* Make it go */ + /* Check flags */ + if (flags & DDMA_FLAGS_IE) + dp->dscr_cmd0 |= DSCR_CMD0_IE; + if (flags & DDMA_FLAGS_NOIE) + dp->dscr_cmd0 &= ~DSCR_CMD0_IE; + + /* + * There is an errata on the Au1200/Au1550 parts that could result + * in "stale" data being DMA'd. It has to do with the snoop logic on + * the dache eviction buffer. NONCOHERENT_IO is on by default for + * these parts. If it is fixedin the future, these dma_cache_inv will + * just be nothing more than empty macros. See io.h. + * */ + dma_cache_wback_inv((unsigned long)buf, nbytes); + dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ + au_sync(); + dma_cache_wback_inv((unsigned long)dp, sizeof(dp)); + ctp->chan_ptr->ddma_dbell = 0; /* Get next descriptor pointer. */ @@ -555,13 +619,14 @@ au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes) */ return nbytes; } +EXPORT_SYMBOL(_au1xxx_dbdma_put_source); /* Put a destination buffer into the DMA ring. * This updates the destination pointer and byte count. Normally used * to place an empty buffer into the ring for fifo to memory transfers. */ u32 -au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes) +_au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags) { chan_tab_t *ctp; au1x_ddma_desc_t *dp; @@ -583,11 +648,33 @@ au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes) if (dp->dscr_cmd0 & DSCR_CMD0_V) return 0; - /* Load up buffer address and byte count. - */ + /* Load up buffer address and byte count */ + + /* Check flags */ + if (flags & DDMA_FLAGS_IE) + dp->dscr_cmd0 |= DSCR_CMD0_IE; + if (flags & DDMA_FLAGS_NOIE) + dp->dscr_cmd0 &= ~DSCR_CMD0_IE; + dp->dscr_dest0 = virt_to_phys(buf); dp->dscr_cmd1 = nbytes; +#if 0 + printk("cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n", + dp->dscr_cmd0, dp->dscr_cmd1, dp->dscr_source0, + dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1 ); +#endif + /* + * There is an errata on the Au1200/Au1550 parts that could result in + * "stale" data being DMA'd. It has to do with the snoop logic on the + * dache eviction buffer. NONCOHERENT_IO is on by default for these + * parts. If it is fixedin the future, these dma_cache_inv will just + * be nothing more than empty macros. See io.h. + * */ + dma_cache_inv((unsigned long)buf,nbytes); dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ + au_sync(); + dma_cache_wback_inv((unsigned long)dp, sizeof(dp)); + ctp->chan_ptr->ddma_dbell = 0; /* Get next descriptor pointer. */ @@ -597,6 +684,7 @@ au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes) */ return nbytes; } +EXPORT_SYMBOL(_au1xxx_dbdma_put_dest); /* Get a destination buffer into the DMA ring. * Normally used to get a full buffer from the ring during fifo @@ -646,7 +734,7 @@ void au1xxx_dbdma_stop(u32 chanid) { chan_tab_t *ctp; - volatile au1x_dma_chan_t *cp; + au1x_dma_chan_t *cp; int halt_timeout = 0; ctp = *((chan_tab_t **)chanid); @@ -666,6 +754,7 @@ au1xxx_dbdma_stop(u32 chanid) cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V); au_sync(); } +EXPORT_SYMBOL(au1xxx_dbdma_stop); /* Start using the current descriptor pointer. If the dbdma encounters * a not valid descriptor, it will stop. In this case, we can just @@ -675,17 +764,17 @@ void au1xxx_dbdma_start(u32 chanid) { chan_tab_t *ctp; - volatile au1x_dma_chan_t *cp; + au1x_dma_chan_t *cp; ctp = *((chan_tab_t **)chanid); - cp = ctp->chan_ptr; cp->ddma_desptr = virt_to_phys(ctp->cur_ptr); cp->ddma_cfg |= DDMA_CFG_EN; /* Enable channel */ au_sync(); - cp->ddma_dbell = 0xffffffff; /* Make it go */ + cp->ddma_dbell = 0; au_sync(); } +EXPORT_SYMBOL(au1xxx_dbdma_start); void au1xxx_dbdma_reset(u32 chanid) @@ -704,15 +793,21 @@ au1xxx_dbdma_reset(u32 chanid) do { dp->dscr_cmd0 &= ~DSCR_CMD0_V; + /* reset our SW status -- this is used to determine + * if a descriptor is in use by upper level SW. Since + * posting can reset 'V' bit. + */ + dp->sw_status = 0; dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); } while (dp != ctp->chan_desc_base); } +EXPORT_SYMBOL(au1xxx_dbdma_reset); u32 au1xxx_get_dma_residue(u32 chanid) { chan_tab_t *ctp; - volatile au1x_dma_chan_t *cp; + au1x_dma_chan_t *cp; u32 rv; ctp = *((chan_tab_t **)chanid); @@ -738,8 +833,7 @@ au1xxx_dbdma_chan_free(u32 chanid) au1xxx_dbdma_stop(chanid); - if (ctp->chan_desc_base != NULL) - kfree(ctp->chan_desc_base); + kfree((void *)ctp->chan_desc_base); stp->dev_flags &= ~DEV_FLAGS_INUSE; dtp->dev_flags &= ~DEV_FLAGS_INUSE; @@ -747,15 +841,16 @@ au1xxx_dbdma_chan_free(u32 chanid) kfree(ctp); } +EXPORT_SYMBOL(au1xxx_dbdma_chan_free); static irqreturn_t dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - u32 intstat; - u32 chan_index; + u32 intstat; + u32 chan_index; chan_tab_t *ctp; au1x_ddma_desc_t *dp; - volatile au1x_dma_chan_t *cp; + au1x_dma_chan_t *cp; intstat = dbdma_gptr->ddma_intstat; au_sync(); @@ -774,19 +869,27 @@ dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs) (ctp->chan_callback)(irq, ctp->chan_callparam, regs); ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); - - return IRQ_HANDLED; + return IRQ_RETVAL(1); } -static void -au1xxx_dbdma_init(void) +static void au1xxx_dbdma_init(void) { + int irq_nr; + dbdma_gptr->ddma_config = 0; dbdma_gptr->ddma_throttle = 0; dbdma_gptr->ddma_inten = 0xffff; au_sync(); - if (request_irq(AU1550_DDMA_INT, dbdma_interrupt, SA_INTERRUPT, +#if defined(CONFIG_SOC_AU1550) + irq_nr = AU1550_DDMA_INT; +#elif defined(CONFIG_SOC_AU1200) + irq_nr = AU1200_DDMA_INT; +#else + #error Unknown Au1x00 SOC +#endif + + if (request_irq(irq_nr, dbdma_interrupt, SA_INTERRUPT, "Au1xxx dbdma", (void *)dbdma_gptr)) printk("Can't get 1550 dbdma irq"); } @@ -797,7 +900,8 @@ au1xxx_dbdma_dump(u32 chanid) chan_tab_t *ctp; au1x_ddma_desc_t *dp; dbdev_tab_t *stp, *dtp; - volatile au1x_dma_chan_t *cp; + au1x_dma_chan_t *cp; + u32 i = 0; ctp = *((chan_tab_t **)chanid); stp = ctp->chan_src; @@ -822,15 +926,64 @@ au1xxx_dbdma_dump(u32 chanid) dp = ctp->chan_desc_base; do { - printk("dp %08x, cmd0 %08x, cmd1 %08x\n", - (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1); - printk("src0 %08x, src1 %08x, dest0 %08x\n", - dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0); - printk("dest1 %08x, stat %08x, nxtptr %08x\n", - dp->dscr_dest1, dp->dscr_stat, dp->dscr_nxtptr); + printk("Dp[%d]= %08x, cmd0 %08x, cmd1 %08x\n", + i++, (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1); + printk("src0 %08x, src1 %08x, dest0 %08x, dest1 %08x\n", + dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1); + printk("stat %08x, nxtptr %08x\n", + dp->dscr_stat, dp->dscr_nxtptr); dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); } while (dp != ctp->chan_desc_base); } +/* Put a descriptor into the DMA ring. + * This updates the source/destination pointers and byte count. + */ +u32 +au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr ) +{ + chan_tab_t *ctp; + au1x_ddma_desc_t *dp; + u32 nbytes=0; + + /* I guess we could check this to be within the + * range of the table...... + */ + ctp = *((chan_tab_t **)chanid); + + /* We should have multiple callers for a particular channel, + * an interrupt doesn't affect this pointer nor the descriptor, + * so no locking should be needed. + */ + dp = ctp->put_ptr; + + /* If the descriptor is valid, we are way ahead of the DMA + * engine, so just return an error condition. + */ + if (dp->dscr_cmd0 & DSCR_CMD0_V) + return 0; + + /* Load up buffer addresses and byte count. + */ + dp->dscr_dest0 = dscr->dscr_dest0; + dp->dscr_source0 = dscr->dscr_source0; + dp->dscr_dest1 = dscr->dscr_dest1; + dp->dscr_source1 = dscr->dscr_source1; + dp->dscr_cmd1 = dscr->dscr_cmd1; + nbytes = dscr->dscr_cmd1; + /* Allow the caller to specifiy if an interrupt is generated */ + dp->dscr_cmd0 &= ~DSCR_CMD0_IE; + dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V; + ctp->chan_ptr->ddma_dbell = 0; + + /* Get next descriptor pointer. + */ + ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); + + /* return something not zero. + */ + return nbytes; +} + #endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */ diff --git a/arch/mips/au1000/common/dma.c b/arch/mips/au1000/common/dma.c index 372c33f1353..1905c6b104f 100644 --- a/arch/mips/au1000/common/dma.c +++ b/arch/mips/au1000/common/dma.c @@ -39,7 +39,6 @@ #include <linux/string.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/module.h> #include <asm/system.h> #include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1000_dma.h> diff --git a/arch/mips/au1000/common/gpio.c b/arch/mips/au1000/common/gpio.c new file mode 100644 index 00000000000..5f5915b8314 --- /dev/null +++ b/arch/mips/au1000/common/gpio.c @@ -0,0 +1,119 @@ +/* + * 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/module.h> +#include <au1000.h> +#include <au1xxx_gpio.h> + +#define gpio1 sys +#if !defined(CONFIG_SOC_AU1000) +static AU1X00_GPIO2 * const gpio2 = (AU1X00_GPIO2 *)GPIO2_BASE; + +#define GPIO2_OUTPUT_ENABLE_MASK 0x00010000 + +int au1xxx_gpio2_read(int signal) +{ + signal -= 200; +/* gpio2->dir &= ~(0x01 << signal); //Set GPIO to input */ + return ((gpio2->pinstate >> signal) & 0x01); +} + +void au1xxx_gpio2_write(int signal, int value) +{ + signal -= 200; + + gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << signal) | + (value << signal); +} + +void au1xxx_gpio2_tristate(int signal) +{ + signal -= 200; + gpio2->dir &= ~(0x01 << signal); /* Set GPIO to input */ +} +#endif + +int au1xxx_gpio1_read(int signal) +{ +/* gpio1->trioutclr |= (0x01 << signal); */ + return ((gpio1->pinstaterd >> signal) & 0x01); +} + +void au1xxx_gpio1_write(int signal, int value) +{ + if(value) + gpio1->outputset = (0x01 << signal); + else + gpio1->outputclr = (0x01 << signal); /* Output a Zero */ +} + +void au1xxx_gpio1_tristate(int signal) +{ + gpio1->trioutclr = (0x01 << signal); /* Tristate signal */ +} + + +int au1xxx_gpio_read(int signal) +{ + if(signal >= 200) +#if defined(CONFIG_SOC_AU1000) + return 0; +#else + return au1xxx_gpio2_read(signal); +#endif + else + return au1xxx_gpio1_read(signal); +} + +void au1xxx_gpio_write(int signal, int value) +{ + if(signal >= 200) +#if defined(CONFIG_SOC_AU1000) + ; +#else + au1xxx_gpio2_write(signal, value); +#endif + else + au1xxx_gpio1_write(signal, value); +} + +void au1xxx_gpio_tristate(int signal) +{ + if(signal >= 200) +#if defined(CONFIG_SOC_AU1000) + ; +#else + au1xxx_gpio2_tristate(signal); +#endif + else + au1xxx_gpio1_tristate(signal); +} + +void au1xxx_gpio1_set_inputs(void) +{ + gpio1->pininputen = 0; +} + +EXPORT_SYMBOL(au1xxx_gpio1_set_inputs); +EXPORT_SYMBOL(au1xxx_gpio_tristate); +EXPORT_SYMBOL(au1xxx_gpio_write); +EXPORT_SYMBOL(au1xxx_gpio_read); diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c index d1eb5a4a9a1..1339a0979f6 100644 --- a/arch/mips/au1000/common/irq.c +++ b/arch/mips/au1000/common/irq.c @@ -83,7 +83,7 @@ inline void local_disable_irq(unsigned int irq_nr); void (*board_init_irq)(void); #ifdef CONFIG_PM -extern void counter0_irq(int irq, void *dev_id, struct pt_regs *regs); +extern irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs); #endif static DEFINE_SPINLOCK(irq_lock); @@ -253,52 +253,72 @@ void restore_local_and_enable(int controller, unsigned long mask) static struct hw_interrupt_type rise_edge_irq_type = { - "Au1000 Rise Edge", - startup_irq, - shutdown_irq, - local_enable_irq, - local_disable_irq, - mask_and_ack_rise_edge_irq, - end_irq, - NULL + .typename = "Au1000 Rise Edge", + .startup = startup_irq, + .shutdown = shutdown_irq, + .enable = local_enable_irq, + .disable = local_disable_irq, + .ack = mask_and_ack_rise_edge_irq, + .end = end_irq, }; static struct hw_interrupt_type fall_edge_irq_type = { - "Au1000 Fall Edge", - startup_irq, - shutdown_irq, - local_enable_irq, - local_disable_irq, - mask_and_ack_fall_edge_irq, - end_irq, - NULL + .typename = "Au1000 Fall Edge", + .startup = startup_irq, + .shutdown = shutdown_irq, + .enable = local_enable_irq, + .disable = local_disable_irq, + .ack = mask_and_ack_fall_edge_irq, + .end = end_irq, }; static struct hw_interrupt_type either_edge_irq_type = { - "Au1000 Rise or Fall Edge", - startup_irq, - shutdown_irq, - local_enable_irq, - local_disable_irq, - mask_and_ack_either_edge_irq, - end_irq, - NULL + .typename = "Au1000 Rise or Fall Edge", + .startup = startup_irq, + .shutdown = shutdown_irq, + .enable = local_enable_irq, + .disable = local_disable_irq, + .ack = mask_and_ack_either_edge_irq, + .end = end_irq, }; static struct hw_interrupt_type level_irq_type = { - "Au1000 Level", - startup_irq, - shutdown_irq, - local_enable_irq, - local_disable_irq, - mask_and_ack_level_irq, - end_irq, - NULL + .typename = "Au1000 Level", + .startup = startup_irq, + .shutdown = shutdown_irq, + .enable = local_enable_irq, + .disable = local_disable_irq, + .ack = mask_and_ack_level_irq, + .end = end_irq, }; #ifdef CONFIG_PM -void startup_match20_interrupt(void) +void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *)) { + struct irq_desc *desc = &irq_desc[AU1000_TOY_MATCH2_INT]; + + static struct irqaction action; + memset(&action, 0, sizeof(struct irqaction)); + + /* This is a big problem.... since we didn't use request_irq + * when kernel/irq.c calls probe_irq_xxx this interrupt will + * be probed for usage. This will end up disabling the device :( + * Give it a bogus "action" pointer -- this will keep it from + * getting auto-probed! + * + * By setting the status to match that of request_irq() we + * can avoid it. --cgray + */ + action.dev_id = handler; + action.flags = SA_INTERRUPT; + cpus_clear(action.mask); + action.name = "Au1xxx TOY"; + action.handler = handler; + action.next = NULL; + + desc->action = &action; + desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS); + local_enable_irq(AU1000_TOY_MATCH2_INT); } #endif @@ -426,7 +446,6 @@ void __init arch_init_irq(void) extern int au1xxx_ic0_nr_irqs; cp0_status = read_c0_status(); - memset(irq_desc, 0, sizeof(irq_desc)); set_except_vector(0, au1000_IRQ); /* Initialize interrupt controllers to a safe state. @@ -492,7 +511,7 @@ void intc0_req0_irqdispatch(struct pt_regs *regs) intc0_req0 |= au_readl(IC0_REQ0INT); if (!intc0_req0) return; - +#ifdef AU1000_USB_DEV_REQ_INT /* * Because of the tight timing of SETUP token to reply * transactions, the USB devices-side packet complete @@ -503,7 +522,7 @@ void intc0_req0_irqdispatch(struct pt_regs *regs) do_IRQ(AU1000_USB_DEV_REQ_INT, regs); return; } - +#endif irq = au_ffs(intc0_req0) - 1; intc0_req0 &= ~(1<<irq); do_IRQ(irq, regs); @@ -521,17 +540,7 @@ void intc0_req1_irqdispatch(struct pt_regs *regs) irq = au_ffs(intc0_req1) - 1; intc0_req1 &= ~(1<<irq); -#ifdef CONFIG_PM - if (irq == 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); - } + do_IRQ(irq, regs); } diff --git a/arch/mips/au1000/common/platform.c b/arch/mips/au1000/common/platform.c index 0776b2db564..1f7b465c803 100644 --- a/arch/mips/au1000/common/platform.c +++ b/arch/mips/au1000/common/platform.c @@ -7,13 +7,15 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ +#include <linux/config.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/resource.h> -#include <asm/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1xxx.h> +/* OHCI (USB full speed host controller) */ static struct resource au1xxx_usb_ohci_resources[] = { [0] = { .start = USB_OHCI_BASE, @@ -41,8 +43,252 @@ static struct platform_device au1xxx_usb_ohci_device = { .resource = au1xxx_usb_ohci_resources, }; +/*** AU1100 LCD controller ***/ + +#ifdef CONFIG_FB_AU1100 +static struct resource au1100_lcd_resources[] = { + [0] = { + .start = LCD_PHYS_ADDR, + .end = LCD_PHYS_ADDR + 0x800 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1100_LCD_INT, + .end = AU1100_LCD_INT, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 au1100_lcd_dmamask = ~(u32)0; + +static struct platform_device au1100_lcd_device = { + .name = "au1100-lcd", + .id = 0, + .dev = { + .dma_mask = &au1100_lcd_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(au1100_lcd_resources), + .resource = au1100_lcd_resources, +}; +#endif + +#ifdef CONFIG_SOC_AU1200 +/* EHCI (USB high speed host controller) */ +static struct resource au1xxx_usb_ehci_resources[] = { + [0] = { + .start = USB_EHCI_BASE, + .end = USB_EHCI_BASE + USB_EHCI_LEN - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1000_USB_HOST_INT, + .end = AU1000_USB_HOST_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 ehci_dmamask = ~(u32)0; + +static struct platform_device au1xxx_usb_ehci_device = { + .name = "au1xxx-ehci", + .id = 0, + .dev = { + .dma_mask = &ehci_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(au1xxx_usb_ehci_resources), + .resource = au1xxx_usb_ehci_resources, +}; + +/* Au1200 UDC (USB gadget controller) */ +static struct resource au1xxx_usb_gdt_resources[] = { + [0] = { + .start = USB_UDC_BASE, + .end = USB_UDC_BASE + USB_UDC_LEN - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1200_USB_INT, + .end = AU1200_USB_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource au1xxx_mmc_resources[] = { + [0] = { + .start = SD0_PHYS_ADDR, + .end = SD0_PHYS_ADDR + 0x40, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = SD1_PHYS_ADDR, + .end = SD1_PHYS_ADDR + 0x40, + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = AU1200_SD_INT, + .end = AU1200_SD_INT, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 udc_dmamask = ~(u32)0; + +static struct platform_device au1xxx_usb_gdt_device = { + .name = "au1xxx-udc", + .id = 0, + .dev = { + .dma_mask = &udc_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(au1xxx_usb_gdt_resources), + .resource = au1xxx_usb_gdt_resources, +}; + +/* Au1200 UOC (USB OTG controller) */ +static struct resource au1xxx_usb_otg_resources[] = { + [0] = { + .start = USB_UOC_BASE, + .end = USB_UOC_BASE + USB_UOC_LEN - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1200_USB_INT, + .end = AU1200_USB_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 uoc_dmamask = ~(u32)0; + +static struct platform_device au1xxx_usb_otg_device = { + .name = "au1xxx-uoc", + .id = 0, + .dev = { + .dma_mask = &uoc_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(au1xxx_usb_otg_resources), + .resource = au1xxx_usb_otg_resources, +}; + +static struct resource au1200_lcd_resources[] = { + [0] = { + .start = LCD_PHYS_ADDR, + .end = LCD_PHYS_ADDR + 0x800 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1200_LCD_INT, + .end = AU1200_LCD_INT, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource au1200_ide0_resources[] = { + [0] = { + .start = AU1XXX_ATA_PHYS_ADDR, + .end = AU1XXX_ATA_PHYS_ADDR + AU1XXX_ATA_PHYS_LEN, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1XXX_ATA_INT, + .end = AU1XXX_ATA_INT, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 au1200_lcd_dmamask = ~(u32)0; + +static struct platform_device au1200_lcd_device = { + .name = "au1200-lcd", + .id = 0, + .dev = { + .dma_mask = &au1200_lcd_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(au1200_lcd_resources), + .resource = au1200_lcd_resources, +}; + + +static u64 ide0_dmamask = ~(u32)0; + +static struct platform_device au1200_ide0_device = { + .name = "au1200-ide", + .id = 0, + .dev = { + .dma_mask = &ide0_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(au1200_ide0_resources), + .resource = au1200_ide0_resources, +}; + +static u64 au1xxx_mmc_dmamask = ~(u32)0; + +static struct platform_device au1xxx_mmc_device = { + .name = "au1xxx-mmc", + .id = 0, + .dev = { + .dma_mask = &au1xxx_mmc_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(au1xxx_mmc_resources), + .resource = au1xxx_mmc_resources, +}; +#endif /* #ifdef CONFIG_SOC_AU1200 */ + +static struct platform_device au1x00_pcmcia_device = { + .name = "au1x00-pcmcia", + .id = 0, +}; + +#ifdef CONFIG_MIPS_DB1200 + +static struct resource smc91x_resources[] = { + [0] = { + .name = "smc91x-regs", + .start = AU1XXX_SMC91111_PHYS_ADDR, + .end = AU1XXX_SMC91111_PHYS_ADDR + 0xfffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = AU1XXX_SMC91111_IRQ, + .end = AU1XXX_SMC91111_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smc91x_device = { + .name = "smc91x", + .id = -1, + .num_resources = ARRAY_SIZE(smc91x_resources), + .resource = smc91x_resources, +}; + +#endif + static struct platform_device *au1xxx_platform_devices[] __initdata = { &au1xxx_usb_ohci_device, + &au1x00_pcmcia_device, +#ifdef CONFIG_FB_AU1100 + &au1100_lcd_device, +#endif +#ifdef CONFIG_SOC_AU1200 +#if 0 /* fixme */ + &au1xxx_usb_ehci_device, +#endif + &au1xxx_usb_gdt_device, + &au1xxx_usb_otg_device, + &au1200_lcd_device, + &au1200_ide0_device, + &au1xxx_mmc_device, +#endif +#ifdef CONFIG_MIPS_DB1200 + &smc91x_device, +#endif }; int au1xxx_platform_init(void) diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c index c40daccbb5b..f85093b8d54 100644 --- a/arch/mips/au1000/common/power.c +++ b/arch/mips/au1000/common/power.c @@ -34,11 +34,13 @@ #include <linux/pm.h> #include <linux/slab.h> #include <linux/sysctl.h> +#include <linux/jiffies.h> #include <asm/string.h> #include <asm/uaccess.h> #include <asm/io.h> #include <asm/system.h> +#include <asm/cacheflush.h> #include <asm/mach-au1x00/au1000.h> #ifdef CONFIG_PM @@ -50,7 +52,7 @@ # define DPRINTK(fmt, args...) #endif -static void calibrate_delay(void); +static void au1000_calibrate_delay(void); extern void set_au1x00_speed(unsigned int new_freq); extern unsigned int get_au1x00_speed(void); @@ -260,7 +262,7 @@ int au_sleep(void) } static int pm_do_sleep(ctl_table * ctl, int write, struct file *file, - void *buffer, size_t * len) + void __user *buffer, size_t * len, loff_t *ppos) { int retval = 0; #ifdef SLEEP_TEST_TIMEOUT @@ -294,10 +296,9 @@ static int pm_do_sleep(ctl_table * ctl, int write, struct file *file, } static int pm_do_suspend(ctl_table * ctl, int write, struct file *file, - void *buffer, size_t * len) + void __user *buffer, size_t * len, loff_t *ppos) { int retval = 0; - void au1k_wait(void); if (!write) { *len = 0; @@ -306,7 +307,7 @@ static int pm_do_suspend(ctl_table * ctl, int write, struct file *file, if (retval) return retval; suspend_mode = 1; - au1k_wait(); + retval = pm_send_all(PM_RESUME, (void *) 0); } return retval; @@ -314,7 +315,7 @@ static int pm_do_suspend(ctl_table * ctl, int write, struct file *file, static int pm_do_freq(ctl_table * ctl, int write, struct file *file, - void *buffer, size_t * len) + void __user *buffer, size_t * len, loff_t *ppos) { int retval = 0, i; unsigned long val, pll; @@ -409,14 +410,14 @@ static int pm_do_freq(ctl_table * ctl, int write, struct file *file, /* We don't want _any_ interrupts other than - * match20. Otherwise our calibrate_delay() + * match20. Otherwise our au1000_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(); + au1000_calibrate_delay(); restore_local_and_enable(0, intc0_mask); restore_local_and_enable(1, intc1_mask); return retval; @@ -456,7 +457,7 @@ __initcall(pm_init); better than 1% */ #define LPS_PREC 8 -static void calibrate_delay(void) +static void au1000_calibrate_delay(void) { unsigned long ticks, loopbit; int lps_precision = LPS_PREC; diff --git a/arch/mips/au1000/common/prom.c b/arch/mips/au1000/common/prom.c index 22e5a85af4d..9c171afd9a5 100644 --- a/arch/mips/au1000/common/prom.c +++ b/arch/mips/au1000/common/prom.c @@ -75,7 +75,8 @@ void prom_init_cmdline(void) } if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ --cp; - *cp = '\0'; + if (prom_argc > 1) + *cp = '\0'; } diff --git a/arch/mips/au1000/common/puts.c b/arch/mips/au1000/common/puts.c index c2ae4624b77..2705829cd46 100644 --- a/arch/mips/au1000/common/puts.c +++ b/arch/mips/au1000/common/puts.c @@ -39,7 +39,6 @@ #define TIMEOUT 0xffffff #define SLOW_DOWN -static const char digits[16] = "0123456789abcdef"; static volatile unsigned long * const com1 = (unsigned long *)SERIAL_BASE; @@ -54,7 +53,7 @@ static inline void slow_down(void) #endif void -putch(const unsigned char c) +prom_putchar(const unsigned char c) { unsigned char ch; int i = 0; @@ -69,77 +68,3 @@ putch(const unsigned char c) } while (0 == (ch & TX_BUSY)); com1[SER_DATA] = c; } - -void -puts(unsigned char *cp) -{ - unsigned char ch; - int i = 0; - - while (*cp) { - do { - ch = com1[SER_CMD]; - slow_down(); - i++; - if (i>TIMEOUT) { - break; - } - } while (0 == (ch & TX_BUSY)); - com1[SER_DATA] = *cp++; - } - putch('\r'); - putch('\n'); -} - -void -fputs(const char *cp) -{ - unsigned char ch; - int i = 0; - - while (*cp) { - - do { - ch = com1[SER_CMD]; - slow_down(); - i++; - if (i>TIMEOUT) { - break; - } - } while (0 == (ch & TX_BUSY)); - com1[SER_DATA] = *cp++; - } -} - - -void -put64(uint64_t ul) -{ - int cnt; - unsigned ch; - - cnt = 16; /* 16 nibbles in a 64 bit long */ - putch('0'); - putch('x'); - do { - cnt--; - ch = (unsigned char)(ul >> cnt * 4) & 0x0F; - putch(digits[ch]); - } while (cnt > 0); -} - -void -put32(unsigned u) -{ - int cnt; - unsigned ch; - - cnt = 8; /* 8 nibbles in a 32 bit long */ - putch('0'); - putch('x'); - do { - cnt--; - ch = (unsigned char)(u >> cnt * 4) & 0x0F; - putch(digits[ch]); - } while (cnt > 0); -} diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c index eff89e109ce..1ef15d5ef94 100644 --- a/arch/mips/au1000/common/setup.c +++ b/arch/mips/au1000/common/setup.c @@ -32,6 +32,7 @@ #include <linux/mm.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <asm/cpu.h> #include <asm/bootinfo.h> @@ -57,7 +58,7 @@ extern void au1xxx_time_init(void); extern void au1xxx_timer_setup(struct irqaction *irq); extern void set_cpuspec(void); -static int __init au1x00_setup(void) +void __init plat_setup(void) { struct cpu_spec *sp; char *argptr; @@ -106,8 +107,6 @@ static int __init au1x00_setup(void) /*strcat(argptr, " video=au1100fb:panel:Sharp_320x240_16");*/ #ifdef CONFIG_MIPS_HYDROGEN3 strcat(argptr, " video=au1100fb:panel:Hydrogen_3_NEC_panel_320x240,nohwcursor"); -#else - strcat(argptr, " video=au1100fb:panel:s10,nohwcursor"); #endif } #endif @@ -153,15 +152,11 @@ static int __init au1x00_setup(void) au_sync(); while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T0S); au_writel(0, SYS_TOYTRIM); - - return 0; } -early_initcall(au1x00_setup); - #if defined(CONFIG_64BIT_PHYS_ADDR) /* This routine should be valid for all Au1x based boards */ -phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size) +phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size) { u32 start, end; @@ -192,4 +187,5 @@ phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size) /* default nop */ return phys_addr; } +EXPORT_SYMBOL(__fixup_bigphys_addr); #endif diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c index 57675b41480..883d3f3d8c5 100644 --- a/arch/mips/au1000/common/time.c +++ b/arch/mips/au1000/common/time.c @@ -50,7 +50,6 @@ #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; @@ -58,14 +57,17 @@ unsigned long missed_heart_beats = 0; 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 */ int no_au1xxx_32khz; -void (*au1k_wait_ptr)(void); +extern int allow_au1k_wait; /* default off for CP0 Counter */ /* Cycle counter value at the previous timer interrupt.. */ static unsigned int timerhi = 0, timerlo = 0; #ifdef CONFIG_PM -#define MATCH20_INC 328 -extern void startup_match20_interrupt(void); +#if HZ < 100 || HZ > 1000 +#error "unsupported HZ value! Must be in [100,1000]" +#endif +#define MATCH20_INC (328*100/HZ) /* magic number 328 is for HZ=100... */ +extern void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *)); static unsigned long last_pc0, last_match20; #endif @@ -117,17 +119,16 @@ null: } #ifdef CONFIG_PM -void counter0_irq(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs) { unsigned long pc0; int time_elapsed; static int jiffie_drift = 0; - kstat.irqs[0][irq]++; if (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) { /* should never happen! */ - printk(KERN_WARNING "counter 0 w status eror\n"); - return; + printk(KERN_WARNING "counter 0 w status error\n"); + return IRQ_NONE; } pc0 = au_readl(SYS_TOYREAD); @@ -164,6 +165,8 @@ void counter0_irq(int irq, void *dev_id, struct pt_regs *regs) update_process_times(user_mode(regs)); #endif } + + return IRQ_HANDLED; } /* When we wakeup from sleep, we have to "catch up" on all of the @@ -388,7 +391,6 @@ void au1xxx_timer_setup(struct irqaction *irq) { unsigned int est_freq; extern unsigned long (*do_gettimeoffset)(void); - extern void au1k_wait(void); printk("calculating r4koff... "); r4k_offset = cal_r4koff(); @@ -441,18 +443,18 @@ void au1xxx_timer_setup(struct irqaction *irq) au_sync(); while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20); - /* setup match20 to interrupt once every 10ms */ + /* setup match20 to interrupt once every HZ */ 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(); + startup_match20_interrupt(counter0_irq); do_gettimeoffset = do_fast_pm_gettimeoffset; /* We can use the real 'wait' instruction. */ - au1k_wait_ptr = au1k_wait; + allow_au1k_wait = 1; } #else diff --git a/arch/mips/au1000/common/usbdev.c b/arch/mips/au1000/common/usbdev.c index 447a9a4612a..0b21bed7ee5 100644 --- a/arch/mips/au1000/common/usbdev.c +++ b/arch/mips/au1000/common/usbdev.c @@ -1005,11 +1005,11 @@ process_ep0_receive (struct usb_dev* dev) #endif dev->ep0_stage = SETUP_STAGE; break; - } + } spin_unlock(&ep0->lock); - // we're done processing the packet, free it - kfree(pkt); + // we're done processing the packet, free it + kfree(pkt); } @@ -1072,8 +1072,7 @@ dma_done_ep0_intr(int irq, void *dev_id, struct pt_regs *regs) clear_dma_done1(ep0->indma); pkt = send_packet_complete(ep0); - if (pkt) - kfree(pkt); + kfree(pkt); } /* @@ -1302,8 +1301,7 @@ usbdev_exit(void) endpoint_flush(ep); } - if (usbdev.full_conf_desc) - kfree(usbdev.full_conf_desc); + kfree(usbdev.full_conf_desc); } int diff --git a/arch/mips/au1000/csb250/init.c b/arch/mips/au1000/csb250/init.c index bd99733abc0..a4898b1bc66 100644 --- a/arch/mips/au1000/csb250/init.c +++ b/arch/mips/au1000/csb250/init.c @@ -35,7 +35,6 @@ #include <asm/bootinfo.h> #include <linux/string.h> #include <linux/kernel.h> -#include <linux/sched.h> int prom_argc; char **prom_argv, **prom_envp; diff --git a/arch/mips/au1000/db1x00/irqmap.c b/arch/mips/au1000/db1x00/irqmap.c index 8f6ef0dbe1f..f63024a9893 100644 --- a/arch/mips/au1000/db1x00/irqmap.c +++ b/arch/mips/au1000/db1x00/irqmap.c @@ -48,6 +48,38 @@ #include <asm/system.h> #include <asm/mach-au1x00/au1000.h> +#ifdef CONFIG_MIPS_DB1500 +char irq_tab_alchemy[][5] __initdata = { + [12] = { -1, INTA, INTX, INTX, INTX}, /* IDSEL 12 - HPT371 */ + [13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot */ +}; +#endif + +#ifdef CONFIG_MIPS_BOSPORUS +char irq_tab_alchemy[][5] __initdata = { + [11] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 11 - miniPCI */ + [12] = { -1, INTA, INTX, INTX, INTX}, /* IDSEL 12 - SN1741 */ + [13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot */ +}; +#endif + +#ifdef CONFIG_MIPS_MIRAGE +char irq_tab_alchemy[][5] __initdata = { + [11] = { -1, INTD, INTX, INTX, INTX}, /* IDSEL 11 - SMI VGX */ + [12] = { -1, INTX, INTX, INTC, INTX}, /* IDSEL 12 - PNX1300 */ + [13] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 13 - miniPCI */ +}; +#endif + +#ifdef CONFIG_MIPS_DB1550 +char irq_tab_alchemy[][5] __initdata = { + [11] = { -1, INTC, INTX, INTX, INTX}, /* IDSEL 11 - on-board HPT371 */ + [12] = { -1, INTB, INTC, INTD, INTA}, /* IDSEL 12 - PCI slot 2 (left) */ + [13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot 1 (right) */ +}; +#endif + + au1xxx_irq_map_t au1xxx_irq_map[] = { #ifndef CONFIG_MIPS_MIRAGE diff --git a/arch/mips/au1000/db1x00/mirage_ts.c b/arch/mips/au1000/db1x00/mirage_ts.c index ade35e43200..c29852c24b4 100644 --- a/arch/mips/au1000/db1x00/mirage_ts.c +++ b/arch/mips/au1000/db1x00/mirage_ts.c @@ -102,15 +102,15 @@ static struct { } mirage_ts_cal = { #if 0 - xscale: 84, - xtrans: -157, - yscale: 66, - ytrans: -150, + .xscale = 84, + .xtrans = -157, + .yscale = 66, + .ytrans = -150, #else - xscale: 84, - xtrans: -150, - yscale: 66, - ytrans: -146, + .xscale = 84, + .xtrans = -150, + .yscale = 66, + .ytrans = -146, #endif }; diff --git a/arch/mips/au1000/hydrogen3/init.c b/arch/mips/au1000/hydrogen3/init.c index 8cc9879dd58..01ab2848395 100644 --- a/arch/mips/au1000/hydrogen3/init.c +++ b/arch/mips/au1000/hydrogen3/init.c @@ -37,7 +37,6 @@ #include <linux/config.h> #include <linux/string.h> #include <linux/kernel.h> -#include <linux/sched.h> int prom_argc; char **prom_argv, **prom_envp; diff --git a/arch/mips/au1000/mtx-1/init.c b/arch/mips/au1000/mtx-1/init.c index 02e7dbcff72..88f2b6d9728 100644 --- a/arch/mips/au1000/mtx-1/init.c +++ b/arch/mips/au1000/mtx-1/init.c @@ -33,7 +33,6 @@ #include <linux/sched.h> #include <linux/init.h> #include <linux/mm.h> -#include <linux/sched.h> #include <linux/bootmem.h> #include <asm/addrspace.h> #include <asm/bootinfo.h> diff --git a/arch/mips/au1000/mtx-1/irqmap.c b/arch/mips/au1000/mtx-1/irqmap.c index ddcb9d089dc..f9a0a8b9def 100644 --- a/arch/mips/au1000/mtx-1/irqmap.c +++ b/arch/mips/au1000/mtx-1/irqmap.c @@ -47,6 +47,17 @@ #include <asm/system.h> #include <asm/mach-au1x00/au1000.h> +char irq_tab_alchemy[][5] __initdata = { + [0] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 00 - AdapterA-Slot0 (top) */ + [1] = { -1, INTB, INTA, INTX, INTX}, /* IDSEL 01 - AdapterA-Slot1 (bottom) */ + [2] = { -1, INTC, INTD, INTX, INTX}, /* IDSEL 02 - AdapterB-Slot0 (top) */ + [3] = { -1, INTD, INTC, INTX, INTX}, /* IDSEL 03 - AdapterB-Slot1 (bottom) */ + [4] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 04 - AdapterC-Slot0 (top) */ + [5] = { -1, INTB, INTA, INTX, INTX}, /* IDSEL 05 - AdapterC-Slot1 (bottom) */ + [6] = { -1, INTC, INTD, INTX, INTX}, /* IDSEL 06 - AdapterD-Slot0 (top) */ + [7] = { -1, INTD, INTC, INTX, INTX}, /* IDSEL 07 - AdapterD-Slot1 (bottom) */ +}; + au1xxx_irq_map_t au1xxx_irq_map[] = { { AU1500_GPIO_204, INTC_INT_HIGH_LEVEL, 0}, { AU1500_GPIO_201, INTC_INT_LOW_LEVEL, 0 }, diff --git a/arch/mips/au1000/pb1000/init.c b/arch/mips/au1000/pb1000/init.c index 34713c5df0d..e9fa1bab81f 100644 --- a/arch/mips/au1000/pb1000/init.c +++ b/arch/mips/au1000/pb1000/init.c @@ -65,5 +65,4 @@ void __init prom_init(void) memsize = simple_strtol(memsize_str, NULL, 0); } add_memory_region(0, memsize, BOOT_MEM_RAM); - return 0; } diff --git a/arch/mips/au1000/pb1200/Makefile b/arch/mips/au1000/pb1200/Makefile new file mode 100644 index 00000000000..22b673cf55a --- /dev/null +++ b/arch/mips/au1000/pb1200/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Alchemy Semiconductor PB1200 board. +# + +lib-y := init.o board_setup.o irqmap.o diff --git a/arch/mips/au1000/pb1200/board_setup.c b/arch/mips/au1000/pb1200/board_setup.c new file mode 100644 index 00000000000..a45b17538ac --- /dev/null +++ b/arch/mips/au1000/pb1200/board_setup.c @@ -0,0 +1,193 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * Alchemy Pb1200/Db1200 board setup. + * + * 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> + +#if defined(CONFIG_BLK_DEV_IDE_AU1XXX) +#include <linux/ide.h> +#endif + +#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/mach-au1x00/au1000.h> +#include <asm/mach-au1x00/au1xxx_dbdma.h> + +#ifdef CONFIG_MIPS_PB1200 +#include <asm/mach-pb1x00/pb1200.h> +#endif + +#ifdef CONFIG_MIPS_DB1200 +#include <asm/mach-db1x00/db1200.h> +#define PB1200_ETH_INT DB1200_ETH_INT +#define PB1200_IDE_INT DB1200_IDE_INT +#endif + +extern void _board_init_irq(void); +extern void (*board_init_irq)(void); + +void board_reset (void) +{ + bcsr->resets = 0; + bcsr->system = 0; +} + +void __init board_setup(void) +{ + char *argptr = NULL; + u32 pin_func; + +#if 0 + /* Enable PSC1 SYNC for AC97. Normaly done in audio driver, + * but it is board specific code, so put it here. + */ + pin_func = au_readl(SYS_PINFUNC); + au_sync(); + pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1; + au_writel(pin_func, SYS_PINFUNC); + + au_writel(0, (u32)bcsr|0x10); /* turn off pcmcia power */ + au_sync(); +#endif + +#if defined(CONFIG_I2C_AU1550) + { + u32 freq0, clksrc; + + /* Select SMBUS in CPLD */ + bcsr->resets &= ~(BCSR_RESETS_PCS0MUX); + + pin_func = au_readl(SYS_PINFUNC); + au_sync(); + pin_func &= ~(3<<17 | 1<<4); + /* Set GPIOs correctly */ + pin_func |= 2<<17; + au_writel(pin_func, SYS_PINFUNC); + au_sync(); + + /* The i2c driver depends on 50Mhz clock */ + freq0 = au_readl(SYS_FREQCTRL0); + au_sync(); + freq0 &= ~(SYS_FC_FRDIV1_MASK | SYS_FC_FS1 | SYS_FC_FE1); + freq0 |= (3<<SYS_FC_FRDIV1_BIT); + /* 396Mhz / (3+1)*2 == 49.5Mhz */ + au_writel(freq0, SYS_FREQCTRL0); + au_sync(); + freq0 |= SYS_FC_FE1; + au_writel(freq0, SYS_FREQCTRL0); + au_sync(); + + clksrc = au_readl(SYS_CLKSRC); + au_sync(); + clksrc &= ~0x01f00000; + /* bit 22 is EXTCLK0 for PSC0 */ + clksrc |= (0x3 << 22); + au_writel(clksrc, SYS_CLKSRC); + au_sync(); + } +#endif + +#ifdef CONFIG_FB_AU1200 + argptr = prom_getcmdline(); +#ifdef CONFIG_MIPS_PB1200 + strcat(argptr, " video=au1200fb:panel:bs"); +#endif +#ifdef CONFIG_MIPS_DB1200 + strcat(argptr, " video=au1200fb:panel:bs"); +#endif +#endif + + /* The Pb1200 development board uses external MUX for PSC0 to + support SMB/SPI. bcsr->resets bit 12: 0=SMB 1=SPI + */ +#if defined(CONFIG_AU1XXX_PSC_SPI) && defined(CONFIG_I2C_AU1550) + #error I2C and SPI are mutually exclusive. Both are physically connected to PSC0.\ + Refer to Pb1200/Db1200 documentation. +#elif defined( CONFIG_AU1XXX_PSC_SPI ) + bcsr->resets |= BCSR_RESETS_PCS0MUX; + /*Hard Coding Value to enable Temp Sensors [bit 14] Value for SOC Au1200. Pls refer documentation*/ + bcsr->resets =0x900f; +#elif defined( CONFIG_I2C_AU1550 ) + bcsr->resets &= (~BCSR_RESETS_PCS0MUX); +#endif + au_sync(); + +#ifdef CONFIG_MIPS_PB1200 + printk("AMD Alchemy Pb1200 Board\n"); +#endif +#ifdef CONFIG_MIPS_DB1200 + printk("AMD Alchemy Db1200 Board\n"); +#endif + + /* Setup Pb1200 External Interrupt Controller */ + { + extern void (*board_init_irq)(void); + extern void _board_init_irq(void); + board_init_irq = _board_init_irq; + } +} + +int +board_au1200fb_panel (void) +{ + BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR; + int p; + + p = bcsr->switches; + p >>= 8; + p &= 0x0F; + return p; +} + +int +board_au1200fb_panel_init (void) +{ + /* Apply power */ + BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR; + bcsr->board |= (BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL); + /*printk("board_au1200fb_panel_init()\n"); */ + return 0; +} + +int +board_au1200fb_panel_shutdown (void) +{ + /* Remove power */ + BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR; + bcsr->board &= ~(BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL); + /*printk("board_au1200fb_panel_shutdown()\n"); */ + return 0; +} + diff --git a/arch/mips/au1000/pb1200/init.c b/arch/mips/au1000/pb1200/init.c new file mode 100644 index 00000000000..27f09e374e1 --- /dev/null +++ b/arch/mips/au1000/pb1200/init.c @@ -0,0 +1,69 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * PB1200 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> + +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 Pb1200"; +} + +void __init prom_init(void) +{ + unsigned char *memsize_str; + unsigned long memsize; + + prom_argc = (int) fw_arg0; + prom_argv = (char **) fw_arg1; + prom_envp = (char **) fw_arg2; + + mips_machgroup = MACH_GROUP_ALCHEMY; + mips_machtype = MACH_PB1200; + + prom_init_cmdline(); + memsize_str = prom_getenv("memsize"); + if (!memsize_str) { + memsize = 0x08000000; + } else { + memsize = simple_strtol(memsize_str, NULL, 0); + } + add_memory_region(0, memsize, BOOT_MEM_RAM); +} diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c new file mode 100644 index 00000000000..59e70e5cf32 --- /dev/null +++ b/arch/mips/au1000/pb1200/irqmap.c @@ -0,0 +1,182 @@ +/* + * BRIEF MODULE DESCRIPTION + * Au1xxx irq map table + * + * 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/errno.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/kernel_stat.h> +#include <linux/module.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/timex.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/delay.h> + +#include <asm/bitops.h> +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/mipsregs.h> +#include <asm/system.h> +#include <asm/mach-au1x00/au1000.h> + +#ifdef CONFIG_MIPS_PB1200 +#include <asm/mach-pb1x00/pb1200.h> +#endif + +#ifdef CONFIG_MIPS_DB1200 +#include <asm/mach-db1x00/db1200.h> +#define PB1200_INT_BEGIN DB1200_INT_BEGIN +#define PB1200_INT_END DB1200_INT_END +#endif + +au1xxx_irq_map_t au1xxx_irq_map[] = { + { AU1000_GPIO_7, INTC_INT_LOW_LEVEL, 0 }, // This is exteranl interrupt cascade +}; + +int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t); + +/* + * Support for External interrupts on the PbAu1200 Development platform. + */ +static volatile int pb1200_cascade_en=0; + +irqreturn_t pb1200_cascade_handler( int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned short bisr = bcsr->int_status; + int extirq_nr = 0; + + /* Clear all the edge interrupts. This has no effect on level */ + bcsr->int_status = bisr; + for( ; bisr; bisr &= (bisr-1) ) + { + extirq_nr = (PB1200_INT_BEGIN-1) + au_ffs(bisr); + /* Ack and dispatch IRQ */ + do_IRQ(extirq_nr,regs); + } + return IRQ_RETVAL(1); +} + +inline void pb1200_enable_irq(unsigned int irq_nr) +{ + bcsr->intset_mask = 1<<(irq_nr - PB1200_INT_BEGIN); + bcsr->intset = 1<<(irq_nr - PB1200_INT_BEGIN); +} + +inline void pb1200_disable_irq(unsigned int irq_nr) +{ + bcsr->intclr_mask = 1<<(irq_nr - PB1200_INT_BEGIN); + bcsr->intclr = 1<<(irq_nr - PB1200_INT_BEGIN); +} + +static unsigned int pb1200_startup_irq( unsigned int irq_nr ) +{ + if (++pb1200_cascade_en == 1) + { + request_irq(AU1000_GPIO_7, &pb1200_cascade_handler, + 0, "Pb1200 Cascade", (void *)&pb1200_cascade_handler ); +#ifdef CONFIG_MIPS_PB1200 + /* We have a problem with CPLD rev3. Enable a workaround */ + if( ((bcsr->whoami & BCSR_WHOAMI_CPLD)>>4) <= 3) + { + printk("\nWARNING!!!\n"); + printk("\nWARNING!!!\n"); + printk("\nWARNING!!!\n"); + printk("\nWARNING!!!\n"); + printk("\nWARNING!!!\n"); + printk("\nWARNING!!!\n"); + printk("Pb1200 must be at CPLD rev4. Please have Pb1200\n"); + printk("updated to latest revision. This software will not\n"); + printk("work on anything less than CPLD rev4\n"); + printk("\nWARNING!!!\n"); + printk("\nWARNING!!!\n"); + printk("\nWARNING!!!\n"); + printk("\nWARNING!!!\n"); + printk("\nWARNING!!!\n"); + printk("\nWARNING!!!\n"); + while(1); + } +#endif + } + pb1200_enable_irq(irq_nr); + return 0; +} + +static void pb1200_shutdown_irq( unsigned int irq_nr ) +{ + pb1200_disable_irq(irq_nr); + if (--pb1200_cascade_en == 0) + { + free_irq(AU1000_GPIO_7,&pb1200_cascade_handler ); + } + return; +} + +static inline void pb1200_mask_and_ack_irq(unsigned int irq_nr) +{ + pb1200_disable_irq( irq_nr ); +} + +static void pb1200_end_irq(unsigned int irq_nr) +{ + if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { + pb1200_enable_irq(irq_nr); + } +} + +static struct hw_interrupt_type external_irq_type = +{ +#ifdef CONFIG_MIPS_PB1200 + "Pb1200 Ext", +#endif +#ifdef CONFIG_MIPS_DB1200 + "Db1200 Ext", +#endif + pb1200_startup_irq, + pb1200_shutdown_irq, + pb1200_enable_irq, + pb1200_disable_irq, + pb1200_mask_and_ack_irq, + pb1200_end_irq, + NULL +}; + +void _board_init_irq(void) +{ + int irq_nr; + + for (irq_nr = PB1200_INT_BEGIN; irq_nr <= PB1200_INT_END; irq_nr++) + { + irq_desc[irq_nr].handler = &external_irq_type; + pb1200_disable_irq(irq_nr); + } + + /* GPIO_7 can not be hooked here, so it is hooked upon first + request of any source attached to the cascade */ +} + diff --git a/arch/mips/au1000/pb1500/irqmap.c b/arch/mips/au1000/pb1500/irqmap.c index 476e2500168..8cb76c2edb5 100644 --- a/arch/mips/au1000/pb1500/irqmap.c +++ b/arch/mips/au1000/pb1500/irqmap.c @@ -47,6 +47,11 @@ #include <asm/system.h> #include <asm/mach-au1x00/au1000.h> +char irq_tab_alchemy[][5] __initdata = { + [12] = { -1, INTA, INTX, INTX, INTX}, /* IDSEL 12 - HPT370 */ + [13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot */ +}; + au1xxx_irq_map_t au1xxx_irq_map[] = { { AU1500_GPIO_204, INTC_INT_HIGH_LEVEL, 0}, { AU1500_GPIO_201, INTC_INT_LOW_LEVEL, 0 }, diff --git a/arch/mips/au1000/pb1550/irqmap.c b/arch/mips/au1000/pb1550/irqmap.c index 889d4949ee7..47c7a1c19f4 100644 --- a/arch/mips/au1000/pb1550/irqmap.c +++ b/arch/mips/au1000/pb1550/irqmap.c @@ -47,6 +47,11 @@ #include <asm/system.h> #include <asm/mach-au1x00/au1000.h> +char irq_tab_alchemy[][5] __initdata = { + [12] = { -1, INTB, INTC, INTD, INTA}, /* IDSEL 12 - PCI slot 2 (left) */ + [13] = { -1, INTA, INTB, INTC, INTD}, /* IDSEL 13 - PCI slot 1 (right) */ +}; + au1xxx_irq_map_t au1xxx_irq_map[] = { { AU1000_GPIO_0, INTC_INT_LOW_LEVEL, 0 }, { AU1000_GPIO_1, INTC_INT_LOW_LEVEL, 0 }, |