aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/platform/coldfire
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/platform/coldfire')
-rw-r--r--arch/m68k/platform/coldfire/Makefile22
-rw-r--r--arch/m68k/platform/coldfire/device.c318
-rw-r--r--arch/m68k/platform/coldfire/entry.S4
-rw-r--r--arch/m68k/platform/coldfire/head.S4
-rw-r--r--arch/m68k/platform/coldfire/pit.c2
-rw-r--r--arch/m68k/platform/coldfire/reset.c50
-rw-r--r--arch/m68k/platform/coldfire/sltimers.c7
-rw-r--r--arch/m68k/platform/coldfire/timers.c27
-rw-r--r--arch/m68k/platform/coldfire/vectors.c2
9 files changed, 415 insertions, 21 deletions
diff --git a/arch/m68k/platform/coldfire/Makefile b/arch/m68k/platform/coldfire/Makefile
index a8967baabd72..a0815c61dec1 100644
--- a/arch/m68k/platform/coldfire/Makefile
+++ b/arch/m68k/platform/coldfire/Makefile
@@ -14,18 +14,18 @@
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
-obj-$(CONFIG_COLDFIRE) += cache.o clk.o dma.o entry.o vectors.o
-obj-$(CONFIG_M5206) += timers.o intc.o
-obj-$(CONFIG_M5206e) += timers.o intc.o
-obj-$(CONFIG_M520x) += pit.o intc-simr.o
-obj-$(CONFIG_M523x) += pit.o dma_timer.o intc-2.o
-obj-$(CONFIG_M5249) += timers.o intc.o
-obj-$(CONFIG_M527x) += pit.o intc-2.o
+obj-$(CONFIG_COLDFIRE) += cache.o clk.o device.o dma.o entry.o vectors.o
+obj-$(CONFIG_M5206) += timers.o intc.o reset.o
+obj-$(CONFIG_M5206e) += timers.o intc.o reset.o
+obj-$(CONFIG_M520x) += pit.o intc-simr.o reset.o
+obj-$(CONFIG_M523x) += pit.o dma_timer.o intc-2.o reset.o
+obj-$(CONFIG_M5249) += timers.o intc.o reset.o
+obj-$(CONFIG_M527x) += pit.o intc-2.o reset.o
obj-$(CONFIG_M5272) += timers.o
-obj-$(CONFIG_M528x) += pit.o intc-2.o
-obj-$(CONFIG_M5307) += timers.o intc.o
-obj-$(CONFIG_M532x) += timers.o intc-simr.o
-obj-$(CONFIG_M5407) += timers.o intc.o
+obj-$(CONFIG_M528x) += pit.o intc-2.o reset.o
+obj-$(CONFIG_M5307) += timers.o intc.o reset.o
+obj-$(CONFIG_M532x) += timers.o intc-simr.o reset.o
+obj-$(CONFIG_M5407) += timers.o intc.o reset.o
obj-$(CONFIG_M54xx) += sltimers.o intc-2.o
obj-y += pinmux.o gpio.o
diff --git a/arch/m68k/platform/coldfire/device.c b/arch/m68k/platform/coldfire/device.c
new file mode 100644
index 000000000000..fa50c48292ff
--- /dev/null
+++ b/arch/m68k/platform/coldfire/device.c
@@ -0,0 +1,318 @@
+/*
+ * device.c -- common ColdFire SoC device support
+ *
+ * (C) Copyright 2011, Greg Ungerer <gerg@uclinux.org>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <asm/traps.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/mcfqspi.h>
+
+/*
+ * All current ColdFire parts contain from 2, 3 or 4 UARTS.
+ */
+static struct mcf_platform_uart mcf_uart_platform_data[] = {
+ {
+ .mapbase = MCFUART_BASE0,
+ .irq = MCF_IRQ_UART0,
+ },
+ {
+ .mapbase = MCFUART_BASE1,
+ .irq = MCF_IRQ_UART1,
+ },
+#ifdef MCFUART_BASE2
+ {
+ .mapbase = MCFUART_BASE2,
+ .irq = MCF_IRQ_UART2,
+ },
+#endif
+#ifdef MCFUART_BASE3
+ {
+ .mapbase = MCFUART_BASE3,
+ .irq = MCF_IRQ_UART3,
+ },
+#endif
+ { },
+};
+
+static struct platform_device mcf_uart = {
+ .name = "mcfuart",
+ .id = 0,
+ .dev.platform_data = mcf_uart_platform_data,
+};
+
+#ifdef CONFIG_FEC
+/*
+ * Some ColdFire cores contain the Fast Ethernet Controller (FEC)
+ * block. It is Freescale's own hardware block. Some ColdFires
+ * have 2 of these.
+ */
+static struct resource mcf_fec0_resources[] = {
+ {
+ .start = MCFFEC_BASE0,
+ .end = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MCF_IRQ_FECRX0,
+ .end = MCF_IRQ_FECRX0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MCF_IRQ_FECTX0,
+ .end = MCF_IRQ_FECTX0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MCF_IRQ_FECENTC0,
+ .end = MCF_IRQ_FECENTC0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mcf_fec0 = {
+ .name = "fec",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mcf_fec0_resources),
+ .resource = mcf_fec0_resources,
+};
+
+#ifdef MCFFEC_BASE1
+static struct resource mcf_fec1_resources[] = {
+ {
+ .start = MCFFEC_BASE1,
+ .end = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MCF_IRQ_FECRX1,
+ .end = MCF_IRQ_FECRX1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MCF_IRQ_FECTX1,
+ .end = MCF_IRQ_FECTX1,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = MCF_IRQ_FECENTC1,
+ .end = MCF_IRQ_FECENTC1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mcf_fec1 = {
+ .name = "fec",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mcf_fec1_resources),
+ .resource = mcf_fec1_resources,
+};
+#endif /* MCFFEC_BASE1 */
+#endif /* CONFIG_FEC */
+
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
+/*
+ * The ColdFire QSPI module is an SPI protocol hardware block used
+ * on a number of different ColdFire CPUs.
+ */
+static struct resource mcf_qspi_resources[] = {
+ {
+ .start = MCFQSPI_BASE,
+ .end = MCFQSPI_BASE + MCFQSPI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MCF_IRQ_QSPI,
+ .end = MCF_IRQ_QSPI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static int mcf_cs_setup(struct mcfqspi_cs_control *cs_control)
+{
+ int status;
+
+ status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0");
+ if (status) {
+ pr_debug("gpio_request for MCFQSPI_CS0 failed\n");
+ goto fail0;
+ }
+ status = gpio_direction_output(MCFQSPI_CS0, 1);
+ if (status) {
+ pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n");
+ goto fail1;
+ }
+
+ status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1");
+ if (status) {
+ pr_debug("gpio_request for MCFQSPI_CS1 failed\n");
+ goto fail1;
+ }
+ status = gpio_direction_output(MCFQSPI_CS1, 1);
+ if (status) {
+ pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n");
+ goto fail2;
+ }
+
+ status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2");
+ if (status) {
+ pr_debug("gpio_request for MCFQSPI_CS2 failed\n");
+ goto fail2;
+ }
+ status = gpio_direction_output(MCFQSPI_CS2, 1);
+ if (status) {
+ pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n");
+ goto fail3;
+ }
+
+#ifdef MCFQSPI_CS3
+ status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3");
+ if (status) {
+ pr_debug("gpio_request for MCFQSPI_CS3 failed\n");
+ goto fail3;
+ }
+ status = gpio_direction_output(MCFQSPI_CS3, 1);
+ if (status) {
+ pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n");
+ gpio_free(MCFQSPI_CS3);
+ goto fail3;
+ }
+#endif
+
+ return 0;
+
+fail3:
+ gpio_free(MCFQSPI_CS2);
+fail2:
+ gpio_free(MCFQSPI_CS1);
+fail1:
+ gpio_free(MCFQSPI_CS0);
+fail0:
+ return status;
+}
+
+static void mcf_cs_teardown(struct mcfqspi_cs_control *cs_control)
+{
+#ifdef MCFQSPI_CS3
+ gpio_free(MCFQSPI_CS3);
+#endif
+ gpio_free(MCFQSPI_CS2);
+ gpio_free(MCFQSPI_CS1);
+ gpio_free(MCFQSPI_CS0);
+}
+
+static void mcf_cs_select(struct mcfqspi_cs_control *cs_control,
+ u8 chip_select, bool cs_high)
+{
+ switch (chip_select) {
+ case 0:
+ gpio_set_value(MCFQSPI_CS0, cs_high);
+ break;
+ case 1:
+ gpio_set_value(MCFQSPI_CS1, cs_high);
+ break;
+ case 2:
+ gpio_set_value(MCFQSPI_CS2, cs_high);
+ break;
+#ifdef MCFQSPI_CS3
+ case 3:
+ gpio_set_value(MCFQSPI_CS3, cs_high);
+ break;
+#endif
+ }
+}
+
+static void mcf_cs_deselect(struct mcfqspi_cs_control *cs_control,
+ u8 chip_select, bool cs_high)
+{
+ switch (chip_select) {
+ case 0:
+ gpio_set_value(MCFQSPI_CS0, !cs_high);
+ break;
+ case 1:
+ gpio_set_value(MCFQSPI_CS1, !cs_high);
+ break;
+ case 2:
+ gpio_set_value(MCFQSPI_CS2, !cs_high);
+ break;
+#ifdef MCFQSPI_CS3
+ case 3:
+ gpio_set_value(MCFQSPI_CS3, !cs_high);
+ break;
+#endif
+ }
+}
+
+static struct mcfqspi_cs_control mcf_cs_control = {
+ .setup = mcf_cs_setup,
+ .teardown = mcf_cs_teardown,
+ .select = mcf_cs_select,
+ .deselect = mcf_cs_deselect,
+};
+
+static struct mcfqspi_platform_data mcf_qspi_data = {
+ .bus_num = 0,
+ .num_chipselect = 4,
+ .cs_control = &mcf_cs_control,
+};
+
+static struct platform_device mcf_qspi = {
+ .name = "mcfqspi",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mcf_qspi_resources),
+ .resource = mcf_qspi_resources,
+ .dev.platform_data = &mcf_qspi_data,
+};
+#endif /* CONFIG_SPI_COLDFIRE_QSPI */
+
+static struct platform_device *mcf_devices[] __initdata = {
+ &mcf_uart,
+#ifdef CONFIG_FEC
+ &mcf_fec0,
+#ifdef MCFFEC_BASE1
+ &mcf_fec1,
+#endif
+#endif
+#ifdef CONFIG_SPI_COLDFIRE_QSPI
+ &mcf_qspi,
+#endif
+};
+
+/*
+ * Some ColdFire UARTs let you set the IRQ line to use.
+ */
+static void __init mcf_uart_set_irq(void)
+{
+#ifdef MCFUART_UIVR
+ /* UART0 interrupt setup */
+ writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
+ writeb(MCF_IRQ_UART0, MCFUART_BASE0 + MCFUART_UIVR);
+ mcf_mapirq2imr(MCF_IRQ_UART0, MCFINTC_UART0);
+
+ /* UART1 interrupt setup */
+ writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR);
+ writeb(MCF_IRQ_UART1, MCFUART_BASE1 + MCFUART_UIVR);
+ mcf_mapirq2imr(MCF_IRQ_UART1, MCFINTC_UART1);
+#endif
+}
+
+static int __init mcf_init_devices(void)
+{
+ mcf_uart_set_irq();
+ platform_add_devices(mcf_devices, ARRAY_SIZE(mcf_devices));
+ return 0;
+}
+
+arch_initcall(mcf_init_devices);
+
diff --git a/arch/m68k/platform/coldfire/entry.S b/arch/m68k/platform/coldfire/entry.S
index 863889fc31c9..281e38c2b6c7 100644
--- a/arch/m68k/platform/coldfire/entry.S
+++ b/arch/m68k/platform/coldfire/entry.S
@@ -136,7 +136,7 @@ Luser_return:
movel %sp,%d1 /* get thread_info pointer */
andl #-THREAD_SIZE,%d1 /* at base of kernel stack */
movel %d1,%a0
- movel %a0@(TINFO_FLAGS),%d1 /* get thread_info->flags */
+ moveb %a0@(TINFO_FLAGS+3),%d1 /* thread_info->flags (low 8 bits) */
jne Lwork_to_do /* still work to do */
Lreturn:
@@ -148,8 +148,6 @@ Lwork_to_do:
btst #TIF_NEED_RESCHED,%d1
jne reschedule
- /* GERG: do we need something here for TRACEing?? */
-
Lsignal_return:
subql #4,%sp /* dummy return address */
SAVE_SWITCH_STACK
diff --git a/arch/m68k/platform/coldfire/head.S b/arch/m68k/platform/coldfire/head.S
index 38f04a3f6207..c3db70ed33b3 100644
--- a/arch/m68k/platform/coldfire/head.S
+++ b/arch/m68k/platform/coldfire/head.S
@@ -158,6 +158,10 @@ _start:
#if defined(CONFIG_UBOOT)
movel %sp,_init_sp /* save initial stack pointer */
#endif
+#ifdef CONFIG_MBAR
+ movel #CONFIG_MBAR+1,%d0 /* configured MBAR address */
+ movec %d0,%MBAR /* set it */
+#endif
/*
* Do any platform or board specific setup now. Most boards
diff --git a/arch/m68k/platform/coldfire/pit.c b/arch/m68k/platform/coldfire/pit.c
index 02663d25822d..e62dbbcb10f6 100644
--- a/arch/m68k/platform/coldfire/pit.c
+++ b/arch/m68k/platform/coldfire/pit.c
@@ -149,7 +149,7 @@ static struct clocksource pit_clk = {
/***************************************************************************/
-void hw_timer_init(void)
+void hw_timer_init(irq_handler_t handler)
{
cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id());
cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
diff --git a/arch/m68k/platform/coldfire/reset.c b/arch/m68k/platform/coldfire/reset.c
new file mode 100644
index 000000000000..933e54eacc69
--- /dev/null
+++ b/arch/m68k/platform/coldfire/reset.c
@@ -0,0 +1,50 @@
+/*
+ * reset.c -- common ColdFire SoC reset support
+ *
+ * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.org>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <asm/machdep.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+
+/*
+ * There are 2 common methods amongst the ColdFure parts for reseting
+ * the CPU. But there are couple of exceptions, the 5272 and the 547x
+ * have something completely special to them, and we let their specific
+ * subarch code handle them.
+ */
+
+#ifdef MCFSIM_SYPCR
+static void mcf_cpu_reset(void)
+{
+ local_irq_disable();
+ /* Set watchdog to soft reset, and enabled */
+ __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR);
+ for (;;)
+ /* wait for watchdog to timeout */;
+}
+#endif
+
+#ifdef MCF_RCR
+static void mcf_cpu_reset(void)
+{
+ local_irq_disable();
+ __raw_writeb(MCF_RCR_SWRESET, MCF_RCR);
+}
+#endif
+
+static int __init mcf_setup_reset(void)
+{
+ mach_reset = mcf_cpu_reset;
+ return 0;
+}
+
+arch_initcall(mcf_setup_reset);
diff --git a/arch/m68k/platform/coldfire/sltimers.c b/arch/m68k/platform/coldfire/sltimers.c
index 54e1452f853a..2027fc20b876 100644
--- a/arch/m68k/platform/coldfire/sltimers.c
+++ b/arch/m68k/platform/coldfire/sltimers.c
@@ -81,12 +81,14 @@ void mcfslt_profile_init(void)
static u32 mcfslt_cycles_per_jiffy;
static u32 mcfslt_cnt;
+static irq_handler_t timer_interrupt;
+
static irqreturn_t mcfslt_tick(int irq, void *dummy)
{
/* Reset Slice Timer 0 */
__raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR));
mcfslt_cnt += mcfslt_cycles_per_jiffy;
- return arch_timer_interrupt(irq, dummy);
+ return timer_interrupt(irq, dummy);
}
static struct irqaction mcfslt_timer_irq = {
@@ -121,7 +123,7 @@ static struct clocksource mcfslt_clk = {
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
-void hw_timer_init(void)
+void hw_timer_init(irq_handler_t handler)
{
mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ;
/*
@@ -136,6 +138,7 @@ void hw_timer_init(void)
/* initialize mcfslt_cnt knowing that slice timers count down */
mcfslt_cnt = mcfslt_cycles_per_jiffy;
+ timer_interrupt = handler;
setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq);
clocksource_register_hz(&mcfslt_clk, MCF_BUSCLK);
diff --git a/arch/m68k/platform/coldfire/timers.c b/arch/m68k/platform/coldfire/timers.c
index 0d90da32fcdb..ed96ce50d79f 100644
--- a/arch/m68k/platform/coldfire/timers.c
+++ b/arch/m68k/platform/coldfire/timers.c
@@ -47,6 +47,27 @@ void coldfire_profile_init(void);
static u32 mcftmr_cycles_per_jiffy;
static u32 mcftmr_cnt;
+static irq_handler_t timer_interrupt;
+
+/***************************************************************************/
+
+static void init_timer_irq(void)
+{
+#ifdef MCFSIM_ICR_AUTOVEC
+ /* Timer1 is always used as system timer */
+ writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3,
+ MCF_MBAR + MCFSIM_TIMER1ICR);
+ mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1);
+
+#ifdef CONFIG_HIGHPROFILE
+ /* Timer2 is to be used as a high speed profile timer */
+ writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3,
+ MCF_MBAR + MCFSIM_TIMER2ICR);
+ mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2);
+#endif
+#endif /* MCFSIM_ICR_AUTOVEC */
+}
+
/***************************************************************************/
static irqreturn_t mcftmr_tick(int irq, void *dummy)
@@ -55,7 +76,7 @@ static irqreturn_t mcftmr_tick(int irq, void *dummy)
__raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER));
mcftmr_cnt += mcftmr_cycles_per_jiffy;
- return arch_timer_interrupt(irq, dummy);
+ return timer_interrupt(irq, dummy);
}
/***************************************************************************/
@@ -94,7 +115,7 @@ static struct clocksource mcftmr_clk = {
/***************************************************************************/
-void hw_timer_init(void)
+void hw_timer_init(irq_handler_t handler)
{
__raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
mcftmr_cycles_per_jiffy = FREQ / HZ;
@@ -110,6 +131,8 @@ void hw_timer_init(void)
clocksource_register_hz(&mcftmr_clk, FREQ);
+ timer_interrupt = handler;
+ init_timer_irq();
setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq);
#ifdef CONFIG_HIGHPROFILE
diff --git a/arch/m68k/platform/coldfire/vectors.c b/arch/m68k/platform/coldfire/vectors.c
index 3a7cc524ecd3..a4dbdecbec7a 100644
--- a/arch/m68k/platform/coldfire/vectors.c
+++ b/arch/m68k/platform/coldfire/vectors.c
@@ -33,8 +33,6 @@ asmlinkage void dbginterrupt_c(struct frame *fp)
/***************************************************************************/
-extern e_vector *_ramvec;
-
/* Assembler routines */
asmlinkage void buserr(void);
asmlinkage void trap(void);