Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c066a32a authored by Thomas Bogendoerfer's avatar Thomas Bogendoerfer Committed by Ralf Baechle
Browse files

[MIPS] Support for several more SNI RM models.

parent 5759906c
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -726,15 +726,16 @@ config SNI_RM
	select BOOT_ELF32
	select DMA_NONCOHERENT
	select GENERIC_ISA_DMA
	select HAVE_STD_PC_SERIAL_PORT
	select HW_HAS_EISA
	select HW_HAS_PCI
	select IRQ_CPU
	select I8253
	select I8259
	select ISA
	select SWAP_IO_SPACE if CPU_BIG_ENDIAN
	select SYS_HAS_CPU_R4X00
	select SYS_HAS_CPU_R5000
	select SYS_HAS_CPU_R10000
	select R5000_CPU_SCACHE
	select SYS_SUPPORTS_32BIT_KERNEL
	select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
@@ -1066,7 +1067,7 @@ config BOOT_ELF32

config MIPS_L1_CACHE_SHIFT
	int
	default "4" if MACH_DECSTATION
	default "4" if MACH_DECSTATION || SNI_RM
	default "7" if SGI_IP27
	default "5"

+62 −4
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@
#include <asm/sni.h>

/*
 * Shortcuts ...
 * PCIMT Shortcuts ...
 */
#define SCSI	PCIMT_IRQ_SCSI
#define ETH	PCIMT_IRQ_ETHERNET
@@ -67,6 +67,50 @@ static char irq_tab_rm300d[8][5] __initdata = {
	{     0, INTD, INTA, INTB, INTC },	/* Slot 4 */
};

static char irq_tab_rm300e[5][5] __initdata = {
	/*       INTA  INTB  INTC  INTD */
	{     0,    0,    0,    0,    0 },	/* HOST bridge */
	{  SCSI, SCSI, SCSI, SCSI, SCSI },	/* SCSI */
	{     0, INTC, INTD, INTA, INTB },	/* Bridge/i960 */
	{     0, INTD, INTA, INTB, INTC },	/* Slot 1 */
	{     0, INTA, INTB, INTC, INTD },	/* Slot 2 */
};
#undef SCSI
#undef ETH
#undef INTA
#undef INTB
#undef INTC
#undef INTD


/*
 * PCIT Shortcuts ...
 */
#define SCSI0	PCIT_IRQ_SCSI0
#define SCSI1	PCIT_IRQ_SCSI1
#define ETH	PCIT_IRQ_ETHERNET
#define INTA	PCIT_IRQ_INTA
#define INTB	PCIT_IRQ_INTB
#define INTC	PCIT_IRQ_INTC
#define INTD	PCIT_IRQ_INTD

static char irq_tab_pcit[13][5] __initdata = {
	/*       INTA  INTB  INTC  INTD */
	{     0,     0,     0,     0,     0 },	/* HOST bridge */
	{ SCSI0, SCSI0, SCSI0, SCSI0, SCSI0 },	/* SCSI */
	{ SCSI1, SCSI1, SCSI1, SCSI1, SCSI1 },	/* SCSI */
	{   ETH,   ETH,   ETH,   ETH,   ETH },	/* Ethernet */
	{     0,  INTA,  INTB,  INTC,  INTD },	/* PCI-PCI bridge */
	{     0,     0,     0,     0,     0 },	/* Unused */
	{     0,     0,     0,     0,     0 },	/* Unused */
	{     0,     0,     0,     0,     0 },	/* Unused */
	{     0,  INTA,  INTB,  INTC,  INTD },	/* Slot 1 */
	{     0,  INTB,  INTC,  INTD,  INTA },	/* Slot 2 */
	{     0,  INTC,  INTD,  INTA,  INTB },	/* Slot 3 */
	{     0,  INTD,  INTA,  INTB,  INTC },	/* Slot 4 */
	{     0,  INTA,  INTB,  INTC,  INTD },	/* Slot 5 */
};

static inline int is_rm300_revd(void)
{
	unsigned char csmsr = *(volatile unsigned char *)PCIMT_CSMSR;
@@ -76,10 +120,24 @@ static inline int is_rm300_revd(void)

int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
	switch (sni_brd_type) {
	case SNI_BRD_PCI_TOWER:
	case SNI_BRD_PCI_TOWER_CPLUS:
	        return irq_tab_pcit[slot][pin];

	case SNI_BRD_PCI_MTOWER:
	        if (is_rm300_revd())
		        return irq_tab_rm300d[slot][pin];
	        /* fall through */

	case SNI_BRD_PCI_DESKTOP:
	        return irq_tab_rm200[slot][pin];

	case SNI_BRD_PCI_MTOWER_CPLUS:
	        return irq_tab_rm300e[slot][pin];
	}

	return 0;
}

