diff options
Diffstat (limited to 'arch/sh/cchips/voyagergx')
-rw-r--r-- | arch/sh/cchips/voyagergx/Makefile | 8 | ||||
-rw-r--r-- | arch/sh/cchips/voyagergx/consistent.c | 126 | ||||
-rw-r--r-- | arch/sh/cchips/voyagergx/irq.c | 194 | ||||
-rw-r--r-- | arch/sh/cchips/voyagergx/setup.c | 37 |
4 files changed, 365 insertions, 0 deletions
diff --git a/arch/sh/cchips/voyagergx/Makefile b/arch/sh/cchips/voyagergx/Makefile new file mode 100644 index 0000000..085de72 --- /dev/null +++ b/arch/sh/cchips/voyagergx/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for VoyagerGX +# + +obj-y := irq.o setup.o + +obj-$(CONFIG_USB_OHCI_HCD) += consistent.o + diff --git a/arch/sh/cchips/voyagergx/consistent.c b/arch/sh/cchips/voyagergx/consistent.c new file mode 100644 index 0000000..5b92585 --- /dev/null +++ b/arch/sh/cchips/voyagergx/consistent.c @@ -0,0 +1,126 @@ +/* + * arch/sh/cchips/voyagergx/consistent.c + * + * Copyright (C) 2004 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/mm.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/types.h> +#include <linux/module.h> +#include <linux/device.h> +#include <asm/io.h> +#include <asm/bus-sh.h> + +struct voya_alloc_entry { + struct list_head list; + unsigned long ofs; + unsigned long len; +}; + +static DEFINE_SPINLOCK(voya_list_lock); +static LIST_HEAD(voya_alloc_list); + +#define OHCI_SRAM_START 0xb0000000 +#define OHCI_HCCA_SIZE 0x100 +#define OHCI_SRAM_SIZE 0x10000 + +void *voyagergx_consistent_alloc(struct device *dev, size_t size, + dma_addr_t *handle, int flag) +{ + struct list_head *list = &voya_alloc_list; + struct voya_alloc_entry *entry; + struct sh_dev *shdev = to_sh_dev(dev); + unsigned long start, end; + unsigned long flags; + + /* + * The SM501 contains an integrated 8051 with its own SRAM. + * Devices within the cchip can all hook into the 8051 SRAM. + * We presently use this for the OHCI. + * + * Everything else goes through consistent_alloc(). + */ + if (!dev || dev->bus != &sh_bus_types[SH_BUS_VIRT] || + (dev->bus == &sh_bus_types[SH_BUS_VIRT] && + shdev->dev_id != SH_DEV_ID_USB_OHCI)) + return NULL; + + start = OHCI_SRAM_START + OHCI_HCCA_SIZE; + + entry = kmalloc(sizeof(struct voya_alloc_entry), GFP_ATOMIC); + if (!entry) + return ERR_PTR(-ENOMEM); + + entry->len = (size + 15) & ~15; + + /* + * The basis for this allocator is dwmw2's malloc.. the + * Matrox allocator :-) + */ + spin_lock_irqsave(&voya_list_lock, flags); + list_for_each(list, &voya_alloc_list) { + struct voya_alloc_entry *p; + + p = list_entry(list, struct voya_alloc_entry, list); + + if (p->ofs - start >= size) + goto out; + + start = p->ofs + p->len; + } + + end = start + (OHCI_SRAM_SIZE - OHCI_HCCA_SIZE); + list = &voya_alloc_list; + + if (end - start >= size) { +out: + entry->ofs = start; + list_add_tail(&entry->list, list); + spin_unlock_irqrestore(&voya_list_lock, flags); + + *handle = start; + return (void *)start; + } + + kfree(entry); + spin_unlock_irqrestore(&voya_list_lock, flags); + + return ERR_PTR(-EINVAL); +} + +int voyagergx_consistent_free(struct device *dev, size_t size, + void *vaddr, dma_addr_t handle) +{ + struct voya_alloc_entry *entry; + struct sh_dev *shdev = to_sh_dev(dev); + unsigned long flags; + + if (!dev || dev->bus != &sh_bus_types[SH_BUS_VIRT] || + (dev->bus == &sh_bus_types[SH_BUS_VIRT] && + shdev->dev_id != SH_DEV_ID_USB_OHCI)) + return -EINVAL; + + spin_lock_irqsave(&voya_list_lock, flags); + list_for_each_entry(entry, &voya_alloc_list, list) { + if (entry->ofs != handle) + continue; + + list_del(&entry->list); + kfree(entry); + + break; + } + spin_unlock_irqrestore(&voya_list_lock, flags); + + return 0; +} + +EXPORT_SYMBOL(voyagergx_consistent_alloc); +EXPORT_SYMBOL(voyagergx_consistent_free); + diff --git a/arch/sh/cchips/voyagergx/irq.c b/arch/sh/cchips/voyagergx/irq.c new file mode 100644 index 0000000..3079234 --- /dev/null +++ b/arch/sh/cchips/voyagergx/irq.c @@ -0,0 +1,194 @@ +/* -------------------------------------------------------------------- */ +/* setup_voyagergx.c: */ +/* -------------------------------------------------------------------- */ +/* This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Copyright 2003 (c) Lineo uSolutions,Inc. +*/ +/* -------------------------------------------------------------------- */ + +#undef DEBUG + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/irq.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/rts7751r2d/rts7751r2d.h> +#include <asm/rts7751r2d/voyagergx_reg.h> + +static void disable_voyagergx_irq(unsigned int irq) +{ + unsigned long flags, val; + unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); + + pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask); + local_irq_save(flags); + val = inl(VOYAGER_INT_MASK); + val &= ~mask; + outl(val, VOYAGER_INT_MASK); + local_irq_restore(flags); +} + + +static void enable_voyagergx_irq(unsigned int irq) +{ + unsigned long flags, val; + unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE); + + pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask); + local_irq_save(flags); + val = inl(VOYAGER_INT_MASK); + val |= mask; + outl(val, VOYAGER_INT_MASK); + local_irq_restore(flags); +} + + +static void mask_and_ack_voyagergx(unsigned int irq) +{ + disable_voyagergx_irq(irq); +} + +static void end_voyagergx_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_voyagergx_irq(irq); +} + +static unsigned int startup_voyagergx_irq(unsigned int irq) +{ + enable_voyagergx_irq(irq); + return 0; +} + +static void shutdown_voyagergx_irq(unsigned int irq) +{ + disable_voyagergx_irq(irq); +} + +static struct hw_interrupt_type voyagergx_irq_type = { + "VOYAGERGX-IRQ", + startup_voyagergx_irq, + shutdown_voyagergx_irq, + enable_voyagergx_irq, + disable_voyagergx_irq, + mask_and_ack_voyagergx, + end_voyagergx_irq, +}; + +static irqreturn_t voyagergx_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + printk(KERN_INFO + "VoyagerGX: spurious interrupt, status: 0x%x\n", + inl(INT_STATUS)); + return IRQ_HANDLED; +} + + +/*====================================================*/ + +static struct { + int (*func)(int, void *); + void *dev; +} voyagergx_demux[VOYAGER_IRQ_NUM]; + +void voyagergx_register_irq_demux(int irq, + int (*demux)(int irq, void *dev), void *dev) +{ + voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = demux; + voyagergx_demux[irq - VOYAGER_IRQ_BASE].dev = dev; +} + +void voyagergx_unregister_irq_demux(int irq) +{ + voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0; +} + +int voyagergx_irq_demux(int irq) +{ + + if (irq == IRQ_VOYAGER ) { + unsigned long i = 0, bit __attribute__ ((unused)); + unsigned long val = inl(INT_STATUS); +#if 1 + if ( val & ( 1 << 1 )){ + i = 1; + } else if ( val & ( 1 << 2 )){ + i = 2; + } else if ( val & ( 1 << 6 )){ + i = 6; + } else if( val & ( 1 << 10 )){ + i = 10; + } else if( val & ( 1 << 11 )){ + i = 11; + } else if( val & ( 1 << 12 )){ + i = 12; + } else if( val & ( 1 << 17 )){ + i = 17; + } else { + printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val); + } + pr_debug("voyagergx_irq_demux %d \n", i); +#else + for (bit = 1, i = 0 ; i < VOYAGER_IRQ_NUM ; bit <<= 1, i++) + if (val & bit) + break; +#endif + if (i < VOYAGER_IRQ_NUM) { + irq = VOYAGER_IRQ_BASE + i; + if (voyagergx_demux[i].func != 0) + irq = voyagergx_demux[i].func(irq, voyagergx_demux[i].dev); + } + } + return irq; +} + +static struct irqaction irq0 = { voyagergx_interrupt, SA_INTERRUPT, 0, "VOYAGERGX", NULL, NULL}; + +void __init setup_voyagergx_irq(void) +{ + int i, flag; + + printk(KERN_INFO "VoyagerGX configured at 0x%x on irq %d(mapped into %d to %d)\n", + VOYAGER_BASE, + IRQ_VOYAGER, + VOYAGER_IRQ_BASE, + VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1); + + for (i=0; i<VOYAGER_IRQ_NUM; i++) { + flag = 0; + switch (VOYAGER_IRQ_BASE + i) { + case VOYAGER_USBH_IRQ: + case VOYAGER_8051_IRQ: + case VOYAGER_UART0_IRQ: + case VOYAGER_UART1_IRQ: + case VOYAGER_AC97_IRQ: + flag = 1; + } + if (flag == 1) + irq_desc[VOYAGER_IRQ_BASE + i].handler = &voyagergx_irq_type; + } + + setup_irq(IRQ_VOYAGER, &irq0); +} + diff --git a/arch/sh/cchips/voyagergx/setup.c b/arch/sh/cchips/voyagergx/setup.c new file mode 100644 index 0000000..139ca88 --- /dev/null +++ b/arch/sh/cchips/voyagergx/setup.c @@ -0,0 +1,37 @@ +/* + * arch/sh/cchips/voyagergx/setup.c + * + * Setup routines for VoyagerGX cchip. + * + * Copyright (C) 2003 Lineo uSolutions, 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. + */ +#include <linux/init.h> +#include <linux/module.h> +#include <asm/io.h> +#include <asm/rts7751r2d/voyagergx_reg.h> + +static int __init setup_voyagergx(void) +{ + unsigned long val; + + val = inl(DRAM_CTRL); + val |= (DRAM_CTRL_CPU_COLUMN_SIZE_256 | + DRAM_CTRL_CPU_ACTIVE_PRECHARGE | + DRAM_CTRL_CPU_RESET | + DRAM_CTRL_REFRESH_COMMAND | + DRAM_CTRL_BLOCK_WRITE_TIME | + DRAM_CTRL_BLOCK_WRITE_PRECHARGE | + DRAM_CTRL_ACTIVE_PRECHARGE | + DRAM_CTRL_RESET | + DRAM_CTRL_REMAIN_ACTIVE); + outl(val, DRAM_CTRL); + + return 0; +} + +module_init(setup_voyagergx); |