Commit 61f8a05d authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] visws: core

Patch from Andrey Panin <pazke@orbita1.ru>

This patch contains core support for visws subarch.
parent e6a88220
......@@ -92,7 +92,6 @@ extern void dmi_scan_machine(void);
extern int root_mountflags;
extern char _text, _etext, _edata, _end;
extern int blk_nohighio;
void __init visws_get_board_type_and_rev(void);
unsigned long saved_videomode;
......
......@@ -4,8 +4,7 @@
EXTRA_CFLAGS += -I../kernel
obj-y := setup.o traps.o
obj-y := setup.o traps.o reboot.o
obj-$(CONFIG_PCI) += pci-visws.o
obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o
obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o
#include <linux/mm.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/config.h>
#include <linux/bootmem.h>
#include <linux/smp_lock.h>
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <asm/smp.h>
#include <asm/mtrr.h>
#include <asm/apic.h>
#include <asm/mpspec.h>
#include <asm/pgalloc.h>
#include <asm/io.h>
#include "cobalt.h"
#include "mach_apic.h"
/* Have we found an MP table */
int smp_found_config;
......@@ -43,25 +41,84 @@ unsigned long mp_lapic_addr;
/* Processor that is doing the boot up */
unsigned int boot_cpu_physical_apicid = -1U;
unsigned int boot_cpu_logical_apicid = -1U;
/* Internal processor count */
static unsigned int num_processors;
/* Bitmask of physically existing CPUs */
unsigned long phys_cpu_present_map;
u8 raw_phys_apicid[NR_CPUS] = { [0 ... NR_CPUS - 1] = BAD_APICID };
/*
* The Visual Workstation is Intel MP compliant in the hardware
* sense, but it doesn't have a BIOS(-configuration table).
* No problem for Linux.
*/
void __init MP_processor_info (struct mpc_config_processor *m)
{
int ver, logical_apicid;
if (!(m->mpc_cpuflag & CPU_ENABLED))
return;
logical_apicid = m->mpc_apicid;
printk(KERN_INFO "%sCPU #%d %ld:%ld APIC version %d\n",
m->mpc_cpuflag & CPU_BOOTPROCESSOR ? "Bootup " : "",
m->mpc_apicid,
(m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8,
(m->mpc_cpufeature & CPU_MODEL_MASK) >> 4,
m->mpc_apicver);
if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
boot_cpu_physical_apicid = m->mpc_apicid;
boot_cpu_logical_apicid = logical_apicid;
}
num_processors++;
if (m->mpc_apicid > MAX_APICS) {
printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
m->mpc_apicid, MAX_APICS);
--num_processors;
return;
}
ver = m->mpc_apicver;
phys_cpu_present_map |= apicid_to_cpu_present(m->mpc_apicid);
/*
* Validate version
*/
if (ver == 0x0) {
printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! "
"fixing up to 0x10. (tell your hw vendor)\n",
m->mpc_apicid);
ver = 0x10;
}
apic_version[m->mpc_apicid] = ver;
raw_phys_apicid[num_processors - 1] = m->mpc_apicid;
}
void __init find_smp_config(void)
{
smp_found_config = 1;
struct mpc_config_processor *mp = phys_to_virt(CO_CPU_TAB_PHYS);
unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS));
phys_cpu_present_map |= 2; /* or in id 1 */
apic_version[1] |= 0x10; /* integrated APIC */
apic_version[0] |= 0x10;
if (ncpus > CO_CPU_MAX) {
printk(KERN_WARNING "find_visws_smp: got cpu count of %d at %p\n",
ncpus, mp);
ncpus = CO_CPU_MAX;
}
smp_found_config = 1;
while (ncpus--)
MP_processor_info(mp++);
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
}
void __init get_smp_config (void)
{
}
#include <linux/smp.h>
#include <linux/delay.h>
#include <linux/platform.h>
#include <asm/io.h>
#include "piix4.h"
void (*pm_power_off)(void);
int reboot_thru_bios;
int reboot_smp;
void machine_restart(char * __unused)
{
#ifdef CONFIG_SMP
smp_send_stop();
#endif
/*
* Visual Workstations restart after this
* register is poked on the PIIX4
*/
outb(PIIX4_RESET_VAL, PIIX4_RESET_PORT);
}
void machine_power_off(void)
{
unsigned short pm_status;
extern unsigned int pci_bus0;
while ((pm_status = inw(PMSTS_PORT)) & 0x100)
outw(pm_status, PMSTS_PORT);
outw(PM_SUSPEND_ENABLE, PMCNTRL_PORT);
mdelay(10);
#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
(0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
outl(PCI_CONF1_ADDRESS(pci_bus0, SPECIAL_DEV, SPECIAL_REG), 0xCF8);
outl(PIIX_SPECIAL_STOP, 0xCFC);
}
void machine_halt(void)
{
}
......@@ -9,67 +9,26 @@
#include <linux/interrupt.h>
#include <asm/fixmap.h>
#include <asm/cobalt.h>
#include <asm/arch_hooks.h>
#include <asm/io.h>
#include "cobalt.h"
#include "piix4.h"
char visws_board_type = -1;
char visws_board_rev = -1;
#define PIIX_PM_START 0x0F80
#define SIO_GPIO_START 0x0FC0
#define SIO_PM_START 0x0FC8
#define PMBASE PIIX_PM_START
#define GPIREG0 (PMBASE+0x30)
#define GPIREG(x) (GPIREG0+((x)/8))
#define PIIX_GPI_BD_ID1 18
#define PIIX_GPI_BD_REG GPIREG(PIIX_GPI_BD_ID1)
#define PIIX_GPI_BD_SHIFT (PIIX_GPI_BD_ID1 % 8)
#define SIO_INDEX 0x2e
#define SIO_DATA 0x2f
#define SIO_DEV_SEL 0x7
#define SIO_DEV_ENB 0x30
#define SIO_DEV_MSB 0x60
#define SIO_DEV_LSB 0x61
#define SIO_GP_DEV 0x7
#define SIO_GP_BASE SIO_GPIO_START
#define SIO_GP_MSB (SIO_GP_BASE>>8)
#define SIO_GP_LSB (SIO_GP_BASE&0xff)
#define SIO_GP_DATA1 (SIO_GP_BASE+0)
#define SIO_PM_DEV 0x8
#define SIO_PM_BASE SIO_PM_START
#define SIO_PM_MSB (SIO_PM_BASE>>8)
#define SIO_PM_LSB (SIO_PM_BASE&0xff)
#define SIO_PM_INDEX (SIO_PM_BASE+0)
#define SIO_PM_DATA (SIO_PM_BASE+1)
#define SIO_PM_FER2 0x1
#define SIO_PM_GP_EN 0x80
void __init visws_get_board_type_and_rev(void)
{
int raw;
visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
>> PIIX_GPI_BD_SHIFT;
/*
* Get Board rev.
* First, we have to initialize the 307 part to allow us access
* to the GPIO registers. Let's map them at 0x0fc0 which is right
* after the PIIX4 PM section.
*/
/*
* Get Board rev.
* First, we have to initialize the 307 part to allow us access
* to the GPIO registers. Let's map them at 0x0fc0 which is right
* after the PIIX4 PM section.
*/
outb_p(SIO_DEV_SEL, SIO_INDEX);
outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */
......@@ -82,11 +41,11 @@ void __init visws_get_board_type_and_rev(void)
outb_p(SIO_DEV_ENB, SIO_INDEX);
outb_p(1, SIO_DATA); /* Enable GPIO registers. */
/*
* Now, we have to map the power management section to write
* a bit which enables access to the GPIO registers.
* What lunatic came up with this shit?
*/
/*
* Now, we have to map the power management section to write
* a bit which enables access to the GPIO registers.
* What lunatic came up with this shit?
*/
outb_p(SIO_DEV_SEL, SIO_INDEX);
outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */
......@@ -99,18 +58,18 @@ void __init visws_get_board_type_and_rev(void)
outb_p(SIO_DEV_ENB, SIO_INDEX);
outb_p(1, SIO_DATA); /* Enable PM registers. */
/*
* Now, write the PM register which enables the GPIO registers.
*/
/*
* Now, write the PM register which enables the GPIO registers.
*/
outb_p(SIO_PM_FER2, SIO_PM_INDEX);
outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
/*
* Now, initialize the GPIO registers.
* We want them all to be inputs which is the
* power on default, so let's leave them alone.
* So, let's just read the board rev!
*/
/*
* Now, initialize the GPIO registers.
* We want them all to be inputs which is the
* power on default, so let's leave them alone.
* So, let's just read the board rev!
*/
raw = inb_p(SIO_GP_DATA1);
raw &= 0x7f; /* 7 bits of valid board revision ID. */
......@@ -128,10 +87,10 @@ void __init visws_get_board_type_and_rev(void)
visws_board_rev = raw;
}
printk(KERN_INFO "Silicon Graphics %s (rev %d)\n",
visws_board_type == VISWS_320 ? "320" :
printk(KERN_INFO "Silicon Graphics Visual Workstation %s (rev %d) detected\n",
(visws_board_type == VISWS_320 ? "320" :
(visws_board_type == VISWS_540 ? "540" :
"unknown"), visws_board_rev);
"unknown")), visws_board_rev);
}
void __init pre_intr_init_hook(void)
......@@ -150,11 +109,16 @@ void __init pre_setup_arch_hook()
{
visws_get_board_type_and_rev();
}
static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
static struct irqaction irq0 = {
.handler = timer_interrupt,
.flags = SA_INTERRUPT,
.name = "timer",
};
void __init time_init_hook(void)
{
printk("Starting Cobalt Timer system clock\n");
printk(KERN_INFO "Starting Cobalt Timer system clock\n");
/* Set the countdown value */
co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
......@@ -166,5 +130,5 @@ void __init time_init_hook(void)
co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
/* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */
setup_irq(CO_IRQ_TIMER, &irq0);
setup_irq(0, &irq0);
}
......@@ -3,132 +3,68 @@
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/highmem.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/atomic.h>
#include <asm/debugreg.h>
#include <asm/desc.h>
#include <asm/i387.h>
#include <asm/smp.h>
#include <asm/pgalloc.h>
#include <asm/arch_hooks.h>
#include <asm/apic.h>
#include "cobalt.h"
#include "lithium.h"
#ifdef CONFIG_X86_VISWS_APIC
#include <asm/fixmap.h>
#include <asm/cobalt.h>
#include <asm/lithium.h>
#endif
#ifdef CONFIG_X86_VISWS_APIC
/*
* On Rev 005 motherboards legacy device interrupt lines are wired directly
* to Lithium from the 307. But the PROM leaves the interrupt type of each
* 307 logical device set appropriate for the 8259. Later we'll actually use
* the 8259, but for now we have to flip the interrupt types to
* level triggered, active lo as required by Lithium.
*/
#define REG 0x2e /* The register to read/write */
#define DEV 0x07 /* Register: Logical device select */
#define VAL 0x2f /* The value to read/write */
static void
superio_outb(int dev, int reg, int val)
{
outb(DEV, REG);
outb(dev, VAL);
outb(reg, REG);
outb(val, VAL);
}
#define A01234 (LI_INTA_0 | LI_INTA_1 | LI_INTA_2 | LI_INTA_3 | LI_INTA_4)
#define BCD (LI_INTB | LI_INTC | LI_INTD)
#define ALLDEVS (A01234 | BCD)
static int __attribute__ ((unused))
superio_inb(int dev, int reg)
static __init void lithium_init(void)
{
outb(DEV, REG);
outb(dev, VAL);
outb(reg, REG);
return inb(VAL);
}
#define FLOP 3 /* floppy logical device */
#define PPORT 4 /* parallel logical device */
#define UART5 5 /* uart2 logical device (not wired up) */
#define UART6 6 /* uart1 logical device (THIS is the serial port!) */
#define IDEST 0x70 /* int. destination (which 307 IRQ line) reg. */
#define ITYPE 0x71 /* interrupt type register */
/* interrupt type bits */
#define LEVEL 0x01 /* bit 0, 0 == edge triggered */
#define ACTHI 0x02 /* bit 1, 0 == active lo */
set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
static __init void
superio_init(void)
{
if (visws_board_type == VISWS_320 && visws_board_rev == 5) {
superio_outb(UART6, IDEST, 0); /* 0 means no intr propagated */
printk("SGI 320 rev 5: disabling 307 uart1 interrupt\n");
if ((li_pcia_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
(li_pcia_read16(PCI_DEVICE_ID) != PCI_VENDOR_ID_SGI_LITHIUM)) {
printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'A');
panic("This machine is not SGI Visual Workstation 320/540");
}
}
static __init void
lithium_init(void)
{
set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
printk("Lithium PCI Bridge A, Bus Number: %d\n",
li_pcia_read16(LI_PCI_BUSNUM) & 0xff);
set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
printk("Lithium PCI Bridge B (PIIX4), Bus Number: %d\n",
li_pcib_read16(LI_PCI_BUSNUM) & 0xff);
if ((li_pcib_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
(li_pcib_read16(PCI_DEVICE_ID) != PCI_VENDOR_ID_SGI_LITHIUM)) {
printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'B');
panic("This machine is not SGI Visual Workstation 320/540");
}
/* XXX blindly enables all interrupts */
li_pcia_write16(LI_PCI_INTEN, 0xffff);
li_pcib_write16(LI_PCI_INTEN, 0xffff);
li_pcia_write16(LI_PCI_INTEN, ALLDEVS);
li_pcib_write16(LI_PCI_INTEN, ALLDEVS);
}
static __init void
cobalt_init(void)
static __init void cobalt_init(void)
{
/*
* On normal SMP PC this is used only with SMP, but we have to
* use it and set it up here to start the Cobalt clock
*/
set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
printk("Local APIC ID %lx\n", apic_read(APIC_ID));
printk("Local APIC Version %lx\n", apic_read(APIC_LVR));
setup_local_APIC();
printk(KERN_INFO "Local APIC Version %#lx, ID %#lx\n",
apic_read(APIC_LVR), apic_read(APIC_ID));
set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV));
set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
printk("Cobalt APIC ID %lx\n", co_apic_read(CO_APIC_ID));
printk(KERN_INFO "Cobalt Revision %#lx, APIC ID %#lx\n",
co_cpu_read(CO_CPU_REV), co_apic_read(CO_APIC_ID));
/* Enable Cobalt APIC being careful to NOT change the ID! */
co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID)|CO_APIC_ENABLE);
co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID) | CO_APIC_ENABLE);
printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID));
printk(KERN_INFO "Cobalt APIC enabled: ID reg %#lx\n",
co_apic_read(CO_APIC_ID));
}
#endif
void __init trap_init_hook()
void __init trap_init_hook(void)
{
#ifdef CONFIG_X86_VISWS_APIC
superio_init();
lithium_init();
cobalt_init();
#endif
}
This diff is collapsed.
/* defines for inline arch setup functions */
#include <asm/fixmap.h>
#include <asm/cobalt.h>
#include "cobalt.h"
static inline void do_timer_interrupt_hook(struct pt_regs *regs)
{
......
......@@ -47,18 +47,8 @@
#define TIMER_IRQ 0
/*
* 16 8259A IRQ's, 208 potential APIC interrupt sources.
* Right now the APIC is mostly only used for SMP.
* 256 vectors is an architectural limit. (we can have
* more than 256 devices theoretically, but they will
* have to use shared interrupts)
* Since vectors 0x00-0x1f are used/reserved for the CPU,
* the usable vector space is 0x20-0xff (224 vectors)
*
*/
#ifdef CONFIG_X86_IO_APIC
#define NR_IRQS 224
#else
#define NR_IRQS 16
#endif
#endif /* _ASM_IRQ_VECTORS_H */
......@@ -3,35 +3,47 @@
* This is included late in kernel/setup.c so that it can make use of all of
* the static functions. */
#define MB (1024 * 1024)
unsigned long sgivwfb_mem_phys;
unsigned long sgivwfb_mem_size;
long long mem_size __initdata = 0;
static inline char * __init machine_specific_memory_setup(void)
{
char *who;
long long gfx_mem_size = 8 * MB;
mem_size = ALT_MEM_K;
who = "BIOS-e820";
if (!mem_size) {
printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
mem_size = 128 * MB;
}
/*
* Try to copy the BIOS-supplied E820-map.
*
* Otherwise fake a memory map; one section from 0k->640k,
* the next section from 1mb->appropriate_mem_k
* this hardcodes the graphics memory to 8 MB
* it really should be sized dynamically (or at least
* set as a boot param)
*/
sanitize_e820_map(E820_MAP, &E820_MAP_NR);
if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
unsigned long mem_size;
/* compare results from other methods and take the greater */
if (ALT_MEM_K < EXT_MEM_K) {
mem_size = EXT_MEM_K;
who = "BIOS-88";
} else {
mem_size = ALT_MEM_K;
who = "BIOS-e801";
}
e820.nr_map = 0;
add_memory_region(0, LOWMEMSIZE(), E820_RAM);
add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
}
return who;
if (!sgivwfb_mem_size) {
printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
sgivwfb_mem_size = 8 * MB;
}
/*
* Trim to nearest MB
*/
sgivwfb_mem_size &= ~((1 << 20) - 1);
sgivwfb_mem_phys = mem_size - gfx_mem_size;
add_memory_region(0, LOWMEMSIZE(), E820_RAM);
add_memory_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
add_memory_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
return "PROM";
/* Remove gcc warnings */
(void) sanitize_e820_map(NULL, NULL);
(void) copy_e820_map(NULL, 0);
}
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