/* Do platform specific device initialization at pci_enable_device() time */
+76 −1
Original line number Diff line number Diff line
@@ -83,7 +83,82 @@ static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg,
	return 0;
}

struct pci_ops sni_pci_ops = {
struct pci_ops sni_pcimt_ops = {
	.read = pcimt_read,
	.write = pcimt_write,
};

static int pcit_set_config_address(unsigned int busno, unsigned int devfn, int reg)
{
	if ((devfn > 255) || (reg > 255) || (busno > 255))
		return PCIBIOS_BAD_REGISTER_NUMBER;

	outl ((1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), 0xcf8);
	return PCIBIOS_SUCCESSFUL;
}

static int pcit_read(struct pci_bus *bus, unsigned int devfn, int reg,
		      int size, u32 * val)
{
	int res;

	/*
	 * on bus 0 we need to check, whether there is a device answering
	 * for the devfn by doing a config write and checking the result. If
	 * we don't do it, we will get a data bus error
	 */
	if (bus->number == 0) {
		pcit_set_config_address (0, 0, 0x68);
		outl (inl (0xcfc) | 0xc0000000, 0xcfc);
		if ((res = pcit_set_config_address(0, devfn, 0)))
			return res;
		outl (0xffffffff, 0xcfc);
		pcit_set_config_address (0, 0, 0x68);
		if (inl(0xcfc) & 0x100000)
			return PCIBIOS_DEVICE_NOT_FOUND;
	}
	if ((res = pcit_set_config_address(bus->number, devfn, reg)))
		return res;

	switch (size) {
	case 1:
		*val = inb(PCIMT_CONFIG_DATA + (reg & 3));
		break;
	case 2:
		*val = inw(PCIMT_CONFIG_DATA + (reg & 2));
		break;
	case 4:
		*val = inl(PCIMT_CONFIG_DATA);
		break;
	}
	return 0;
}

static int pcit_write(struct pci_bus *bus, unsigned int devfn, int reg,
		       int size, u32 val)
{
	int res;

	if ((res = pcit_set_config_address(bus->number, devfn, reg)))
		return res;

	switch (size) {
	case 1:
		outb (val, PCIMT_CONFIG_DATA + (reg & 3));
		break;
	case 2:
		outw (val, PCIMT_CONFIG_DATA + (reg & 2));
		break;
	case 4:
		outl (val, PCIMT_CONFIG_DATA);
		break;
	}

	return 0;
}


struct pci_ops sni_pcit_ops = {
	.read = pcit_read,
	.write = pcit_write,
};
+1 −1
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
# Makefile for the SNI specific part of the kernel
#

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

EXTRA_AFLAGS := $(CFLAGS)

arch/mips/sni/a20r.c

0 → 100644
+227 −0
Original line number Diff line number Diff line
/*
 * A20R specific code
 *
 * 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) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
 */

#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>

#include <asm/sni.h>
#include <asm/time.h>
#include <asm/ds1216.h>

#define PORT(_base,_irq)				\
	{						\
		.iobase		= _base,		\
		.irq		= _irq,			\
		.uartclk	= 1843200,		\
		.iotype		= UPIO_PORT,		\
		.flags		= UPF_BOOT_AUTOCONF,	\
	}

static struct plat_serial8250_port a20r_data[] = {
	PORT(0x3f8, 4),
	PORT(0x2f8, 3),
	{ },
};

static struct platform_device a20r_serial8250_device = {
	.name			= "serial8250",
	.id			= PLAT8250_DEV_PLATFORM,
	.dev			= {
		.platform_data	= a20r_data,
	},
};

static struct resource snirm_82596_rsrc[] = {
	{
		.start = 0xb8000000,
		.end   = 0xb8000004,
		.flags = IORESOURCE_MEM
	},
	{
		.start = 0xb8010000,
		.end   = 0xb8010004,
		.flags = IORESOURCE_MEM
	},
	{
		.start = 0xbff00000,
		.end   = 0xbff00020,
		.flags = IORESOURCE_MEM
	},
	{
		.start = 22,
		.end   = 22,
		.flags = IORESOURCE_IRQ
	},
	{
		.flags = 0x01                /* 16bit mpu port access */
	}
};

static struct platform_device snirm_82596_pdev = {
	.name           = "snirm_82596",
	.num_resources  = ARRAY_SIZE(snirm_82596_rsrc),
	.resource       = snirm_82596_rsrc
};

static struct resource snirm_53c710_rsrc[] = {
	{
		.start = 0xb9000000,
		.end   = 0xb90fffff,
		.flags = IORESOURCE_MEM
	},
	{
		.start = 19,
		.end   = 19,
		.flags = IORESOURCE_IRQ
	}
};

static struct platform_device snirm_53c710_pdev = {
	.name           = "snirm_53c710",
	.num_resources  = ARRAY_SIZE(snirm_53c710_rsrc),
	.resource       = snirm_53c710_rsrc
};

static struct resource sc26xx_rsrc[] = {
	{
		.start = 0xbc070000,
		.end   = 0xbc0700ff,
		.flags = IORESOURCE_MEM
	},
	{
		.start = 20,
		.end   = 20,
		.flags = IORESOURCE_IRQ
	}
};

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

static u32 a20r_ack_hwint(void)
{
	u32 status = read_c0_status();

	write_c0_status (status | 0x00010000);
	asm volatile(
	"	.set	push			\n"
	"	.set	noat			\n"
	"	.set	noreorder		\n"
	"	lw	$1, 0(%0)		\n"
	"	sb	$0, 0(%1)		\n"
	"	sync				\n"
	"	lb	%1, 0(%1)		\n"
	"	b	1f			\n"
	"	ori	%1, $1, 2		\n"
	"	.align	8			\n"
	"1:					\n"
	"	nop				\n"
	"	sw	%1, 0(%0)		\n"
	"	sync				\n"
	"	li	%1, 0x20		\n"
	"2:					\n"
	"	nop				\n"
	"	bnez	%1,2b			\n"
	"	addiu	%1, -1			\n"
	"	sw	$1, 0(%0)		\n"
	"	sync				\n"
		".set   pop			\n"
	:
	: "Jr" (PCIMT_UCONF), "Jr" (0xbc000000));
	write_c0_status(status);

	return status;
}

static inline void unmask_a20r_irq(unsigned int irq)
{
	set_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE));
	irq_enable_hazard();
}

