rm200.c 4.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
/*
 * RM200 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>
#include <asm/irq_cpu.h>

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

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

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

static struct resource snirm_82596_rm200_rsrc[] = {
	{
		.start = 0xb8000000,
		.end   = 0xb80fffff,
		.flags = IORESOURCE_MEM
	},
	{
		.start = 0xbb000000,
		.end   = 0xbb000004,
		.flags = IORESOURCE_MEM
	},
	{
		.start = 0xbff00000,
		.end   = 0xbff00020,
		.flags = IORESOURCE_MEM
	},
	{
		.start = 27,
		.end   = 27,
		.flags = IORESOURCE_IRQ
	},
	{
		.flags = 0x00
	}
};

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

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

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

static int __init snirm_setup_devinit(void)
{
	if (sni_brd_type == SNI_BRD_RM200) {
		platform_device_register(&rm200_serial8250_device);
		platform_device_register(&snirm_82596_rm200_pdev);
		platform_device_register(&snirm_53c710_rm200_pdev);
	}
	return 0;
}

device_initcall(snirm_setup_devinit);


#define SNI_RM200_INT_STAT_REG  0xbc000000
#define SNI_RM200_INT_ENA_REG   0xbc080000

#define SNI_RM200_INT_START  24
#define SNI_RM200_INT_END    28

static void enable_rm200_irq(unsigned int irq)
{
	unsigned int mask = 1 << (irq - SNI_RM200_INT_START);

	*(volatile u8 *)SNI_RM200_INT_ENA_REG &= ~mask;
}

void disable_rm200_irq(unsigned int irq)
{
	unsigned int mask = 1 << (irq - SNI_RM200_INT_START);

	*(volatile u8 *)SNI_RM200_INT_ENA_REG |= mask;
}

void end_rm200_irq(unsigned int irq)
{
	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
		enable_rm200_irq(irq);
}

static struct irq_chip rm200_irq_type = {
	.typename = "RM200",
	.ack = disable_rm200_irq,
	.mask = disable_rm200_irq,
	.mask_ack = disable_rm200_irq,
	.unmask = enable_rm200_irq,
	.end = end_rm200_irq,
};

static void sni_rm200_hwint(void)
{
	u32 pending = read_c0_cause() & read_c0_status();
	u8 mask;
	u8 stat;
	int irq;

	if (pending & C_IRQ5)
		do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 7);
	else if (pending & C_IRQ0) {
		clear_c0_status (IE_IRQ0);
		mask = *(volatile u8 *)SNI_RM200_INT_ENA_REG ^ 0x1f;
		stat = *(volatile u8 *)SNI_RM200_INT_STAT_REG ^ 0x14;
		irq = ffs(stat & mask & 0x1f);

		if (likely(irq > 0))
			do_IRQ (irq + SNI_RM200_INT_START - 1);
		set_c0_status (IE_IRQ0);
	}
}

void __init sni_rm200_irq_init(void)
{
	int i;

	* (volatile u8 *)SNI_RM200_INT_ENA_REG = 0x1f;

	mips_cpu_irq_init();
	/* Actually we've got more interrupts to handle ...  */
	for (i = SNI_RM200_INT_START; i <= SNI_RM200_INT_END; i++)
		set_irq_chip(i, &rm200_irq_type);
	sni_hwint = sni_rm200_hwint;
	change_c0_status(ST0_IM, IE_IRQ0);
	setup_irq (SNI_RM200_INT_START + 0, &sni_isa_irq);
}

void sni_rm200_init(void)
{
	set_io_port_base(SNI_PORT_BASE + 0x02000000);
	ioport_resource.end += 0x02000000;
	ds1216_base = (volatile unsigned char *) SNI_DS1216_RM200_BASE;
	rtc_mips_get_time = ds1216_get_cmos_time;
	board_time_init = sni_cpu_time_init;
}