Skip to content
/ linux Public
forked from torvalds/linux

Commit

Permalink
[MIPS] RM: Collected changes
Browse files Browse the repository at this point in the history
- EISA support for non PCI RMs (RM200 and RM400-xxx). The major part
  is the splitting of the EISA and onboard ISA of the RM200, which
  makes the EISA bus on the RM200 look like on other RMs.
- 64bit kernel support
- system type detection is now common for big and little endian
- moved sniprom code to arch/mips/fw
- added call_o32 function to arch/mips/fw/lib, which uses a private
  stack for calling prom functions
- fix problem with ISA interrupts, which makes using PIT clockevent
  possible

Signed-off-by: Thomas Bogendoerfer <[email protected]>
Signed-off-by: Ralf Baechle <[email protected]>
  • Loading branch information
tsbogend authored and ralfbaechle committed Jan 29, 2008
1 parent 237cfee commit 231a35d
Show file tree
Hide file tree
Showing 17 changed files with 878 additions and 338 deletions.
4 changes: 4 additions & 0 deletions arch/mips/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,7 @@ config SNI_RM
bool "SNI RM200/300/400"
select ARC if CPU_LITTLE_ENDIAN
select ARC32 if CPU_LITTLE_ENDIAN
select SNIPROM if CPU_BIG_ENDIAN
select ARCH_MAY_HAVE_PC_FDC
select BOOT_ELF32
select CEVT_R4K
Expand Down Expand Up @@ -1003,6 +1004,9 @@ config DEFAULT_SGI_PARTITION
config ARC32
bool

config SNIPROM
bool

config BOOT_ELF32
bool

Expand Down
2 changes: 2 additions & 0 deletions arch/mips/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ endif
#
libs-$(CONFIG_ARC) += arch/mips/fw/arc/
libs-$(CONFIG_CFE) += arch/mips/fw/cfe/
libs-$(CONFIG_SNIPROM) += arch/mips/fw/sni/
libs-y += arch/mips/fw/lib/
libs-$(CONFIG_SIBYTE_CFE) += arch/mips/sibyte/cfe/

#
Expand Down
5 changes: 5 additions & 0 deletions arch/mips/fw/lib/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
# Makefile for generic prom monitor library routines under Linux.
#

lib-$(CONFIG_64BIT) += call_o32.o
97 changes: 97 additions & 0 deletions arch/mips/fw/lib/call_o32.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* arch/mips/dec/prom/call_o32.S
*
* O32 interface for the 64 (or N32) ABI.
*
* Copyright (C) 2002 Maciej W. Rozycki
*
* 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 <asm/asm.h>
#include <asm/regdef.h>

/* Maximum number of arguments supported. Must be even! */
#define O32_ARGC 32
/* Number of static registers we save. */
#define O32_STATC 11
/* Frame size for static register */
#define O32_FRAMESZ (SZREG * O32_STATC)
/* Frame size on new stack */
#define O32_FRAMESZ_NEW (SZREG + 4 * O32_ARGC)

.text

/*
* O32 function call dispatcher, for interfacing 32-bit ROM routines.
*
* The standard 64 (N32) calling sequence is supported, with a0
* holding a function pointer, a1 a new stack pointer, a2-a7 -- its
* first six arguments and the stack -- remaining ones (up to O32_ARGC,
* including a2-a7). Static registers, gp and fp are preserved, v0 holds
* a result. This code relies on the called o32 function for sp and ra
* restoration and this dispatcher has to be placed in a KSEGx (or KUSEG)
* address space. Any pointers passed have to point to addresses within
* one of these spaces as well.
*/
NESTED(call_o32, O32_FRAMESZ, ra)
REG_SUBU sp,O32_FRAMESZ

REG_S ra,O32_FRAMESZ-1*SZREG(sp)
REG_S fp,O32_FRAMESZ-2*SZREG(sp)
REG_S gp,O32_FRAMESZ-3*SZREG(sp)
REG_S s7,O32_FRAMESZ-4*SZREG(sp)
REG_S s6,O32_FRAMESZ-5*SZREG(sp)
REG_S s5,O32_FRAMESZ-6*SZREG(sp)
REG_S s4,O32_FRAMESZ-7*SZREG(sp)
REG_S s3,O32_FRAMESZ-8*SZREG(sp)
REG_S s2,O32_FRAMESZ-9*SZREG(sp)
REG_S s1,O32_FRAMESZ-10*SZREG(sp)
REG_S s0,O32_FRAMESZ-11*SZREG(sp)

move jp,a0
REG_SUBU s0,a1,O32_FRAMESZ_NEW
REG_S sp,O32_FRAMESZ_NEW-1*SZREG(s0)

sll a0,a2,zero
sll a1,a3,zero
sll a2,a4,zero
sll a3,a5,zero
sw a6,0x10(s0)
sw a7,0x14(s0)

