Update of /cvsroot/linux-vax/kernel-2.4/arch/arm/mach-integrator
In directory usw-pr-cvs1:/tmp/cvs-serv24336/arm/mach-integrator
Added Files:
Makefile arch.c cpu.c dma.c irq.c leds.c mm.c pci.c pci_v3.c
time.c
Log Message:
synch 2.4.15 commit 32
--- NEW FILE ---
#
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
USE_STANDARD_AS_RULE := true
O_TARGET := integrator.o
# Object file lists.
obj-y := arch.o cpu.o irq.o mm.o time.o
obj-m :=
obj-n :=
obj- :=
export-objs := leds.o
obj-$(CONFIG_LEDS) += leds.o
obj-$(CONFIG_PCI) += pci_v3.o pci.o
include $(TOPDIR)/Rules.make
--- NEW FILE ---
/*
* linux/arch/arm/mach-integrator/arch.c
*
* Copyright (C) 2000 Deep Blue Solutions Ltd
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/amba_kmi.h>
extern void integrator_map_io(void);
extern void integrator_init_irq(void);
#ifdef CONFIG_KMI_KEYB
static struct kmi_info integrator_keyboard __initdata = {
base: IO_ADDRESS(KMI0_BASE),
irq: IRQ_KMIINT0,
divisor: 24 / 8 - 1,
type: KMI_KEYBOARD,
};
static struct kmi_info integrator_mouse __initdata = {
base: IO_ADDRESS(KMI1_BASE),
irq: IRQ_KMIINT1,
divisor: 24 / 8 - 1,
type: KMI_MOUSE,
};
#endif
static void __init
integrator_fixup(struct machine_desc *desc, struct param_struct *unused,
char **cmdline, struct meminfo *mi)
{
#ifdef CONFIG_KMI_KEYB
register_kmi(&integrator_keyboard);
register_kmi(&integrator_mouse);
#endif
}
MACHINE_START(INTEGRATOR, "ARM-Integrator")
MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
BOOT_MEM(0x00000000, 0x16000000, 0xf1600000)
BOOT_PARAMS(0x00000100)
FIXUP(integrator_fixup)
MAPIO(integrator_map_io)
INITIRQ(integrator_init_irq)
MACHINE_END
--- NEW FILE ---
/*
* linux/arch/arm/mach-integrator/cpu.c
*
* Copyright (C) 2001 Deep Blue Solutions Ltd.
*
* $Id: cpu.c,v 1.1 2002/04/10 13:51:22 atp Exp $
*
* 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.
*
* CPU support functions
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/cpufreq.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/io.h>
#define CM_ID (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_ID_OFFSET)
#define CM_OSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_OSC_OFFSET)
#define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET)
#define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
struct vco {
unsigned char vdw;
unsigned char od;
};
/*
* Divisors for each OD setting.
*/
static unsigned char cc_divisor[8] = { 10, 2, 8, 4, 5, 7, 9, 6 };
static unsigned int vco_to_freq(struct vco vco, int factor)
{
return 2000 * (vco.vdw + 8) / cc_divisor[vco.od] / factor;
}
#ifdef CONFIG_CPU_FREQ
/*
* Divisor indexes for in ascending divisor order
*/
static unsigned char s2od[] = { 1, 3, 4, 7, 5, 2, 6, 0 };
static struct vco freq_to_vco(unsigned int freq_khz, int factor)
{
struct vco vco = {0, 0};
unsigned int i, f;
freq_khz *= factor;
for (i = 0; i < 8; i++) {
f = freq_khz * cc_divisor[s2od[i]];
/* f must be between 10MHz and 320MHz */
if (f > 10000 && f <= 320000)
break;
}
vco.od = s2od[i];
vco.vdw = f / 2000 - 8;
return vco;
}
/*
* Validate the speed in khz. If it is outside our
* range, then return the lowest.
*/
unsigned int integrator_validatespeed(unsigned int freq_khz)
{
struct vco vco;
if (freq_khz < 12000)
freq_khz = 12000;
if (freq_khz > 160000)
freq_khz = 160000;
vco = freq_to_vco(freq_khz, 1);
if (vco.vdw < 4 || vco.vdw > 152)
return -EINVAL;
return vco_to_freq(vco, 1);
}
void integrator_setspeed(unsigned int freq_khz)
{
struct vco vco = freq_to_vco(freq_khz, 1);
u_int cm_osc;
cm_osc = __raw_readl(CM_OSC);
cm_osc &= 0xfffff800;
cm_osc |= vco.vdw | vco.od << 8;
__raw_writel(0xa05f, CM_LOCK);
__raw_writel(cm_osc, CM_OSC);
__raw_writel(0, CM_LOCK);
}
#endif
static int __init cpu_init(void)
{
u_int cm_osc, cm_stat, cpu_freq_khz, mem_freq_khz;
struct vco vco;
cm_osc = __raw_readl(CM_OSC);
vco.od = (cm_osc >> 20) & 7;
vco.vdw = (cm_osc >> 12) & 255;
mem_freq_khz = vco_to_freq(vco, 2);
printk(KERN_INFO "Memory clock = %d.%03d MHz\n",
mem_freq_khz / 1000, mem_freq_khz % 1000);
vco.od = (cm_osc >> 8) & 7;
vco.vdw = cm_osc & 255;
cpu_freq_khz = vco_to_freq(vco, 1);
#ifdef CONFIG_CPU_FREQ
cpufreq_init(cpu_freq_khz);
cpufreq_setfunctions(integrator_validatespeed, integrator_setspeed);
#endif
cm_stat = __raw_readl(CM_STAT);
printk("Module id: %d\n", cm_stat & 255);
return 0;
}
__initcall(cpu_init);
--- NEW FILE ---
/*
* linux/arch/arm/mach-integrator/dma.c
*
* Copyright (C) 1999 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/mman.h>
#include <linux/init.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/mach/dma.h>
void __init arch_dma_init(dma_t *dma)
{
}
--- NEW FILE ---
/*
* linux/arch/arm/mach-integrator/irq.c
*
* Copyright (C) 1999 ARM Limited
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/mach/irq.h>
/*
* All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
* is the (PA >> 12).
*
* Setup a VA for the Integrator interrupt controller (for header #0,
* just for now).
*/
#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE)
#define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET
#define ALLPCI ( (1 << IRQ_PCIINT0) | (1 << IRQ_PCIINT1) | (1 << IRQ_PCIINT2) | (1 << IRQ_PCIINT3) )
static void sc_mask_irq(unsigned int irq)
{
__raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR);
}
static void sc_unmask_irq(unsigned int irq)
{
__raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET);
}
void __init integrator_init_irq(void)
{
unsigned int i;
for (i = 0; i < NR_IRQS; i++) {
if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) {
irq_desc[i].valid = 1;
irq_desc[i].probe_ok = 1;
irq_desc[i].mask_ack = sc_mask_irq;
irq_desc[i].mask = sc_mask_irq;
irq_desc[i].unmask = sc_unmask_irq;
}
}
/* Disable all interrupts initially. */
/* Do the core module ones */
__raw_writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
/* do the header card stuff next */
__raw_writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
__raw_writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
}
--- NEW FILE ---
/*
* linux/arch/arm/mach-integrator/leds.c
*
* Integrator LED control routines
*
* Copyright (C) 1999 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/leds.h>
#include <asm/system.h>
#include <asm/mach-types.h>
static int saved_leds;
static void integrator_leds_event(led_event_t ledevt)
{
unsigned long flags;
const unsigned int dbg_base = IO_ADDRESS(INTEGRATOR_DBG_BASE);
const unsigned int hdr_ctrl = IO_ADDRESS(INTEGRATOR_HDR_BASE) +
INTEGRATOR_HDR_CTRL_OFFSET;
unsigned int ctrl;
unsigned int update_alpha_leds;
// yup, change the LEDs
local_irq_save(flags);
update_alpha_leds = 0;
switch(ledevt) {
case led_idle_start:
ctrl = __raw_readl(hdr_ctrl);
ctrl &= ~INTEGRATOR_HDR_CTRL_LED;
__raw_writel(ctrl, hdr_ctrl);
break;
case led_idle_end:
ctrl = __raw_readl(hdr_ctrl);
ctrl |= INTEGRATOR_HDR_CTRL_LED;
__raw_writel(ctrl, hdr_ctrl);
break;
case led_timer:
saved_leds ^= GREEN_LED;
update_alpha_leds = 1;
break;
case led_red_on:
saved_leds |= RED_LED;
update_alpha_leds = 1;
break;
case led_red_off:
saved_leds &= ~RED_LED;
update_alpha_leds = 1;
break;
default:
break;
}
if (update_alpha_leds) {
while (__raw_readl(dbg_base + INTEGRATOR_DBG_ALPHA_OFFSET) & 1);
__raw_writel(saved_leds, dbg_base + INTEGRATOR_DBG_LEDS_OFFSET);
}
local_irq_restore(flags);
}
static int __init leds_init(void)
{
if (machine_is_integrator())
leds_event = integrator_leds_event;
return 0;
}
__initcall(leds_init);
--- NEW FILE ---
/*
* linux/arch/arm/mach-integrator/mm.c
*
* Extra MM routines for the ARM Integrator board
*
* Copyright (C) 1999,2000 Arm Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/mach/map.h>
/*
* Logical Physical
* e8000000 40000000 PCI memory
* ec000000 62000000 PCI config space
* ed000000 61000000 PCI V3 regs
* ee000000 60000000 PCI IO
* ef000000 Cache flush
* f1000000 10000000 Core module registers
* f1100000 11000000 System controller registers
* f1200000 12000000 EBI registers
* f1300000 13000000 Counter/Timer
* f1400000 14000000 Interrupt controller
* f1500000 15000000 RTC
* f1600000 16000000 UART 0
* f1700000 17000000 UART 1
* f1800000 18000000 Keyboard
* f1900000 19000000 Mouse
* f1a00000 1a000000 Debug LEDs
* f1b00000 1b000000 GPIO
*/
static struct map_desc integrator_io_desc[] __initdata = {
{ IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K , DOMAIN_IO, 0, 1},
{ IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K , DOMAIN_IO, 0, 1},
{ IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K , DOMAIN_IO, 0, 1},
{ IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K , DOMAIN_IO, 0, 1},
{ IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K , DOMAIN_IO, 0, 1},
{ IO_ADDRESS(INTEGRATOR_RTC_BASE), INTEGRATOR_RTC_BASE, SZ_4K , DOMAIN_IO, 0, 1},
{ IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K , DOMAIN_IO, 0, 1},
{ IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K , DOMAIN_IO, 0, 1},
{ IO_ADDRESS(INTEGRATOR_KBD_BASE), INTEGRATOR_KBD_BASE, SZ_4K , DOMAIN_IO, 0, 1},
{ IO_ADDRESS(INTEGRATOR_MOUSE_BASE), INTEGRATOR_MOUSE_BASE, SZ_4K , DOMAIN_IO, 0, 1},
{ IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K , DOMAIN_IO, 0, 1},
{ IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K , DOMAIN_IO, 0, 1},
{ PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M , DOMAIN_IO, 0, 1},
{ PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M , DOMAIN_IO, 0, 1},
{ PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_512K , DOMAIN_IO, 0, 1},
{ PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K , DOMAIN_IO, 0, 1},
LAST_DESC
};
void __init integrator_map_io(void)
{
iotable_init(integrator_io_desc);
}
--- NEW FILE ---
/*
* linux/arch/arm/mach-integrator/pci-integrator.c
*
* Copyright (C) 1999 ARM Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* PCI functions for Integrator
*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/mach/pci.h>
/*
* A small note about bridges and interrupts. The DECchip 21050 (and
* later) adheres to the PCI-PCI bridge specification. This says that
* the interrupts on the other side of a bridge are swizzled in the
* following manner:
*
* Dev Interrupt Interrupt
* Pin on Pin on
* Device Connector
*
* 4 A A
* B B
* C C
* D D
*
* 5 A B
* B C
* C D
* D A
*
* 6 A C
* B D
* C A
* D B
*
* 7 A D
* B A
* C B
* D C
*
* Where A = pin 1, B = pin 2 and so on and pin=0 = default = A.
* Thus, each swizzle is ((pin-1) + (device#-4)) % 4
*
* The following code swizzles for exactly one bridge.
*/
static inline int bridge_swizzle(int pin, unsigned int slot)
{
return (pin + slot) & 3;
}
/*
* This routine handles multiple bridges.
*/
static u8 __init integrator_swizzle(struct pci_dev *dev, u8 *pinp)
{
int pin = *pinp;
if (pin == 0)
pin = 1;
pin -= 1;
while (dev->bus->self) {
pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
/*
* move up the chain of bridges, swizzling as we go.
*/
dev = dev->bus->self;
}
*pinp = pin + 1;
return PCI_SLOT(dev->devfn);
}
static int irq_tab[4] __initdata = {
IRQ_PCIINT0, IRQ_PCIINT1, IRQ_PCIINT2, IRQ_PCIINT3
};
/*
* map the specified device/slot/pin to an IRQ. This works out such
* that slot 9 pin 1 is INT0, pin 2 is INT1, and slot 10 pin 1 is INT1.
*/
static int __init integrator_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
int intnr = ((slot - 9) + (pin - 1)) & 3;
return irq_tab[intnr];
}
extern void pci_v3_setup_resources(struct resource **res);
extern void pci_v3_init(void *);
struct hw_pci integrator_pci __initdata = {
setup_resources: pci_v3_setup_resources,
init: pci_v3_init,
mem_offset: 0x40000000,
swizzle: integrator_swizzle,
map_irq: integrator_map_irq,
};
--- NEW FILE ---
/*
* linux/arch/arm/mach-integrator/pci_v3.c
*
* PCI functions for V3 host PCI bridge
*
* Copyright (C) 1999 ARM Limited
* Copyright (C) 2000-2001 Deep Blue Solutions Ltd
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/mach/pci.h>
#include <asm/hardware/pci_v3.h>
/*
* The V3 PCI interface chip in Integrator provides several windows from
* local bus memory into the PCI memory areas. Unfortunately, there
* are not really enough windows for our usage, therefore we reuse
* one of the windows for access to PCI configuration space. The
* memory map is as follows:
*
* Local Bus Memory Usage
*
* 40000000 - 4FFFFFFF PCI memory. 256M non-prefetchable
* 50000000 - 5FFFFFFF PCI memory. 256M prefetchable
* 60000000 - 60FFFFFF PCI IO. 16M
* 68000000 - 68FFFFFF PCI Configuration. 16M
*
* There are three V3 windows, each described by a pair of V3 registers.
* These are LB_BASE0/LB_MAP0, LB_BASE1/LB_MAP1 and LB_BASE2/LB_MAP2.
* Base0 and Base1 can be used for any type of PCI memory access. Base2
* can be used either for PCI I/O or for I20 accesses. By default, uHAL
* uses this only for PCI IO space.
*
* PCI Memory is mapped so that assigned addresses in PCI Memory match
* local bus memory addresses. In other words, if a PCI device is assigned
* address 80200000 then that address is a valid local bus address as well
* as a valid PCI Memory address. PCI IO addresses are mapped to start
* at zero. This means that local bus address 60000000 maps to PCI IO address
* 00000000 and so on. Device driver writers need to be aware of this
* distinction.
*
* Normally these spaces are mapped using the following base registers:
*
* Usage Local Bus Memory Base/Map registers used
*
* Mem 40000000 - 4FFFFFFF LB_BASE0/LB_MAP0
* Mem 50000000 - 5FFFFFFF LB_BASE1/LB_MAP1
* IO 60000000 - 60FFFFFF LB_BASE2/LB_MAP2
* Cfg 68000000 - 68FFFFFF
*
* This means that I20 and PCI configuration space accesses will fail.
* When PCI configuration accesses are needed (via the uHAL PCI
* configuration space primitives) we must remap the spaces as follows:
*
* Usage Local Bus Memory Base/Map registers used
*
* Mem 40000000 - 4FFFFFFF LB_BASE0/LB_MAP0
* Mem 50000000 - 5FFFFFFF LB_BASE0/LB_MAP0
* IO 60000000 - 60FFFFFF LB_BASE2/LB_MAP2
* Cfg 68000000 - 68FFFFFF LB_BASE1/LB_MAP1
*
* To make this work, the code depends on overlapping windows working.
* The V3 chip translates an address by checking its range within
* each of the BASE/MAP pairs in turn (in ascending register number
* order). It will use the first matching pair. So, for example,
* if the same address is mapped by both LB_BASE0/LB_MAP0 and
* LB_BASE1/LB_MAP1, the V3 will use the translation from
* LB_BASE0/LB_MAP0.
*
* To allow PCI Configuration space access, the code enlarges the
* window mapped by LB_BASE0/LB_MAP0 from 256M to 512M. This occludes
* the windows currently mapped by LB_BASE1/LB_MAP1 so that it can
* be remapped for use by configuration cycles.
*
* At the end of the PCI Configuration space accesses,
* LB_BASE1/LB_MAP1 is reset to map PCI Memory. Finally the window
* mapped by LB_BASE0/LB_MAP0 is reduced in size from 512M to 256M to
* reveal the now restored LB_BASE1/LB_MAP1 window.
*
* NOTE: We do not set up I2O mapping. I suspect that this is only
* for an intelligent (target) device. Using I2O disables most of
* the mappings into PCI memory.
*/
// V3 access routines
#define v3_writeb(o,v) __raw_writeb(v, PCI_V3_VADDR + (unsigned int)(o))
#define v3_readb(o) (__raw_readb(PCI_V3_VADDR + (unsigned int)(o)))
#define v3_writew(o,v) __raw_writew(v, PCI_V3_VADDR + (unsigned int)(o))
#define v3_readw(o) (__raw_readw(PCI_V3_VADDR + (unsigned int)(o)))
#define v3_writel(o,v) __raw_writel(v, PCI_V3_VADDR + (unsigned int)(o))
#define v3_readl(o) (__raw_readl(PCI_V3_VADDR + (unsigned int)(o)))
/*============================================================================
*
* routine: uHALir_PCIMakeConfigAddress()
*
* parameters: bus = which bus
* device = which device
* function = which function
* offset = configuration space register we are interested in
*
* description: this routine will generate a platform dependant config
* address.
*
* calls: none
*
* returns: configuration address to play on the PCI bus
*
* To generate the appropriate PCI configuration cycles in the PCI
* configuration address space, you present the V3 with the following pattern
* (which is very nearly a type 1 (except that the lower two bits are 00 and
* not 01). In order for this mapping to work you need to set up one of
* the local to PCI aperatures to 16Mbytes in length translating to
* PCI configuration space starting at 0x0000.0000.
*
* PCI configuration cycles look like this:
*
* Type 0:
*
* 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
* 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* 31:11 Device select bit.
* 10:8 Function number
* 7:2 Register number
*
* Type 1:
*
* 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
* 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* 31:24 reserved
* 23:16 bus number (8 bits = 128 possible buses)
* 15:11 Device number (5 bits)
* 10:8 function number
* 7:2 register number
*
*/
static spinlock_t v3_lock = SPIN_LOCK_UNLOCKED;
#define PCI_BUS_NONMEM_START 0x00000000
#define PCI_BUS_NONMEM_SIZE 0x10000000
#define PCI_BUS_PREMEM_START 0x10000000
#define PCI_BUS_PREMEM_SIZE 0x10000000
#if PCI_BUS_NONMEM_START & 0x000fffff
#error PCI_BUS_NONMEM_START must be megabyte aligned
#endif
#if PCI_BUS_PREMEM_START & 0x000fffff
#error PCI_BUS_PREMEM_START must be megabyte aligned
#endif
#undef V3_LB_BASE_PREFETCH
#define V3_LB_BASE_PREFETCH 0
static unsigned long v3_open_config_window(struct pci_dev *dev, int offset)
{
unsigned int address, mapaddress, busnr;
busnr = dev->bus->number;
/*
* Trap out illegal values
*/
if (offset > 255)
BUG();
if (busnr > 255)
BUG();
if (dev->devfn > 255)
BUG();
if (busnr == 0) {
int slot = PCI_SLOT(dev->devfn);
/*
* local bus segment so need a type 0 config cycle
*
* build the PCI configuration "address" with one-hot in
* A31-A11
*
* mapaddress:
* 3:1 = config cycle (101)
* 0 = PCI A1 & A0 are 0 (0)
*/
address = PCI_FUNC(dev->devfn) << 8;
mapaddress = V3_LB_MAP_TYPE_CONFIG;
if (slot > 12)
/*
* high order bits are handled by the MAP register
*/
mapaddress |= 1 << (slot - 5);
else
/*
* low order bits handled directly in the address
*/
address |= 1 << (slot + 11);
} else {
/*
* not the local bus segment so need a type 1 config cycle
*
* address:
* 23:16 = bus number
* 15:11 = slot number (7:3 of devfn)
* 10:8 = func number (2:0 of devfn)
*
* mapaddress:
* 3:1 = config cycle (101)
* 0 = PCI A1 & A0 from host bus (1)
*/
mapaddress = V3_LB_MAP_TYPE_CONFIG | V3_LB_MAP_AD_LOW_EN;
address = (busnr << 16) | (dev->devfn << 8);
}
/*
* Set up base0 to see all 512Mbytes of memory space (not
* prefetchable), this frees up base1 for re-use by
* configuration memory
*/
v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) |
V3_LB_BASE_ADR_SIZE_512MB | V3_LB_BASE_ENABLE);
/*
* Set up base1/map1 to point into configuration space.
*/
v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_CONFIG_BASE) |
V3_LB_BASE_ADR_SIZE_16MB | V3_LB_BASE_ENABLE);
v3_writew(V3_LB_MAP1, mapaddress);
return PCI_CONFIG_VADDR + address + offset;
}
static void v3_close_config_window(void)
{
/*
* Reassign base1 for use by prefetchable PCI memory
*/
v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE + SZ_256M) |
V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_PREFETCH |
V3_LB_BASE_ENABLE);
v3_writew(V3_LB_MAP1, v3_addr_to_lb_map(PCI_BUS_PREMEM_START) |
V3_LB_MAP_TYPE_MEM_MULTIPLE);
/*
* And shrink base0 back to a 256M window (NOTE: MAP0 already correct)
*/
v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) |
V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_ENABLE);
}
static int v3_read_config_byte(struct pci_dev *dev, int where, u8 *val)
{
unsigned long addr;
unsigned long flags;
u8 v;
spin_lock_irqsave(&v3_lock, flags);
addr = v3_open_config_window(dev, where);
v = __raw_readb(addr);
v3_close_config_window();
spin_unlock_irqrestore(&v3_lock, flags);
*val = v;
return PCIBIOS_SUCCESSFUL;
}
static int v3_read_config_word(struct pci_dev *dev, int where, u16 *val)
{
unsigned long addr;
unsigned long flags;
u16 v;
spin_lock_irqsave(&v3_lock, flags);
addr = v3_open_config_window(dev, where);
v = __raw_readw(addr);
v3_close_config_window();
spin_unlock_irqrestore(&v3_lock, flags);
*val = v;
return PCIBIOS_SUCCESSFUL;
}
static int v3_read_config_dword(struct pci_dev *dev, int where, u32 *val)
{
unsigned long addr;
unsigned long flags;
u32 v;
spin_lock_irqsave(&v3_lock, flags);
addr = v3_open_config_window(dev, where);
v = __raw_readl(addr);
v3_close_config_window();
spin_unlock_irqrestore(&v3_lock, flags);
*val = v;
return PCIBIOS_SUCCESSFUL;
}
static int v3_write_config_byte(struct pci_dev *dev, int where, u8 val)
{
unsigned long addr;
unsigned long flags;
spin_lock_irqsave(&v3_lock, flags);
addr = v3_open_config_window(dev, where);
__raw_writeb(val, addr);
__raw_readb(addr);
v3_close_config_window();
spin_unlock_irqrestore(&v3_lock, flags);
return PCIBIOS_SUCCESSFUL;
}
static int v3_write_config_word(struct pci_dev *dev, int where, u16 val)
{
unsigned long addr;
unsigned long flags;
spin_lock_irqsave(&v3_lock, flags);
addr = v3_open_config_window(dev, where);
__raw_writew(val, addr);
__raw_readw(addr);
v3_close_config_window();
spin_unlock_irqrestore(&v3_lock, flags);
return PCIBIOS_SUCCESSFUL;
}
static int v3_write_config_dword(struct pci_dev *dev, int where, u32 val)
{
unsigned long addr;
unsigned long flags;
spin_lock_irqsave(&v3_lock, flags);
addr = v3_open_config_window(dev, where);
__raw_writel(val, addr);
__raw_readl(addr);
v3_close_config_window();
spin_unlock_irqrestore(&v3_lock, flags);
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops pci_v3_ops = {
read_byte: v3_read_config_byte,
read_word: v3_read_config_word,
read_dword: v3_read_config_dword,
write_byte: v3_write_config_byte,
write_word: v3_write_config_word,
write_dword: v3_write_config_dword,
};
static struct resource non_mem = {
name: "PCI non-prefetchable",
start: 0x40000000 + PCI_BUS_NONMEM_START,
end: 0x40000000 + PCI_BUS_NONMEM_START + PCI_BUS_NONMEM_SIZE - 1,
flags: IORESOURCE_MEM,
};
static struct resource pre_mem = {
name: "PCI prefetchable",
start: 0x40000000 + PCI_BUS_PREMEM_START,
end: 0x40000000 + PCI_BUS_PREMEM_START + PCI_BUS_PREMEM_SIZE - 1,
flags: IORESOURCE_MEM | IORESOURCE_PREFETCH,
};
void __init pci_v3_setup_resources(struct resource **resource)
{
if (request_resource(&iomem_resource, &non_mem))
printk("PCI: unable to allocate non-prefetchable memory region\n");
if (request_resource(&iomem_resource, &pre_mem))
printk("PCI: unable to allocate prefetchable memory region\n");
/*
* bus->resource[0] is the IO resource for this bus
* bus->resource[1] is the mem resource for this bus
* bus->resource[2] is the prefetch mem resource for this bus
*/
resource[0] = &ioport_resource;
resource[1] = &non_mem;
resource[2] = &pre_mem;
}
/*
* These don't seem to be implemented on the Integrator I have, which
* means I can't get additional information on the reason for the pm2fb
* problems. I suppose I'll just have to mind-meld with the machine. ;)
*/
#define SC_PCI (IO_ADDRESS(INTEGRATOR_SC_PCIENABLE))
#define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE+0x20))
#define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE+0x24))
static int v3_fault(unsigned long addr, struct pt_regs *regs)
{
unsigned long pc = instruction_pointer(regs);
unsigned long instr = *(unsigned long *)pc;
printk("V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n",
addr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
v3_readb(V3_LB_ISTAT));
v3_writeb(V3_LB_ISTAT, 0);
__raw_writel(3, SC_PCI);
/*
* If the instruction being executed was a read,
* make it look like it read all-ones.
*/
if ((instr & 0x0c100000) == 0x04100000) {
int reg = (instr >> 12) & 15;
unsigned long val;
if (instr & 0x00400000)
val = 255;
else
val = -1;
regs->uregs[reg] = val;
regs->ARM_pc += 4;
return 0;
}
return 1;
}
static void v3_irq(int irq, void *devid, struct pt_regs *regs)
{
unsigned long pc = instruction_pointer(regs);
unsigned long instr = *(unsigned long *)pc;
char buf[128];
sprintf(buf, "V3 int %d: pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n", irq,
pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
v3_readb(V3_LB_ISTAT));
printascii(buf);
v3_writeb(V3_LB_ISTAT, 0);
__raw_writel(3, SC_PCI);
/*
* If the instruction being executed was a read,
* make it look like it read all-ones.
*/
if ((instr & 0x0c100000) == 0x04100000) {
int reg = (instr >> 16) & 15;
sprintf(buf, " reg%d = %08lx\n", reg, regs->uregs[reg]);
printascii(buf);
}
}
static struct irqaction v3_int = {
name: "V3",
handler: v3_irq,
};
static struct irqaction v3_int2 = {
name: "V3TM",
handler: v3_irq,
};
extern int (*external_fault)(unsigned long addr, struct pt_regs *regs);
/*
* V3_LB_BASE? - local bus address
* V3_LB_MAP? - pci bus address
*/
void __init pci_v3_init(void *sysdata)
{
unsigned int pci_cmd;
unsigned long flags;
/*
* Hook in our fault handler for PCI errors
*/
external_fault = v3_fault;
spin_lock_irqsave(&v3_lock, flags);
/*
* Setup window 0 - PCI non-prefetchable memory
* Local: 0x40000000 Bus: 0x00000000 Size: 256MB
*/
v3_writel(V3_LB_BASE0, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE) |
V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_ENABLE);
v3_writew(V3_LB_MAP0, v3_addr_to_lb_map(PCI_BUS_NONMEM_START) |
V3_LB_MAP_TYPE_MEM);
/*
* Setup window 1 - PCI prefetchable memory
* Local: 0x50000000 Bus: 0x10000000 Size: 256MB
*/
v3_writel(V3_LB_BASE1, v3_addr_to_lb_base(PHYS_PCI_MEM_BASE + SZ_256M) |
V3_LB_BASE_ADR_SIZE_256MB | V3_LB_BASE_PREFETCH |
V3_LB_BASE_ENABLE);
v3_writew(V3_LB_MAP1, v3_addr_to_lb_map(PCI_BUS_PREMEM_START) |
V3_LB_MAP_TYPE_MEM_MULTIPLE);
/*
* Setup window 2 - PCI IO
*/
v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(PHYS_PCI_IO_BASE) |
V3_LB_BASE_ENABLE);
v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0));
spin_unlock_irqrestore(&v3_lock, flags);
pci_scan_bus(0, &pci_v3_ops, sysdata);
pci_cmd = PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
v3_writew(V3_PCI_CMD, pci_cmd);
/*
* Clear any error conditions.
*/
__raw_writel(3, SC_PCI);
v3_writew(V3_LB_CFG, v3_readw(V3_LB_CFG) | (1 << 10));
v3_writeb(V3_LB_ISTAT, 0);
v3_writeb(V3_LB_IMASK, 0x68);
printk("LB_CFG: %04x LB_ISTAT: %02x LB_IMASK: %02x\n",
v3_readw(V3_LB_CFG),
v3_readb(V3_LB_ISTAT),
v3_readb(V3_LB_IMASK));
setup_arm_irq(IRQ_V3INT, &v3_int);
// setup_arm_irq(IRQ_LBUSTIMEOUT, &v3_int2);
}
--- NEW FILE ---
/*
* linux/arch/arm/mach-integrator/time.c
*
* Copyright (C) 2000-2001 Deep Blue Solutions
*
* 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/sched.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/io.h>
#define RTC_DR (IO_ADDRESS(INTEGRATOR_RTC_BASE) + 0)
#define RTC_MR (IO_ADDRESS(INTEGRATOR_RTC_BASE) + 4)
#define RTC_STAT (IO_ADDRESS(INTEGRATOR_RTC_BASE) + 8)
#define RTC_EOI (IO_ADDRESS(INTEGRATOR_RTC_BASE) + 8)
#define RTC_LR (IO_ADDRESS(INTEGRATOR_RTC_BASE) + 12)
#define RTC_CR (IO_ADDRESS(INTEGRATOR_RTC_BASE) + 16)
#define RTC_CR_MIE 0x00000001
extern int (*set_rtc)(void);
static int integrator_set_rtc(void)
{
__raw_writel(xtime.tv_sec, RTC_LR);
return 1;
}
static int integrator_rtc_init(void)
{
__raw_writel(0, RTC_CR);
__raw_writel(0, RTC_EOI);
xtime.tv_sec = __raw_readl(RTC_DR);
set_rtc = integrator_set_rtc;
return 0;
}
__initcall(integrator_rtc_init);
|