Commit fb946cdc authored by Dave Jiang's avatar Dave Jiang Committed by Russell King

[ARM PATCH] 2048/1: Patch 2036/1 (2033/4) resubmission

Patch from Dave Jiang

arch/arm/mach-iop3xx update
Removed busy while loop and replaced with mdelay() from patch 2036/1
parent 124bd47d
if ARCH_IOP3XX
menu "IOP3xx Implementation Options"
choice
prompt "IOP3xx System Type"
default ARCH_IQ80321
comment "IOP3xx Platform Types"
config ARCH_IQ80321
bool "IQ80321"
bool "Enable support for IQ80321"
select ARCH_IOP321
help
Say Y here if you want to run your kernel on the Intel IQ80321
evaluation kit for the IOP321 chipset.
endchoice
config ARCH_IQ31244
bool "Enable support for IQ31244"
select ARCH_IOP321
help
Say Y here if you want to run your kernel on the Intel IQ31244
evaluation kit for the IOP321 chipset.
config ARCH_IQ80331
bool "Enable support for IQ80331"
select ARCH_IOP331
help
Say Y here if you want to run your kernel on the Intel IQ80331
evaluation kit for the IOP331 chipset.
config ARCH_EP80219
bool "Enable support for EP80219"
select ARCH_IOP321
select ARCH_IQ31244
# Which IOP variant are we running?
config ARCH_IOP321
bool
default ARCH_IQ80321
help
The IQ80321 uses the IOP321 variant.
The IQ31244 and EP80219 uses the IOP321 variant.
comment "IOP3xx Chipset Features"
config IOP3XX_AAU
bool "Support Intel IOP3xx Application Accelerator Unit (EXPERIMENTAL)"
depends on EXPERIMENTAL
config ARCH_IOP331
bool
default ARCH_IQ80331
help
The IQ80331 uses the IOP331 variant.
config IOP3XX_DMA
bool "Support Intel IOP3xx DMA (EXPERIMENTAL)"
depends on EXPERIMENTAL
comment "IOP3xx Chipset Features"
endmenu
endif
......@@ -4,15 +4,18 @@
# Object file lists.
obj-y := arch.o
obj-y := common.o
obj-m :=
obj-n :=
obj- :=
obj-$(CONFIG_ARCH_IOP321) += iop321-irq.o iop321-pci.o mm-321.o iop321-time.o
obj-$(CONFIG_ARCH_IOP321) += iop321-setup.o iop321-irq.o iop321-pci.o iop321-mm.o iop321-time.o
obj-$(CONFIG_ARCH_IQ80321) += iq80321-pci.o
obj-$(CONFIG_ARCH_IOP331) += iop331-setup.o iop331-irq.o iop331-pci.o iop331-time.o
obj-$(CONFIG_IOP3XX_AAU) += aau.o
obj-$(CONFIG_IOP3XX_DMA) += dma.o
obj-$(CONFIG_ARCH_IQ80321) += iq80321-mm.o iq80321-pci.o
obj-$(CONFIG_ARCH_IQ31244) += iq31244-mm.o iq31244-pci.o
obj-$(CONFIG_ARCH_IQ80331) += iq80331-mm.o iq80331-pci.o
......@@ -21,30 +21,30 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#ifdef CONFIG_ARCH_IQ80321
extern void iq80321_map_io(void);
extern void iop321_init_irq(void);
extern void iop321_init_time(void);
#ifdef CONFIG_ARCH_IQ80331
extern void iq80331_map_io(void);
extern void iop331_init_irq(void);
extern void iop331_init_time(void);
#endif
#ifdef CONFIG_ARCH_IQ80321
#ifdef CONFIG_ARCH_IQ80331
static void __init
fixup_iop321(struct machine_desc *desc, struct tag *tags,
fixup_iop331(struct machine_desc *desc, struct tag *tags,
char **cmdline, struct meminfo *mi)
{
}
#endif
#if defined(CONFIG_ARCH_IQ80321)
MACHINE_START(IQ80321, "Intel IQ80321")
MAINTAINER("Intel Corporation")
BOOT_MEM(PHYS_OFFSET, IQ80321_UART1, 0xfe800000)
FIXUP(fixup_iop321)
MAPIO(iq80321_map_io)
INITIRQ(iop321_init_irq)
INITTIME(iop321_init_time)
#if defined(CONFIG_ARCH_IQ80331)
MACHINE_START(IQ80331, "Intel IQ80331")
MAINTAINER("Intel Corp.")
BOOT_MEM(PHYS_OFFSET, 0xfff01000, 0xfffff000) // virtual, physical
// BOOT_MEM(PHYS_OFFSET, IQ80331_UART0_VIRT, IQ80331_UART0_PHYS)
MAPIO(iq80331_map_io)
INITIRQ(iop331_init_irq)
INITTIME(iop331_init_time)
BOOT_PARAMS(0x0100)
MACHINE_END
#else
#error No machine descriptor defined for this IOP3xx implementation
#endif
/*
* arch/arm/mach-iop3xx/common.c
*
* Common routines shared across all IOP3xx implementations
*
* Author: Deepak Saxena <dsaxena@mvista.com>
*
* Copyright 2003 (c) MontaVista, Software, Inc.
*
* This file is licensed under the terms of the GNU General Public
* 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/delay.h>
#include <asm/hardware.h>
/*
* Shared variables
*/
unsigned long iop3xx_pcibios_min_io = 0;
unsigned long iop3xx_pcibios_min_mem = 0;
#ifdef CONFIG_ARCH_EP80219
#include <linux/kernel.h>
/*
* Default power-off for EP80219
*/
#include <asm/mach-types.h>
#include <asm/hardware.h>
static inline void ep80219_send_to_pic(__u8 c) {
}
void ep80219_power_off(void)
{
/*
* This function will send a SHUTDOWN_COMPLETE message to the PIC controller
* over I2C. We are not using the i2c subsystem since we are going to power
* off and it may be removed
*/
/* Send the Address byte w/ the start condition */
*IOP321_IDBR1 = 0x60;
*IOP321_ICR1 = 0xE9;
mdelay(1);
/* Send the START_MSG byte w/ no start or stop condition */
*IOP321_IDBR1 = 0x0F;
*IOP321_ICR1 = 0xE8;
mdelay(1);
/* Send the SHUTDOWN_COMPLETE Message ID byte w/ no start or stop condition */
*IOP321_IDBR1 = 0x03;
*IOP321_ICR1 = 0xE8;
mdelay(1);
/* Send an ignored byte w/ stop condition */
*IOP321_IDBR1 = 0x00;
*IOP321_ICR1 = 0xEA;
while (1) ;
}
#include <linux/init.h>
#include <linux/pm.h>
static int __init ep80219_init(void)
{
pm_power_off = ep80219_power_off;
return 0;
}
arch_initcall(ep80219_init);
#endif
......@@ -81,7 +81,8 @@ void __init iop321_init_irq(void)
intctl_write(0); // disable all interrupts
intstr_write(0); // treat all as IRQ
if(machine_is_iq80321()) // all interrupts are inputs to chip
if(machine_is_iq80321() ||
machine_is_iq31244()) // all interrupts are inputs to chip
*IOP321_PCIIRSR = 0x0f;
for(i = IOP321_IRQ_OFS; i < NR_IOP321_IRQS; i++)
......
/*
* linux/arch/arm/mach-iop3xx/mm.c
*
* Low level memory initialization for IOP321 based systems
*
* Author: Rory Bolt <rorybolt@pacbell.net>
* Copyright (C) 2002 Rory Bolt
*
* 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/mm.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/mach/map.h>
#include <asm/mach-types.h>
/*
* Standard IO mapping for all IOP321 based systems
*/
static struct map_desc iop321_std_desc[] __initdata = {
/* virtual physical length type */
/* mem mapped registers */
{ IOP321_VIRT_MEM_BASE, IOP321_PHY_MEM_BASE, 0x00002000, MT_DEVICE },
/* PCI IO space */
{ 0xfe000000, 0x90000000, 0x00020000, MT_DEVICE }
};
void __init iop321_map_io(void)
{
iotable_init(iop321_std_desc, ARRAY_SIZE(iop321_std_desc));
}
......@@ -44,7 +44,7 @@ static u32 iop321_cfg_address(struct pci_bus *bus, int devfn, int where)
u32 addr;
if (sys->busnr == bus->number)
addr = 1 << (PCI_SLOT(devfn) + 16);
addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11);
else
addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
......@@ -158,7 +158,8 @@ iop321_write_config(struct pci_bus *bus, unsigned int devfn, int where,
: "r" (value), "r" (addr),
"r" (IOP321_OCCAR), "r" (IOP321_OCCDR));
}
return PCIBIOS_SUCCESSFUL;
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops iop321_ops = {
......@@ -194,53 +195,16 @@ struct pci_bus *iop321_scan_bus(int nr, struct pci_sys_data *sys)
return pci_scan_bus(sys->busnr, &iop321_ops, sys);
}
/*
* Setup the system data for controller 'nr'. Return 0 if none found,
* 1 if found, or negative error.
*/
int iop321_setup(int nr, struct pci_sys_data *sys)
{
struct resource *res;
if (nr >= 1)
return 0;
res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL);
if (!res)
panic("PCI: unable to alloc resources");
memset(res, 0, sizeof(struct resource) * 2);
switch (nr) {
case 0:
res[0].start = IOP321_PCI_IO_BASE + 0x6e000000;
res[0].end = IOP321_PCI_IO_BASE + IOP321_PCI_IO_SIZE-1 + 0x6e000000;
res[0].name = "PCI IO Primary";
res[0].flags = IORESOURCE_IO;
res[1].start = IOP321_PCI_MEM_BASE;
res[1].end = IOP321_PCI_MEM_BASE + IOP321_PCI_MEM_SIZE;
res[1].name = "PCI Memory Primary";
res[1].flags = IORESOURCE_MEM;
break;
}
request_resource(&ioport_resource, &res[0]);
request_resource(&iomem_resource, &res[1]);
sys->resource[0] = &res[0];
sys->resource[1] = &res[1];
sys->resource[2] = NULL;
sys->io_offset = 0x6e000000;
return 1;
}
void iop321_init(void)
{
#if CONFIG_ARCH_EP80219
*IOP321_ATUCR = 0x2;
*IOP321_OIOWTVR = 0x90000000;
*IOP321_IABAR0 = 0x00000004;
*IOP321_IABAR2 = 0xa000000c;
*IOP321_IALR2 = 0xe0000000;
#endif
DBG("PCI: Intel 80321 PCI init code.\n");
DBG("\tATU: IOP321_ATUCMD=0x%04x\n", *IOP321_ATUCMD);
DBG("\tATU: IOP321_OMWTVR0=0x%04x, IOP321_OIOWTVR=0x%04x\n",
......@@ -252,7 +216,12 @@ void iop321_init(void)
DBG("\tATU: IOP321_IABAR2=0x%08x IOP321_IALR2=0x%08x IOP321_IATVR2=%08x\n", *IOP321_IABAR2, *IOP321_IALR2, *IOP321_IATVR2);
DBG("\tATU: IOP321_IABAR3=0x%08x IOP321_IALR3=0x%08x IOP321_IATVR3=%08x\n", *IOP321_IABAR3, *IOP321_IALR3, *IOP321_IATVR3);
#if 0
hook_fault_code(4, iop321_pci_abort, SIGBUS, "external abort on linefetch");
hook_fault_code(6, iop321_pci_abort, SIGBUS, "external abort on linefetch");
hook_fault_code(8, iop321_pci_abort, SIGBUS, "external abort on non-linefetch");
hook_fault_code(10, iop321_pci_abort, SIGBUS, "external abort on non-linefetch");
#endif
hook_fault_code(16+6, iop321_pci_abort, SIGBUS, "imprecise external abort");
}
/*
* linux/arch/arm/mach-iop3xx/iop321-setup.c
*
* Author: Nicolas Pitre <nico@cam.org>
* Copyright (C) 2001 MontaVista Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <asm/setup.h>
#include <asm/system.h>
#include <asm/memory.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#ifdef CONFIG_ARCH_IQ80321
extern void iq80321_map_io(void);
extern void iop321_init_irq(void);
extern void iop321_init_time(void);
#endif
#ifdef CONFIG_ARCH_IQ31244
extern void iq31244_map_io(void);
extern void iop321_init_irq(void);
extern void iop321_init_time(void);
#endif
static void __init
fixup_iop321(struct machine_desc *desc, struct tag *tags,
char **cmdline, struct meminfo *mi)
{
}
#if defined(CONFIG_ARCH_IQ80321)
MACHINE_START(IQ80321, "Intel IQ80321")
MAINTAINER("Intel Corporation")
BOOT_MEM(PHYS_OFFSET, IQ80321_UART, 0xfe800000)
FIXUP(fixup_iop321)
MAPIO(iq80321_map_io)
INITIRQ(iop321_init_irq)
INITTIME(iop321_init_time)
BOOT_PARAMS(0xa0000100)
MACHINE_END
#elif defined(CONFIG_ARCH_IQ31244)
MACHINE_START(IQ31244, "Intel IQ31244")
MAINTAINER("Intel Corp.")
BOOT_MEM(PHYS_OFFSET, IQ31244_UART, IQ31244_UART)
MAPIO(iq31244_map_io)
INITIRQ(iop321_init_irq)
INITTIME(iop321_init_time)
BOOT_PARAMS(0xa0000100)
MACHINE_END
#else
#error No machine descriptor defined for this IOP3XX implementation
#endif
......@@ -5,7 +5,7 @@
*
* Author: Deepak Saxena <dsaxena@mvista.com>
*
* Copyright 2002 MontaVista Software Inc.
* Copyright 2002-2003 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
......@@ -23,17 +23,25 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/mach-types.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
#define IOP321_TIME_SYNC 0
static unsigned long iop321_latch;
static inline unsigned long get_elapsed(void)
{
return iop321_latch - *IOP321_TU_TCR0;
}
static unsigned long iop321_gettimeoffset(void)
{
unsigned long elapsed, usec;
u32 tisr1, tisr2;
/*
* FIXME: Implement what is described in this comment.
*
* If an interrupt was pending before we read the timer,
* we've already wrapped. Factor this into the time.
* If an interrupt was pending after we read the timer,
......@@ -42,12 +50,19 @@ static unsigned long iop321_gettimeoffset(void)
* be sure its value is after the wrap.
*/
elapsed = *IOP321_TU_TCR0;
asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1));
elapsed = get_elapsed();
asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2));
if(tisr1 & 1)
elapsed += iop321_latch;
else if (tisr2 & 1)
elapsed = iop321_latch + get_elapsed();
/*
* Now convert them to usec.
*/
usec = (unsigned long)((LATCH - elapsed) * (tick_nsec / 1000)) / LATCH;
usec = (unsigned long)(elapsed * (tick_nsec / 1000)) / iop321_latch;
return usec;
}
......@@ -56,6 +71,10 @@ static irqreturn_t
iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
u32 tisr;
#ifdef IOP321_TIME_SYNC
u32 passed;
#define TM_THRESH (iop321_latch*2)
#endif
asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr));
......@@ -63,7 +82,24 @@ iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr));
timer_tick(regs);
#ifdef IOP321_TIME_SYNC
passed = 0xffffffff - *IOP321_TU_TCR1;
do
{
do_timer(regs);
if(passed < TM_THRESH)
break;
if(passed > iop321_latch)
passed -= iop321_latch;
else
passed = 0;
} while(1);
asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (0xffffffff));
#else
do_timer(regs);
#endif
return IRQ_HANDLED;
}
......@@ -79,17 +115,27 @@ extern int setup_arm_irq(int, struct irqaction*);
void __init iop321_init_time(void)
{
u32 timer_ctl;
/* u32 latch = LATCH; */
iop321_latch = (CLOCK_TICK_RATE + HZ / 2) / HZ;
gettimeoffset = iop321_gettimeoffset;
setup_irq(IRQ_IOP321_TIMER0, &iop321_timer_irq);
timer_ctl = IOP321_TMR_EN | IOP321_TMR_PRIVILEGED | IOP321_TMR_RELOAD |
IOP321_TMR_RATIO_1_1;
asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (LATCH));
asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (iop321_latch));
asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl));
#ifdef IOP321_TIME_SYNC
/* Setup second timer */
/* setup counter */
timer_ctl = IOP321_TMR_EN | IOP321_TMR_PRIVILEGED |
IOP321_TMR_RATIO_1_1;
asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (0xffffffff));
/* setup control */
asm volatile("mcr p6, 0, %0, c1, c1, 0" : : "r" (timer_ctl));
#endif
}
/*
* linux/arch/arm/mach-iop3xx/iop331-irq.c
*
* Generic IOP331 IRQ handling functionality
*
* Author: Dave Jiang <dave.jiang@intel.com>
* Copyright (C) 2003 Intel Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <asm/mach/irq.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
static u32 iop331_mask0 = 0;
static u32 iop331_mask1 = 0;
static inline void intctl_write0(u32 val)
{
// INTCTL0
asm volatile("mcr p6,0,%0,c0,c0,0"::"r" (val));
}
static inline void intctl_write1(u32 val)
{
// INTCTL1
asm volatile("mcr p6,0,%0,c1,c0,0"::"r" (val));
}
static inline void intstr_write0(u32 val)
{
// INTSTR0
asm volatile("mcr p6,0,%0,c2,c0,0"::"r" (val));
}
static inline void intstr_write1(u32 val)
{
// INTSTR1
asm volatile("mcr p6,0,%0,c3,c0,0"::"r" (val));
}
static void
iop331_irq_mask1 (unsigned int irq)
{
iop331_mask0 &= ~(1 << (irq - IOP331_IRQ_OFS));
intctl_write0(iop331_mask0);
}
static void
iop331_irq_mask2 (unsigned int irq)
{
iop331_mask1 &= ~(1 << (irq - IOP331_IRQ_OFS - 32));
intctl_write1(iop331_mask1);
}
static void
iop331_irq_unmask1(unsigned int irq)
{
iop331_mask0 |= (1 << (irq - IOP331_IRQ_OFS));
intctl_write0(iop331_mask0);
}
static void
iop331_irq_unmask2(unsigned int irq)
{
iop331_mask1 |= (1 << (irq - IOP331_IRQ_OFS - 32));
intctl_write1(iop331_mask1);
}
struct irqchip iop331_irqchip1 = {
.ack = iop331_irq_mask1,
.mask = iop331_irq_mask1,
.unmask = iop331_irq_unmask1,
};
struct irqchip iop331_irqchip2 = {
.ack = iop331_irq_mask2,
.mask = iop331_irq_mask2,
.unmask = iop331_irq_unmask2,
};
void __init iop331_init_irq(void)
{
unsigned int i, tmp;
/* Enable access to coprocessor 6 for dealing with IRQs.
* From RMK:
* Basically, the Intel documentation here is poor. It appears that
* you need to set the bit to be able to access the coprocessor from
* SVC mode. Whether that allows access from user space or not is
* unclear.
*/
asm volatile (
"mrc p15, 0, %0, c15, c1, 0\n\t"
"orr %0, %0, %1\n\t"
"mcr p15, 0, %0, c15, c1, 0\n\t"
/* The action is delayed, so we have to do this: */
"mrc p15, 0, %0, c15, c1, 0\n\t"
"mov %0, %0\n\t"
"sub pc, pc, #4"
: "=r" (tmp) : "i" (1 << 6) );
intctl_write0(0); // disable all interrupts
intctl_write1(0);
intstr_write0(0); // treat all as IRQ
intstr_write1(0);
if(machine_is_iq80331()) // all interrupts are inputs to chip
*IOP331_PCIIRSR = 0x0f;
for(i = IOP331_IRQ_OFS; i < NR_IOP331_IRQS; i++)
{
set_irq_chip(i, (i < 32) ? &iop331_irqchip1 : &iop331_irqchip2);
set_irq_handler(i, do_level_IRQ);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
}
}
/*
* linux/arch/arm/mach-iop3xx/mm.c
*
* Low level memory initialization for IOP331 based systems
*
* Author: Dave Jiang <dave.jiang@intel.com>
* Copyright (C) 2003 Intel Corp.
*
* 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/mm.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/mach/map.h>
#include <asm/mach-types.h>
/*
* Standard IO mapping for all IOP331 based systems
*/
static struct map_desc iop331_std_desc[] __initdata = {
/* virtual physical length type */
/* mem mapped registers */
{ IOP331_VIRT_MEM_BASE, IOP331_PHYS_MEM_BASE, 0x00002000, MT_DEVICE },
/* PCI IO space */
{ 0xfe000000, 0x90000000, 0x00020000, MT_DEVICE }
};
void __init iop331_map_io(void)
{
iotable_init(iop331_std_desc, ARRAY_SIZE(iop331_std_desc));
}
/*
* arch/arm/mach-iop3xx/iop331-pci.c
*
* PCI support for the Intel IOP331 chipset
*
* Author: Dave Jiang (dave.jiang@intel.com)
* Copyright (C) 2003 Intel Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/hardware.h>
#include <asm/mach/pci.h>
#include <asm/arch/iop331.h>
//#define DEBUG
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...) do { } while (0)
#endif
/*
* This routine builds either a type0 or type1 configuration command. If the
* bus is on the 80331 then a type0 made, else a type1 is created.
*/
static u32 iop331_cfg_address(struct pci_bus *bus, int devfn, int where)
{
struct pci_sys_data *sys = bus->sysdata;
u32 addr;
if (sys->busnr == bus->number)
addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11);
else
addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
addr |= PCI_FUNC(devfn) << 8 | (where & ~3);
return addr;
}
/*
* This routine checks the status of the last configuration cycle. If an error
* was detected it returns a 1, else it returns a 0. The errors being checked
* are parity, master abort, target abort (master and target). These types of
* errors occure during a config cycle where there is no device, like during
* the discovery stage.
*/
static int iop331_pci_status(void)
{
unsigned int status;
int ret = 0;
/*
* Check the status registers.
*/
status = *IOP331_ATUSR;
if (status & 0xf900)
{
DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status);
*IOP331_ATUSR = status & 0xf900;
ret = 1;
}
status = *IOP331_ATUISR;
if (status & 0x679f)
{
DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status);
*IOP331_ATUISR = status & 0x679f;
ret = 1;
}
return ret;
}
/*
* Simply write the address register and read the configuration
* data. Note that the 4 nop's ensure that we are able to handle
* a delayed abort (in theory.)
*/
static inline u32 iop331_read(unsigned long addr)
{
u32 val;
__asm__ __volatile__(
"str %1, [%2]\n\t"
"ldr %0, [%3]\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
: "=r" (val)
: "r" (addr), "r" (IOP331_OCCAR), "r" (IOP331_OCCDR));
return val;
}
/*
* The read routines must check the error status of the last configuration
* cycle. If there was an error, the routine returns all hex f's.
*/
static int
iop331_read_config(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 *value)
{
unsigned long addr = iop331_cfg_address(bus, devfn, where);
u32 val = iop331_read(addr) >> ((where & 3) * 8);
if( iop331_pci_status() )
val = 0xffffffff;
*value = val;
return PCIBIOS_SUCCESSFUL;
}
static int
iop331_write_config(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 value)
{
unsigned long addr = iop331_cfg_address(bus, devfn, where);
u32 val;
if (size != 4) {
val = iop331_read(addr);
if (!iop331_pci_status() == 0)
return PCIBIOS_SUCCESSFUL;
where = (where & 3) * 8;
if (size == 1)
val &= ~(0xff << where);
else
val &= ~(0xffff << where);
*IOP331_OCCDR = val | value << where;
} else {
asm volatile(
"str %1, [%2]\n\t"
"str %0, [%3]\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
"nop\n\t"
:
: "r" (value), "r" (addr),
"r" (IOP331_OCCAR), "r" (IOP331_OCCDR));
}
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops iop331_ops = {
.read = iop331_read_config,
.write = iop331_write_config,
};
/*
* When a PCI device does not exist during config cycles, the XScale gets a
* bus error instead of returning 0xffffffff. This handler simply returns.
*/
int
iop331_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n",
addr, fsr, regs->ARM_pc, regs->ARM_lr);
/*
* If it was an imprecise abort, then we need to correct the
* return address to be _after_ the instruction.
*/
if (fsr & (1 << 10))
regs->ARM_pc += 4;
return 0;
}
/*
* Scan an IOP331 PCI bus. sys->bus defines which bus we scan.
*/
struct pci_bus *iop331_scan_bus(int nr, struct pci_sys_data *sys)
{
return pci_scan_bus(sys->busnr, &iop331_ops, sys);
}
void iop331_init(void)
{
DBG("PCI: Intel 80331 PCI init code.\n");
DBG("\tATU: IOP331_ATUCMD=0x%04x\n", *IOP331_ATUCMD);
DBG("\tATU: IOP331_OMWTVR0=0x%04x, IOP331_OIOWTVR=0x%04x\n",
*IOP331_OMWTVR0,
*IOP331_OIOWTVR);
DBG("\tATU: IOP331_ATUCR=0x%08x\n", *IOP331_ATUCR);
DBG("\tATU: IOP331_IABAR0=0x%08x IOP331_IALR0=0x%08x IOP331_IATVR0=%08x\n", *IOP331_IABAR0, *IOP331_IALR0, *IOP331_IATVR0);
DBG("\tATU: IOP331_ERBAR=0x%08x IOP331_ERLR=0x%08x IOP331_ERTVR=%08x\n", *IOP331_ERBAR, *IOP331_ERLR, *IOP331_ERTVR);
DBG("\tATU: IOP331_IABAR2=0x%08x IOP331_IALR2=0x%08x IOP331_IATVR2=%08x\n", *IOP331_IABAR2, *IOP331_IALR2, *IOP331_IATVR2);
DBG("\tATU: IOP331_IABAR3=0x%08x IOP331_IALR3=0x%08x IOP331_IATVR3=%08x\n", *IOP331_IABAR3, *IOP331_IALR3, *IOP331_IATVR3);
#if 0
hook_fault_code(4, iop331_pci_abort, SIGBUS, "external abort on linefetch");
hook_fault_code(6, iop331_pci_abort, SIGBUS, "external abort on linefetch");
hook_fault_code(8, iop331_pci_abort, SIGBUS, "external abort on non-linefetch");
hook_fault_code(10, iop331_pci_abort, SIGBUS, "external abort on non-linefetch");
#endif
hook_fault_code(16+6, iop331_pci_abort, SIGBUS, "imprecise external abort");
}
/*
* linux/arch/arm/mach-iop3xx/iop331-setup.c
*
* Author: Dave Jiang (dave.jiang@intel.com)
* Copyright (C) 2004 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/mach/map.h>
#include <asm/setup.h>
#include <asm/system.h>
#include <asm/memory.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#define IOP331_UART_XTAL 33334000
/*
* Standard IO mapping for all IOP331 based systems
*/
static struct map_desc iop331_std_desc[] __initdata = {
/* virtual physical length type */
/* mem mapped registers */
{ IOP331_VIRT_MEM_BASE, IOP331_PHYS_MEM_BASE, 0x00002000, MT_DEVICE },
/* PCI IO space */
{ 0xfe000000, 0x90000000, 0x00020000, MT_DEVICE }
};
static struct uart_port iop331_serial_ports[] = {
{
.membase = (char*)(IQ80331_UART0_VIRT),
.mapbase = (IQ80331_UART0_PHYS),
.irq = IRQ_IOP331_UART0,
.flags = UPF_SKIP_TEST,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = IOP331_UART_XTAL,
.line = 0,
.type = PORT_XSCALE,
.fifosize = 32
} , {
.membase = (char*)(IQ80331_UART1_VIRT),
.mapbase = (IQ80331_UART1_PHYS),
.irq = IRQ_IOP331_UART1,
.flags = UPF_SKIP_TEST,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = IOP331_UART_XTAL,
.line = 1,
.type = PORT_XSCALE,
.fifosize = 32
}
};
void __init iop331_map_io(void)
{
iotable_init(iop331_std_desc, ARRAY_SIZE(iop331_std_desc));
early_serial_setup(&iop331_serial_ports[0]);
early_serial_setup(&iop331_serial_ports[1]);
}
#ifdef CONFIG_ARCH_IQ80331
extern void iop331_init_irq(void);
extern void iop331_init_time(void);
extern void iq80331_map_io(void);
#endif
#if defined(CONFIG_ARCH_IQ80331)
MACHINE_START(IQ80331, "Intel IQ80331")
MAINTAINER("Intel Corp.")
BOOT_MEM(PHYS_OFFSET, 0xfefff000, 0xfffff000) // virtual, physical
//BOOT_MEM(PHYS_OFFSET, IQ80331_UART0_VIRT, IQ80331_UART0_PHYS)
MAPIO(iq80331_map_io)
INITIRQ(iop331_init_irq)
INITTIME(iop331_init_time)
BOOT_PARAMS(0x0100)
MACHINE_END
#else
#error No machine descriptor defined for this IOP3XX implementation
#endif
/*
* arch/arm/mach-iop3xx/iop331-time.c
*
* Timer code for IOP331 based systems
*
* Author: Dave Jiang <dave.jiang@intel.com>
*
* Copyright 2003 Intel Corp.
*
* 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/kernel.h>
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/timex.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/mach-types.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
#undef IOP331_TIME_SYNC
static unsigned long iop331_latch;
static inline unsigned long get_elapsed(void)
{
return iop331_latch - *IOP331_TU_TCR0;
}
static unsigned long iop331_gettimeoffset(void)
{
unsigned long elapsed, usec;
u32 tisr1, tisr2;
/*
* If an interrupt was pending before we read the timer,
* we've already wrapped. Factor this into the time.
* If an interrupt was pending after we read the timer,
* it may have wrapped between checking the interrupt
* status and reading the timer. Re-read the timer to
* be sure its value is after the wrap.
*/
asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1));
elapsed = get_elapsed();
asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2));
if(tisr1 & 1)
elapsed += iop331_latch;
else if (tisr2 & 1)
elapsed = iop331_latch + get_elapsed();
/*
* Now convert them to usec.
*/
usec = (unsigned long)(elapsed * (tick_nsec / 1000)) / iop331_latch;
return usec;
}
static irqreturn_t
iop331_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
u32 tisr;
#ifdef IOP331_TIME_SYNC
u32 passed;
#define TM_THRESH (iop331_latch*2)
#endif
asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr));
tisr |= 1;
asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr));
#ifdef IOP331_TIME_SYNC
passed = 0xffffffff - *IOP331_TU_TCR1;
do
{
do_timer(regs);
if(passed < TM_THRESH)
break;
if(passed > iop331_latch)
passed -= iop331_latch;
else
passed = 0;
} while(1);
asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (0xffffffff));
#else
do_timer(regs);
#endif
return IRQ_HANDLED;
}
static struct irqaction iop331_timer_irq = {
.name = "IOP331 Timer Tick",
.handler = iop331_timer_interrupt,
.flags = SA_INTERRUPT
};
extern int setup_arm_irq(int, struct irqaction*);
void __init iop331_init_time(void)
{
u32 timer_ctl;
iop331_latch = (CLOCK_TICK_RATE + HZ / 2) / HZ;
gettimeoffset = iop331_gettimeoffset;
setup_irq(IRQ_IOP331_TIMER0, &iop331_timer_irq);
timer_ctl = IOP331_TMR_EN | IOP331_TMR_PRIVILEGED | IOP331_TMR_RELOAD |
IOP331_TMR_RATIO_1_1;
asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (iop331_latch));
asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl));
#ifdef IOP331_TIME_SYNC
/* Setup second timer */
/* setup counter */
timer_ctl = IOP331_TMR_EN | IOP331_TMR_PRIVILEGED |
IOP331_TMR_RATIO_1_1;
asm volatile("mcr p6, 0, %0, c3, c1, 0" : : "r" (0xffffffff));
/* setup control */
asm volatile("mcr p6, 0, %0, c1, c1, 0" : : "r" (timer_ctl));
#endif
}
/*
* linux/arch/arm/mach-iop3xx/mm.c
*
* Low level memory initialization for iq80321 platform
*
* Author: Rory Bolt <rorybolt@pacbell.net>
* Copyright (C) 2002 Rory Bolt
*
* 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/mm.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/mach/map.h>
#include <asm/mach-types.h>
/*
* IQ80321 specific IO mappings
*
* We use RedBoot's setup for the onboard devices.
*/
static struct map_desc iq31244_io_desc[] __initdata = {
/* virtual physical length type */
/* on-board devices */
{ IQ31244_UART, IQ31244_UART, 0x00100000, MT_DEVICE }
};
void __init iq31244_map_io(void)
{
iop321_map_io();
iotable_init(iq31244_io_desc, ARRAY_SIZE(iq31244_io_desc));
}
/*
* arch/arm/mach-iop3xx/iq80321-pci.c
*
* PCI support for the Intel IQ80321 reference board
*
* Author: Rory Bolt <rorybolt@pacbell.net>
* Copyright (C) 2002 Rory Bolt
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/mach/pci.h>
#include <asm/mach-types.h>
/*
* The following macro is used to lookup irqs in a standard table
* format for those systems that do not already have PCI
* interrupts properly routed. We assume 1 <= pin <= 4
*/
#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \
({ int _ctl_ = -1; \
unsigned int _idsel = idsel - minid; \
if (_idsel <= maxid) \
_ctl_ = pci_irq_table[_idsel][pin-1]; \
_ctl_; })
#define INTA IRQ_IQ31244_INTA
#define INTB IRQ_IQ31244_INTB
#define INTC IRQ_IQ31244_INTC
#define INTD IRQ_IQ31244_INTD
#define INTE IRQ_IQ31244_I82546
static inline int __init
iq31244_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
{
static int pci_irq_table[][4] = {
/*
* PCI IDSEL/INTPIN->INTLINE
* A B C D
*/
#ifdef CONFIG_ARCH_EP80219
{INTB, INTB, INTB, INTB}, /* CFlash */
{INTE, INTE, INTE, INTE}, /* 82551 Pro 100 */
{INTD, INTD, INTD, INTD}, /* PCI-X Slot */
{INTC, INTC, INTC, INTC}, /* SATA */
#else
{INTB, INTB, INTB, INTB}, /* CFlash */
{INTC, INTC, INTC, INTC}, /* SATA */
{INTD, INTD, INTD, INTD}, /* PCI-X Slot */
{INTE, INTE, INTE, INTE}, /* 82546 GigE */
#endif // CONFIG_ARCH_EP80219
};
BUG_ON(pin < 1 || pin > 4);
return PCI_IRQ_TABLE_LOOKUP(0, 7);
}
static int iq31244_setup(int nr, struct pci_sys_data *sys)
{
struct resource *res;
if(nr != 0)
return 0;
res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL);
if (!res)
panic("PCI: unable to alloc resources");
memset(res, 0, sizeof(struct resource) * 2);
res[0].start = IQ31244_PCI_IO_BASE + 0x6e000000;
res[0].end = IQ31244_PCI_IO_BASE + IQ31244_PCI_IO_SIZE - 1 + IQ31244_PCI_IO_OFFSET;
res[0].name = "IQ31244 PCI I/O Space";
res[0].flags = IORESOURCE_IO;
res[1].start = IQ31244_PCI_MEM_BASE;
res[1].end = IQ31244_PCI_MEM_BASE + IQ31244_PCI_MEM_SIZE;
res[1].name = "IQ31244 PCI Memory Space";
res[1].flags = IORESOURCE_MEM;
request_resource(&ioport_resource, &res[0]);
request_resource(&iomem_resource, &res[1]);
sys->resource[0] = &res[0];
sys->resource[1] = &res[1];
sys->resource[2] = NULL;
sys->io_offset = IQ31244_PCI_IO_OFFSET;
sys->mem_offset = IQ80321_PCI_MEM_BASE -
(*IOP321_IABAR1 & PCI_BASE_ADDRESS_MEM_MASK);
iop3xx_pcibios_min_io = IQ31244_PCI_IO_BASE;
iop3xx_pcibios_min_mem = IQ31244_PCI_MEM_BASE;
return 1;
}
static void iq31244_preinit(void)
{
iop321_init();
/* setting up the second translation window */
*IOP321_OMWTVR1 = IQ31244_PCI_MEM_BASE + 0x04000000;
*IOP321_OUMWTVR1 = 0x0;
}
static struct hw_pci iq31244_pci __initdata = {
.swizzle = pci_std_swizzle,
.nr_controllers = 1,
.setup = iq31244_setup,
.scan = iop321_scan_bus,
.preinit = iq31244_preinit,
.map_irq = iq31244_map_irq
};
static int __init iq31244_pci_init(void)
{
if (machine_is_iq31244())
pci_common_init(&iq31244_pci);
return 0;
}
subsys_initcall(iq31244_pci_init);
/*
* linux/arch/arm/mach-iop3xx/mm.c
*
* Low level memory initialization for iq80321 platform
*
* Author: Rory Bolt <rorybolt@pacbell.net>
* Copyright (C) 2002 Rory Bolt
*
* 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/mm.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/mach/map.h>
#include <asm/mach-types.h>
/*
* IQ80321 specific IO mappings
*
* We use RedBoot's setup for the onboard devices.
*/
static struct map_desc iq80321_io_desc[] __initdata = {
/* virtual physical length type */
/* on-board devices */
{ IQ80321_UART, IQ80321_UART, 0x00100000, MT_DEVICE }
};
void __init iq80321_map_io(void)
{
iop321_map_io();
iotable_init(iq80321_io_desc, ARRAY_SIZE(iq80321_io_desc));
}
......@@ -38,37 +38,79 @@
#define INTE IRQ_IQ80321_I82544
typedef u8 irq_table[4];
static irq_table pci_irq_table[] = {
/*
* PCI IDSEL/INTPIN->INTLINE
* A B C D
*/
{INTE, INTE, INTE, INTE}, /* Gig-E */
{INTD, INTC, INTD, INTA}, /* Unused */
{INTC, INTD, INTA, INTB}, /* PCI-X Slot */
};
static inline int __init
iq80321_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
{
static int pci_irq_table[][4] = {
/*
* PCI IDSEL/INTPIN->INTLINE
* A B C D
*/
{INTE, INTE, INTE, INTE}, /* Gig-E */
{-1, -1, -1, -1}, /* Unused */
{INTC, INTD, INTA, INTB}, /* PCI-X Slot */
{-1, -1, -1, -1},
};
BUG_ON(pin < 1 || pin > 4);
return PCI_IRQ_TABLE_LOOKUP(2, 3);
// return PCI_IRQ_TABLE_LOOKUP(4, 7);
return pci_irq_table[idsel%4][pin-1];
}
static int iq80321_setup(int nr, struct pci_sys_data *sys)
{
switch (nr) {
case 0:
sys->map_irq = iq80321_map_irq;
break;
default:
struct resource *res;
if(nr != 0)
return 0;
}
return iop321_setup(nr, sys);
res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL);
if (!res)
panic("PCI: unable to alloc resources");
memset(res, 0, sizeof(struct resource) * 2);
res[0].start = IQ80321_PCI_IO_BASE + IQ80321_PCI_IO_OFFSET;
res[0].end = IQ80321_PCI_IO_BASE + IQ80321_PCI_IO_SIZE - 1 + IQ80321_PCI_IO_OFFSET;
res[0].name = "IQ80321 PCI I/O Space";
res[0].flags = IORESOURCE_IO;
res[1].start = IQ80321_PCI_MEM_BASE;
res[1].end = IQ80321_PCI_MEM_BASE + IQ80321_PCI_MEM_SIZE;
res[1].name = "IQ80321 PCI Memory Space";
res[1].flags = IORESOURCE_MEM;
request_resource(&ioport_resource, &res[0]);
request_resource(&iomem_resource, &res[1]);
/*
* Since the IQ80321 is a slave card on a PCI backplane,
* it uses BAR1 to reserve a portion of PCI memory space for
* use with the private devices on the secondary bus
* (GigE and PCI-X slot). We read BAR1 and configure
* our outbound translation windows to target that
* address range and assign all devices in that
* address range. W/O this, certain BIOSes will fail
* to boot as the IQ80321 claims addresses that are
* in use by other devices.
*
* Note that the same cannot be done with I/O space,
* so hopefully the host will stick to the lower 64K for
* PCI I/O and leave us alone.
*/
sys->mem_offset = IQ80321_PCI_MEM_BASE -
(*IOP321_IABAR1 & PCI_BASE_ADDRESS_MEM_MASK);
sys->resource[0] = &res[0];
sys->resource[1] = &res[1];
sys->resource[2] = NULL;
sys->io_offset = IQ80321_PCI_IO_OFFSET;
iop3xx_pcibios_min_io = IQ80321_PCI_IO_BASE;
iop3xx_pcibios_min_mem = IQ80321_PCI_MEM_BASE;
return 1;
}
static void iq80321_preinit(void)
......@@ -82,6 +124,7 @@ static struct hw_pci iq80321_pci __initdata = {
.setup = iq80321_setup,
.scan = iop321_scan_bus,
.preinit = iq80321_preinit,
.map_irq = iq80321_map_irq
};
static int __init iq80321_pci_init(void)
......
/*
* linux/arch/arm/mach-iop3xx/mm.c
*
* Low level memory initialization for iq80331 platform
*
* Author: Dave Jiang <dave.jiang@intel.com>
* Copyright (C) 2003 Intel Corp.
*
* 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/mm.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/mach/map.h>
#include <asm/mach-types.h>
/*
* IQ80331 specific IO mappings
*
* We use RedBoot's setup for the onboard devices.
*/
void __init iq80331_map_io(void)
{
iop331_map_io();
}
/*
* arch/arm/mach-iop3xx/iq80331-pci.c
*
* PCI support for the Intel IQ80331 reference board
*
* Author: Dave Jiang <dave.jiang@intel.com>
* Copyright (C) 2003 Intel Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/mach/pci.h>
#include <asm/mach-types.h>
/*
* The following macro is used to lookup irqs in a standard table
* format for those systems that do not already have PCI
* interrupts properly routed. We assume 1 <= pin <= 4
*/
#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \
({ int _ctl_ = -1; \
unsigned int _idsel = idsel - minid; \
if (_idsel <= maxid) \
_ctl_ = pci_irq_table[_idsel][pin-1]; \
_ctl_; })
#define INTA IRQ_IQ80331_INTA
#define INTB IRQ_IQ80331_INTB
#define INTC IRQ_IQ80331_INTC
#define INTD IRQ_IQ80331_INTD
//#define INTE IRQ_IQ80331_I82544
static inline int __init
iq80331_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
{
static int pci_irq_table[][4] = {
/*
* PCI IDSEL/INTPIN->INTLINE
* A B C D
*/
{INTB, INTC, INTD, INTA}, /* PCI-X Slot */
{INTC, INTC, INTC, INTC}, /* GigE */
};
BUG_ON(pin < 1 || pin > 4);
return PCI_IRQ_TABLE_LOOKUP(1, 7);
}
static int iq80331_setup(int nr, struct pci_sys_data *sys)
{
struct resource *res;
if(nr != 0)
return 0;
res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL);
if (!res)
panic("PCI: unable to alloc resources");
memset(res, 0, sizeof(struct resource) * 2);
res[0].start = IQ80331_PCI_IO_BASE + 0x6e000000;
res[0].end = IQ80331_PCI_IO_BASE + IQ80331_PCI_IO_SIZE - 1 + IQ80331_PCI_IO_OFFSET;
res[0].name = "IQ80331 PCI I/O Space";
res[0].flags = IORESOURCE_IO;
res[1].start = IQ80331_PCI_MEM_BASE;
res[1].end = IQ80331_PCI_MEM_BASE + IQ80331_PCI_MEM_SIZE;
res[1].name = "IQ80331 PCI Memory Space";
res[1].flags = IORESOURCE_MEM;
request_resource(&ioport_resource, &res[0]);
request_resource(&iomem_resource, &res[1]);
/*
* Since the IQ80331 is a slave card on a PCI backplane,
* it uses BAR1 to reserve a portion of PCI memory space for
* use with the private devices on the secondary bus
* (GigE and PCI-X slot). We read BAR1 and configure
* our outbound translation windows to target that
* address range and assign all devices in that
* address range. W/O this, certain BIOSes will fail
* to boot as the IQ80331 claims addresses that are
* in use by other devices.
*
* Note that the same cannot be done with I/O space,
* so hopefully the host will stick to the lower 64K for
* PCI I/O and leave us alone.
*/
sys->mem_offset = IQ80331_PCI_MEM_BASE -
(*IOP331_IABAR1 & PCI_BASE_ADDRESS_MEM_MASK);
sys->resource[0] = &res[0];
sys->resource[1] = &res[1];
sys->resource[2] = NULL;
sys->io_offset = IQ80331_PCI_IO_OFFSET;
iop3xx_pcibios_min_io = IQ80331_PCI_IO_BASE;
iop3xx_pcibios_min_mem = IQ80331_PCI_MEM_BASE;
return 1;
}
static void iq80331_preinit(void)
{
iop331_init();
}
static struct hw_pci iq80331_pci __initdata = {
.swizzle = pci_std_swizzle,
.nr_controllers = 1,
.setup = iq80331_setup,
.scan = iop331_scan_bus,
.preinit = iq80331_preinit,
.map_irq = iq80331_map_irq
};
static int __init iq80331_pci_init(void)
{
if (machine_is_iq80331())
pci_common_init(&iq80331_pci);
return 0;
}
subsys_initcall(iq80331_pci_init);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment