diff options
Diffstat (limited to 'arch/mips/loongson1')
| -rw-r--r-- | arch/mips/loongson1/Kconfig | 23 | ||||
| -rw-r--r-- | arch/mips/loongson1/Makefile | 11 | ||||
| -rw-r--r-- | arch/mips/loongson1/Platform | 7 | ||||
| -rw-r--r-- | arch/mips/loongson1/common/Makefile | 5 | ||||
| -rw-r--r-- | arch/mips/loongson1/common/clock.c | 28 | ||||
| -rw-r--r-- | arch/mips/loongson1/common/irq.c | 147 | ||||
| -rw-r--r-- | arch/mips/loongson1/common/platform.c | 129 | ||||
| -rw-r--r-- | arch/mips/loongson1/common/prom.c | 87 | ||||
| -rw-r--r-- | arch/mips/loongson1/common/reset.c | 46 | ||||
| -rw-r--r-- | arch/mips/loongson1/common/setup.c | 29 | ||||
| -rw-r--r-- | arch/mips/loongson1/ls1b/Makefile | 5 | ||||
| -rw-r--r-- | arch/mips/loongson1/ls1b/board.c | 30 | 
12 files changed, 547 insertions, 0 deletions
diff --git a/arch/mips/loongson1/Kconfig b/arch/mips/loongson1/Kconfig new file mode 100644 index 00000000000..e23c25d0996 --- /dev/null +++ b/arch/mips/loongson1/Kconfig @@ -0,0 +1,23 @@ +if MACH_LOONGSON1 + +choice +	prompt "Machine Type" + +config LOONGSON1_LS1B +	bool "Loongson LS1B board" +	select CEVT_R4K +	select CSRC_R4K +	select SYS_HAS_CPU_LOONGSON1B +	select DMA_NONCOHERENT +	select BOOT_ELF32 +	select IRQ_CPU +	select SYS_SUPPORTS_32BIT_KERNEL +	select SYS_SUPPORTS_LITTLE_ENDIAN +	select SYS_SUPPORTS_HIGHMEM +	select SYS_SUPPORTS_MIPS16 +	select SYS_HAS_EARLY_PRINTK +	select COMMON_CLK + +endchoice + +endif # MACH_LOONGSON1 diff --git a/arch/mips/loongson1/Makefile b/arch/mips/loongson1/Makefile new file mode 100644 index 00000000000..9719c75886f --- /dev/null +++ b/arch/mips/loongson1/Makefile @@ -0,0 +1,11 @@ +# +# Common code for all Loongson 1 based systems +# + +obj-$(CONFIG_MACH_LOONGSON1) += common/ + +# +# Loongson LS1B board +# + +obj-$(CONFIG_LOONGSON1_LS1B)  += ls1b/ diff --git a/arch/mips/loongson1/Platform b/arch/mips/loongson1/Platform new file mode 100644 index 00000000000..11863441dea --- /dev/null +++ b/arch/mips/loongson1/Platform @@ -0,0 +1,7 @@ +cflags-$(CONFIG_CPU_LOONGSON1)	+= \ +	$(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \ +	-Wa,-mips32r2 -Wa,--trap + +platform-$(CONFIG_MACH_LOONGSON1)	+= loongson1/ +cflags-$(CONFIG_MACH_LOONGSON1)		+= -I$(srctree)/arch/mips/include/asm/mach-loongson1 +load-$(CONFIG_LOONGSON1_LS1B)		+= 0xffffffff80100000 diff --git a/arch/mips/loongson1/common/Makefile b/arch/mips/loongson1/common/Makefile new file mode 100644 index 00000000000..b2797709ef5 --- /dev/null +++ b/arch/mips/loongson1/common/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for common code of loongson1 based machines. +# + +obj-y	+= clock.o irq.o platform.o prom.o reset.o setup.o diff --git a/arch/mips/loongson1/common/clock.c b/arch/mips/loongson1/common/clock.c new file mode 100644 index 00000000000..b4437f19c3d --- /dev/null +++ b/arch/mips/loongson1/common/clock.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> + * + * 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 <linux/clk.h> +#include <linux/err.h> +#include <asm/time.h> +#include <platform.h> + +void __init plat_time_init(void) +{ +	struct clk *clk; + +	/* Initialize LS1X clocks */ +	ls1x_clk_init(); + +	/* setup mips r4k timer */ +	clk = clk_get(NULL, "cpu"); +	if (IS_ERR(clk)) +		panic("unable to get cpu clock, err=%ld", PTR_ERR(clk)); + +	mips_hpt_frequency = clk_get_rate(clk) / 2; +} diff --git a/arch/mips/loongson1/common/irq.c b/arch/mips/loongson1/common/irq.c new file mode 100644 index 00000000000..455a7704a90 --- /dev/null +++ b/arch/mips/loongson1/common/irq.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> + * + * 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 <linux/interrupt.h> +#include <linux/irq.h> +#include <asm/irq_cpu.h> + +#include <loongson1.h> +#include <irq.h> + +#define LS1X_INTC_REG(n, x) \ +		((void __iomem *)KSEG1ADDR(LS1X_INTC_BASE + (n * 0x18) + (x))) + +#define LS1X_INTC_INTISR(n)		LS1X_INTC_REG(n, 0x0) +#define LS1X_INTC_INTIEN(n)		LS1X_INTC_REG(n, 0x4) +#define LS1X_INTC_INTSET(n)		LS1X_INTC_REG(n, 0x8) +#define LS1X_INTC_INTCLR(n)		LS1X_INTC_REG(n, 0xc) +#define LS1X_INTC_INTPOL(n)		LS1X_INTC_REG(n, 0x10) +#define LS1X_INTC_INTEDGE(n)		LS1X_INTC_REG(n, 0x14) + +static void ls1x_irq_ack(struct irq_data *d) +{ +	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; +	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; + +	__raw_writel(__raw_readl(LS1X_INTC_INTCLR(n)) +			| (1 << bit), LS1X_INTC_INTCLR(n)); +} + +static void ls1x_irq_mask(struct irq_data *d) +{ +	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; +	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; + +	__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) +			& ~(1 << bit), LS1X_INTC_INTIEN(n)); +} + +static void ls1x_irq_mask_ack(struct irq_data *d) +{ +	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; +	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; + +	__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) +			& ~(1 << bit), LS1X_INTC_INTIEN(n)); +	__raw_writel(__raw_readl(LS1X_INTC_INTCLR(n)) +			| (1 << bit), LS1X_INTC_INTCLR(n)); +} + +static void ls1x_irq_unmask(struct irq_data *d) +{ +	unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; +	unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; + +	__raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) +			| (1 << bit), LS1X_INTC_INTIEN(n)); +} + +static struct irq_chip ls1x_irq_chip = { +	.name		= "LS1X-INTC", +	.irq_ack	= ls1x_irq_ack, +	.irq_mask	= ls1x_irq_mask, +	.irq_mask_ack	= ls1x_irq_mask_ack, +	.irq_unmask	= ls1x_irq_unmask, +}; + +static void ls1x_irq_dispatch(int n) +{ +	u32 int_status, irq; + +	/* Get pending sources, masked by current enables */ +	int_status = __raw_readl(LS1X_INTC_INTISR(n)) & +			__raw_readl(LS1X_INTC_INTIEN(n)); + +	if (int_status) { +		irq = LS1X_IRQ(n, __ffs(int_status)); +		do_IRQ(irq); +	} +} + +asmlinkage void plat_irq_dispatch(void) +{ +	unsigned int pending; + +	pending = read_c0_cause() & read_c0_status() & ST0_IM; + +	if (pending & CAUSEF_IP7) +		do_IRQ(TIMER_IRQ); +	else if (pending & CAUSEF_IP2) +		ls1x_irq_dispatch(0); /* INT0 */ +	else if (pending & CAUSEF_IP3) +		ls1x_irq_dispatch(1); /* INT1 */ +	else if (pending & CAUSEF_IP4) +		ls1x_irq_dispatch(2); /* INT2 */ +	else if (pending & CAUSEF_IP5) +		ls1x_irq_dispatch(3); /* INT3 */ +	else if (pending & CAUSEF_IP6) +		ls1x_irq_dispatch(4); /* INT4 */ +	else +		spurious_interrupt(); + +} + +struct irqaction cascade_irqaction = { +	.handler = no_action, +	.name = "cascade", +	.flags = IRQF_NO_THREAD, +}; + +static void __init ls1x_irq_init(int base) +{ +	int n; + +	/* Disable interrupts and clear pending, +	 * setup all IRQs as high level triggered +	 */ +	for (n = 0; n < 4; n++) { +		__raw_writel(0x0, LS1X_INTC_INTIEN(n)); +		__raw_writel(0xffffffff, LS1X_INTC_INTCLR(n)); +		__raw_writel(0xffffffff, LS1X_INTC_INTPOL(n)); +		/* set DMA0, DMA1 and DMA2 to edge trigger */ +		__raw_writel(n ? 0x0 : 0xe000, LS1X_INTC_INTEDGE(n)); +	} + + +	for (n = base; n < LS1X_IRQS; n++) { +		irq_set_chip_and_handler(n, &ls1x_irq_chip, +					 handle_level_irq); +	} + +	setup_irq(INT0_IRQ, &cascade_irqaction); +	setup_irq(INT1_IRQ, &cascade_irqaction); +	setup_irq(INT2_IRQ, &cascade_irqaction); +	setup_irq(INT3_IRQ, &cascade_irqaction); +} + +void __init arch_init_irq(void) +{ +	mips_cpu_irq_init(); +	ls1x_irq_init(LS1X_IRQ_BASE); +} diff --git a/arch/mips/loongson1/common/platform.c b/arch/mips/loongson1/common/platform.c new file mode 100644 index 00000000000..fdf8cb5987a --- /dev/null +++ b/arch/mips/loongson1/common/platform.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> + * + * 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 <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/phy.h> +#include <linux/serial_8250.h> +#include <linux/stmmac.h> +#include <linux/usb/ehci_pdriver.h> +#include <asm-generic/sizes.h> + +#include <loongson1.h> + +#define LS1X_UART(_id)						\ +	{							\ +		.mapbase	= LS1X_UART ## _id ## _BASE,	\ +		.irq		= LS1X_UART ## _id ## _IRQ,	\ +		.iotype		= UPIO_MEM,			\ +		.flags		= UPF_IOREMAP | UPF_FIXED_TYPE, \ +		.type		= PORT_16550A,			\ +	} + +static struct plat_serial8250_port ls1x_serial8250_port[] = { +	LS1X_UART(0), +	LS1X_UART(1), +	LS1X_UART(2), +	LS1X_UART(3), +	{}, +}; + +struct platform_device ls1x_uart_device = { +	.name		= "serial8250", +	.id		= PLAT8250_DEV_PLATFORM, +	.dev		= { +		.platform_data = ls1x_serial8250_port, +	}, +}; + +void __init ls1x_serial_setup(struct platform_device *pdev) +{ +	struct clk *clk; +	struct plat_serial8250_port *p; + +	clk = clk_get(NULL, pdev->name); +	if (IS_ERR(clk)) +		panic("unable to get %s clock, err=%ld", +			pdev->name, PTR_ERR(clk)); + +	for (p = pdev->dev.platform_data; p->flags != 0; ++p) +		p->uartclk = clk_get_rate(clk); +} + +/* Synopsys Ethernet GMAC */ +static struct resource ls1x_eth0_resources[] = { +	[0] = { +		.start	= LS1X_GMAC0_BASE, +		.end	= LS1X_GMAC0_BASE + SZ_64K - 1, +		.flags	= IORESOURCE_MEM, +	}, +	[1] = { +		.name	= "macirq", +		.start	= LS1X_GMAC0_IRQ, +		.flags	= IORESOURCE_IRQ, +	}, +}; + +static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = { +	.phy_mask	= 0, +}; + +static struct plat_stmmacenet_data ls1x_eth_data = { +	.bus_id		= 0, +	.phy_addr	= -1, +	.mdio_bus_data	= &ls1x_mdio_bus_data, +	.has_gmac	= 1, +	.tx_coe		= 1, +}; + +struct platform_device ls1x_eth0_device = { +	.name		= "stmmaceth", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(ls1x_eth0_resources), +	.resource	= ls1x_eth0_resources, +	.dev		= { +		.platform_data = &ls1x_eth_data, +	}, +}; + +/* USB EHCI */ +static u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32); + +static struct resource ls1x_ehci_resources[] = { +	[0] = { +		.start	= LS1X_EHCI_BASE, +		.end	= LS1X_EHCI_BASE + SZ_32K - 1, +		.flags	= IORESOURCE_MEM, +	}, +	[1] = { +		.start	= LS1X_EHCI_IRQ, +		.flags	= IORESOURCE_IRQ, +	}, +}; + +static struct usb_ehci_pdata ls1x_ehci_pdata = { +}; + +struct platform_device ls1x_ehci_device = { +	.name		= "ehci-platform", +	.id		= -1, +	.num_resources	= ARRAY_SIZE(ls1x_ehci_resources), +	.resource	= ls1x_ehci_resources, +	.dev		= { +		.dma_mask = &ls1x_ehci_dmamask, +		.platform_data = &ls1x_ehci_pdata, +	}, +}; + +/* Real Time Clock */ +struct platform_device ls1x_rtc_device = { +	.name		= "ls1x-rtc", +	.id		= -1, +}; diff --git a/arch/mips/loongson1/common/prom.c b/arch/mips/loongson1/common/prom.c new file mode 100644 index 00000000000..2a47af5a55c --- /dev/null +++ b/arch/mips/loongson1/common/prom.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> + * + * Modified from arch/mips/pnx833x/common/prom.c. + * + * 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 <linux/serial_reg.h> +#include <asm/bootinfo.h> + +#include <loongson1.h> +#include <prom.h> + +int prom_argc; +char **prom_argv, **prom_envp; +unsigned long memsize, highmemsize; + +char *prom_getenv(char *envname) +{ +	char **env = prom_envp; +	int i; + +	i = strlen(envname); + +	while (*env) { +		if (strncmp(envname, *env, i) == 0 && *(*env+i) == '=') +			return *env + i + 1; +		env++; +	} + +	return 0; +} + +static inline unsigned long env_or_default(char *env, unsigned long dfl) +{ +	char *str = prom_getenv(env); +	return str ? simple_strtol(str, 0, 0) : dfl; +} + +void __init prom_init_cmdline(void) +{ +	char *c = &(arcs_cmdline[0]); +	int i; + +	for (i = 1; i < prom_argc; i++) { +		strcpy(c, prom_argv[i]); +		c += strlen(prom_argv[i]); +		if (i < prom_argc-1) +			*c++ = ' '; +	} +	*c = 0; +} + +void __init prom_init(void) +{ +	prom_argc = fw_arg0; +	prom_argv = (char **)fw_arg1; +	prom_envp = (char **)fw_arg2; + +	prom_init_cmdline(); + +	memsize = env_or_default("memsize", DEFAULT_MEMSIZE); +	highmemsize = env_or_default("highmemsize", 0x0); +} + +void __init prom_free_prom_memory(void) +{ +} + +#define PORT(offset)	(u8 *)(KSEG1ADDR(LS1X_UART0_BASE + offset)) + +void prom_putchar(char c) +{ +	int timeout; + +	timeout = 1024; + +	while (((readb(PORT(UART_LSR)) & UART_LSR_THRE) == 0) +			&& (timeout-- > 0)) +		; + +	writeb(c, PORT(UART_TX)); +} diff --git a/arch/mips/loongson1/common/reset.c b/arch/mips/loongson1/common/reset.c new file mode 100644 index 00000000000..547f34b69e4 --- /dev/null +++ b/arch/mips/loongson1/common/reset.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> + * + * 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 <linux/io.h> +#include <linux/pm.h> +#include <asm/idle.h> +#include <asm/reboot.h> + +#include <loongson1.h> + +static void ls1x_restart(char *command) +{ +	__raw_writel(0x1, LS1X_WDT_EN); +	__raw_writel(0x5000000, LS1X_WDT_TIMER); +	__raw_writel(0x1, LS1X_WDT_SET); +} + +static void ls1x_halt(void) +{ +	while (1) { +		if (cpu_wait) +			cpu_wait(); +	} +} + +static void ls1x_power_off(void) +{ +	ls1x_halt(); +} + +static int __init ls1x_reboot_setup(void) +{ +	_machine_restart = ls1x_restart; +	_machine_halt = ls1x_halt; +	pm_power_off = ls1x_power_off; + +	return 0; +} + +arch_initcall(ls1x_reboot_setup); diff --git a/arch/mips/loongson1/common/setup.c b/arch/mips/loongson1/common/setup.c new file mode 100644 index 00000000000..62f41afee24 --- /dev/null +++ b/arch/mips/loongson1/common/setup.c @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> + * + * 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/bootinfo.h> + +#include <prom.h> + +void __init plat_mem_setup(void) +{ +	add_memory_region(0x0, (memsize << 20), BOOT_MEM_RAM); +} + +const char *get_system_type(void) +{ +	unsigned int processor_id = (¤t_cpu_data)->processor_id; + +	switch (processor_id & PRID_REV_MASK) { +	case PRID_REV_LOONGSON1B: +		return "LOONGSON LS1B"; +	default: +		return "LOONGSON (unknown)"; +	} +} diff --git a/arch/mips/loongson1/ls1b/Makefile b/arch/mips/loongson1/ls1b/Makefile new file mode 100644 index 00000000000..891eac482b8 --- /dev/null +++ b/arch/mips/loongson1/ls1b/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for loongson1B based machines. +# + +obj-y += board.o diff --git a/arch/mips/loongson1/ls1b/board.c b/arch/mips/loongson1/ls1b/board.c new file mode 100644 index 00000000000..b26b10dac70 --- /dev/null +++ b/arch/mips/loongson1/ls1b/board.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> + * + * 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 <platform.h> + +static struct platform_device *ls1b_platform_devices[] __initdata = { +	&ls1x_uart_device, +	&ls1x_eth0_device, +	&ls1x_ehci_device, +	&ls1x_rtc_device, +}; + +static int __init ls1b_platform_init(void) +{ +	int err; + +	ls1x_serial_setup(&ls1x_uart_device); + +	err = platform_add_devices(ls1b_platform_devices, +				   ARRAY_SIZE(ls1b_platform_devices)); +	return err; +} + +arch_initcall(ls1b_platform_init);  | 
