Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
This commit is contained in:
10
arch/arm/mach-imx/Kconfig
Normal file
10
arch/arm/mach-imx/Kconfig
Normal file
@@ -0,0 +1,10 @@
|
||||
menu "IMX Implementations"
|
||||
depends on ARCH_IMX
|
||||
|
||||
config ARCH_MX1ADS
|
||||
bool "mx1ads"
|
||||
depends on ARCH_IMX
|
||||
help
|
||||
Say Y here if you are using the Motorola MX1ADS board
|
||||
|
||||
endmenu
|
19
arch/arm/mach-imx/Makefile
Normal file
19
arch/arm/mach-imx/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
# Note! Dependencies are done automagically by 'make dep', which also
|
||||
# removes any old dependencies. DON'T put your own dependencies here
|
||||
# unless it's something special (ie not a .c file).
|
||||
|
||||
# Object file lists.
|
||||
|
||||
obj-y += irq.o time.o dma.o generic.o
|
||||
|
||||
# Specific board support
|
||||
obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o
|
||||
|
||||
# Support for blinky lights
|
||||
led-y := leds.o
|
||||
|
||||
obj-$(CONFIG_LEDS) += $(led-y)
|
||||
led-$(CONFIG_ARCH_MX1ADS) += leds-mx1ads.o
|
2
arch/arm/mach-imx/Makefile.boot
Normal file
2
arch/arm/mach-imx/Makefile.boot
Normal file
@@ -0,0 +1,2 @@
|
||||
zreladdr-$(CONFIG_ARCH_MX1ADS) := 0x08008000
|
||||
|
203
arch/arm/mach-imx/dma.c
Normal file
203
arch/arm/mach-imx/dma.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-imx/dma.c
|
||||
*
|
||||
* imx DMA registration and IRQ dispatching
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 03/03/2004 Sascha Hauer <sascha@saschahauer.de>
|
||||
* initial version heavily inspired by
|
||||
* linux/arch/arm/mach-pxa/dma.c
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/dma.h>
|
||||
|
||||
static struct dma_channel {
|
||||
char *name;
|
||||
void (*irq_handler) (int, void *, struct pt_regs *);
|
||||
void (*err_handler) (int, void *, struct pt_regs *);
|
||||
void *data;
|
||||
} dma_channels[11];
|
||||
|
||||
/* set err_handler to NULL to have the standard info-only error handler */
|
||||
int
|
||||
imx_request_dma(char *name, imx_dma_prio prio,
|
||||
void (*irq_handler) (int, void *, struct pt_regs *),
|
||||
void (*err_handler) (int, void *, struct pt_regs *), void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i, found = 0;
|
||||
|
||||
/* basic sanity checks */
|
||||
if (!name || !irq_handler)
|
||||
return -EINVAL;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
/* try grabbing a DMA channel with the requested priority */
|
||||
for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) {
|
||||
if (!dma_channels[i].name) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
/* requested prio group is full, try hier priorities */
|
||||
for (i = prio - 1; i >= 0; i--) {
|
||||
if (!dma_channels[i].name) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
DIMR &= ~(1 << i);
|
||||
dma_channels[i].name = name;
|
||||
dma_channels[i].irq_handler = irq_handler;
|
||||
dma_channels[i].err_handler = err_handler;
|
||||
dma_channels[i].data = data;
|
||||
} else {
|
||||
printk(KERN_WARNING "No more available DMA channels for %s\n",
|
||||
name);
|
||||
i = -ENODEV;
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
return i;
|
||||
}
|
||||
|
||||
void
|
||||
imx_free_dma(int dma_ch)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!dma_channels[dma_ch].name) {
|
||||
printk(KERN_CRIT
|
||||
"%s: trying to free channel %d which is already freed\n",
|
||||
__FUNCTION__, dma_ch);
|
||||
return;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
DIMR &= ~(1 << dma_ch);
|
||||
dma_channels[dma_ch].name = NULL;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
int i, disr = DISR;
|
||||
struct dma_channel *channel;
|
||||
unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
|
||||
|
||||
DISR = disr;
|
||||
for (i = 0; i < 11; i++) {
|
||||
channel = &dma_channels[i];
|
||||
|
||||
if ( (err_mask & 1<<i) && channel->name && channel->err_handler) {
|
||||
channel->err_handler(i, channel->data, regs);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (DBTOSR & (1 << i)) {
|
||||
printk(KERN_WARNING
|
||||
"Burst timeout on channel %d (%s)\n",
|
||||
i, channel->name);
|
||||
DBTOSR |= (1 << i);
|
||||
}
|
||||
if (DRTOSR & (1 << i)) {
|
||||
printk(KERN_WARNING
|
||||
"Request timeout on channel %d (%s)\n",
|
||||
i, channel->name);
|
||||
DRTOSR |= (1 << i);
|
||||
}
|
||||
if (DSESR & (1 << i)) {
|
||||
printk(KERN_WARNING
|
||||
"Transfer timeout on channel %d (%s)\n",
|
||||
i, channel->name);
|
||||
DSESR |= (1 << i);
|
||||
}
|
||||
if (DBOSR & (1 << i)) {
|
||||
printk(KERN_WARNING
|
||||
"Buffer overflow timeout on channel %d (%s)\n",
|
||||
i, channel->name);
|
||||
DBOSR |= (1 << i);
|
||||
}
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
int i, disr = DISR;
|
||||
|
||||
DISR = disr;
|
||||
for (i = 0; i < 11; i++) {
|
||||
if (disr & (1 << i)) {
|
||||
struct dma_channel *channel = &dma_channels[i];
|
||||
if (channel->name && channel->irq_handler) {
|
||||
channel->irq_handler(i, channel->data, regs);
|
||||
} else {
|
||||
/*
|
||||
* IRQ for an unregistered DMA channel:
|
||||
* let's clear the interrupts and disable it.
|
||||
*/
|
||||
printk(KERN_WARNING
|
||||
"spurious IRQ for DMA channel %d\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init
|
||||
imx_dma_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* reset DMA module */
|
||||
DCR = DCR_DRST;
|
||||
|
||||
ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
|
||||
if (ret) {
|
||||
printk(KERN_CRIT "Wow! Can't register IRQ for DMA\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_irq(DMA_ERR, dma_err_handler, 0, "DMA", NULL);
|
||||
if (ret) {
|
||||
printk(KERN_CRIT "Wow! Can't register ERRIRQ for DMA\n");
|
||||
free_irq(DMA_INT, NULL);
|
||||
}
|
||||
|
||||
/* enable DMA module */
|
||||
DCR = DCR_DEN;
|
||||
|
||||
/* clear all interrupts */
|
||||
DISR = 0x3ff;
|
||||
|
||||
/* enable interrupts */
|
||||
DIMR = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
arch_initcall(imx_dma_init);
|
||||
|
||||
EXPORT_SYMBOL(imx_request_dma);
|
||||
EXPORT_SYMBOL(imx_free_dma);
|
274
arch/arm/mach-imx/generic.c
Normal file
274
arch/arm/mach-imx/generic.c
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* arch/arm/mach-imx/generic.c
|
||||
*
|
||||
* author: Sascha Hauer
|
||||
* Created: april 20th, 2004
|
||||
* Copyright: Synertronixx GmbH
|
||||
*
|
||||
* Common code for i.MX machines
|
||||
*
|
||||
* 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/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/hardware.h>
|
||||
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
void imx_gpio_mode(int gpio_mode)
|
||||
{
|
||||
unsigned int pin = gpio_mode & GPIO_PIN_MASK;
|
||||
unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> 5;
|
||||
unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> 10;
|
||||
unsigned int tmp;
|
||||
|
||||
/* Pullup enable */
|
||||
if(gpio_mode & GPIO_PUEN)
|
||||
PUEN(port) |= (1<<pin);
|
||||
else
|
||||
PUEN(port) &= ~(1<<pin);
|
||||
|
||||
/* Data direction */
|
||||
if(gpio_mode & GPIO_OUT)
|
||||
DDIR(port) |= 1<<pin;
|
||||
else
|
||||
DDIR(port) &= ~(1<<pin);
|
||||
|
||||
/* Primary / alternate function */
|
||||
if(gpio_mode & GPIO_AF)
|
||||
GPR(port) |= (1<<pin);
|
||||
else
|
||||
GPR(port) &= ~(1<<pin);
|
||||
|
||||
/* use as gpio? */
|
||||
if( ocr == 3 )
|
||||
GIUS(port) |= (1<<pin);
|
||||
else
|
||||
GIUS(port) &= ~(1<<pin);
|
||||
|
||||
/* Output / input configuration */
|
||||
/* FIXME: I'm not very sure about OCR and ICONF, someone
|
||||
* should have a look over it
|
||||
*/
|
||||
if(pin<16) {
|
||||
tmp = OCR1(port);
|
||||
tmp &= ~( 3<<(pin*2));
|
||||
tmp |= (ocr << (pin*2));
|
||||
OCR1(port) = tmp;
|
||||
|
||||
if( gpio_mode & GPIO_AOUT )
|
||||
ICONFA1(port) &= ~( 3<<(pin*2));
|
||||
if( gpio_mode & GPIO_BOUT )
|
||||
ICONFB1(port) &= ~( 3<<(pin*2));
|
||||
} else {
|
||||
tmp = OCR2(port);
|
||||
tmp &= ~( 3<<((pin-16)*2));
|
||||
tmp |= (ocr << ((pin-16)*2));
|
||||
OCR2(port) = tmp;
|
||||
|
||||
if( gpio_mode & GPIO_AOUT )
|
||||
ICONFA2(port) &= ~( 3<<((pin-16)*2));
|
||||
if( gpio_mode & GPIO_BOUT )
|
||||
ICONFB2(port) &= ~( 3<<((pin-16)*2));
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(imx_gpio_mode);
|
||||
|
||||
/*
|
||||
* get the system pll clock in Hz
|
||||
*
|
||||
* mfi + mfn / (mfd +1)
|
||||
* f = 2 * f_ref * --------------------
|
||||
* pd + 1
|
||||
*/
|
||||
static unsigned int imx_decode_pll(unsigned int pll)
|
||||
{
|
||||
u32 mfi = (pll >> 10) & 0xf;
|
||||
u32 mfn = pll & 0x3ff;
|
||||
u32 mfd = (pll >> 16) & 0x3ff;
|
||||
u32 pd = (pll >> 26) & 0xf;
|
||||
u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512);
|
||||
|
||||
mfi = mfi <= 5 ? 5 : mfi;
|
||||
|
||||
return (2 * (f_ref>>10) * ( (mfi<<10) + (mfn<<10) / (mfd+1) )) / (pd+1);
|
||||
}
|
||||
|
||||
unsigned int imx_get_system_clk(void)
|
||||
{
|
||||
return imx_decode_pll(SPCTL0);
|
||||
}
|
||||
EXPORT_SYMBOL(imx_get_system_clk);
|
||||
|
||||
unsigned int imx_get_mcu_clk(void)
|
||||
{
|
||||
return imx_decode_pll(MPCTL0);
|
||||
}
|
||||
EXPORT_SYMBOL(imx_get_mcu_clk);
|
||||
|
||||
/*
|
||||
* get peripheral clock 1 ( UART[12], Timer[12], PWM )
|
||||
*/
|
||||
unsigned int imx_get_perclk1(void)
|
||||
{
|
||||
return imx_get_system_clk() / (((PCDR) & 0xf)+1);
|
||||
}
|
||||
EXPORT_SYMBOL(imx_get_perclk1);
|
||||
|
||||
/*
|
||||
* get peripheral clock 2 ( LCD, SD, SPI[12] )
|
||||
*/
|
||||
unsigned int imx_get_perclk2(void)
|
||||
{
|
||||
return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1);
|
||||
}
|
||||
EXPORT_SYMBOL(imx_get_perclk2);
|
||||
|
||||
/*
|
||||
* get peripheral clock 3 ( SSI )
|
||||
*/
|
||||
unsigned int imx_get_perclk3(void)
|
||||
{
|
||||
return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1);
|
||||
}
|
||||
EXPORT_SYMBOL(imx_get_perclk3);
|
||||
|
||||
/*
|
||||
* get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
|
||||
*/
|
||||
unsigned int imx_get_hclk(void)
|
||||
{
|
||||
return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1);
|
||||
}
|
||||
EXPORT_SYMBOL(imx_get_hclk);
|
||||
|
||||
static struct resource imx_mmc_resources[] = {
|
||||
[0] = {
|
||||
.start = 0x00214000,
|
||||
.end = 0x002140FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = (SDHC_INT),
|
||||
.end = (SDHC_INT),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device imx_mmc_device = {
|
||||
.name = "imx-mmc",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(imx_mmc_resources),
|
||||
.resource = imx_mmc_resources,
|
||||
};
|
||||
|
||||
static struct resource imx_uart1_resources[] = {
|
||||
[0] = {
|
||||
.start = 0x00206000,
|
||||
.end = 0x002060FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = (UART1_MINT_RX),
|
||||
.end = (UART1_MINT_RX),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = (UART1_MINT_TX),
|
||||
.end = (UART1_MINT_TX),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device imx_uart1_device = {
|
||||
.name = "imx-uart",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(imx_uart1_resources),
|
||||
.resource = imx_uart1_resources,
|
||||
};
|
||||
|
||||
static struct resource imx_uart2_resources[] = {
|
||||
[0] = {
|
||||
.start = 0x00207000,
|
||||
.end = 0x002070FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = (UART2_MINT_RX),
|
||||
.end = (UART2_MINT_RX),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[2] = {
|
||||
.start = (UART2_MINT_TX),
|
||||
.end = (UART2_MINT_TX),
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device imx_uart2_device = {
|
||||
.name = "imx-uart",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(imx_uart2_resources),
|
||||
.resource = imx_uart2_resources,
|
||||
};
|
||||
|
||||
static struct resource imxfb_resources[] = {
|
||||
[0] = {
|
||||
.start = 0x00205000,
|
||||
.end = 0x002050FF,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = LCDC_INT,
|
||||
.end = LCDC_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device imxfb_device = {
|
||||
.name = "imx-fb",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(imxfb_resources),
|
||||
.resource = imxfb_resources,
|
||||
};
|
||||
|
||||
static struct platform_device *devices[] __initdata = {
|
||||
&imx_mmc_device,
|
||||
&imxfb_device,
|
||||
&imx_uart1_device,
|
||||
&imx_uart2_device,
|
||||
};
|
||||
|
||||
static struct map_desc imx_io_desc[] __initdata = {
|
||||
/* virtual physical length type */
|
||||
{IMX_IO_BASE, IMX_IO_PHYS, IMX_IO_SIZE, MT_DEVICE},
|
||||
};
|
||||
|
||||
void __init
|
||||
imx_map_io(void)
|
||||
{
|
||||
iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc));
|
||||
}
|
||||
|
||||
static int __init imx_init(void)
|
||||
{
|
||||
return platform_add_devices(devices, ARRAY_SIZE(devices));
|
||||
}
|
||||
|
||||
subsys_initcall(imx_init);
|
16
arch/arm/mach-imx/generic.h
Normal file
16
arch/arm/mach-imx/generic.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-imx/generic.h
|
||||
*
|
||||
* Author: Sascha Hauer <sascha@saschahauer.de>
|
||||
* Copyright: Synertronixx GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
extern void __init imx_map_io(void);
|
||||
extern void __init imx_init_irq(void);
|
||||
|
||||
struct sys_timer;
|
||||
extern struct sys_timer imx_timer;
|
252
arch/arm/mach-imx/irq.c
Normal file
252
arch/arm/mach-imx/irq.c
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-imx/irq.c
|
||||
*
|
||||
* Copyright (C) 1999 ARM Limited
|
||||
* Copyright (C) 2002 Shane Nay (shane@minirl.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.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 03/03/2004 Sascha Hauer <sascha@saschahauer.de>
|
||||
* Copied from the motorola bsp package and added gpio demux
|
||||
* interrupt handler
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
/*
|
||||
*
|
||||
* We simply use the ENABLE DISABLE registers inside of the IMX
|
||||
* to turn on/off specific interrupts. FIXME- We should
|
||||
* also add support for the accelerated interrupt controller
|
||||
* by putting offets to irq jump code in the appropriate
|
||||
* places.
|
||||
*
|
||||
*/
|
||||
|
||||
#define INTENNUM_OFF 0x8
|
||||
#define INTDISNUM_OFF 0xC
|
||||
|
||||
#define VA_AITC_BASE IO_ADDRESS(IMX_AITC_BASE)
|
||||
#define IMX_AITC_INTDISNUM (VA_AITC_BASE + INTDISNUM_OFF)
|
||||
#define IMX_AITC_INTENNUM (VA_AITC_BASE + INTENNUM_OFF)
|
||||
|
||||
#if 0
|
||||
#define DEBUG_IRQ(fmt...) printk(fmt)
|
||||
#else
|
||||
#define DEBUG_IRQ(fmt...) do { } while (0)
|
||||
#endif
|
||||
|
||||
static void
|
||||
imx_mask_irq(unsigned int irq)
|
||||
{
|
||||
__raw_writel(irq, IMX_AITC_INTDISNUM);
|
||||
}
|
||||
|
||||
static void
|
||||
imx_unmask_irq(unsigned int irq)
|
||||
{
|
||||
__raw_writel(irq, IMX_AITC_INTENNUM);
|
||||
}
|
||||
|
||||
static int
|
||||
imx_gpio_irq_type(unsigned int _irq, unsigned int type)
|
||||
{
|
||||
unsigned int irq_type = 0, irq, reg, bit;
|
||||
|
||||
irq = _irq - IRQ_GPIOA(0);
|
||||
reg = irq >> 5;
|
||||
bit = 1 << (irq % 32);
|
||||
|
||||
if (type == IRQT_PROBE) {
|
||||
/* Don't mess with enabled GPIOs using preconfigured edges or
|
||||
GPIOs set to alternate function during probe */
|
||||
/* TODO: support probe */
|
||||
// if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) &
|
||||
// GPIO_bit(gpio))
|
||||
// return 0;
|
||||
// if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2)))
|
||||
// return 0;
|
||||
// type = __IRQT_RISEDGE | __IRQT_FALEDGE;
|
||||
}
|
||||
|
||||
GIUS(reg) |= bit;
|
||||
DDIR(reg) &= ~(bit);
|
||||
|
||||
DEBUG_IRQ("setting type of irq %d to ", _irq);
|
||||
|
||||
if (type & __IRQT_RISEDGE) {
|
||||
DEBUG_IRQ("rising edges\n");
|
||||
irq_type = 0x0;
|
||||
}
|
||||
if (type & __IRQT_FALEDGE) {
|
||||
DEBUG_IRQ("falling edges\n");
|
||||
irq_type = 0x1;
|
||||
}
|
||||
if (type & __IRQT_LOWLVL) {
|
||||
DEBUG_IRQ("low level\n");
|
||||
irq_type = 0x3;
|
||||
}
|
||||
if (type & __IRQT_HIGHLVL) {
|
||||
DEBUG_IRQ("high level\n");
|
||||
irq_type = 0x2;
|
||||
}
|
||||
|
||||
if (irq % 32 < 16) {
|
||||
ICR1(reg) = (ICR1(reg) & ~(0x3 << ((irq % 16) * 2))) |
|
||||
(irq_type << ((irq % 16) * 2));
|
||||
} else {
|
||||
ICR2(reg) = (ICR2(reg) & ~(0x3 << ((irq % 16) * 2))) |
|
||||
(irq_type << ((irq % 16) * 2));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
imx_gpio_ack_irq(unsigned int irq)
|
||||
{
|
||||
DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
|
||||
ISR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32);
|
||||
}
|
||||
|
||||
static void
|
||||
imx_gpio_mask_irq(unsigned int irq)
|
||||
{
|
||||
DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
|
||||
IMR(IRQ_TO_REG(irq)) &= ~( 1 << ((irq - IRQ_GPIOA(0)) % 32));
|
||||
}
|
||||
|
||||
static void
|
||||
imx_gpio_unmask_irq(unsigned int irq)
|
||||
{
|
||||
DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
|
||||
IMR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32);
|
||||
}
|
||||
|
||||
static void
|
||||
imx_gpio_handler(unsigned int mask, unsigned int irq,
|
||||
struct irqdesc *desc, struct pt_regs *regs)
|
||||
{
|
||||
desc = irq_desc + irq;
|
||||
while (mask) {
|
||||
if (mask & 1) {
|
||||
DEBUG_IRQ("handling irq %d\n", irq);
|
||||
desc->handle(irq, desc, regs);
|
||||
}
|
||||
irq++;
|
||||
desc++;
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
unsigned int mask, irq;
|
||||
|
||||
mask = ISR(0);
|
||||
irq = IRQ_GPIOA(0);
|
||||
imx_gpio_handler(mask, irq, desc, regs);
|
||||
}
|
||||
|
||||
static void
|
||||
imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
unsigned int mask, irq;
|
||||
|
||||
mask = ISR(1);
|
||||
irq = IRQ_GPIOB(0);
|
||||
imx_gpio_handler(mask, irq, desc, regs);
|
||||
}
|
||||
|
||||
static void
|
||||
imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
unsigned int mask, irq;
|
||||
|
||||
mask = ISR(2);
|
||||
irq = IRQ_GPIOC(0);
|
||||
imx_gpio_handler(mask, irq, desc, regs);
|
||||
}
|
||||
|
||||
static void
|
||||
imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
unsigned int mask, irq;
|
||||
|
||||
mask = ISR(3);
|
||||
irq = IRQ_GPIOD(0);
|
||||
imx_gpio_handler(mask, irq, desc, regs);
|
||||
}
|
||||
|
||||
static struct irqchip imx_internal_chip = {
|
||||
.ack = imx_mask_irq,
|
||||
.mask = imx_mask_irq,
|
||||
.unmask = imx_unmask_irq,
|
||||
};
|
||||
|
||||
static struct irqchip imx_gpio_chip = {
|
||||
.ack = imx_gpio_ack_irq,
|
||||
.mask = imx_gpio_mask_irq,
|
||||
.unmask = imx_gpio_unmask_irq,
|
||||
.type = imx_gpio_irq_type,
|
||||
};
|
||||
|
||||
void __init
|
||||
imx_init_irq(void)
|
||||
{
|
||||
unsigned int irq;
|
||||
|
||||
DEBUG_IRQ("Initializing imx interrupts\n");
|
||||
|
||||
/* Mask all interrupts initially */
|
||||
IMR(0) = 0;
|
||||
IMR(1) = 0;
|
||||
IMR(2) = 0;
|
||||
IMR(3) = 0;
|
||||
|
||||
for (irq = 0; irq < IMX_IRQS; irq++) {
|
||||
set_irq_chip(irq, &imx_internal_chip);
|
||||
set_irq_handler(irq, do_level_IRQ);
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
}
|
||||
|
||||
for (irq = IRQ_GPIOA(0); irq < IRQ_GPIOD(32); irq++) {
|
||||
set_irq_chip(irq, &imx_gpio_chip);
|
||||
set_irq_handler(irq, do_edge_IRQ);
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
}
|
||||
|
||||
set_irq_chained_handler(GPIO_INT_PORTA, imx_gpioa_demux_handler);
|
||||
set_irq_chained_handler(GPIO_INT_PORTB, imx_gpiob_demux_handler);
|
||||
set_irq_chained_handler(GPIO_INT_PORTC, imx_gpioc_demux_handler);
|
||||
set_irq_chained_handler(GPIO_INT_PORTD, imx_gpiod_demux_handler);
|
||||
|
||||
/* Disable all interrupts initially. */
|
||||
/* In IMX this is done in the bootloader. */
|
||||
}
|
54
arch/arm/mach-imx/leds-mx1ads.c
Normal file
54
arch/arm/mach-imx/leds-mx1ads.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-imx/leds-mx1ads.c
|
||||
*
|
||||
* Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
|
||||
*
|
||||
* Original (leds-footbridge.c) by Russell King
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/leds.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include "leds.h"
|
||||
|
||||
/*
|
||||
* The MX1ADS Board has only one usable LED,
|
||||
* so select only the timer led or the
|
||||
* cpu usage led
|
||||
*/
|
||||
void
|
||||
mx1ads_leds_event(led_event_t ledevt)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
switch (ledevt) {
|
||||
#ifdef CONFIG_LEDS_CPU
|
||||
case led_idle_start:
|
||||
DR(0) &= ~(1<<2);
|
||||
break;
|
||||
|
||||
case led_idle_end:
|
||||
DR(0) |= 1<<2;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LEDS_TIMER
|
||||
case led_timer:
|
||||
DR(0) ^= 1<<2;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
31
arch/arm/mach-imx/leds.c
Normal file
31
arch/arm/mach-imx/leds.c
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-imx/leds.h
|
||||
*
|
||||
* Copyright (C) 2004 Sascha Hauer <sascha@saschahauer.de>
|
||||
*
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <asm/leds.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include "leds.h"
|
||||
|
||||
static int __init
|
||||
leds_init(void)
|
||||
{
|
||||
if (machine_is_mx1ads()) {
|
||||
leds_event = mx1ads_leds_event;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__initcall(leds_init);
|
9
arch/arm/mach-imx/leds.h
Normal file
9
arch/arm/mach-imx/leds.h
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* include/asm-arm/arch-imx/leds.h
|
||||
*
|
||||
* Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
|
||||
*
|
||||
* blinky lights for IMX-based systems
|
||||
*
|
||||
*/
|
||||
extern void mx1ads_leds_event(led_event_t evt);
|
88
arch/arm/mach-imx/mx1ads.c
Normal file
88
arch/arm/mach-imx/mx1ads.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* arch/arm/mach-imx/mx1ads.c
|
||||
*
|
||||
* Initially based on:
|
||||
* linux-2.6.7-imx/arch/arm/mach-imx/scb9328.c
|
||||
* Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
|
||||
*
|
||||
* 2004 (c) MontaVista Software, Inc.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#include <asm/mach/map.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <asm/mach/arch.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include "generic.h"
|
||||
#include <asm/serial.h>
|
||||
|
||||
static struct resource mx1ads_resources[] = {
|
||||
[0] = {
|
||||
.start = IMX_CS4_VIRT,
|
||||
.end = IMX_CS4_VIRT + 16,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = 13,
|
||||
.end = 13,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device mx1ads_device = {
|
||||
.name = "mx1ads",
|
||||
.num_resources = ARRAY_SIZE(mx1ads_resources),
|
||||
.resource = mx1ads_resources,
|
||||
};
|
||||
|
||||
static struct platform_device *devices[] __initdata = {
|
||||
&mx1ads_device,
|
||||
};
|
||||
|
||||
static void __init
|
||||
mx1ads_init(void)
|
||||
{
|
||||
#ifdef CONFIG_LEDS
|
||||
imx_gpio_mode(GPIO_PORTA | GPIO_OUT | GPIO_GPIO | 2);
|
||||
#endif
|
||||
platform_add_devices(devices, ARRAY_SIZE(devices));
|
||||
}
|
||||
|
||||
static struct map_desc mx1ads_io_desc[] __initdata = {
|
||||
/* virtual physical length type */
|
||||
{IMX_CS0_VIRT, IMX_CS0_PHYS, IMX_CS0_SIZE, MT_DEVICE},
|
||||
{IMX_CS1_VIRT, IMX_CS1_PHYS, IMX_CS1_SIZE, MT_DEVICE},
|
||||
{IMX_CS2_VIRT, IMX_CS2_PHYS, IMX_CS2_SIZE, MT_DEVICE},
|
||||
{IMX_CS3_VIRT, IMX_CS3_PHYS, IMX_CS3_SIZE, MT_DEVICE},
|
||||
{IMX_CS4_VIRT, IMX_CS4_PHYS, IMX_CS4_SIZE, MT_DEVICE},
|
||||
{IMX_CS5_VIRT, IMX_CS5_PHYS, IMX_CS5_SIZE, MT_DEVICE},
|
||||
};
|
||||
|
||||
static void __init
|
||||
mx1ads_map_io(void)
|
||||
{
|
||||
imx_map_io();
|
||||
iotable_init(mx1ads_io_desc, ARRAY_SIZE(mx1ads_io_desc));
|
||||
}
|
||||
|
||||
MACHINE_START(MX1ADS, "Motorola MX1ADS")
|
||||
MAINTAINER("Sascha Hauer, Pengutronix")
|
||||
BOOT_MEM(0x08000000, 0x00200000, 0xe0200000)
|
||||
BOOT_PARAMS(0x08000100)
|
||||
MAPIO(mx1ads_map_io)
|
||||
INITIRQ(imx_init_irq)
|
||||
.timer = &imx_timer,
|
||||
INIT_MACHINE(mx1ads_init)
|
||||
MACHINE_END
|
101
arch/arm/mach-imx/time.c
Normal file
101
arch/arm/mach-imx/time.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* linux/arch/arm/mach-imx/time.c
|
||||
*
|
||||
* Copyright (C) 2000-2001 Deep Blue Solutions
|
||||
* Copyright (C) 2002 Shane Nay (shane@minirl.com)
|
||||
*
|
||||
* 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/config.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/leds.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/mach/time.h>
|
||||
|
||||
/* Use timer 1 as system timer */
|
||||
#define TIMER_BASE IMX_TIM1_BASE
|
||||
|
||||
/*
|
||||
* Returns number of us since last clock interrupt. Note that interrupts
|
||||
* will have been disabled by do_gettimeoffset()
|
||||
*/
|
||||
static unsigned long imx_gettimeoffset(void)
|
||||
{
|
||||
unsigned long ticks;
|
||||
|
||||
/*
|
||||
* Get the current number of ticks. Note that there is a race
|
||||
* condition between us reading the timer and checking for
|
||||
* an interrupt. We get around this by ensuring that the
|
||||
* counter has not reloaded between our two reads.
|
||||
*/
|
||||
ticks = IMX_TCN(TIMER_BASE);
|
||||
|
||||
/*
|
||||
* Interrupt pending? If so, we've reloaded once already.
|
||||
*/
|
||||
if (IMX_TSTAT(TIMER_BASE) & TSTAT_COMP)
|
||||
ticks += LATCH;
|
||||
|
||||
/*
|
||||
* Convert the ticks to usecs
|
||||
*/
|
||||
return (1000000 / CLK32) * ticks;
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQ handler for the timer
|
||||
*/
|
||||
static irqreturn_t
|
||||
imx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
write_seqlock(&xtime_lock);
|
||||
|
||||
/* clear the interrupt */
|
||||
if (IMX_TSTAT(TIMER_BASE))
|
||||
IMX_TSTAT(TIMER_BASE) = 0;
|
||||
|
||||
timer_tick(regs);
|
||||
write_sequnlock(&xtime_lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct irqaction imx_timer_irq = {
|
||||
.name = "i.MX Timer Tick",
|
||||
.flags = SA_INTERRUPT,
|
||||
.handler = imx_timer_interrupt
|
||||
};
|
||||
|
||||
/*
|
||||
* Set up timer interrupt, and return the current time in seconds.
|
||||
*/
|
||||
static void __init imx_timer_init(void)
|
||||
{
|
||||
/*
|
||||
* Initialise to a known state (all timers off, and timing reset)
|
||||
*/
|
||||
IMX_TCTL(TIMER_BASE) = 0;
|
||||
IMX_TPRER(TIMER_BASE) = 0;
|
||||
IMX_TCMP(TIMER_BASE) = LATCH - 1;
|
||||
IMX_TCTL(TIMER_BASE) = TCTL_CLK_32 | TCTL_IRQEN | TCTL_TEN;
|
||||
|
||||
/*
|
||||
* Make irqs happen for the system timer
|
||||
*/
|
||||
setup_irq(TIM1_INT, &imx_timer_irq);
|
||||
}
|
||||
|
||||
struct sys_timer imx_timer = {
|
||||
.init = imx_timer_init,
|
||||
.offset = imx_gettimeoffset,
|
||||
};
|
Reference in New Issue
Block a user