static inline void mask_a20r_irq(unsigned int irq)
{
	clear_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE));
	irq_disable_hazard();
}

static void end_a20r_irq(unsigned int irq)
{
	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
		a20r_ack_hwint();
		unmask_a20r_irq(irq);
	}
}

static struct irq_chip a20r_irq_type = {
	.typename	= "A20R",
	.ack		= mask_a20r_irq,
	.mask		= mask_a20r_irq,
	.mask_ack	= mask_a20r_irq,
	.unmask		= unmask_a20r_irq,
	.end		= end_a20r_irq,
};

/*
 * hwint 0 receive all interrupts
 */
static void a20r_hwint(void)
{
	u32 cause, status;
	int irq;

	clear_c0_status (IE_IRQ0);
	status = a20r_ack_hwint();
	cause = read_c0_cause();

	irq = ffs(((cause & status) >> 8) & 0xf8);
	if (likely(irq > 0))
		do_IRQ(SNI_A20R_IRQ_BASE + irq - 1);
	set_c0_status(IE_IRQ0);
}

void __init sni_a20r_irq_init(void)
{
	int i;

	for (i = SNI_A20R_IRQ_BASE + 2 ; i < SNI_A20R_IRQ_BASE + 8; i++)
		set_irq_chip(i, &a20r_irq_type);
	sni_hwint = a20r_hwint;
	change_c0_status(ST0_IM, IE_IRQ0);
	setup_irq (SNI_A20R_IRQ_BASE + 3, &sni_isa_irq);
}

void sni_a20r_init(void)
{
	ds1216_base = (volatile unsigned char *) SNI_DS1216_A20R_BASE;
	rtc_mips_get_time = ds1216_get_cmos_time;
}

static int __init snirm_a20r_setup_devinit(void)
{
	switch (sni_brd_type) {
	case SNI_BRD_TOWER_OASIC:
	case SNI_BRD_MINITOWER:
	        platform_device_register(&snirm_82596_pdev);
	        platform_device_register(&snirm_53c710_pdev);
	        platform_device_register(&sc26xx_pdev);
	        platform_device_register(&a20r_serial8250_device);
	        break;
	}

	return 0;
}

device_initcall(snirm_a20r_setup_devinit);
Loading