diff options
-rw-r--r-- | arch/arm/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-mx1/Kconfig | 14 | ||||
-rw-r--r-- | arch/arm/mach-mx1/Makefile | 10 | ||||
-rw-r--r-- | arch/arm/mach-mx1/Makefile.boot | 4 | ||||
-rw-r--r-- | arch/arm/mach-mx1/clock.c | 656 | ||||
-rw-r--r-- | arch/arm/mach-mx1/crm_regs.h | 55 | ||||
-rw-r--r-- | arch/arm/mach-mx1/devices.c | 118 | ||||
-rw-r--r-- | arch/arm/mach-mx1/devices.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-mx1/generic.c | 43 | ||||
-rw-r--r-- | arch/arm/mach-mx1/mx1ads.c | 148 | ||||
-rw-r--r-- | arch/arm/plat-mxc/Kconfig | 6 | ||||
-rw-r--r-- | arch/arm/plat-mxc/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/plat-mxc/gpio.c | 6 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/hardware.h | 4 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/mx1.h | 197 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/mxc_timer.h | 4 |
16 files changed, 1264 insertions, 5 deletions
diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 260864f3f01..c8548a18741 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -139,6 +139,7 @@ endif plat-$(CONFIG_ARCH_MXC) := mxc machine-$(CONFIG_ARCH_MX2) := mx2 machine-$(CONFIG_ARCH_MX3) := mx3 + machine-$(CONFIG_ARCH_MX1) := mx1 machine-$(CONFIG_ARCH_ORION5X) := orion5x plat-$(CONFIG_PLAT_ORION) := orion machine-$(CONFIG_ARCH_MSM) := msm diff --git a/arch/arm/mach-mx1/Kconfig b/arch/arm/mach-mx1/Kconfig new file mode 100644 index 00000000000..2b59fc74784 --- /dev/null +++ b/arch/arm/mach-mx1/Kconfig @@ -0,0 +1,14 @@ +if ARCH_MX1 + +comment "MX1 Platforms" + +config MACH_MXLADS + bool + +config ARCH_MX1ADS + bool "MX1ADS platform" + select MACH_MXLADS + help + Say Y here if you are using Motorola MX1ADS/MXLADS boards + +endif diff --git a/arch/arm/mach-mx1/Makefile b/arch/arm/mach-mx1/Makefile new file mode 100644 index 00000000000..b969719011f --- /dev/null +++ b/arch/arm/mach-mx1/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y += generic.o clock.o devices.o + +# Specific board support +obj-$(CONFIG_ARCH_MX1ADS) += mx1ads.o diff --git a/arch/arm/mach-mx1/Makefile.boot b/arch/arm/mach-mx1/Makefile.boot new file mode 100644 index 00000000000..8ed1492288a --- /dev/null +++ b/arch/arm/mach-mx1/Makefile.boot @@ -0,0 +1,4 @@ + zreladdr-y := 0x08008000 +params_phys-y := 0x08000100 +initrd_phys-y := 0x08800000 + diff --git a/arch/arm/mach-mx1/clock.c b/arch/arm/mach-mx1/clock.c new file mode 100644 index 00000000000..4bcd1ece55f --- /dev/null +++ b/arch/arm/mach-mx1/clock.c @@ -0,0 +1,656 @@ +/* + * Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/math64.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <mach/clock.h> +#include <mach/hardware.h> +#include "crm_regs.h" + +static int _clk_enable(struct clk *clk) +{ + unsigned int reg; + + reg = __raw_readl(clk->enable_reg); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + return 0; +} + +static void _clk_disable(struct clk *clk) +{ + unsigned int reg; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(1 << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +static int _clk_can_use_parent(const struct clk *clk_arr[], unsigned int size, + struct clk *parent) +{ + int i; + + for (i = 0; i < size; i++) + if (parent == clk_arr[i]) + return i; + + return -EINVAL; +} + +static unsigned long +_clk_simple_round_rate(struct clk *clk, unsigned long rate, unsigned int limit) +{ + int div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (parent_rate % rate) + div++; + + if (div > limit) + div = limit; + + return parent_rate / div; +} + +static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate) +{ + return clk->parent->round_rate(clk->parent, rate); +} + +static int _clk_parent_set_rate(struct clk *clk, unsigned long rate) +{ + return clk->parent->set_rate(clk->parent, rate); +} + +/* + * get the system pll clock in Hz + * + * mfi + mfn / (mfd +1) + * f = 2 * f_ref * -------------------- + * pd + 1 + */ +static unsigned long mx1_decode_pll(unsigned int pll, u32 f_ref) +{ + unsigned long long ll; + unsigned long quot; + + u32 mfi = (pll >> 10) & 0xf; + u32 mfn = pll & 0x3ff; + u32 mfd = (pll >> 16) & 0x3ff; + u32 pd = (pll >> 26) & 0xf; + + mfi = mfi <= 5 ? 5 : mfi; + + ll = 2 * (unsigned long long)f_ref * + ((mfi << 16) + (mfn << 16) / (mfd + 1)); + quot = (pd + 1) * (1 << 16); + ll += quot / 2; + do_div(ll, quot); + return (unsigned long)ll; +} + +static unsigned long clk16m_get_rate(struct clk *clk) +{ + return 16000000; +} + +static struct clk clk16m = { + .name = "CLK16M", + .get_rate = clk16m_get_rate, + .enable = _clk_enable, + .enable_reg = CCM_CSCR, + .enable_shift = CCM_CSCR_OSC_EN_SHIFT, + .disable = _clk_disable, +}; + +/* in Hz */ +static unsigned long clk32_rate; + +static unsigned long clk32_get_rate(struct clk *clk) +{ + return clk32_rate; +} + +static struct clk clk32 = { + .name = "CLK32", + .get_rate = clk32_get_rate, +}; + +static unsigned long clk32_premult_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) * 512; +} + +static struct clk clk32_premult = { + .name = "CLK32_premultiplier", + .parent = &clk32, + .get_rate = clk32_premult_get_rate, +}; + +static const struct clk *prem_clk_clocks[] = { + &clk32_premult, + &clk16m, +}; + +static int prem_clk_set_parent(struct clk *clk, struct clk *parent) +{ + int i; + unsigned int reg = __raw_readl(CCM_CSCR); + + i = _clk_can_use_parent(prem_clk_clocks, ARRAY_SIZE(prem_clk_clocks), + parent); + + switch (i) { + case 0: + reg &= ~CCM_CSCR_SYSTEM_SEL; + break; + case 1: + reg |= CCM_CSCR_SYSTEM_SEL; + break; + default: + return i; + } + + __raw_writel(reg, CCM_CSCR); + + return 0; +} + +static struct clk prem_clk = { + .name = "prem_clk", + .set_parent = prem_clk_set_parent, +}; + +static unsigned long system_clk_get_rate(struct clk *clk) +{ + return mx1_decode_pll(__raw_readl(CCM_SPCTL0), + clk_get_rate(clk->parent)); +} + +static struct clk system_clk = { + .name = "system_clk", + .parent = &prem_clk, + .get_rate = system_clk_get_rate, +}; + +static unsigned long mcu_clk_get_rate(struct clk *clk) +{ + return mx1_decode_pll(__raw_readl(CCM_MPCTL0), + clk_get_rate(clk->parent)); +} + +static struct clk mcu_clk = { + .name = "mcu_clk", + .parent = &clk32_premult, + .get_rate = mcu_clk_get_rate, +}; + +static unsigned long fclk_get_rate(struct clk *clk) +{ + unsigned long fclk = clk_get_rate(clk->parent); + + if (__raw_readl(CCM_CSCR) & CCM_CSCR_PRESC) + fclk /= 2; + + return fclk; +} + +static struct clk fclk = { + .name = "fclk", + .parent = &mcu_clk, + .get_rate = fclk_get_rate, +}; + +/* + * get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA ) + */ +static unsigned long hclk_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) & + CCM_CSCR_BCLK_MASK) >> CCM_CSCR_BCLK_OFFSET) + 1); +} + +static unsigned long hclk_round_rate(struct clk *clk, unsigned long rate) +{ + return _clk_simple_round_rate(clk, rate, 16); +} + +static int hclk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int div; + unsigned int reg; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if (div > 16 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + + div--; + + reg = __raw_readl(CCM_CSCR); + reg &= ~CCM_CSCR_BCLK_MASK; + reg |= div << CCM_CSCR_BCLK_OFFSET; + __raw_writel(reg, CCM_CSCR); + + return 0; +} + +static struct clk hclk = { + .name = "hclk", + .parent = &system_clk, + .get_rate = hclk_get_rate, + .round_rate = hclk_round_rate, + .set_rate = hclk_set_rate, +}; + +static unsigned long clk48m_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) & + CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET) + 1); +} + +static unsigned long clk48m_round_rate(struct clk *clk, unsigned long rate) +{ + return _clk_simple_round_rate(clk, rate, 8); +} + +static int clk48m_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int div; + unsigned int reg; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if (div > 8 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + + div--; + + reg = __raw_readl(CCM_CSCR); + reg &= ~CCM_CSCR_USB_MASK; + reg |= div << CCM_CSCR_USB_OFFSET; + __raw_writel(reg, CCM_CSCR); + + return 0; +} + +static struct clk clk48m = { + .name = "CLK48M", + .parent = &system_clk, + .get_rate = clk48m_get_rate, + .round_rate = clk48m_round_rate, + .set_rate = clk48m_set_rate, +}; + +/* + * get peripheral clock 1 ( UART[12], Timer[12], PWM ) + */ +static unsigned long perclk1_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) & + CCM_PCDR_PCLK1_MASK) >> CCM_PCDR_PCLK1_OFFSET) + 1); +} + +static unsigned long perclk1_round_rate(struct clk *clk, unsigned long rate) +{ + return _clk_simple_round_rate(clk, rate, 16); +} + +static int perclk1_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int div; + unsigned int reg; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if (div > 16 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + + div--; + + reg = __raw_readl(CCM_PCDR); + reg &= ~CCM_PCDR_PCLK1_MASK; + reg |= div << CCM_PCDR_PCLK1_OFFSET; + __raw_writel(reg, CCM_PCDR); + + return 0; +} + +/* + * get peripheral clock 2 ( LCD, SD, SPI[12] ) + */ +static unsigned long perclk2_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) & + CCM_PCDR_PCLK2_MASK) >> CCM_PCDR_PCLK2_OFFSET) + 1); +} + +static unsigned long perclk2_round_rate(struct clk *clk, unsigned long rate) +{ + return _clk_simple_round_rate(clk, rate, 16); +} + +static int perclk2_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int div; + unsigned int reg; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if (div > 16 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + + div--; + + reg = __raw_readl(CCM_PCDR); + reg &= ~CCM_PCDR_PCLK2_MASK; + reg |= div << CCM_PCDR_PCLK2_OFFSET; + __raw_writel(reg, CCM_PCDR); + + return 0; +} + +/* + * get peripheral clock 3 ( SSI ) + */ +static unsigned long perclk3_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) & + CCM_PCDR_PCLK3_MASK) >> CCM_PCDR_PCLK3_OFFSET) + 1); +} + +static unsigned long perclk3_round_rate(struct clk *clk, unsigned long rate) +{ + return _clk_simple_round_rate(clk, rate, 128); +} + +static int perclk3_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int div; + unsigned int reg; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if (div > 128 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + + div--; + + reg = __raw_readl(CCM_PCDR); + reg &= ~CCM_PCDR_PCLK3_MASK; + reg |= div << CCM_PCDR_PCLK3_OFFSET; + __raw_writel(reg, CCM_PCDR); + + return 0; +} + +static struct clk perclk[] = { + { + .name = "perclk", + .id = 0, + .parent = &system_clk, + .get_rate = perclk1_get_rate, + .round_rate = perclk1_round_rate, + .set_rate = perclk1_set_rate, + }, { + .name = "perclk", + .id = 1, + .parent = &system_clk, + .get_rate = perclk2_get_rate, + .round_rate = perclk2_round_rate, + .set_rate = perclk2_set_rate, + }, { + .name = "perclk", + .id = 2, + .parent = &system_clk, + .get_rate = perclk3_get_rate, + .round_rate = perclk3_round_rate, + .set_rate = perclk3_set_rate, + } +}; + +static const struct clk *clko_clocks[] = { + &perclk[0], + &hclk, + &clk48m, + &clk16m, + &prem_clk, + &fclk, +}; + +static int clko_set_parent(struct clk *clk, struct clk *parent) +{ + int i; + unsigned int reg; + + i = _clk_can_use_parent(clko_clocks, ARRAY_SIZE(clko_clocks), parent); + if (i < 0) + return i; + + reg = __raw_readl(CCM_CSCR) & ~CCM_CSCR_CLKO_MASK; + reg |= i << CCM_CSCR_CLKO_OFFSET; + __raw_writel(reg, CCM_CSCR); + + if (clko_clocks[i]->set_rate && clko_clocks[i]->round_rate) { + clk->set_rate = _clk_parent_set_rate; + clk->round_rate = _clk_parent_round_rate; + } else { + clk->set_rate = NULL; + clk->round_rate = NULL; + } + + return 0; +} + +static struct clk clko_clk = { + .name = "clko_clk", + .set_parent = clko_set_parent, +}; + +static struct clk dma_clk = { + .name = "dma_clk", + .parent = &hclk, + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, + .enable = _clk_enable, + .enable_reg = SCM_GCCR, + .enable_shift = SCM_GCCR_DMA_CLK_EN_OFFSET, + .disable = _clk_disable, +}; + +static struct clk csi_clk = { + .name = "csi_clk", + .parent = &hclk, + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, + .enable = _clk_enable, + .enable_reg = SCM_GCCR, + .enable_shift = SCM_GCCR_CSI_CLK_EN_OFFSET, + .disable = _clk_disable, +}; + +static struct clk mma_clk = { + .name = "mma_clk", + .parent = &hclk, + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, + .enable = _clk_enable, + .enable_reg = SCM_GCCR, + .enable_shift = SCM_GCCR_MMA_CLK_EN_OFFSET, + .disable = _clk_disable, +}; + +static struct clk usbd_clk = { + .name = "usbd_clk", + .parent = &clk48m, + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, + .enable = _clk_enable, + .enable_reg = SCM_GCCR, + .enable_shift = SCM_GCCR_USBD_CLK_EN_OFFSET, + .disable = _clk_disable, +}; + +static struct clk gpt_clk = { + .name = "gpt_clk", + .parent = &perclk[0], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk uart_clk = { + .name = "uart_clk", + .parent = &perclk[0], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk i2c_clk = { + .name = "i2c_clk", + .parent = &hclk, + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk spi_clk = { + .name = "spi_clk", + .parent = &perclk[1], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk sdhc_clk = { + .name = "sdhc_clk", + .parent = &perclk[1], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk lcdc_clk = { + .name = "lcdc_clk", + .parent = &perclk[1], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk mshc_clk = { + .name = "mshc_clk", + .parent = &hclk, + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk ssi_clk = { + .name = "ssi_clk", + .parent = &perclk[2], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk rtc_clk = { + .name = "rtc_clk", + .parent = &clk32, +}; + +static struct clk *mxc_clks[] = { + &clk16m, + &clk32, + &clk32_premult, + &prem_clk, + &system_clk, + &mcu_clk, + &fclk, + &hclk, + &clk48m, + &perclk[0], + &perclk[1], + &perclk[2], + &clko_clk, + &dma_clk, + &csi_clk, + &mma_clk, + &usbd_clk, + &gpt_clk, + &uart_clk, + &i2c_clk, + &spi_clk, + &sdhc_clk, + &lcdc_clk, + &mshc_clk, + &ssi_clk, + &rtc_clk, +}; + +int __init mxc_clocks_init(unsigned long fref) +{ + struct clk **clkp; + unsigned int reg; + + /* disable clocks we are able to */ + __raw_writel(0, SCM_GCCR); + + clk32_rate = fref; + reg = __raw_readl(CCM_CSCR); + + /* detect clock reference for system PLL */ + if (reg & CCM_CSCR_SYSTEM_SEL) { + prem_clk.parent = &clk16m; + } else { + /* ensure that oscillator is disabled */ + reg &= ~(1 << CCM_CSCR_OSC_EN_SHIFT); + __raw_writel(reg, CCM_CSCR); + prem_clk.parent = &clk32_premult; + } + + /* detect reference for CLKO */ + reg = (reg & CCM_CSCR_CLKO_MASK) >> CCM_CSCR_CLKO_OFFSET; + clko_clk.parent = (struct clk *)clko_clocks[reg]; + + for (clkp = mxc_clks; clkp < mxc_clks + ARRAY_SIZE(mxc_clks); clkp++) + clk_register(*clkp); + + clk_enable(&hclk); + clk_enable(&fclk); + + return 0; +} diff --git a/arch/arm/mach-mx1/crm_regs.h b/arch/arm/mach-mx1/crm_regs.h new file mode 100644 index 00000000000..22e866ff0c0 --- /dev/null +++ b/arch/arm/mach-mx1/crm_regs.h @@ -0,0 +1,55 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (c) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> + * + * This file may be distributed under the terms of the GNU General + * Public License, version 2. + */ + +#ifndef __ARCH_ARM_MACH_MX1_CRM_REGS_H__ +#define __ARCH_ARM_MACH_MX1_CRM_REGS_H__ + +#define CCM_BASE IO_ADDRESS(CCM_BASE_ADDR) +#define SCM_BASE IO_ADDRESS(SCM_BASE_ADDR) + +/* CCM register addresses */ +#define CCM_CSCR (CCM_BASE + 0x0) +#define CCM_MPCTL0 (CCM_BASE + 0x4) +#define CCM_MPCTL1 (CCM_BASE + 0x8) +#define CCM_SPCTL0 (CCM_BASE + 0xC) +#define CCM_SPCTL1 (CCM_BASE + 0x10) +#define CCM_PCDR (CCM_BASE + 0x20) + +#define CCM_CSCR_CLKO_OFFSET 29 +#define CCM_CSCR_CLKO_MASK (0x7 << 29) +#define CCM_CSCR_USB_OFFSET 26 +#define CCM_CSCR_USB_MASK (0x7 << 26) +#define CCM_CSCR_SPLL_RESTART (1 << 22) +#define CCM_CSCR_MPLL_RESTART (1 << 21) +#define CCM_CSCR_OSC_EN_SHIFT 17 +#define CCM_CSCR_SYSTEM_SEL (1 << 16) +#define CCM_CSCR_BCLK_OFFSET 10 +#define CCM_CSCR_BCLK_MASK (0xF << 10) +#define CCM_CSCR_PRESC (1 << 15) +#define CCM_CSCR_SPEN (1 << 1) +#define CCM_CSCR_MPEN (1 << 0) + +#define CCM_PCDR_PCLK3_OFFSET 16 +#define CCM_PCDR_PCLK3_MASK (0x7F << 16) +#define CCM_PCDR_PCLK2_OFFSET 4 +#define CCM_PCDR_PCLK2_MASK (0xF << 4) +#define CCM_PCDR_PCLK1_OFFSET 0 +#define CCM_PCDR_PCLK1_MASK 0xF + +/* SCM register addresses */ +#define SCM_SIDR (SCM_BASE + 0x0) +#define SCM_FMCR (SCM_BASE + 0x4) +#define SCM_GPCR (SCM_BASE + 0x8) +#define SCM_GCCR (SCM_BASE + 0xC) + +#define SCM_GCCR_DMA_CLK_EN_OFFSET 3 +#define SCM_GCCR_CSI_CLK_EN_OFFSET 2 +#define SCM_GCCR_MMA_CLK_EN_OFFSET 1 +#define SCM_GCCR_USBD_CLK_EN_OFFSET 0 + +#endif /* __ARCH_ARM_MACH_MX2_CRM_REGS_H__ */ diff --git a/arch/arm/mach-mx1/devices.c b/arch/arm/mach-mx1/devices.c new file mode 100644 index 00000000000..aa7b0b08dfc --- /dev/null +++ b/arch/arm/mach-mx1/devices.c @@ -0,0 +1,118 @@ +/* + * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Sascha Hauer, kernel@pengutronix.de + * Copyright (c) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <mach/hardware.h> + +static struct resource imx_uart1_resources[] = { + [0] = { + .start = UART1_BASE_ADDR, + .end = UART1_BASE_ADDR + 0xD0, + .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, + }, + [3] = { + .start = UART1_MINT_RTS, + .end = UART1_MINT_RTS, + .flags = IORESOURCE_IRQ, + }, +}; + +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 = UART2_BASE_ADDR, + .end = UART2_BASE_ADDR + 0xD0, + .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, + }, + [3] = { + .start = UART2_MINT_RTS, + .end = UART2_MINT_RTS, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device imx_uart2_device = { + .name = "imx-uart", + .id = 1, + .num_resources = ARRAY_SIZE(imx_uart2_resources), + .resource = imx_uart2_resources, +}; + +/* GPIO port description */ +static struct mxc_gpio_port imx_gpio_ports[] = { + [0] = { + .chip.label = "gpio-0", + .base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR), + .irq = GPIO_INT_PORTA, + .virtual_irq_start = MXC_MAX_INT_LINES + }, + [1] = { + .chip.label = "gpio-1", + .base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR + 0x100), + .irq = GPIO_INT_PORTB, + .virtual_irq_start = MXC_MAX_INT_LINES + 32 + }, + [2] = { + .chip.label = "gpio-2", + .base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR + 0x200), + .irq = GPIO_INT_PORTC, + .virtual_irq_start = MXC_MAX_INT_LINES + 64 + }, + [3] = { + .chip.label = "gpio-3", + .base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR + 0x300), + .irq = GPIO_INT_PORTD, + .virtual_irq_start = MXC_MAX_INT_LINES + 96 + } +}; + +int __init mxc_register_gpios(void) +{ + return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports)); +} diff --git a/arch/arm/mach-mx1/devices.h b/arch/arm/mach-mx1/devices.h new file mode 100644 index 00000000000..408485b0acf --- /dev/null +++ b/arch/arm/mach-mx1/devices.h @@ -0,0 +1,2 @@ +extern struct platform_device imx_uart1_device; +extern struct platform_device imx_uart2_device; diff --git a/arch/arm/mach-mx1/generic.c b/arch/arm/mach-mx1/generic.c new file mode 100644 index 00000000000..0dec6f300ff --- /dev/null +++ b/arch/arm/mach-mx1/generic.c @@ -0,0 +1,43 @@ +/* + * 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/kernel.h> +#include <linux/init.h> +#include <linux/io.h> + +#include <asm/mach/map.h> + +#include <mach/hardware.h> + +static struct map_desc imx_io_desc[] __initdata = { + { + .virtual = IMX_IO_BASE, + .pfn = __phys_to_pfn(IMX_IO_PHYS), + .length = IMX_IO_SIZE, + .type = MT_DEVICE + } +}; + +void __init mxc_map_io(void) +{ + iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc)); +} diff --git a/arch/arm/mach-mx1/mx1ads.c b/arch/arm/mach-mx1/mx1ads.c new file mode 100644 index 00000000000..2e4b185fe4a --- /dev/null +++ b/arch/arm/mach-mx1/mx1ads.c @@ -0,0 +1,148 @@ +/* + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/imx-uart.h> +#include <mach/iomux-mx1-mx2.h> +#include "devices.h" + +/* + * UARTs platform data + */ +static int mxc_uart1_pins[] = { + PC9_PF_UART1_CTS, + PC10_PF_UART1_RTS, + PC11_PF_UART1_TXD, + PC12_PF_UART1_RXD, +}; + +static int uart1_mxc_init(struct platform_device *pdev) +{ + return mxc_gpio_setup_multiple_pins(mxc_uart1_pins, + ARRAY_SIZE(mxc_uart1_pins), "UART1"); +} + +static int uart1_mxc_exit(struct platform_device *pdev) +{ + mxc_gpio_release_multiple_pins(mxc_uart1_pins, + ARRAY_SIZE(mxc_uart1_pins)); + return 0; +} + +static int mxc_uart2_pins[] = { + PB28_PF_UART2_CTS, + PB29_PF_UART2_RTS, + PB30_PF_UART2_TXD, + PB31_PF_UART2_RXD, +}; + +static int uart2_mxc_init(struct platform_device *pdev) +{ + return mxc_gpio_setup_multiple_pins(mxc_uart2_pins, + ARRAY_SIZE(mxc_uart2_pins), "UART2"); +} + +static int uart2_mxc_exit(struct platform_device *pdev) +{ + mxc_gpio_release_multiple_pins(mxc_uart2_pins, + ARRAY_SIZE(mxc_uart2_pins)); + return 0; +} + +static struct imxuart_platform_data uart_pdata[] = { + { + .init = uart1_mxc_init, + .exit = uart1_mxc_exit, + .flags = IMXUART_HAVE_RTSCTS, + }, { + .init = uart2_mxc_init, + .exit = uart2_mxc_exit, + .flags = IMXUART_HAVE_RTSCTS, + }, +}; + +/* + * Physmap flash + */ + +static struct physmap_flash_data mx1ads_flash_data = { + .width = 4, /* bankwidth in bytes */ +}; + +static struct resource flash_resource = { + .start = IMX_CS0_PHYS, + .end = IMX_CS0_PHYS + SZ_32M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device flash_device = { + .name = "physmap-flash", + .id = 0, + .resource = &flash_resource, + .num_resources = 1, +}; + +/* + * Board init + */ +static void __init mx1ads_init(void) +{ + /* UART */ + mxc_register_device(&imx_uart1_device, &uart_pdata[0]); + mxc_register_device(&imx_uart2_device, &uart_pdata[1]); + + /* Physmap flash */ + mxc_register_device(&flash_device, &mx1ads_flash_data); +} + +static void __init mx1ads_timer_init(void) +{ + mxc_clocks_init(32000); + mxc_timer_init("gpt_clk"); +} + +struct sys_timer mx1ads_timer = { + .init = mx1ads_timer_init, +}; + +MACHINE_START(MX1ADS, "Freescale MX1ADS") + /* Maintainer: Sascha Hauer, Pengutronix */ + .phys_io = IMX_IO_PHYS, + .io_pg_offst = (IMX_IO_BASE >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x100, + .map_io = mxc_map_io, + .init_irq = mxc_init_irq, + .timer = &mx1ads_timer, + .init_machine = mx1ads_init, +MACHINE_END + +MACHINE_START(MXLADS, "Freescale MXLADS") + .phys_io = IMX_IO_PHYS, + .io_pg_offst = (IMX_IO_BASE >> 18) & 0xfffc, + .boot_params = PHYS_OFFSET + 0x100, + .map_io = mxc_map_io, + .init_irq = mxc_init_irq, + .timer = &mx1ads_timer, + .init_machine = mx1ads_init, +MACHINE_END diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index a1612958a59..16cb07cd916 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -6,6 +6,11 @@ choice prompt "MXC/iMX Base Type" default ARCH_MX3 +config ARCH_MX1 + bool "MX1-based" + help + This enables support for systems based on the Freescale i.MX1 family + config ARCH_MX2 bool "MX2-based" select CPU_ARM926T @@ -20,6 +25,7 @@ config ARCH_MX3 endchoice +source "arch/arm/mach-mx1/Kconfig" source "arch/arm/mach-mx2/Kconfig" source "arch/arm/mach-mx3/Kconfig" diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 067556f7c91..db74a929179 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -5,4 +5,5 @@ # Common support obj-y := irq.o clock.o gpio.o time.o devices.o +obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c index de5c4747453..ccbd94adc66 100644 --- a/arch/arm/plat-mxc/gpio.c +++ b/arch/arm/plat-mxc/gpio.c @@ -115,8 +115,8 @@ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) } } -#ifdef CONFIG_ARCH_MX3 -/* MX3 has one interrupt *per* gpio port */ +#if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX1) +/* MX1 and MX3 has one interrupt *per* gpio port */ static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc) { u32 irq_stat; @@ -237,7 +237,7 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt) /* its a serious configuration bug when it fails */ BUG_ON( gpiochip_add(&port[i].chip) < 0 ); -#ifdef CONFIG_ARCH_MX3 +#if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX1) /* setup one handler for each entry */ set_irq_chained_handler(port[i].irq, mx3_gpio_irq_handler); set_irq_data(port[i].irq, &port[i]); diff --git a/arch/arm/plat-mxc/include/mach/hardware.h b/arch/arm/plat-mxc/include/mach/hardware.h index 3caadeeda70..a612d8bb73c 100644 --- a/arch/arm/plat-mxc/include/mach/hardware.h +++ b/arch/arm/plat-mxc/include/mach/hardware.h @@ -32,6 +32,10 @@ # endif #endif +#ifdef CONFIG_ARCH_MX1 +# include <mach/mx1.h> +#endif + #include <mach/mxc.h> #endif /* __ASM_ARCH_MXC_HARDWARE_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/mx1.h b/arch/arm/plat-mxc/include/mach/mx1.h new file mode 100644 index 00000000000..e7f6d00009a --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/mx1.h @@ -0,0 +1,197 @@ +/* + * Copyright (C) 1997,1998 Russell King + * Copyright (C) 1999 ARM Limited + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (c) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> + * + * 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. + */ + +#ifndef __ASM_ARCH_MXC_MX1_H__ +#define __ASM_ARCH_MXC_MX1_H__ + +#ifndef __ASM_ARCH_MXC_HARDWARE_H__ +#error "Do not include directly." +#endif + +#include <mach/vmalloc.h> + +/* + * defines the hardware clock tick rate + */ +#define CLOCK_TICK_RATE 16000000 + +#define PHYS_OFFSET UL(0x08000000) + +/* + * Memory map + */ +#define IMX_IO_PHYS 0x00200000 +#define IMX_IO_SIZE 0x00100000 +#define IMX_IO_BASE VMALLOC_END + +#define IMX_CS0_PHYS 0x10000000 +#define IMX_CS0_SIZE 0x02000000 + +#define IMX_CS1_PHYS 0x12000000 +#define IMX_CS1_SIZE 0x01000000 + +#define IMX_CS2_PHYS 0x13000000 +#define IMX_CS2_SIZE 0x01000000 + +#define IMX_CS3_PHYS 0x14000000 +#define IMX_CS3_SIZE 0x01000000 + +#define IMX_CS4_PHYS 0x15000000 +#define IMX_CS4_SIZE 0x01000000 + +#define IMX_CS5_PHYS 0x16000000 +#define IMX_CS5_SIZE 0x01000000 + +/* + * Register BASEs, based on OFFSETs + */ +#define AIPI1_BASE_ADDR (0x00000 + IMX_IO_PHYS) +#define WDT_BASE_ADDR (0x01000 + IMX_IO_PHYS) +#define TIM1_BASE_ADDR (0x02000 + IMX_IO_PHYS) +#define TIM2_BASE_ADDR (0x03000 + IMX_IO_PHYS) +#define RTC_BASE_ADDR (0x04000 + IMX_IO_PHYS) +#define LCDC_BASE_ADDR (0x05000 + IMX_IO_PHYS) +#define UART1_BASE_ADDR (0x06000 + IMX_IO_PHYS) +#define UART2_BASE_ADDR (0x07000 + IMX_IO_PHYS) +#define PWM_BASE_ADDR (0x08000 + IMX_IO_PHYS) +#define DMA_BASE_ADDR (0x09000 + IMX_IO_PHYS) +#define AIPI2_BASE_ADDR (0x10000 + IMX_IO_PHYS) +#define SIM_BASE_ADDR (0x11000 + IMX_IO_PHYS) +#define USBD_BASE_ADDR (0x12000 + IMX_IO_PHYS) +#define SPI1_BASE_ADDR (0x13000 + IMX_IO_PHYS) +#define MMC_BASE_ADDR (0x14000 + IMX_IO_PHYS) +#define ASP_BASE_ADDR (0x15000 + IMX_IO_PHYS) +#define BTA_BASE_ADDR (0x16000 + IMX_IO_PHYS) +#define I2C_BASE_ADDR (0x17000 + IMX_IO_PHYS) +#define SSI_BASE_ADDR (0x18000 + IMX_IO_PHYS) +#define SPI2_BASE_ADDR (0x19000 + IMX_IO_PHYS) +#define MSHC_BASE_ADDR (0x1A000 + IMX_IO_PHYS) +#define CCM_BASE_ADDR (0x1B000 + IMX_IO_PHYS) +#define SCM_BASE_ADDR (0x1B804 + IMX_IO_PHYS) +#define GPIO_BASE_ADDR (0x1C000 + IMX_IO_PHYS) +#define EIM_BASE_ADDR (0x20000 + IMX_IO_PHYS) +#define SDRAMC_BASE_ADDR (0x21000 + IMX_IO_PHYS) +#define MMA_BASE_ADDR (0x22000 + IMX_IO_PHYS) +#define AVIC_BASE_ADDR (0x23000 + IMX_IO_PHYS) +#define CSI_BASE_ADDR (0x24000 + IMX_IO_PHYS) + +/* macro to get at IO space when running virtually */ +#define IO_ADDRESS(x) ((x) - IMX_IO_PHYS + IMX_IO_BASE) + +/* define macros needed for entry-macro.S */ +#define AVIC_IO_ADDRESS(x) IO_ADDRESS(x) + +/* fixed interrput numbers */ +#define INT_SOFTINT 0 +#define CSI_INT 6 +#define DSPA_MAC_INT 7 +#define DSPA_INT 8 +#define COMP_INT 9 +#define MSHC_XINT 10 +#define GPIO_INT_PORTA 11 +#define GPIO_INT_PORTB 12 +#define GPIO_INT_PORTC 13 +#define LCDC_INT 14 +#define SIM_INT 15 +#define SIM_DATA_INT 16 +#define RTC_INT 17 +#define RTC_SAMINT 18 +#define UART2_MINT_PFERR 19 +#define UART2_MINT_RTS 20 +#define UART2_MINT_DTR 21 +#define UART2_MINT_UARTC 22 +#define UART2_MINT_TX 23 +#define UART2_MINT_RX 24 +#define UART1_MINT_PFERR 25 +#define UART1_MINT_RTS 26 +#define UART1_MINT_DTR 27 +#define UART1_MINT_UARTC 28 +#define UART1_MINT_TX 29 +#define UART1_MINT_RX 30 +#define VOICE_DAC_INT 31 +#define VOICE_ADC_INT 32 +#define PEN_DATA_INT 33 +#define PWM_INT 34 +#define SDHC_INT 35 +#define I2C_INT 39 +#define CSPI_INT 41 +#define SSI_TX_INT 42 +#define SSI_TX_ERR_INT 43 +#define SSI_RX_INT 44 +#define SSI_RX_ERR_INT 45 +#define TOUCH_INT 46 +#define USBD_INT0 47 +#define USBD_INT1 48 +#define USBD_INT2 49 +#define USBD_INT3 50 +#define USBD_INT4 51 +#define USBD_INT5 52 +#define USBD_INT6 53 +#define BTSYS_INT 55 +#define BTTIM_INT 56 +#define BTWUI_INT 57 +#define TIM2_INT 58 +#define TIM1_INT 59 +#define DMA_ERR 60 +#define DMA_INT 61 +#define GPIO_INT_PORTD 62 +#define WDT_INT 63 + +#define MXC_MAX_INT_LINES 64 + +#define NR_IRQS 256 + +/* gpio and gpio based interrupt handling */ +#define GPIO_DR 0x1C +#define GPIO_GDIR 0x00 +#define GPIO_PSR 0x24 +#define GPIO_ICR1 0x28 +#define GPIO_ICR2 0x2C +#define GPIO_IMR 0x30 +#define GPIO_ISR 0x34 +#define GPIO_INT_LOW_LEV 0x3 +#define GPIO_INT_HIGH_LEV 0x2 +#define GPIO_INT_RISE_EDGE 0x0 +#define GPIO_INT_FALL_EDGE 0x1 +#define GPIO_INT_NONE 0x4 + +/* DMA */ +#define DMA_REQ_UART3_T 2 +#define DMA_REQ_UART3_R 3 +#define DMA_REQ_SSI2_T 4 +#define DMA_REQ_SSI2_R 5 +#define DMA_REQ_CSI_STAT 6 +#define DMA_REQ_CSI_R 7 +#define DMA_REQ_MSHC 8 +#define DMA_REQ_DSPA_DCT_DOUT 9 +#define DMA_REQ_DSPA_DCT_DIN 10 +#define DMA_REQ_DSPA_MAC 11 +#define DMA_REQ_EXT 12 +#define DMA_REQ_SDHC 13 +#define DMA_REQ_SPI1_R 14 +#define DMA_REQ_SPI1_T 15 +#define DMA_REQ_SSI_T 16 +#define DMA_REQ_SSI_R 17 +#define DMA_REQ_ASP_DAC 18 +#define DMA_REQ_ASP_ADC 19 +#define DMA_REQ_USP_EP(x) (20 + (x)) +#define DMA_REQ_SPI2_R 26 +#define DMA_REQ_SPI2_T 27 +#define DMA_REQ_UART2_T 28 +#define DMA_REQ_UART2_R 29 +#define DMA_REQ_UART1_T 30 +#define DMA_REQ_UART1_R 31 + +/* mandatory for CONFIG_LL_DEBUG */ +#define MXC_LL_UART_PADDR UART1_BASE_ADDR +#define MXC_LL_UART_VADDR IO_ADDRESS(UART1_BASE_ADDR) + +#endif /* __ASM_ARCH_MXC_MX1_H__ */ diff --git a/arch/arm/plat-mxc/include/mach/mxc_timer.h b/arch/arm/plat-mxc/include/mach/mxc_timer.h index 130aebfbe16..6c19a134744 100644 --- a/arch/arm/plat-mxc/include/mach/mxc_timer.h +++ b/arch/arm/plat-mxc/include/mach/mxc_timer.h @@ -26,7 +26,7 @@ #include <linux/clk.h> #include <mach/hardware.h> -#ifdef CONFIG_ARCH_IMX +#ifdef CONFIG_ARCH_MX1 #define TIMER_BASE IO_ADDRESS(TIM1_BASE_ADDR) #define TIMER_INTERRUPT TIM1_INT @@ -65,7 +65,7 @@ static void gpt_irq_acknowledge(void) { __raw_writel(0, TIMER_BASE + MXC_TSTAT); } -#endif /* CONFIG_ARCH_IMX */ +#endif /* CONFIG_ARCH_MX1 */ #ifdef CONFIG_ARCH_MX2 #define TIMER_BASE IO_ADDRESS(GPT1_BASE_ADDR) |