PTR_LA t0,O32_FRAMESZ(sp)
PTR_LA t1,0x18(s0)
li t2,O32_ARGC-6
1:
lw t3,(t0)
REG_ADDU t0,SZREG
sw t3,(t1)
REG_SUBU t2,1
REG_ADDU t1,4
bnez t2,1b

move sp,s0

jalr jp

REG_L sp,O32_FRAMESZ_NEW-1*SZREG(sp)

REG_L s0,O32_FRAMESZ-11*SZREG(sp)
REG_L s1,O32_FRAMESZ-10*SZREG(sp)
REG_L s2,O32_FRAMESZ-9*SZREG(sp)
REG_L s3,O32_FRAMESZ-8*SZREG(sp)
REG_L s4,O32_FRAMESZ-7*SZREG(sp)
REG_L s5,O32_FRAMESZ-6*SZREG(sp)
REG_L s6,O32_FRAMESZ-5*SZREG(sp)
REG_L s7,O32_FRAMESZ-4*SZREG(sp)
REG_L gp,O32_FRAMESZ-3*SZREG(sp)
REG_L fp,O32_FRAMESZ-2*SZREG(sp)
REG_L ra,O32_FRAMESZ-1*SZREG(sp)

REG_ADDU sp,O32_FRAMESZ
jr ra
END(call_o32)
5 changes: 5 additions & 0 deletions arch/mips/fw/sni/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
# Makefile for the SNI prom monitor routines under Linux.
#

lib-$(CONFIG_SNIPROM) += sniprom.o
151 changes: 151 additions & 0 deletions arch/mips/fw/sni/sniprom.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* Big Endian PROM code for SNI RM machines
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2005-2006 Florian Lohoff ([email protected])
* Copyright (C) 2005-2006 Thomas Bogendoerfer ([email protected])
*/

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/console.h>

#include <asm/addrspace.h>
#include <asm/sni.h>
#include <asm/mipsprom.h>
#include <asm/mipsregs.h>
#include <asm/bootinfo.h>

/* special SNI prom calls */
/*
* This does not exist in all proms - SINIX compares
* the prom env variable "version" against "2.0008"
* or greater. If lesser it tries to probe interesting
* registers
*/
#define PROM_GET_MEMCONF 58
#define PROM_GET_HWCONF 61

#define PROM_VEC (u64 *)CKSEG1ADDR(0x1fc00000)
#define PROM_ENTRY(x) (PROM_VEC + (x))

#define ___prom_putchar ((int *(*)(int))PROM_ENTRY(PROM_PUTCHAR))
#define ___prom_getenv ((char *(*)(char *))PROM_ENTRY(PROM_GETENV))
#define ___prom_get_memconf ((void (*)(void *))PROM_ENTRY(PROM_GET_MEMCONF))
#define ___prom_get_hwconf ((u32 (*)(void))PROM_ENTRY(PROM_GET_HWCONF))

#ifdef CONFIG_64BIT

static u8 o32_stk[16384];
#define O32_STK &o32_stk[sizeof(o32_stk)]

#define __PROM_O32(fun, arg) fun arg __asm__(#fun); \
__asm__(#fun " = call_o32")

int __PROM_O32(__prom_putchar, (int *(*)(int), void *, int));
char *__PROM_O32(__prom_getenv, (char *(*)(char *), void *, char *));
void __PROM_O32(__prom_get_memconf, (void (*)(void *), void *, void *));
u32 __PROM_O32(__prom_get_hwconf, (u32 (*)(void), void *));

#define _prom_putchar(x) __prom_putchar(___prom_putchar, O32_STK, x)
#define _prom_getenv(x) __prom_getenv(___prom_getenv, O32_STK, x)
#define _prom_get_memconf(x) __prom_get_memconf(___prom_get_memconf, O32_STK, x)
#define _prom_get_hwconf() __prom_get_hwconf(___prom_get_hwconf, O32_STK)

#else
#define _prom_putchar(x) ___prom_putchar(x)
#define _prom_getenv(x) ___prom_getenv(x)
#define _prom_get_memconf(x) ___prom_get_memconf(x)
#define _prom_get_hwconf(x) ___prom_get_hwconf(x)
#endif

void prom_putchar(char c)
{
_prom_putchar(c);
}


char *prom_getenv(char *s)
{
return _prom_getenv(s);
}

void *prom_get_hwconf(void)
{
u32 hwconf = _prom_get_hwconf();

if (hwconf == 0xffffffff)
return NULL;

return (void *)CKSEG1ADDR(hwconf);
}

void __init prom_free_prom_memory(void)
{
}

/*
* /proc/cpuinfo system type
*
*/
char *system_type = "Unknown";
const char *get_system_type(void)
{
return system_type;
}

static void __init sni_mem_init(void)
{
int i, memsize;
struct membank {
u32 size;
u32 base;
u32 size2;
u32 pad1;
u32 pad2;
} memconf[8];
int brd_type = *(unsigned char *)SNI_IDPROM_BRDTYPE;


/* MemSIZE from prom in 16MByte chunks */
memsize = *((unsigned char *) SNI_IDPROM_MEMSIZE) * 16;

pr_debug("IDProm memsize: %u MByte\n", memsize);

/* get memory bank layout from prom */
_prom_get_memconf(&memconf);

pr_debug("prom_get_mem_conf memory configuration:\n");
for (i = 0; i < 8 && memconf[i].size; i++) {
if (brd_type == SNI_BRD_PCI_TOWER ||
brd_type == SNI_BRD_PCI_TOWER_CPLUS) {
if (memconf[i].base >= 0x20000000 &&
memconf[i].base < 0x30000000)
memconf[i].base -= 0x20000000;
}
pr_debug("Bank%d: %08x @ %08x\n", i,
memconf[i].size, memconf[i].base);
add_memory_region(memconf[i].base, memconf[i].size,
BOOT_MEM_RAM);
}
}

void __init prom_init(void)
{
int argc = fw_arg0;
u32 *argv = (u32 *)CKSEG0ADDR(fw_arg1);
int i;

sni_mem_init();

/* copy prom cmdline parameters to kernel cmdline */
for (i = 1; i < argc; i++) {
strcat(arcs_cmdline, (char *)CKSEG0ADDR(argv[i]));
if (i < (argc - 1))
strcat(arcs_cmdline, " ");
}
}
2 changes: 1 addition & 1 deletion arch/mips/sni/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
#

obj-y += irq.o reset.o setup.o a20r.o rm200.o pcimt.o pcit.o time.o
obj-$(CONFIG_CPU_BIG_ENDIAN) += sniprom.o
obj-$(CONFIG_EISA) += eisa.o

EXTRA_CFLAGS += -Werror
13 changes: 11 additions & 2 deletions arch/mips/sni/a20r.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,19 @@ static struct resource sc26xx_rsrc[] = {
}
};

static unsigned int sc26xx_data[2] = {
/* DTR | RTS | DSR | CTS | DCD | RI */
(8 << 0) | (4 << 4) | (6 << 8) | (0 << 12) | (6 << 16) | (0 << 20),
(3 << 0) | (2 << 4) | (1 << 8) | (2 << 12) | (3 << 16) | (4 << 20)
};

static struct platform_device sc26xx_pdev = {
.name = "SC26xx",
.num_resources = ARRAY_SIZE(sc26xx_rsrc),
.resource = sc26xx_rsrc
.resource = sc26xx_rsrc,
.dev = {
.platform_data = sc26xx_data,
}
};

static u32 a20r_ack_hwint(void)
Expand Down Expand Up @@ -231,9 +240,9 @@ static int __init snirm_a20r_setup_devinit(void)
platform_device_register(&sc26xx_pdev);
platform_device_register(&a20r_serial8250_device);
platform_device_register(&a20r_ds1216_device);
sni_eisa_root_init();
break;
}

return 0;
}

Expand Down
50 changes: 50 additions & 0 deletions arch/mips/sni/eisa.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Virtual EISA root driver.
* Acts as a placeholder if we don't have a proper EISA bridge.
*
* (C) 2003 Marc Zyngier <[email protected]>
* modified for SNI usage by Thomas Bogendoerfer
*
* This code is released under the GPL version 2.
*/

#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/eisa.h>
#include <linux/init.h>

/* The default EISA device parent (virtual root device).
* Now use a platform device, since that's the obvious choice. */

static struct platform_device eisa_root_dev = {
.name = "eisa",
.id = 0,
};

static struct eisa_root_device eisa_bus_root = {
.dev = &eisa_root_dev.dev,
.bus_base_addr = 0,
.res = &ioport_resource,
.slots = EISA_MAX_SLOTS,
.dma_mask = 0xffffffff,
.force_probe = 1,
};

int __init sni_eisa_root_init(void)
{
int r;

r = platform_device_register(&eisa_root_dev);
if (!r)
return r;

eisa_root_dev.dev.driver_data = &eisa_bus_root;

if (eisa_root_register(&eisa_bus_root)) {
/* A real bridge may have been registered before
* us. So quietly unregister. */
platform_device_unregister(&eisa_root_dev);
return -1;
}
return 0;
}
4 changes: 2 additions & 2 deletions arch/mips/sni/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ static irqreturn_t sni_isa_irq_handler(int dummy, void *p)
if (unlikely(irq < 0))
return IRQ_NONE;

do_IRQ(irq);
generic_handle_irq(irq);
return IRQ_HANDLED;
}

struct irqaction sni_isa_irq = {
.handler = sni_isa_irq_handler,
.name = "ISA",
.flags = IRQF_SHARED
.flags = IRQF_SHARED | IRQF_DISABLED
};

/*
Expand Down
Loading

0 comments on commit 231a35d

Please sign in to comment.