[ARM] 4461/1: MXC platform and i.MX31ADS core support

This patch adds the foundation pieces for
the Freescale MXC platforms, including
i.MX2 and i.MX3 based systems.

The bare-bones MX31 support in this patch
boots to the rootdev panic with 8250 serial
console configured "console=ttyS0,115200".
It assumes that Redboot is the boot loader.

Signed-off-by: Quinn Jensen <[email protected]>
Acked-by: Lennert Buytenhek <[email protected]>
Signed-off-by: Russell King <[email protected]>
This commit is contained in:
Quinn Jensen 2007-07-09 22:06:53 +01:00 • committed by Russell King
commit 52c543f90c
26 changed files with 1563 additions and 2 deletions

View file

@ -324,6 +324,12 @@ config ARCH_NS9XXX
<http://www.digi.com/products/microprocessors/index.jsp>
config ARCH_MXC
bool "Freescale MXC/iMX-based"
select ARCH_MTD_XIP
help
Support for Freescale MXC/iMX-based family of processors
config ARCH_PNX4008
bool "Philips Nexperia PNX4008 Mobile"
help
@ -456,6 +462,8 @@ source "arch/arm/mach-realview/Kconfig"
source "arch/arm/mach-at91/Kconfig"
source "arch/arm/plat-mxc/Kconfig"
source "arch/arm/mach-netx/Kconfig"
source "arch/arm/mach-ns9xxx/Kconfig"

View file

@ -137,6 +137,8 @@ endif
textofs-$(CONFIG_ARCH_NS9XXX) := 0x00108000
machine-$(CONFIG_ARCH_DAVINCI) := davinci
machine-$(CONFIG_ARCH_KS8695) := ks8695
incdir-$(CONFIG_ARCH_MXC) := mxc
machine-$(CONFIG_ARCH_MX3) := mx3
ifeq ($(CONFIG_ARCH_EBSA110),y)
# This is what happens if you forget the IOCS16 line.
@ -183,6 +185,7 @@ core-$(CONFIG_VFP) += arch/arm/vfp/
core-$(CONFIG_PLAT_IOP) += arch/arm/plat-iop/
core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/
core-$(CONFIG_PLAT_S3C24XX) += arch/arm/plat-s3c24xx/
core-$(CONFIG_ARCH_MXC) += arch/arm/plat-mxc/
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/

12
arch/arm/mach-mx3/Kconfig Normal file
View file

@ -0,0 +1,12 @@
menu "MX3 Options"
depends on ARCH_MX3
config MACH_MX31ADS
bool "Support MX31ADS platforms"
default y
help
Include support for MX31ADS platform. This includes specific
configurations for the board and its peripherals.
endmenu

View file

@ -0,0 +1,8 @@
#
# Makefile for the linux kernel.
#
# Object file lists.
obj-y := mm.o time.o
obj-$(CONFIG_MACH_MX31ADS) += mx31ads.o

View file

@ -0,0 +1,3 @@
zreladdr-y := 0x80008000
params_phys-y := 0x80000100
initrd_phys-y := 0x80800000

64
arch/arm/mach-mx3/mm.c Normal file
View file

@ -0,0 +1,64 @@
/*
* Copyright (C) 1999,2000 Arm Limited
* Copyright (C) 2000 Deep Blue Solutions Ltd
* Copyright (C) 2002 Shane Nay (shane@minirl.com)
* Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
* - add MX31 specific definitions
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/mm.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/pgtable.h>
#include <asm/mach/map.h>
#include <asm/arch/common.h>
/*!
* @file mm.c
*
* @brief This file creates static virtual to physical mappings, common to all MX3 boards.
*
* @ingroup Memory
*/
/*!
* This table defines static virtual address mappings for I/O regions.
* These are the mappings common across all MX3 boards.
*/
static struct map_desc mxc_io_desc[] __initdata = {
{
.virtual = X_MEMC_BASE_ADDR_VIRT,
.pfn = __phys_to_pfn(X_MEMC_BASE_ADDR),
.length = X_MEMC_SIZE,
.type = MT_DEVICE
}, {
.virtual = AVIC_BASE_ADDR_VIRT,
.pfn = __phys_to_pfn(AVIC_BASE_ADDR),
.length = AVIC_SIZE,
.type = MT_NONSHARED_DEVICE
},
};
/*!
* This function initializes the memory map. It is called during the
* system startup to create static physical to virtual memory mappings
* for the IO modules.
*/
void __init mxc_map_io(void)
{
iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
}

142
arch/arm/mach-mx3/mx31ads.c Normal file
View file

@ -0,0 +1,142 @@
/*
* Copyright (C) 2000 Deep Blue Solutions Ltd
* Copyright (C) 2002 Shane Nay (shane@minirl.com)
* Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/types.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/serial_8250.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/memory.h>
#include <asm/mach/map.h>
#include <asm/arch/common.h>
/*!
* @file mx31ads.c
*
* @brief This file contains the board-specific initialization routines.
*
* @ingroup System
*/
#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
/*!
* The serial port definition structure.
*/
static struct plat_serial8250_port serial_platform_data[] = {
{
.membase = (void *)(PBC_BASE_ADDRESS + PBC_SC16C652_UARTA),
.mapbase = (unsigned long)(CS4_BASE_ADDR + PBC_SC16C652_UARTA),
.irq = EXPIO_INT_XUART_INTA,
.uartclk = 14745600,
.regshift = 0,
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ,
}, {
.membase = (void *)(PBC_BASE_ADDRESS + PBC_SC16C652_UARTB),
.mapbase = (unsigned long)(CS4_BASE_ADDR + PBC_SC16C652_UARTB),
.irq = EXPIO_INT_XUART_INTB,
.uartclk = 14745600,
.regshift = 0,
.iotype = UPIO_MEM,
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ,
},
{},
};
static struct platform_device serial_device = {
.name = "serial8250",
.id = 0,
.dev = {
.platform_data = serial_platform_data,
},
};
static int __init mxc_init_extuart(void)
{
return platform_device_register(&serial_device);
}
#else
static inline int mxc_init_extuart(void)
{
return 0;
}
#endif
/*!
* This structure defines static mappings for the i.MX31ADS board.
*/
static struct map_desc mx31ads_io_desc[] __initdata = {
{
.virtual = AIPS1_BASE_ADDR_VIRT,
.pfn = __phys_to_pfn(AIPS1_BASE_ADDR),
.length = AIPS1_SIZE,
.type = MT_NONSHARED_DEVICE
}, {
.virtual = SPBA0_BASE_ADDR_VIRT,
.pfn = __phys_to_pfn(SPBA0_BASE_ADDR),
.length = SPBA0_SIZE,
.type = MT_NONSHARED_DEVICE
}, {
.virtual = AIPS2_BASE_ADDR_VIRT,
.pfn = __phys_to_pfn(AIPS2_BASE_ADDR),
.length = AIPS2_SIZE,
.type = MT_NONSHARED_DEVICE
}, {
.virtual = CS4_BASE_ADDR_VIRT,
.pfn = __phys_to_pfn(CS4_BASE_ADDR),
.length = CS4_SIZE / 2,
.type = MT_DEVICE
},
};
/*!
* Set up static virtual mappings.
*/
void __init mx31ads_map_io(void)
{
mxc_map_io();
iotable_init(mx31ads_io_desc, ARRAY_SIZE(mx31ads_io_desc));
}
/*!
* Board specific initialization.
*/
static void __init mxc_board_init(void)
{
mxc_init_extuart();
}
/*
* The following uses standard kernel macros defined in arch.h in order to
* initialize __mach_desc_MX31ADS data structure.
*/
MACHINE_START(MX31ADS, "Freescale MX31ADS")
/* Maintainer: Freescale Semiconductor, Inc. */
.phys_io = AIPS1_BASE_ADDR,
.io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
.boot_params = PHYS_OFFSET + 0x100,
.map_io = mx31ads_map_io,
.init_irq = mxc_init_irq,
.init_machine = mxc_board_init,
.timer = &mxc_timer,
MACHINE_END

152
arch/arm/mach-mx3/time.c Normal file
View file

@ -0,0 +1,152 @@
/*
* System Timer Interrupt reconfigured to run in free-run mode.
* Author: Vitaly Wool
* Copyright 2004 MontaVista Software Inc.
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*!
* @file time.c
* @brief This file contains OS tick and wdog timer implementations.
*
* This file contains OS tick and wdog timer implementations.
*
* @ingroup Timers
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <asm/hardware.h>
#include <asm/mach/time.h>
#include <asm/io.h>
#include <asm/arch/common.h>
/*!
* This is the timer interrupt service routine to do required tasks.
* It also services the WDOG timer at the frequency of twice per WDOG
* timeout value. For example, if the WDOG's timeout value is 4 (2
* seconds since the WDOG runs at 0.5Hz), it will be serviced once
* every 2/2=1 second.
*
* @param irq GPT interrupt source number (not used)
* @param dev_id this parameter is not used
* @return always returns \b IRQ_HANDLED as defined in
* include/linux/interrupt.h.
*/
static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
{
unsigned int next_match;
write_seqlock(&xtime_lock);
if (__raw_readl(MXC_GPT_GPTSR) & GPTSR_OF1) {
do {
timer_tick();
next_match = __raw_readl(MXC_GPT_GPTOCR1) + LATCH;
__raw_writel(GPTSR_OF1, MXC_GPT_GPTSR);
__raw_writel(next_match, MXC_GPT_GPTOCR1);
} while ((signed long)(next_match -
__raw_readl(MXC_GPT_GPTCNT)) <= 0);
}
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}
/*!
* This function is used to obtain the number of microseconds since the last
* timer interrupt. Note that interrupts is disabled by do_gettimeofday().
*
* @return the number of microseconds since the last timer interrupt.
*/
static unsigned long mxc_gettimeoffset(void)
{
unsigned long ticks_to_match, elapsed, usec, tick_usec, i;
/* Get ticks before next timer match */
ticks_to_match =
__raw_readl(MXC_GPT_GPTOCR1) - __raw_readl(MXC_GPT_GPTCNT);
/* We need elapsed ticks since last match */
elapsed = LATCH - ticks_to_match;
/* Now convert them to usec */
/* Insure no overflow when calculating the usec below */
for (i = 1, tick_usec = tick_nsec / 1000;; i *= 2) {
tick_usec /= i;
if ((0xFFFFFFFF / tick_usec) > elapsed)
break;
}
usec = (unsigned long)(elapsed * tick_usec) / (LATCH / i);
return usec;
}
/*!
* The OS tick timer interrupt structure.
*/
static struct irqaction timer_irq = {
.name = "MXC Timer Tick",
.flags = IRQF_DISABLED | IRQF_TIMER,
.handler = mxc_timer_interrupt
};
/*!
* This function is used to initialize the GPT to produce an interrupt
* based on HZ. It is called by start_kernel() during system startup.
*/
void __init mxc_init_time(void)
{
u32 reg, v;
reg = __raw_readl(MXC_GPT_GPTCR);
reg &= ~GPTCR_ENABLE;
__raw_writel(reg, MXC_GPT_GPTCR);
reg |= GPTCR_SWR;
__raw_writel(reg, MXC_GPT_GPTCR);
while ((__raw_readl(MXC_GPT_GPTCR) & GPTCR_SWR) != 0)
cpu_relax();
reg = GPTCR_FRR | GPTCR_CLKSRC_HIGHFREQ;
__raw_writel(reg, MXC_GPT_GPTCR);
/* TODO: get timer rate from clk driver */
v = 66500000;
__raw_writel((v / CLOCK_TICK_RATE) - 1, MXC_GPT_GPTPR);
if ((v % CLOCK_TICK_RATE) != 0) {
pr_info("\nWARNING: Can't generate CLOCK_TICK_RATE at %d Hz\n",
CLOCK_TICK_RATE);
}
pr_info("Actual CLOCK_TICK_RATE is %d Hz\n",
v / ((__raw_readl(MXC_GPT_GPTPR) & 0xFFF) + 1));
reg = __raw_readl(MXC_GPT_GPTCNT);
reg += LATCH;
__raw_writel(reg, MXC_GPT_GPTOCR1);
setup_irq(MXC_INT_GPT, &timer_irq);
reg = __raw_readl(MXC_GPT_GPTCR);
reg =
GPTCR_FRR | GPTCR_CLKSRC_HIGHFREQ | GPTCR_STOPEN | GPTCR_DOZEN |
GPTCR_WAITEN | GPTCR_ENMOD | GPTCR_ENABLE;
__raw_writel(reg, MXC_GPT_GPTCR);
__raw_writel(GPTIR_OF1IE, MXC_GPT_GPTIR);
}
struct sys_timer mxc_timer = {
.init = mxc_init_time,
.offset = mxc_gettimeoffset,
};

View file

@ -345,7 +345,8 @@ config CPU_XSC3
# ARMv6
config CPU_V6
bool "Support ARM V6 processor"
depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2
depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3
default y if ARCH_MX3
select CPU_32v6
select CPU_ABRT_EV6
select CPU_CACHE_V6
@ -359,7 +360,7 @@ config CPU_V6
config CPU_32v6K
bool "Support ARM V6K processor extensions" if !SMP
depends on CPU_V6
default y if SMP
default y if SMP && !ARCH_MX3
help
Say Y here if your ARMv6 processor supports the 'K' extension.
This enables the kernel to use some instructions not present

20
arch/arm/plat-mxc/Kconfig Normal file
View file

@ -0,0 +1,20 @@
if ARCH_MXC
menu "Freescale MXC Implementations"
choice
prompt "MXC/iMX System Type"
default 0
config ARCH_MX3
bool "MX3-based"
help
This enables support for systems based on the Freescale i.MX3 family
endchoice
source "arch/arm/mach-mx3/Kconfig"
endmenu
endif

View file

@ -0,0 +1,10 @@
#
# Makefile for the linux kernel.
#
# Common support
obj-y := irq.o
obj-m :=
obj-n :=
obj- :=

83
arch/arm/plat-mxc/irq.c Normal file
View file

@ -0,0 +1,83 @@
/*
* Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/arch/common.h>
/*!
* Disable interrupt number "irq" in the AVIC
*
* @param irq interrupt source number
*/
static void mxc_mask_irq(unsigned int irq)
{
__raw_writel(irq, AVIC_INTDISNUM);
}
/*!
* Enable interrupt number "irq" in the AVIC
*
* @param irq interrupt source number
*/
static void mxc_unmask_irq(unsigned int irq)
{
__raw_writel(irq, AVIC_INTENNUM);
}
static struct irq_chip mxc_avic_chip = {
.mask_ack = mxc_mask_irq,
.mask = mxc_mask_irq,
.unmask = mxc_unmask_irq,
};
/*!
* This function initializes the AVIC hardware and disables all the
* interrupts. It registers the interrupt enable and disable functions
* to the kernel for each interrupt source.
*/
void __init mxc_init_irq(void)
{
int i;
u32 reg;
/* put the AVIC into the reset value with
* all interrupts disabled
*/
__raw_writel(0, AVIC_INTCNTL);
__raw_writel(0x1f, AVIC_NIMASK);
/* disable all interrupts */
__raw_writel(0, AVIC_INTENABLEH);
__raw_writel(0, AVIC_INTENABLEL);
/* all IRQ no FIQ */
__raw_writel(0, AVIC_INTTYPEH);
__raw_writel(0, AVIC_INTTYPEL);
for (i = 0; i < MXC_MAX_INT_LINES; i++) {
set_irq_chip(i, &mxc_avic_chip);
set_irq_handler(i, handle_level_irq);
set_irq_flags(i, IRQF_VALID);
}
/* Set WDOG2's interrupt the highest priority level (bit 28-31) */
reg = __raw_readl(AVIC_NIPRIORITY6);
reg |= (0xF << 28);
__raw_writel(reg, AVIC_NIPRIORITY6);
printk(KERN_INFO "MXC IRQ initialized\n");
}