diff options
Diffstat (limited to 'target/linux/adm5120-2.6/files/arch')
8 files changed, 849 insertions, 0 deletions
| diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile b/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile new file mode 100644 index 000000000..63024e36d --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the ADMtek ADM5120 SoC specific parts of the kernel +# + +obj-y  := setup.o prom.o irq.o memory.o mipsIRQ.o + +EXTRA_AFLAGS := $(CFLAGS) diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c new file mode 100644 index 000000000..46f3bb05e --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/irq.c @@ -0,0 +1,156 @@ +/* + *	Copyright (C) ADMtek Incorporated. + *		Creator : daniell@admtek.com.tw + *	Carsten Langgaard, carstenl@mips.com + *	Copyright (C) 2000, 2001 MIPS Technologies, Inc. + *	Copyright (C) 2001 Ralf Baechle + *	Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) + */ + +#include <linux/autoconf.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/pm.h> + +#include <asm/irq.h> +#include <asm/time.h> +#include <asm/mipsregs.h> +#include <asm/gdb-stub.h> +#include <asm/irq_cpu.h> + +#define MIPS_CPU_TIMER_IRQ 7 + +extern int setup_irq(unsigned int irq, struct irqaction *irqaction); +extern irq_desc_t irq_desc[]; +extern asmlinkage void mipsIRQ(void); + +int mips_int_lock(void); +void mips_int_unlock(int); + +unsigned int mips_counter_frequency; + +#define ADM5120_INTC_REG(reg)	(*(volatile u32 *)(KSEG1ADDR(0x12200000+(reg)))) +#define ADM5120_INTC_STATUS	ADM5120_INTC_REG(0x00) +#define ADM5120_INTC_ENABLE	ADM5120_INTC_REG(0x08) +#define ADM5120_INTC_DISABLE	ADM5120_INTC_REG(0x0c) +#define ADM5120_IRQ_MAX		9 +#define ADM5120_IRQ_MASK	0x3ff + +void adm5120_hw0_irqdispatch(struct pt_regs *regs) +{ +	unsigned long intsrc; +	int i; + +	intsrc = ADM5120_INTC_STATUS & ADM5120_IRQ_MASK; + +	for (i = 0; intsrc; intsrc >>= 1, i++) +		if (intsrc & 0x1) +			do_IRQ(i); +		else +			spurious_interrupt(); +} + +void mips_timer_interrupt(struct pt_regs *regs) +{ +        write_c0_compare(read_c0_count()+ mips_counter_frequency/HZ); +        ll_timer_interrupt(MIPS_CPU_TIMER_IRQ); +} + +/* Main interrupt dispatcher */ +asmlinkage void plat_irq_dispatch(struct pt_regs *regs) +{ +        unsigned int cp0_cause = read_c0_cause() & read_c0_status(); + +        if (cp0_cause & CAUSEF_IP7) { +                mips_timer_interrupt( regs); +        } else if (cp0_cause & CAUSEF_IP2) { +                adm5120_hw0_irqdispatch( regs); +        } +} + +void enable_adm5120_irq(unsigned int irq) +{ +	int s; + +	/* Disable all interrupts (FIQ/IRQ) */ +	s = mips_int_lock(); + +	if ((irq < 0) || (irq > ADM5120_IRQ_MAX))  +		goto err_exit; + +	ADM5120_INTC_ENABLE = (1<<irq); + +err_exit: + +	/* Restore the interrupts states */ +	mips_int_unlock(s); +} + + +void disable_adm5120_irq(unsigned int irq) +{ +	int s; + +	/* Disable all interrupts (FIQ/IRQ) */ +	s = mips_int_lock(); + +	if ((irq < 0) || (irq > ADM5120_IRQ_MAX))  +		goto err_exit; + +	ADM5120_INTC_DISABLE = (1<<irq); + +err_exit: +	/* Restore the interrupts states */ +	mips_int_unlock(s); +} + +unsigned int startup_adm5120_irq(unsigned int irq) +{ +	enable_adm5120_irq(irq); +	return 0; +} + +void shutdown_adm5120_irq(unsigned int irq) +{ +	disable_adm5120_irq(irq); +} + +static inline void ack_adm5120_irq(unsigned int irq_nr) +{ +	ADM5120_INTC_DISABLE = (1 << irq_nr); +} + + +static void end_adm5120_irq(unsigned int irq_nr) +{ +	ADM5120_INTC_ENABLE = (1 << irq_nr); +} + +static hw_irq_controller adm5120_irq_type = { +	.typename 	= "MIPS", +	.startup	= startup_adm5120_irq, +	.shutdown	= shutdown_adm5120_irq, +	.enable		= enable_adm5120_irq, +	.disable	= disable_adm5120_irq, +	.ack 		= ack_adm5120_irq, +	.end		= end_adm5120_irq, +	.set_affinity	= NULL, +}; + + +void __init arch_init_irq(void) +{ +	int i; +	 +	for (i = 0; i <= ADM5120_IRQ_MAX; i++) { +		irq_desc[i].status = IRQ_DISABLED; +		irq_desc[i].action = 0; +		irq_desc[i].depth = 1; +		irq_desc[i].chip = &adm5120_irq_type; +	} +} diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/memory.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/memory.c new file mode 100644 index 000000000..a8ffb0c8f --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/memory.c @@ -0,0 +1,154 @@ +/***************************************************************************** + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved. + * Copyright (C) 2003 ADMtek Incorporated. + *	daniell@admtek.com.tw + * Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) + * + * ######################################################################## + * + *  This program is free software; you can distribute it and/or modify it + *  under the terms of the GNU General Public License (Version 2) as + *  published by the Free Software Foundation. + * + *  This program is distributed in the hope it will be useful, but WITHOUT + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License + *  for more details. + * + *  You should have received a copy of the GNU General Public License along + *  with this program; if not, write to the Free Software Foundation, Inc., + *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + *****************************************************************************/ + +#include <linux/autoconf.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/bootmem.h> +#include <linux/pfn.h> +#include <linux/string.h> + +#include <asm/bootinfo.h> +#include <asm/page.h> +#include <asm/sections.h> + +#include <asm-mips/mips-boards/prom.h> + +extern char *prom_getenv(char *envname); + +#define PFN_ALIGN(x)    (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) + +#define ADM5120_MEMCTRL			0x1200001c +#define ADM5120_MEMCTRL_SDRAM_MASK	0x7 + +static const unsigned long adm_sdramsize[] __initdata = { +	0x0,		/* Reserved */ +	0x0400000,	/* 4Mb */ +	0x0800000,	/* 8Mb */ +	0x1000000,	/* 16Mb */ +	0x4000000,	/* 64Mb */ +	0x8000000,	/* 128Mb */ +}; + +/* determined physical memory size, not overridden by command line args  */ +unsigned long physical_memsize = 0L; + +struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; + +struct prom_pmemblock * __init prom_getmdesc(void) +{ +	char *memsize_str; +	unsigned int memsize; +	char cmdline[CL_SIZE], *ptr; + +	memsize_str = prom_getenv("memsize"); + +	if (!memsize_str) +	{ +		prom_printf("memsize not set in boot prom, set to default (8Mb)\n"); +		physical_memsize = 0x00800000; +	} +	else +#ifdef DEBUG +		prom_printf("prom_memsize = %s\n", memsize_str); +#endif +		physical_memsize = simple_strtol(memsize_str, NULL, 0); + +	/* Check the command line for a memsize directive that overrides +	 * the physical/default amount */ +	strcpy(cmdline, arcs_cmdline); +	ptr = strstr(cmdline, "memsize="); +	if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' ')) +	ptr = strstr(ptr, " memsize="); +	 +	if (ptr) +		memsize = memparse(ptr + 8, &ptr); +	else +		memsize = physical_memsize; + +       memset(mdesc, 0, sizeof(mdesc)); + +       mdesc[0].type = BOOT_MEM_RAM; +       mdesc[0].base = CPHYSADDR(PFN_ALIGN(&_end)); +       mdesc[0].size = memsize - mdesc[0].base; + +       return &mdesc[0]; +} + +void __init prom_meminit(void) +{ +	struct prom_pmemblock *p; + +	p = prom_getmdesc(); + +	while (p->size) +	{ +		long type; +		unsigned long base, size; +		base = p->base; +		type = p->type, +		size = p->size; +		add_memory_region(base, size, type); +		p++; +	} +} + +#if 0 +void __init prom_meminit(void) +{ +	unsigned long base = CPHYSADDR(PFN_ALIGN(&_end)); +	unsigned long size; + +	u32 memctrl = *(u32*)KSEG1ADDR(ADM5120_MEMCTRL); +	size = adm_sdramsize[memctrl & ADM5120_MEMCTRL_SDRAM_MASK]; +	add_memory_region(base, size-base, BOOT_MEM_RAM); +} +#endif + +unsigned long __init prom_free_prom_memory(void) +{ +        unsigned long freed = 0; +        unsigned long addr; +        int i; + +        for (i = 0; i < boot_mem_map.nr_map; i++) { +                if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) +                        continue; + +                addr = PAGE_ALIGN(boot_mem_map.map[i].addr); +                while (addr < boot_mem_map.map[i].addr +                              + boot_mem_map.map[i].size) { +                        ClearPageReserved(virt_to_page(__va(addr))); +                        init_page_count(virt_to_page(__va(addr))); +                        free_page((unsigned long)__va(addr)); +                        addr += PAGE_SIZE; +                        freed += PAGE_SIZE; +                } +        } +        printk("Freeing prom memory: %ldkb freed\n", freed >> 10); + +        return freed; +} diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/mipsIRQ.S b/target/linux/adm5120-2.6/files/arch/mips/adm5120/mipsIRQ.S new file mode 100644 index 000000000..f118fb402 --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/mipsIRQ.S @@ -0,0 +1,135 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999, 2000 MIPS Technologies, Inc.  All rights reserved. + * + * ######################################################################## + * + *  This program is free software; you can distribute it and/or modify it + *  under the terms of the GNU General Public License (Version 2) as + *  published by the Free Software Foundation. + * + *  This program is distributed in the hope it will be useful, but WITHOUT + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License + *  for more details. + * + *  You should have received a copy of the GNU General Public License along + *  with this program; if not, write to the Free Software Foundation, Inc., + *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Interrupt exception dispatch code. + * + */ +#include <linux/autoconf.h> + +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + +#define STATUS_IE	0x00000001 + +/* A lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop and moving across + *    all the pending IRQ bits in the cause register is _NOT_ the answer, the + *    common case is one pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register IRQ mask, that + *    would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in + *    between like BSD spl() brain-damage. + * + * Furthermore, the IRQs on the MIPS board look basically (barring software + * IRQs which we don't use at all and all external interrupt sources are + * combined together on hardware interrupt 0 (MIPS IRQ 2)) like: + * + *	MIPS IRQ	Source + *      --------        ------ + *             0	Software (ignored) + *             1        Software (ignored) + *             2        Combined hardware interrupt (hw0) + *             3        Hardware (ignored) + *             4        Hardware (ignored) + *             5        Hardware (ignored) + *             6        Hardware (ignored) + *             7        R4k timer (what we use) + * + * Note: On the SEAD board thing are a little bit different. + *       Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired + *       wired to UART1. + *	 + * We handle the IRQ according to _our_ priority which is: + * + * Highest ----     R4k Timer + * Lowest  ----     Combined hardware interrupt + * + * then we just return, if multiple IRQs are pending then we will just take + * another exception, big deal. + */ + +	.text +	.set	noreorder +	.set	noat +	.align	5 + +NESTED(mipsIRQ, PT_SIZE, sp) +	SAVE_ALL +	CLI +	.set	at + +	mfc0	s0, CP0_CAUSE		 +	mfc0	s1, CP0_STATUS +	and     s0, s0, s1 +	 +	/* First we check for r4k counter/timer IRQ. */ +	andi	a0, s0, CAUSEF_IP7 +	beq		a0, zero, 1f +	nop + +	move	a0, sp +	jal		mips_timer_interrupt +	nop + +	j		ret_from_irq +	nop				 + +1: +	andi	a0, s0, CAUSEF_IP2 +	beq		a0, zero, 1f	 +	nop +	 +	move	a0, sp			 +	jal		adm5120_hw0_irqdispatch	  +	nop +1: +	j		ret_from_irq +	nop							 + +END(mipsIRQ) + + +LEAF(mips_int_lock) +	.set noreorder +	mfc0	v0, CP0_STATUS +	li		v1, ~STATUS_IE +	and		v1, v1, v0 +	mtc0	v1, CP0_STATUS +	j		ra +	and		v0, v0, STATUS_IE +	.set reorder +END(mips_int_lock) + + +LEAF(mips_int_unlock) +	mfc0	v0, CP0_STATUS +	and		a0, a0, STATUS_IE +	or		v0, v0, a0 +	mtc0	v0, CP0_STATUS +	j		ra +	nop +END(mips_int_unlock) + diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/prom.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/prom.c new file mode 100644 index 000000000..ba8051ea8 --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/prom.c @@ -0,0 +1,113 @@ +/***************************************************************************** + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved. + * Copyright (C) 2003 ADMtek Incorporated. + *	daniell@admtek.com.tw + * + *  This program is free software; you can distribute it and/or modify it + *  under the terms of the GNU General Public License (Version 2) as + *  published by the Free Software Foundation. + * + *  This program is distributed in the hope it will be useful, but WITHOUT + *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License + *  for more details. + * + *  You should have received a copy of the GNU General Public License along + *  with this program; if not, write to the Free Software Foundation, Inc., + *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + *****************************************************************************/ + +#include <linux/init.h> +#include <linux/autoconf.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/bootmem.h> + +#include <asm/bootinfo.h> +#include <asm/addrspace.h> + +void setup_prom_printf(int); +void prom_printf(char *, ...); +void prom_meminit(void); + +#define ADM5120_ENVC           1 + +char *adm5120_envp[2*ADM5120_ENVC] = {"memsize","0x001000000"}; + +#define READCSR(r)      *(volatile unsigned long *)(0xB2600000+(r)) +#define WRITECSR(r,v)   *(volatile unsigned long *)(0xB2600000+(r)) = v + +#define UART_DR_REG         0x00 +#define UART_FR_REG         0x18 +#define UART_TX_FIFO_FULL   0x20 + +int putPromChar(char c) +{ +	WRITECSR(UART_DR_REG, c); +        while ( (READCSR(UART_FR_REG) & UART_TX_FIFO_FULL) ); +        return 0; +} + +/* + * Ugly prom_printf used for debugging + */ + +void prom_printf(char *fmt, ...) +{ +        va_list args; +        int l; +        char *p, *buf_end; +        char buf[1024]; + +        va_start(args, fmt); +        l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */ +        va_end(args); + +        buf_end = buf + l; + +        for (p = buf; p < buf_end; p++) { +                /* Crude cr/nl handling is better than none */ +                if (*p == '\n') +                        putPromChar('\r'); +                putPromChar(*p); +        } +} + +char *prom_getenv(char *envname) +{ +	int i, index=0; + +	i = strlen(envname); + +	printk(KERN_INFO "GETENV: envname is %s\n", envname); + +	while(index < (2*ADM5120_ENVC)) { +		if(strncmp(envname, adm5120_envp[index], i) == 0) { +			printk(KERN_INFO "GETENV: returning %s\n", adm5120_envp[index+1]); +			return(adm5120_envp[index+1]); +		} +		index += 2; +	} + +	printk(KERN_INFO "GETENV: not found.\n"); +	return(NULL); +} +	 +/* + * initialize the prom module. + */ +void __init prom_init(void) +{ +	/* you should these macros defined in include/asm/bootinfo.h */ +	mips_machgroup = MACH_GROUP_ADM_GW; +	mips_machtype = MACH_ADM_GW_5120; + +	/* init command line, register a default kernel command line */ +	strcpy(&(arcs_cmdline[0]), "console=ttyS0,115200 rootfstype=jffs2 init=/etc/preinit"); + +	/* init memory map */ +	prom_meminit(); +} diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c new file mode 100644 index 000000000..23e668411 --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/setup.c @@ -0,0 +1,132 @@ +/* + *	Copyright (C) ADMtek Incorporated. + *		Creator : daniell@admtek.com.tw + *	Copyright 1999, 2000 MIPS Technologies, Inc. + *	Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005 + */ + +#include <linux/autoconf.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> + +#include <asm/reboot.h> +#include <asm/io.h> +#include <asm/time.h> + +#define ADM5120_SOFTRESET	0x12000004 +#define STATUS_IE		0x00000001 +#define ALLINTS (IE_IRQ0 | IE_IRQ5 | STATUS_IE) + +#define ADM5120_CODEREG		0x12000000 +#define ADM5120_CPU_CLK_MASK	0x00300000 +#define ADM5120_CPU_CLK_175	0x00000000 +#define ADM5120_CPU_CLK_200	0x00100000 +#define ADM5120_CPU_CLK_225	0x00200000 +#define ADM5120_CPU_CLK_250	0x00300000 + +void  mips_time_init(void); + +extern unsigned int mips_counter_frequency; + +void adm5120_restart(char *command) +{ +	*(u32*)KSEG1ADDR(ADM5120_SOFTRESET)=1; +} + + +void adm5120_halt(void) +{ +        printk(KERN_NOTICE "\n** You can safely turn off the power\n"); +        while (1); +} + + +void adm5120_power_off(void) +{ +        adm5120_halt(); +} + +void __init mips_time_init(void) +{ +	u32 clock; + +	clock = *(u32*)KSEG1ADDR(ADM5120_CODEREG); + +	switch (clock & ADM5120_CPU_CLK_MASK) { +		case ADM5120_CPU_CLK_175: +			mips_counter_frequency = 87500000; +			printk("CPU clock: 175MHz\n"); +			break; +		case ADM5120_CPU_CLK_200: +			mips_counter_frequency = 100000000; +			printk("CPU clock: 200MHz\n"); +			break; +		case ADM5120_CPU_CLK_225: +			mips_counter_frequency = 112500000; +			printk("CPU clock: 225MHz\n"); +			break; +		case ADM5120_CPU_CLK_250: +			mips_counter_frequency = 125000000; +			printk("CPU clock: 250MHz\n"); +			break; +	} +} + +void __init plat_timer_setup(struct irqaction *irq) +{ +	/* to generate the first timer interrupt */ +	write_c0_compare(read_c0_count()+ mips_counter_frequency/HZ); +	clear_c0_status(ST0_BEV); +	set_c0_status(ALLINTS); +} + +void __init plat_mem_setup(void) +{ +	printk(KERN_INFO "ADM5120 board setup\n"); + +	board_time_init = mips_time_init; +	//board_timer_setup = mips_timer_setup; + +	_machine_restart = adm5120_restart; +	_machine_halt = adm5120_halt; +	pm_power_off = adm5120_power_off; + +	set_io_port_base(KSEG1); +} + +const char *get_system_type(void) +{ +	return "ADM5120 Board"; +} + +static struct resource adm5120_hcd_resources[] = { +	[0] = { +		.start	= 0x11200000, +		.end	= 0x11200084, +		.flags	= IORESOURCE_MEM, +	}, +	[1] = { +		.start	= 0x3, +		.end	= 0x3, +		.flags	= IORESOURCE_IRQ, +	}, +}; + +static struct platform_device adm5120hcd_device = { +	.name		= "adm5120-hcd", +	.id		= -1, +	.num_resources	= ARRAY_SIZE(adm5120_hcd_resources), +	.resource	= adm5120_hcd_resources, +}; + +static struct platform_device *devices[] __initdata = { +	&adm5120hcd_device, +}; + +static int __init adm5120_init(void) +{ +	return platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +subsys_initcall(adm5120_init); diff --git a/target/linux/adm5120-2.6/files/arch/mips/pci/ops-adm5120.c b/target/linux/adm5120-2.6/files/arch/mips/pci/ops-adm5120.c new file mode 100644 index 000000000..80b8531ea --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/pci/ops-adm5120.c @@ -0,0 +1,59 @@ +/* + *	Copyright (C) ADMtek Incorporated. + *	Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) + */ + +#include <linux/autoconf.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +volatile u32* pci_config_address_reg = (volatile u32*)KSEG1ADDR(0x115ffff0); +volatile u32* pci_config_data_reg = (volatile u32*)KSEG1ADDR(0x115ffff8); + +#define PCI_ENABLE 0x80000000 +                           +static int pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, +                           int size, uint32_t *val) +{ +	*pci_config_address_reg = ((bus->number & 0xff) << 0x10) | +	    ((devfn & 0xff) << 0x08) | (where & 0xfc) | PCI_ENABLE; +	switch (size) { +		case 1: +			*val = ((*pci_config_data_reg)>>((where&3)<<3))&0xff; +			break; +		case 2: +			*val = ((*pci_config_data_reg)>>((where&3)<<3))&0xffff; +			break; +		default: +			*val = (*pci_config_data_reg); +	} +	return PCIBIOS_SUCCESSFUL; +} + +static int pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, +                            int size, uint32_t val) +{ +	*pci_config_address_reg = ((bus->number & 0xff) << 0x10) | +	    ((devfn & 0xff) << 0x08) | (where & 0xfc) | PCI_ENABLE; +	switch (size) { +		case 1: +			*(volatile u8 *)(((int)pci_config_data_reg) + +			    (where & 3)) = val; +			break; +		case 2: +			*(volatile u16 *)(((int)pci_config_data_reg) + +			    (where & 2)) = (val); +			break; +		default: +			*pci_config_data_reg = (val); +	} + +	return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops adm5120_pci_ops = { +	.read	= pci_config_read, +	.write	= pci_config_write, +}; diff --git a/target/linux/adm5120-2.6/files/arch/mips/pci/pci-adm5120.c b/target/linux/adm5120-2.6/files/arch/mips/pci/pci-adm5120.c new file mode 100644 index 000000000..a8585747e --- /dev/null +++ b/target/linux/adm5120-2.6/files/arch/mips/pci/pci-adm5120.c @@ -0,0 +1,93 @@ +/* + *	Copyright (C) ADMtek Incorporated. + *	Copyright (C) 2005 Jeroen Vreeken (pe1rxq@amsat.org) + */ + +#include <linux/autoconf.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +extern struct pci_ops adm5120_pci_ops; + +#define ADM5120_CODE		0x12000000 +#define ADM5120_CODE_PQFP	0x20000000 + +#define PCI_CMM_IOACC_EN	0x1 +#define PCI_CMM_MEMACC_EN	0x2 +#define PCI_CMM_MASTER_EN	0x4 +#define PCI_CMM_DEF \ +		(PCI_CMM_IOACC_EN | PCI_CMM_MEMACC_EN | PCI_CMM_MASTER_EN) + +#define PCI_DEF_CACHE_LINE_SZ	4 + + +struct resource pci_io_resource = { +	"PCI IO space",  +	0x11500000,   +	0x115ffff0-1, +	IORESOURCE_IO +}; + +struct resource pci_mem_resource = { +	"PCI memory space",  +	0x11400000, +	0x11500000, +	IORESOURCE_MEM +}; + +static struct pci_controller adm5120_controller = { +	.pci_ops	= &adm5120_pci_ops, +	.io_resource	= &pci_io_resource, +	.mem_resource	= &pci_mem_resource, +}; + +int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ +	if (slot < 2 || slot > 4) +		return -1; +	return slot + 4; +} + +static void adm5120_pci_fixup(struct pci_dev *dev) +{ +	if (dev->devfn == 0) { +		pci_write_config_word(dev, PCI_COMMAND, PCI_CMM_DEF); +		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, +		    PCI_DEF_CACHE_LINE_SZ); +		pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0); +		pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0); +	} +} + +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, adm5120_pci_fixup); + + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ +	return 0; +} + +static int __init adm5120_pci_setup(void) +{ + +	if ((*(volatile u32 *)(KSEG1ADDR(ADM5120_CODE))) & ADM5120_CODE_PQFP) { +		printk("System has no PCI BIOS\n"); +		return 1; +	} +	printk("System has PCI BIOS\n"); + +	/* Avoid ISA compat ranges.  */ +	PCIBIOS_MIN_IO = 0x00000000; +	PCIBIOS_MIN_MEM = 0x00000000; + +	/* Set I/O resource limits.  */ +	ioport_resource.end = 0x1fffffff; +	iomem_resource.end = 0xffffffff;	 + +	register_pci_controller(&adm5120_controller); +	return 0; +} + +subsys_initcall(adm5120_pci_setup); | 
